sql >> データベース >  >> RDS >> Sqlserver

カンマ区切りのデータ列を結合する

    理想的には、最善の解決策は、コンマ区切りのリストを保存しないようにTable2を正規化することです。

    このデータを正規化すると、データを簡単にクエリできます。新しいテーブル構造は次のようになります:

    CREATE TABLE T1
    (
      [col1] varchar(2), 
      [col2] varchar(5),
      constraint pk1_t1 primary key (col1)
    );
    
    INSERT INTO T1
        ([col1], [col2])
    VALUES
        ('C1', 'john'),
        ('C2', 'alex'),
        ('C3', 'piers'),
        ('C4', 'sara')
    ;
    
    CREATE TABLE T2
    (
      [col1] varchar(2), 
      [col2] varchar(2),
      constraint pk1_t2 primary key (col1, col2),
      constraint fk1_col2 foreign key (col2) references t1 (col1)
    );
    
    INSERT INTO T2
        ([col1], [col2])
    VALUES
        ('R1', 'C1'),
        ('R1', 'C2'),
        ('R1', 'C4'),
        ('R2', 'C3'),
        ('R2', 'C4'),
        ('R3', 'C1'),
        ('R3', 'C4')
    ;
    

    テーブルを正規化すると、テーブルを結合してデータをクエリするのがはるかに簡単になります。

    select t2.col1, t1.col2
    from t2
    inner join t1
      on t2.col2 = t1.col1
    

    デモを見る

    次に、データをコンマ区切りのリストとして表示する場合は、FOR XML PATHを使用できます。 およびSTUFF

    select distinct t2.col1, 
      STUFF(
             (SELECT distinct ', ' + t1.col2
              FROM t1
              inner join t2 t
                on t1.col1 = t.col2
              where t2.col1 = t.col1
              FOR XML PATH ('')), 1, 1, '') col2
    from t2;
    

    デモをご覧ください。

    データを正規化できない場合は、いくつかの方法があります。

    まず、リストに格納されているデータを結合可能な行に変換する分割関数を作成できます。分割関数は次のようになります:

    CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
    returns @temptable TABLE (items varchar(MAX))       
    as       
    begin      
        declare @idx int       
        declare @slice varchar(8000)       
    
        select @idx = 1       
            if len(@String)<1 or @String is null  return       
    
        while @idx!= 0       
        begin       
            set @idx = charindex(@Delimiter,@String)       
            if @idx!=0       
                set @slice = left(@String,@idx - 1)       
            else       
                set @slice = @String       
    
            if(len(@slice)>0)  
                insert into @temptable(Items) values(@slice)       
    
            set @String = right(@String,len(@String) - @idx)       
            if len(@String) = 0 break       
        end   
    return 
    end;
    

    split、functionを使用する場合、データを複数の行に残すか、値をコンマ区切りのリストに連結して戻すことができます。

    ;with cte as
    (
      select c.col1, t1.col2
      from t1
      inner join 
      (
        select t2.col1, i.items col2
        from t2
        cross apply dbo.split(t2.col2, ',') i
      ) c
        on t1.col1 = c.col2
    ) 
    select distinct c.col1, 
      STUFF(
             (SELECT distinct ', ' + c1.col2
              FROM cte c1
              where c.col1 = c1.col1
              FOR XML PATH ('')), 1, 1, '') col2
    from cte c
    

    デモをご覧ください。

    結果を得る最後の方法は、FOR XML PATHを適用することです。 直接。

    select col1, 
    (
      select ', '+t1.col2
      from t1
      where ','+t2.col2+',' like '%,'+cast(t1.col1 as varchar(10))+',%'
      for xml path(''), type
    ).value('substring(text()[1], 3)', 'varchar(max)') as col2
    from t2;
    

    SQL Fiddle with Demo

    を参照してください

    1. OracleでSYSDATEのUTC値を取得する方法

    2. MySQLまたはMariaDBデータベースをエクスポートする

    3. ケーススタディ:ARKWARE MS ACCESS CRM

    4. 巨大なテーブルの列タイプを変更する