Giải pháp tôi đề xuất ở đây sử dụng khái niệm con đường vật chất hóa. Sau đây là một ví dụ về các đường dẫn cụ thể hóa bằng cách sử dụng dữ liệu mẫu của bạn. Tôi hy vọng nó sẽ giúp bạn hiểu khái niệm đường dẫn cụ thể hóa:
+----+--------------------------+----------+------------------+
| ID | Name | ParentID | MaterializedPath |
+----+--------------------------+----------+------------------+
| 1 | Parent 1 | 0 | 1 |
| 2 | Parent 2 | 0 | 2 |
| 4 | Parent 2 Child 1 | 2 | 2.4 |
| 6 | Parent 2 Child 1 Child 1 | 4 | 2.4.6 |
| 7 | Parent 2 Child 1 Child 2 | 4 | 2.4.7 |
| 3 | Parent 1 Child 1 | 1 | 1.3 |
| 5 | Parent 1 Child 1 Child | 3 | 1.3.5 |
+----+--------------------------+----------+------------------+
Mỗi nút N
có một đường dẫn cụ thể hóa, đường dẫn này cho bạn biết cách đi từ nút gốc đến nút N
. Nó có thể được xây dựng nối các id của nút. Ví dụ:để đến nút 5
bắt đầu từ nút gốc của nó, bạn truy cập vào nút 1
, nút 3
và nút 5
, vì vậy nút 5
đường dẫn cụ thể hóa là 1.3.5
Thật trùng hợp, thứ tự bạn đang tìm kiếm có thể đạt được thứ tự bằng con đường cụ thể hóa.
Trong ví dụ trước, các đường dẫn cụ thể hóa là các chuỗi nối liền nhau, nhưng tôi thích nối nhị phân hơn vì một số lý do.
Để xây dựng các đường dẫn cụ thể hóa, bạn cần CTE đệ quy sau:
CREATE TABLE Tree
(
ID int NOT NULL CONSTRAINT PK_Tree PRIMARY KEY,
Name nvarchar(250) NOT NULL,
ParentID int NOT NULL,
)
INSERT INTO Tree(ID, Name, ParentID) VALUES
(1, 'Parent 1', 0),
(2, 'Parent 2', 0),
(3, 'Parent 1 Child 1', 1),
(4, 'Parent 2 Child 1', 2),
(5, 'Parent 1 Child 1 Child', 3),
(6, 'Parent 2 Child 1 Child 1', 4),
(7, 'Parent 2 Child 1 Child 2', 4)
GO
WITH T AS
(
SELECT
N.ID, N.Name, N.ParentID, CAST(N.ID AS varbinary(512)) AS MaterializedPath
FROM
Tree N
WHERE
N.ParentID = 0
UNION ALL
SELECT
N.ID, N.Name, N.ParentID, CAST( T.MaterializedPath + CAST(N.ID AS binary(4)) AS varbinary(512) ) AS MaterializedPath
FROM
Tree N INNER JOIN T
ON N.ParentID = T.ID
)
SELECT *
FROM T
ORDER BY T.MaterializedPath
Kết quả:
+----+--------------------------+----------+----------------------------+
| ID | Name | ParentID | MaterializedPath |
+----+--------------------------+----------+----------------------------+
| 1 | Parent 1 | 0 | 0x00000001 |
| 3 | Parent 1 Child 1 | 1 | 0x0000000100000003 |
| 5 | Parent 1 Child 1 Child | 3 | 0x000000010000000300000005 |
| 2 | Parent 2 | 0 | 0x00000002 |
| 4 | Parent 2 Child 1 | 2 | 0x0000000200000004 |
| 6 | Parent 2 Child 1 Child 1 | 4 | 0x000000020000000400000006 |
| 7 | Parent 2 Child 1 Child 2 | 4 | 0x000000020000000400000007 |
+----+--------------------------+----------+----------------------------+
CTE đệ quy ở trên bắt đầu với các nút gốc. Việc tính toán đường dẫn cụ thể hóa cho một nút gốc rất đơn giản, đó là ID của chính nút đó. Trong lần lặp tiếp theo, CTE kết hợp các nút gốc với các nút con của nó. Đường dẫn cụ thể hóa cho nút con CN
là sự kết hợp của đường dẫn cụ thể hóa của nút cha của nó PN
và id của nút CN
. Các lần lặp tiếp theo tiến xuống một cấp trên cây cho đến khi đạt đến các nút lá.