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

列に複数の値を持つテーブルに結合する方法は?

    "Arrays and Lists in SQL Server 2005 and Beyond, When Table値パラメータはカットしないでください" Erland Sommarskog 著 の場合、SQL Server で文字列を分割する方法は多数あります。この記事では、ほぼすべての方法の長所と短所について説明します。一般に、分割関数を作成する必要があります。これは、分割関数を使用して行を結合する方法です:

    SELECT
        * 
        FROM dbo.yourSplitFunction(@Parameter) b
            INNER JOIN YourCodesTable          c ON b.ListValue=c.CodeValue
    

    TSQL で文字列を分割する数値テーブル アプローチを好む ただし、SQL Server で文字列を分割する方法は多数あります。それぞれの長所と短所を説明している前のリンクを参照してください。

    Numbers Table メソッドを機能させるには、テーブル Numbers を作成するこの 1 回のテーブル設定を行う必要があります。 1 から 10,000 までの行を含む:

    SELECT TOP 10000 IDENTITY(int,1,1) AS Number
        INTO Numbers
        FROM sys.objects s1
        CROSS JOIN sys.objects s2
    ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
    

    Numbers テーブルを設定したら、次の分割関数を作成します:

    CREATE FUNCTION [dbo].[FN_ListToTable]
    (
         @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
        ,@List     varchar(8000)--REQUIRED, the list to split apart
    )
    RETURNS TABLE
    AS
    RETURN 
    (
    
        ----------------
        --SINGLE QUERY-- --this will not return empty rows
        ----------------
        SELECT
            ListValue
            FROM (SELECT
                      LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                      FROM (
                               SELECT @SplitOn + @List + @SplitOn AS List2
                           ) AS dt
                          INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                      WHERE SUBSTRING(List2, number, 1) = @SplitOn
                 ) dt2
            WHERE ListValue IS NOT NULL AND ListValue!=''
    
    );
    GO 
    

    CSV 文字列を簡単にテーブルに分割して結合できるようになりました:

    DECLARE @ErrorCode table (ErrorCode varchar(20), Description varchar(30))
    INSERT @ErrorCode VALUES ('001','Problem with person file')
    INSERT @ErrorCode VALUES ('002','Problem with address file')
    INSERT @ErrorCode VALUES ('003','Problem with grade')
    
    DECLARE @Person table (RecID int, ErrorCode varchar(20))
    INSERT @Person VALUES (12345 ,'001'    )
    INSERT @Person VALUES (12346 ,'003'    )
    INSERT @Person VALUES (12347 ,'002,003')
    
    
    SELECT
        p.RecID,c.ListValue,e.Description
        FROM @Person                                        p
            CROSS APPLY dbo.FN_ListToTable(',',p.ErrorCode) c
            INNER JOIN @ErrorCode                           e ON c.ListValue=e.ErrorCode
    

    出力:

    RecID       ListValue     Description              
    ----------- ------------- -------------------------
    12345       001           Problem with person file 
    12346       003           Problem with grade       
    12347       002           Problem with address file
    12347       003           Problem with grade       
    
    (4 row(s) affected)
    

    XML トリックを使用して、行を連結して戻すことができます:

    SELECT
        t1.RecID,t1.ErrorCode
            ,STUFF(
                       (SELECT
                            ', ' + e.Description
                            FROM @Person                                        p
                                CROSS APPLY dbo.FN_ListToTable(',',p.ErrorCode) c
                                INNER JOIN @ErrorCode                           e ON c.ListValue=e.ErrorCode
                            WHERE t1.RecID=p.RecID
                            ORDER BY p.ErrorCode
                            FOR XML PATH(''), TYPE
                       ).value('.','varchar(max)')
                       ,1,2, ''
                  ) AS ChildValues
        FROM @Person t1
        GROUP BY t1.RecID,t1.ErrorCode
    

    出力:

    RecID       ErrorCode            ChildValues
    ----------- -------------------- -----------------------------------------------
    12345       001                  Problem with person file
    12346       003                  Problem with grade
    12347       002,003              Problem with address file, Problem with grade
    
    (3 row(s) affected)
    

    これは上記と同じ結果セットを返しますが、パフォーマンスが向上する可能性があります:

    SELECT
        t1.RecID,t1.ErrorCode
            ,STUFF(
                       (SELECT
                            ', ' + e.Description
                            FROM (SELECT ListValue FROM dbo.FN_ListToTable(',',t1.ErrorCode)) c
                                INNER JOIN @ErrorCode e ON c.ListValue=e.ErrorCode
                            ORDER BY c.ListValue
                            FOR XML PATH(''), TYPE
                       ).value('.','varchar(max)')
                       ,1,2, ''
                  ) AS ChildValues
        FROM @Person t1
        GROUP BY t1.RecID,t1.ErrorCode
    


    1. MySQLの1つを除くすべての列を選択しますか?

    2. clearDBherokuデータベースへのリモート接続

    3. (psycopg2.DataError)整数の無効な入力構文:csvファイルからインポートしますか?

    4. 整数を文字列に変換して文字列の長さを取得する方法