Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Hasil tabel SQL Server ke array di SQL Server 2005

Anda sebenarnya dapat melakukan ini semua dalam satu kueri pemilihan CTE, tanpa menggunakan fungsi apa pun. Begini caranya:

Pertama, pertimbangkan struktur tabel induk/anak ini:

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));

(Saya telah menggunakan P dan C untuk menghemat pengetikan!)

Dan mari tambahkan beberapa data pengujian, yang cocok dengan data penanya:

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');

Kemudian akhirnya, ekspresi 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

Hasil:

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

Untuk menjelaskan apa yang terjadi di sini, saya akan menjelaskan setiap bagian dari CTE dan fungsinya.

Item Pertama melihat semua anak, dan menemukan ID terendah di setiap grup induk untuk digunakan sebagai jangkar untuk SELECT rekursif berikutnya:

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

SubItemList adalah SELECT rekursif yang mengambil anak terendah dari kueri sebelumnya, dan mengalokasikan nomor item yang bertambah untuk setiap anak mulai dari 1:

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
)

Masalahnya adalah menduplikasi dan mengulang banyak item, jadi ItemList filter untuk hanya memilih maksimal dari setiap grup:

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

Sekarang kami memiliki daftar ID orang tua dengan masing-masing anak dinomori dari 1 hingga x:

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

SubArrayList mengambil baris anak-anak, bergabung secara rekursif ke daftar angka dan mulai menambahkan semua deskripsi satu sama lain, dimulai dengan satu deskripsi:

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)
)

Hasilnya sekarang:

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

Jadi yang perlu kita lakukan adalah menyingkirkan semua baris yang sebagian bersambung.

MaxItems cukup ambil daftar orang tua dan nomor item tertinggi mereka, yang membuat kueri berikut sedikit lebih sederhana:

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

Daftar Array melakukan pemusnahan terakhir dari sebagian baris yang digabungkan menggunakan nomor item maksimum yang diperoleh dari kueri sebelumnya:

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)     
)

Dan akhirnya, yang tersisa hanyalah menanyakan hasilnya:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara mereferensikan alias dalam klausa WHERE?

  2. Perbedaan antara numerik, float dan desimal di SQL Server

  3. Pengemudi tidak dapat membuat sambungan aman ke SQL Server dengan menggunakan enkripsi Secure Sockets Layer (SSL)

  4. Bagaimana cara menghapus tanda kutip ganda di sekitar teks saat mengimpor file CSV?

  5. Mendapatkan boolean dari tanggal dibandingkan di t-sql pilih