ลำดับชั้นต้นไม้พ่อแม่และลูก


21

ฉันต้องติดตามข้อมูลใน SQL Server 2008 R2 SQLFiddle

schema:

สร้างตาราง [dbo] [ICFilters] (
   [ICFilterID] [int] ตัวตน (1,1) ไม่เป็นโมฆะ
   [ParentID] [int] ไม่เสียค่าเริ่มต้น 0
   [FilterDesc] [varchar] (50) ไม่เป็นโมฆะ
   [ใช้งาน] [tinyint] ไม่เป็นค่าเริ่มต้น 1
 CONSTRAINT [PK_ICFilters] คีย์หลักที่คลัสเตอร์ 
 ([ICFilterID] ASC) พร้อม 
    PAD_INDEX = ปิด
    STATISTICS_NORECOMPUTE = OFF
    IGNORE_DUP_KEY = ปิด
    ALLOW_ROW_LOCKS = เปิด
    ALLOW_PAGE_LOCKS = เปิด
 ) เปิด [หลัก]
) เปิด [หลัก]

INSERT INTO [dbo]. [ICFilters] (ParentID, FilterDesc, Active)
ค่า 
(0, 'ประเภทผลิตภัณฑ์', 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)

ตาราง:

| ICFILTERID | PARENTID | FILTERDESC | ใช้งานอยู่
--------------------------------------------------
| 1 | 0 | ประเภทสินค้า | 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 |

ทุกแถวมี ID ของพาเรนต์และรูparentid = 0FilterDescs เป็นคำอธิบายตัวอย่างเพียงดังนั้นฉันไม่สามารถพยายามที่จะแยกเหล่านั้นสำหรับการสั่งซื้อ

คำถาม

เป็นไปได้หรือไม่ที่จะเลือกแถวทั้งหมดในลักษณะเหมือนต้นไม้ ถ้าเป็นเช่นนั้นได้อย่างไร เมื่อฉันพูดว่า 'เหมือนต้นไม้' ฉันหมายถึงเลือกผู้ปกครองซ้ำแล้วตามด้วยลูกทั้งหมดของมันจากนั้นก็เป็นลูกของทุกคนในนั้น ความลึกของการสำรวจต้นไม้ครั้งแรก

เพื่อนของฉันและฉันได้ลอง แต่เราขาดวิธีการทำงาน แต่จะพยายามต่อไป ฉันค่อนข้างใหม่กับ sql ดังนั้นอาจจะสามารถทำได้อย่างง่ายดายและฉันแค่ทำสิ่งที่ยากกว่าที่จำเป็น

ตัวอย่างเอาต์พุต (ต้องการ):

| ICFILTERID | PARENTID | FILTERDESC | ใช้งานอยู่
--------------------------------------------------
| 1 | 0 | ประเภทสินค้า | 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 |

จะเป็นการดีที่สุดที่จะใช้ CTE
Kin Shah

1
นี่คือเธรดที่แสดงการเรียงลำดับผลลัพธ์ที่ต้องการโดยไม่ต้องโหลดข้อมูลตารางในลำดับใด ๆ มันใช้ row_number () และพาร์ทิชันโดยเพื่อสร้าง "เส้นทาง" ซึ่งช่วยให้การเรียงลำดับที่ต้องการ ask.sqlservercentral.com/questions/48518/…

คำตอบ:


25

ตกลงเซลล์สมองก็พอตายแล้ว

ซอ Fiddle

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
นี่คือสิ่งที่ฉันต้องการ! ฉันเห็นด้วยเซลล์สมองมากเกินไปเสียชีวิตในเรื่องนี้ ฉันไม่ชัดเจนในสิ่งที่ฉันต้องการหรือไม่ ถ้าเป็นเช่นนั้นฉันจะแก้ไขคำถามเพื่อใช้อ้างอิงในอนาคต ฉันทำให้มันยากกว่าที่คิดจะเป็น ...
Archangel33

1
@ Archangel33 คุณทำได้ดีในการวางประเด็นและสิ่งที่คุณต้องการ นอกจากนี้ sqlfiddle ช่วยได้จริงๆ
เทรวิส

2
+1 แต่การใช้ [ICFilterID] [int] IDENTITY (1,1) สำหรับการเรียงลำดับจะใช้งานได้เฉพาะไอเท็มที่ถูกแทรกในลำดับที่ถูกต้อง แต่ยังไม่มีการใช้ฟิลด์อื่นสำหรับการเรียงลำดับใน OT
bummi

4
ฉันไม่เชื่อว่านี่เป็นทางออกที่ถูกต้อง 100% ยากมากที่จะแสดงรายการแถวทั้งหมดที่มีระดับที่ถูกต้องในลำดับชั้น แต่จะไม่แสดงรายการตามลำดับที่คำถามถามให้เป็น เป็นไปได้ไหมที่จะแสดงรายการแถวตามลำดับที่ถูกต้องตามคำถาม? นั่นคือสิ่งที่ฉันกำลังมองหาเช่นกัน

1
สิ่งนี้จะตอบคำถามของฉันเนื่องจากข้อมูลที่ให้ไว้ใน[FilterDesc]คอลัมน์นั้นเป็นเรื่องโกหกและคำสั่งนั้นไม่จำเป็น / ไม่สำคัญ ต่อไปนี้ตรรกะในคำตอบ @Travis กานที่หนึ่งทุกคนจะต้องทำเพื่อให้ได้การสั่งซื้อนี้คือการเพิ่มอีกไปCAST Levelเช่น. จะกลายเป็นLevel + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS Level Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
Archangel33

1

ดูเหมือนว่าจะทำงานไม่ถูกต้องสำหรับฉัน ลองนึกภาพการตั้งค่า 2 ตารางพร้อมข้อมูลประเภท facebook ตารางที่ 1 มี PostId + คุณสาขาอื่น ๆ PostId เป็นการเพิ่มอัตโนมัติและเห็นได้ชัดในอินเทอร์เฟซของคุณคุณจะเรียงลำดับ DESC เพื่อให้มีการโพสต์ล่าสุดที่ด้านบน

ตอนนี้สำหรับตารางแสดงความคิดเห็น ตารางที่ 2 ตารางนี้ CommentId เป็นหมายเลขหลักหมายเลขอัตโนมัติ ใน gui ของคุณคุณต้องการแสดง ASC เพื่อให้เมื่ออ่านเธรด (เก่าที่สุด (จำนวนน้อยลง) ที่ด้านบน) คีย์สำคัญอื่น ๆ ในตารางที่ 2 คือ: PostId (FK กลับไปที่โพสต์) และ ParentId (FK ถึง CommentId) โดยที่ ParentId จะเป็น NULL หากนี่เป็นความคิดเห็น "root" ในโพสต์ หากมีคนตอบความคิดเห็นซ้ำ ๆ parentId จะถูกเติมด้วย commentid
หวังว่าพวกคุณจะได้รับสิ่งนี้ CTE จะมีลักษณะเช่นนี้:

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

ตัวอย่างผลลัพธ์

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

บนโพสต์ F / B 105 มีความคิดเห็นสองรายการ (ความคิดเห็น 1 และ 2) มีคนตอบกลับความคิดเห็น 1 (ความคิดเห็น 1 5, ผู้ปกครอง 1) จากนั้นมีคนอื่นแสดงความคิดเห็นต่อการตอบกลับนั้นดังนั้นในความคิดเห็น 5 (ความคิดเห็น 6 ผู้ปกครอง 6)

และวิโอลาลำดับนั้นถูกต้องภายใต้โพสต์ตอนนี้คุณสามารถแสดงความคิดเห็นในลำดับที่ถูกต้อง หากต้องการเยื้องข้อความเพื่อให้รูปแบบและเค้าโครงเหมือนใน Facebook (ยิ่งระดับยิ่งลึกยิ่งต้องทำให้ห่างจากด้านซ้ายมากขึ้น) ฉันยังมีคอลัมน์ที่เรียกว่าเยื้อง รากเป็น 0 และจากนั้นในสหภาพเรามี c.Indent + 1 AS เยื้องในรหัสตอนนี้คุณสามารถคูณการเยื้องด้วยให้สมมติ 32px และแสดงความคิดเห็นในลำดับชั้นที่ดีและร่าง

ฉันเห็นว่าไม่มีปัญหาในการใช้คีย์หลักที่เพิ่มขึ้นโดยอัตโนมัติ CommentId เป็นแรงผลักดันในการสร้าง SortKey ของฉันเนื่องจากมีการเปลี่ยนแปลงที่ดีขึ้นของคุณที่ทำวันที่ (commentdate) ดีกว่า messing up คีย์การจัดการฐานข้อมูลที่มี +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

สิ่งนี้จะให้ลูกหลานและระดับทั้งหมดให้กับคุณ
หวังว่าจะช่วย :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.