ORDER Hirarki Pohon Orangtua-Anak

21

Saya harus mengikuti data dalam SQL Server 2008 R2. SQLFiddle

Skema:

CREATE TABLE [dbo]. [ICFilters] (
   [ICFilterID] [int] IDENTITY (1,1) TIDAK NULL,
   [ParentID] [int] BUKAN NULL DEFAULT 0,
   [FilterDesc] [varchar] (50) BUKAN NULL,
   [Aktif] [tinyint] BUKAN NULL DEFAULT 1,
 CONSTRAINT [PK_ICFilters] PRIMARY KEY CLUSTERED 
 ([ICFilterID] ASC) DENGAN 
    PAD_INDEX = MATI,
    STATISTICS_NORECOMPUTE = MATI,
    IGNORE_DUP_KEY = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON
 ) ON [PRIMARY]
) ON [PRIMARY]

Masukkan ke [dbo]. [ICFilters] (ParentID, FilterDesc, Aktif)
Nilai-nilai 
(0, 'Jenis Produk', 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)

Meja:

| ICFILTERID | PARENTID | FILTERDESC | AKTIF |
--------------------------------------------------
| 1 | 0 | Jenis Produk | 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 |

Setiap baris memiliki ID induknya dan root parentid = 0. The FilterDescs adalah deskripsi hanya sampel jadi saya tidak bisa mencoba untuk mengurai mereka untuk pemesanan.

Pertanyaan

Apakah mungkin untuk memilih semua baris dengan cara seperti pohon? Jika ya, bagaimana caranya? Ketika saya mengatakan 'seperti pohon', maksud saya secara rekursif memilih orang tua diikuti oleh semua anak-anaknya, lalu semua anak dari masing-masing dari mereka dan seterusnya. Traversal pohon pertama Kedalaman.

Teman-teman saya dan saya telah mencoba tetapi kami gagal dalam solusi kerja tetapi akan terus berusaha. Saya cukup baru untuk sql jadi mungkin ini bisa dilakukan dengan mudah dan saya hanya membuat segalanya lebih sulit dari yang diperlukan.

Contoh (diinginkan) output:

| ICFILTERID | PARENTID | FILTERDESC | AKTIF |
--------------------------------------------------
| 1 | 0 | Jenis Produk | 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 |
Malaikat Agung33
sumber
Akan lebih baik menggunakan CTE
Kin Shah
1
Berikut adalah utas yang menunjukkan penyortiran hasil yang diinginkan tanpa data tabel yang harus dimuat dalam urutan tertentu. Ia menggunakan row_number () dan partisi by untuk membuat "path" yang memungkinkan penyortiran yang diinginkan. ask.sqlservercentral.com/questions/48518/…

Jawaban:

25

OK, cukup sel-sel otak yang mati.

SQL 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];
Travis
sumber
2
Inilah yang saya butuhkan! Saya Setuju terlalu banyak sel otak yang mati dalam hal ini. Apakah saya tidak jelas dengan apa yang saya inginkan? Jika demikian, saya akan mengedit pertanyaan untuk referensi di masa mendatang. Saya pasti membuatnya lebih sulit daripada yang seharusnya ...
Archangel33
1
@ Archangel33 Anda melakukan pekerjaan yang baik dengan mengeluarkan masalah dan apa yang Anda butuhkan. Plus, sqlfiddle sangat membantu.
Travis
2
+1 tetapi menggunakan [ICFilterID] [int] IDENTITY (1,1) untuk menyortir hanya akan berfungsi jika item dimasukkan dalam urutan yang benar, tetapi bidang lain untuk menyortir belum diterapkan oleh OT
bummi
4
Saya tidak percaya bahwa ini adalah solusi yang 100% benar. Meskipun sulit, daftar semua baris dengan tingkat yang benar dalam hierarki, tidak mencantumkannya dalam urutan pertanyaan yang diminta. Apakah mungkin untuk membuat daftar baris dalam urutan yang benar sesuai pertanyaan? Itulah yang saya cari juga.
1
Ini menjawab pertanyaan saya karena data yang disediakan di [FilterDesc]kolom adalah fiktif dan urutan itu tidak perlu / tidak penting. Mengikuti logika dalam jawaban @Travis Gan yang harus dilakukan seseorang untuk mendapatkan pemesanan ini adalah menambahkan yang lain CASTke Level. misalnya. Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS LevelMenjadi Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level.
Archangel33
1

Di atas sepertinya tidak berfungsi dengan benar untuk saya. Bayangkan pengaturan 2 tabel dengan tipe data facebook. Tabel 1, memiliki PostId + Anda bidang lainnya. PostId adalah kenaikan otomatis dan jelas di antarmuka Anda, Anda akan mengurutkan DESC untuk memiliki posting terbaru di bagian atas.

Sekarang untuk tabel komentar. Tabel 2 Tabel ini CommentId adalah kunci utama, nomor otomatis. Di gui Anda, Anda ingin menampilkannya ASC, sehingga saat membaca utas, masuk akal. (tertua (angka lebih kecil) di bagian atas) Kunci penting lainnya dalam tabel 2 adalah: PostId (FK kembali ke posting), dan ParentId (FK ke CommentId) di mana ParentId akan NULL jika ini adalah "root" komentar pada sebuah Post. Jika seseorang MEMBalas komentar, maka parentId akan diisi dengan commentid tersebut.
Semoga kalian mengerti. CTE akan terlihat seperti ini:

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

Output sampel

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

Pada F / B posting 105, ada dua komentar (CommentIds 1 dan 2) Seseorang kemudian menjawab pada Comment1 (CommentId 5, ParentId 1), dan kemudian orang lain mengomentari jawaban itu, begitu juga dengan Comment5 (CommentId 6, ParentId 6)

Dan viola, urutannya benar, di bawah pos, Anda sekarang dapat menampilkan komentar dalam urutan yang benar. Untuk membuat indentasi posting sehingga terbentuk dan garis besar seperti di facebook (semakin dalam levelnya, semakin harus dibatasi dari kiri), saya juga memiliki kolom yang disebut Indent. Akarnya 0 dan kemudian di dalam serikat, kita memiliki c.Indent + 1 AS Indent Dalam kode, kamu sekarang dapat melipatgandakan indentasi dengan anggap 32px, dan tampilkan komentar dalam hierarki dan garis besar yang bagus.

Saya melihat tidak ada masalah menggunakan CommentId kunci primer kenaikan otomatis sebagai kekuatan pendorong untuk membangun SortKey saya, karena ada perubahan yang lebih baik dari Anda mengacaukan tanggal (commentdate) daripada mengacaukan kunci basis data yang dikelola yang menghasilkan +1.

Guss Davey
sumber
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

Ini akan memberi Anda semua keturunan dan level.
Semoga ini membantu :)

Wohoooo
sumber