Thứ tự phân cấp cây mẹ-con


21

Tôi phải theo dõi dữ liệu trong SQL Server 2008 R2. SQLFiddle

Lược đồ:

TẠO BẢNG [dbo]. [ICFilters] (
   [ICFilterID] [int] IDENTITY (1,1) KHÔNG PHẢI,
   [ParentID] [int] KHÔNG NULL DEFAULT 0,
   [FilterDesc] [varchar] (50) KHÔNG NULL,
   [Hoạt động] [tinyint] KHÔNG NULL DEFAULT 1,
 CONSTRAINT [PK_ICFilters] KHÓA CHÍNH XÁC 
 ([ICFilterID] ASC) VỚI 
    PAD_INDEX = TẮT,
    STATISTICS_NORECOMPUTE = TẮT,
    IGNORE_DUP_KEY = TẮT,
    ALLOW_law_LOCKS = BẬT,
    ALLOW_PAGE_LOCKS = BẬT
 ) TRÊN [CHÍNH HÃNG]
) TRÊN [CHÍNH HÃNG]

XÁC NHẬN VÀO [dbo]. [ICFilters] (ParentID, FilterDesc, Active)
Giá trị 
(0, Type Loại sản phẩm ', 1),
(1, 'ProdSubType_1', 1),
(1, 'ProdSubType_2', 1),
(1, 'ProdSubType_3', 1),
(1, 'ProdSubType_4', 1),
(2, 'PST_1.1', 1),
(2, 'PST_1.2', 1),
(2, 'PST_1.3', 1),
(2, 'PST_1.4', 1),
(2, 'PST_1.5', 1),
(2, 'PST_1.6', 1),
(2, 'PST_1.7', 0),
(3, 'PST_2.1', 1),
(3, 'PST_2.2', 0),
(3, 'PST_2.3', 1),
(3, 'PST_2.4', 1),
(14, 'PST_2.2.1', 1),
(14, 'PST_2.2.2', 1),
(14, 'PST_2.2.3', 1),
(3, 'PST_2.8', 1)

Bàn:

| ICFILTERID | PHỤ HUYNH | BỘ LỌC | HOẠT ĐỘNG |
--------------------------------------------------
| 1 | 0 | Loại sản phẩm | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 3 | 1 | ProdSubType_2 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 20 | 3 | PST_2.8 | 1 |

Mỗi hàng có ID của cha mẹ và gốc parentid = 0. Các FilterDescchỉ là mô tả mẫu vì vậy tôi không thể cố phân tích chúng để đặt hàng.

Câu hỏi

Có thể chọn tất cả các hàng theo cách giống như cây không? Nếu vậy thì thế nào? Khi tôi nói 'giống như cây', tôi có nghĩa là chọn đệ quy cha mẹ theo sau bởi tất cả các con của nó, sau đó tất cả con của mỗi một trong số chúng và cứ thế. Một chiều sâu cây đầu tiên đi qua.

Bạn bè của tôi và tôi đã cố gắng nhưng chúng tôi đã thiếu các giải pháp làm việc nhưng sẽ tiếp tục cố gắng. Tôi còn khá mới với sql nên có lẽ điều này có thể được thực hiện dễ dàng và tôi chỉ làm mọi thứ khó khăn hơn mức cần thiết.

Ví dụ (mong muốn) đầu ra:

| ICFILTERID | PHỤ HUYNH | BỘ LỌC | HOẠT ĐỘNG |
--------------------------------------------------
| 1 | 0 | Loại sản phẩm | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 3 | 1 | ProdSubType_2 | 1 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 20 | 3 | PST_2.8 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |

Tốt nhất nên sử dụng CTE
Kin Shah

1
Đây là một chủ đề hiển thị sắp xếp kết quả mong muốn mà không cần phải tải dữ liệu bảng theo bất kỳ thứ tự cụ thể nào. Nó sử dụng row_number () và phân vùng bằng cách tạo một "đường dẫn" cho phép sắp xếp mong muốn. hỏi.sqlservercentral.com/questions/48518/ Lần

Câu trả lời:


25

OK, đủ tế bào não đã chết.

Câu đố SQL

WITH cte AS
(
  SELECT 
    [ICFilterID], 
    [ParentID],
    [FilterDesc],
    [Active],
    CAST(0 AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters]
  WHERE [ParentID] = 0
  UNION ALL
  SELECT 
    i.[ICFilterID], 
    i.[ParentID],
    i.[FilterDesc],
    i.[Active],  
    Level + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters] i
  INNER JOIN cte c
    ON c.[ICFilterID] = i.[ParentID]
)

SELECT 
  [ICFilterID], 
  [ParentID],
  [FilterDesc],
  [Active]
FROM cte
ORDER BY [Level];

2
Đây chính xác là những gì tôi cần! Tôi đồng ý quá nhiều tế bào não đã chết về điều này. Tôi đã không rõ ràng trong những gì tôi muốn? Nếu vậy tôi sẽ chỉnh sửa câu hỏi để tham khảo trong tương lai. Tôi chắc chắn đã làm cho nó trở nên khó khăn hơn mức cần thiết ...
Archangel33

1
@ Archangel33 Bạn đã làm tốt công việc đặt ra vấn đề và những gì bạn cần. Thêm vào đó, sqlfiddle thực sự hữu ích.
Travis

2
+1 nhưng sử dụng [ICFilterID] [int] IDENTITY (1,1) để sắp xếp sẽ chỉ hoạt động, các mục được chèn theo trình tự chính xác, nhưng một trường khác để sắp xếp chưa được thực hiện bởi OT
bummi

4
Tôi không tin rằng đây là một giải pháp chính xác 100%. Mặc dù khó khăn, nó liệt kê tất cả các hàng với cấp chính xác của chúng trong hệ thống phân cấp, nó không liệt kê nó theo thứ tự câu hỏi yêu cầu chúng. Có thể liệt kê các hàng theo đúng thứ tự theo câu hỏi không? Đó là những gì tôi đang tìm kiếm quá.

1
Điều này không trả lời câu hỏi của tôi vì dữ liệu được cung cấp trong [FilterDesc]cột là hư cấu và thứ tự đó là không cần thiết / không quan trọng. Theo logic trong câu trả lời của @Travis Gan, tất cả những gì phải làm để có được thứ tự này là thêm một thứ khác CASTvào Level. ví dụ. Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS LevelTrở thành Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level.
Archangel33

1

Ở trên dường như không hoạt động chính xác cho tôi. Hãy tưởng tượng một thiết lập 2 bảng với loại dữ liệu facebook. Bảng 1, có PostId + các trường khác. PostId là tự động tăng và rõ ràng trong giao diện của bạn, bạn sẽ sắp xếp DESC để có bài đăng mới nhất ở trên cùng.

Bây giờ cho bảng ý kiến. Bảng 2 Bảng này CommentId là khóa chính, số tự động. Trong gui của bạn, bạn muốn hiển thị ASC, để khi đọc chủ đề, nó có ý nghĩa. (cũ nhất (số nhỏ hơn) ở trên cùng) Các khóa quan trọng khác trong bảng 2 là: PostId (FK trở lại bài đăng) và ParentId (FK to CommentId) trong đó ParentId sẽ là NULL nếu đây là nhận xét "gốc" trên Bài đăng. Nếu ai đó TRẢ LỜI trên một bình luận, thì ParentId sẽ được điền với bình luận.
Hy vọng các bạn có được sự trôi dạt. CTE sẽ trông như thế này:

WITH  Comments
        AS ( SELECT  CommentId , ParentId, CAST(CommentId AS VARBINARY(MAX)) AS Sortkey, 0 AS Indent
             FROM    dbo.Comments
             WHERE   ParentId IS NULL AND PostId = 105
             UNION ALL
             SELECT  b.CommentId , b.ParentId,  c.Sortkey + CAST(b.CommentId AS varbinary(max))  AS Sortkey, c.Indent + 1 AS Indent
             FROM    dbo.Comments b
             INNER JOIN Comments c ON c.CommentId = b.ParentId
           )
   SELECT   *
   FROM     Comments
   ORDER BY Sortkey

Sản lượng mẫu

1   NULL    0x0000000000000001  0
5   1   0x00000000000000010000000000000001  1
6   5   0x000000000000000100000000000000010000000000000005  2
2   NULL    0x0000000000000002  0

Trên bài đăng F / B 105, có hai bình luận (CommentIds 1 và 2) Sau đó, một người nào đó đã trả lời trên Comment1 (CommentId 5, ParentId 1), và sau đó một người khác đã nhận xét về câu trả lời đó, vì vậy trên Comment5 (CommentId 6, ParentId 6)

Và viola, trình tự là chính xác, dưới bài đăng, bây giờ bạn có thể hiển thị các ý kiến ​​theo đúng trình tự. Để thụt lề các bài đăng để nó hình thành và phác thảo như trong facebook (cấp độ càng sâu, nó càng phải được đặt lề bên trái), tôi cũng có một cột có tên là Indent. Các gốc là 0 và sau đó trong liên kết, chúng ta có mã centent + 1 AS AS, giờ đây bạn có thể nhân số thụt lề với giả sử 32px, và hiển thị các nhận xét theo thứ bậc và phác thảo đẹp.

Tôi thấy không có vấn đề gì khi sử dụng khóa chính tăng tự động CommentId làm động lực cho việc xây dựng SortKey của tôi, vì có một sự thay đổi tốt hơn về việc bạn làm xáo trộn ngày (bình luận) hơn là làm rối khóa cơ sở dữ liệu được quản lý bằng +1


0
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
insert into pc values('b','f');
insert into pc values('a','d');
Insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');

 DECLARE @parent varchar(10) = 'a';
 WITH cte AS
 (
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
  FROM pc a JOIN cte c ON a.parent = c.child
  )
  SELECT distinct parent, child , level
  FROM cte
  order by level, parent

Điều này sẽ cung cấp cho bạn tất cả con cháu và cấp độ.
Hi vọng điêu nay co ich :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.