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

SQL Server 2005 の配列への SQL Server テーブルの結果

    実際には、関数を使用せずに、これをすべて 1 つの CTE 選択クエリで実行できます。方法は次のとおりです:

    まず、この親子テーブル構造を考えてみましょう:

    CREATE TABLE P (ID INT PRIMARY KEY, Description VARCHAR(20));
    CREATE TABLE C (ID INT PRIMARY KEY, PID INT, 
                    Description VARCHAR(20), 
                    CONSTRAINT fk FOREIGN KEY (PID) REFERENCES P(ID));
    

    (入力の手間を省くために P と C を使用しました!)

    そして、質問者のものと一致するいくつかのテストデータを追加しましょう:

    INSERT INTO P VALUES (36, 'Blah Blah');
    INSERT INTO P VALUES (20, 'Pah Pah');
    
    INSERT INTO C VALUES (1, 36, 'Bob');
    INSERT INTO C VALUES (2, 36, 'Gary');
    INSERT INTO C VALUES (3, 36, 'Reginald');
    INSERT INTO C VALUES (4, 20, 'Emily');
    INSERT INTO C VALUES (5, 20, 'Dave');
    

    そして最後に、CTE 式:

    WITH
    FirstItems (PID, FirstCID) AS (    
    
        SELECT C.PID, MIN(C.ID)
          FROM C
         GROUP BY C.PID      
    ),  
    SubItemList (PID, CID, ItemNum) AS (
    
        SELECT C.PID, C.ID, 1
          FROM C JOIN FirstItems FI ON (C.ID = FI.FirstCID)
        UNION ALL
        SELECT C.PID, C.ID, IL.ItemNum + 1
          FROM C JOIN SubItemList IL ON C.PID = IL.PID AND C.ID > CID
    ),
    ItemList (PID, CID, ItemNum) AS (
    
        SELECT PID, CID, MAX(ItemNum)
          FROM SubItemList
         GROUP BY PID, CID
    ),
    SubArrayList (PID, CID, Array, ItemNum) AS (
    
        SELECT IL.PID, IL.CID, CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
          FROM ItemList IL JOIN C ON IL.CID = C.ID
         WHERE IL.ItemNum = 1
        UNION ALL
        SELECT IL.PID, IL.CID, AL.Array + ',' + CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
          FROM ItemList IL
          JOIN SubArrayList AL ON (IL.PID = AL.PID AND IL.ItemNum = AL.ItemNum + 1)
          JOIN C ON (IL.CID = C.ID)
    ),
    MaxItems (PID, MaxItem) AS (
    
        SELECT PID, MAX(ItemNum)
          FROM SubItemList
         GROUP BY PID
    
    ),
    ArrayList (PID, List) AS (
    
        SELECT SAL.PID, SAL.Array
          FROM SubArrayList SAL 
          JOIN MaxItems MI ON (SAL.PID = MI.PID AND SAL.ItemNum = MI.MaxItem)
    
    )
    SELECT P.ID, P.Description, AL.List
      FROM ArrayList AL JOIN P ON P.ID = AL.PID
     ORDER BY P.ID
    

    結果:

    ID Description    List
    -- -------------- --------
    20 Pah Pah        Emily,Dave
    36 Blah Blah      Bob,Gary,Reginald   
    

    ここで何が起こっているかを説明するために、CTE の各部分とその機能について説明します。

    ファーストアイテム すべての子を見て、次の再帰 SELECT のアンカーとして使用する各親グループの最小 ID を見つけます:

    FirstItems (PID, FirstCID) AS (
        SELECT C.PID, MIN(C.ID)
          FROM C
         GROUP BY C.PID  
    )
    

    サブアイテム リスト 前のクエリから最下位の子を選択し、1 から始まる増分項目番号を各子に割り当てる再帰 SELECT です:

    SubItemList (PID, CID, ItemNum) AS (    
        SELECT C.PID, C.ID, 1
          FROM C JOIN FirstItems FI ON (C.ID = FI.FirstCID)
        UNION ALL
        SELECT C.PID, C.ID, IL.ItemNum + 1
          FROM C JOIN SubItemList IL ON C.PID = IL.PID AND C.ID > CID
    )
    

    問題は、多くのアイテムを複製して繰り返すことです。そのため、ItemList 各グループから最大値を選択するようにフィルタリングします:

    ItemList (PID, CID, ItemNum) AS (
    SELECT PID, CID, MAX(ItemNum)
      FROM SubItemList
     GROUP BY PID, CID
    )
    

    これで、1 から x までの番号が付けられたそれぞれの子を持つ親の ID リストができました:

    PID         CID         ItemNum
    ----------- ----------- -----------
    36          1           1
    36          2           2
    36          3           3
    20          4           1
    20          5           2
    

    SubArrayList 子行を取得し、数値リストに再帰的に結合し、単一の説明から始めて、すべての説明を相互に追加し始めます:

    SubArrayList (PID, CID, Array, ItemNum) AS (    
        SELECT IL.PID, IL.CID, CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
          FROM ItemList IL JOIN C ON IL.CID = C.ID
         WHERE IL.ItemNum = 1
        UNION ALL
        SELECT IL.PID, IL.CID, AL.Array + ',' + CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
          FROM ItemList IL
          JOIN SubArrayList AL ON (IL.PID = AL.PID AND IL.ItemNum = AL.ItemNum + 1)
          JOIN C ON (IL.CID = C.ID)
    )
    

    結果は次のとおりです:

    PID         CID         Array             ItemNum
    ----------- ----------- ----------------- -----------
    36          1           Bob               1
    20          4           Emily             1
    20          5           Emily,Dave        2
    36          2           Bob,Gary          2
    36          3           Bob,Gary,Reginald 3
    

    したがって、部分的に連結されたすべての行を取り除くだけで済みます。

    MaxItems 親のリストとそれらの最大アイテム番号を取得するだけで、次のクエリが少し簡単になります:

    MaxItems (PID, MaxItem) AS (    
        SELECT PID, MAX(ItemNum)
          FROM SubItemList
         GROUP BY PID        
    )
    

    配列リスト 前のクエリから取得した最大項目数を使用して、部分的に連結された行の最終カリングを実行します:

    ArrayList (PID, List) AS (
    SELECT SAL.PID, SAL.Array
      FROM SubArrayList SAL 
      JOIN MaxItems MI ON (SAL.PID = MI.PID AND SAL.ItemNum = MI.MaxItem)     
    )
    

    そして最後に、結果をクエリするだけです:

    SELECT P.ID, P.Description, AL.List
      FROM ArrayList AL JOIN P ON P.ID = AL.PID
     ORDER BY P.ID
    


    1. Selenium Scraper(Python)の使用中に%記号を削除する

    2. Mysqlは、情報スキーマの列照合と文字セットを変更します

    3. 接続をoracle.jdbc.OracleConnectionにキャストできません

    4. 2005/2008 の Sync SQL Logins ユーティリティ