Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Bảng SQL Server kết quả thành mảng trong SQL Server 2005

Bạn thực sự có thể thực hiện tất cả trong một truy vấn chọn CTE mà không cần sử dụng bất kỳ chức năng nào. Đây là cách thực hiện:

Trước tiên, hãy xem xét cấu trúc bảng cha / con này:

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

(Tôi sử dụng P và C để tiết kiệm khi nhập!)

Và cho phép thêm một số dữ liệu thử nghiệm, khớp với dữ liệu của người đặt câu hỏi:

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

Cuối cùng, biểu thức 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

Kết quả:

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

Để giải thích những gì đang diễn ra ở đây, tôi sẽ mô tả từng phần của CTE và chức năng của nó.

FirstItems xem xét tất cả các nhóm con và tìm ID thấp nhất trong mỗi nhóm mẹ để sử dụng làm neo cho SELECT đệ quy tiếp theo:

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

Danh sách phụ là một SELECT đệ quy chọn con thấp nhất từ ​​truy vấn trước đó và phân bổ số mục tăng dần cho mỗi con bắt đầu từ 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
)

Rắc rối là nó đổ đầy và lặp lại rất nhiều mục, vì vậy Danh sách mục lọc nó để chỉ chọn giá trị tối đa từ mỗi nhóm:

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

Bây giờ chúng tôi có một danh sách ID của các bậc cha mẹ với mỗi đứa trẻ trong số đó được đánh số từ 1 đến x:

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

Danh sách con lấy các hàng con, tham gia đệ quy vào danh sách số và bắt đầu nối tất cả các mô tả với nhau, bắt đầu bằng một mô tả duy nhất:

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

Kết quả bây giờ là:

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

Vì vậy, tất cả những gì chúng ta cần làm là loại bỏ tất cả các hàng được nối một phần.

MaxItems chỉ cần lấy danh sách các bậc cha mẹ và số mục cao nhất của họ, điều này làm cho truy vấn sau đây đơn giản hơn một chút:

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

ArrayList thực hiện việc sắp xếp cuối cùng của các hàng được nối một phần bằng cách sử dụng số mục tối đa có được từ truy vấn trước đó:

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

Và cuối cùng, tất cả những gì còn lại là truy vấn kết quả:

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. Câu lệnh SQL try-catch không xử lý được lỗi (SQL Server 2008)

  2. Hết thời gian truy vấn từ ứng dụng web nhưng chạy tốt từ studio quản lý

  3. Tính toán giá trị bằng cách sử dụng giá trị trước đó của một hàng trong T-SQL

  4. Truy vấn SQL cho chuỗi cha-con

  5. Tại sao quyền đặt lại tempdb của tôi khi máy chủ được khởi động lại?