2012-05-11 27 views
7

Tôi có 2 bảng. itemsitemItemsCó thể viết truy vấn SQLite đệ quy nhận tất cả các mục là mục con của nút gốc

itemItems mô tả mối quan hệ nhiều đến nhiều giữa items. I E. thành viên của items có thể có nhiều trẻ em và họ có thể có nhiều trẻ em từ đó có thể có nhiều trẻ em vv ..

mục:

itemID | more stuff ...... 
1   ...  
2   ... 
3   ... 
4   ... 

itemItems:

parentItemID | childItemID 
1    2 
1    3 
2    4 

Tôi muốn viết một truy vấn mà đệ quy sẽ nhận được tất cả các trẻ em dưới một nút gốc.

Tôi tin rằng điều này là có thể với một cái gì đó gọi là đệ quy tham gia nhưng tôi thấy khái niệm rất khó hiểu .... (tương tự như this câu hỏi, nhưng với sqlite máy chủ không sql và nhiều nhiều không phải là người nhiều)

tôi có thể nhận được mức độ đầu tiên (tức là tất cả trẻ em dưới một mục) bằng cách làm như sau

SELECT * 
FROM items 
INNER JOIN itemItems 
ON items.itemID = itemItems.childItemID 
WHERE itemItems.parentItemID = 1 

làm thế nào tôi có thể mở rộng này để đệ quy có được tất cả trẻ em dành cho trẻ em vv ...?

Trả lời

8

Tôi vừa có một truy vấn tương tự để làm việc sử dụng cú pháp with recursive. Dạng chung là:

with recursive tc(i) 
    as (select [... initial-query ...] 
     union [... recursive-part (include tc) ...] 
    ) 
select * from tc; 

Chìa khóa trong trường hợp của tôi là đảm bảo rằng tc được liệt kê trong phần đệ quy. Ngoài ra, lựa chọn cuối cùng này chỉ để hiển thị toàn bộ nội dung của việc đóng cửa chuyển tiếp, người thực sự nên chọn các hàng bạn cần.

Tôi nghĩ rằng công thức này sẽ áp dụng cho trường hợp của bạn như sau. Tôi đã không thử nghiệm này, tôi chỉ cần sao chép/dán từ truy vấn của tôi và thay thế bằng tên bảng của bạn. Nó làm việc cho tôi, nhưng tôi có thể đã dịch nó không chính xác. Tôi cũng không thực sự chắc chắn về hiệu quả, vv, nó chỉ là một cái gì đó mà tôi đã làm việc.

with recursive tc(i) 
    as (select childItemID from itemItems where parentItemID = 1 
     union select childItemID from itemItems, tc 
       where itemItems.parentItemID = tc.i 
    ) 
    select * from item where itemID in tc; 

LƯU Ý: Tính năng này làm việc cho tôi trên phiên bản 3.8.3.1 nhưng không hoạt động trên 3.7.2.

+0

Văn bản xung quanh khu vực này https://sqlite.org/lang_with.html#rcex1 hữu ích khi làm việc, đặc biệt là phần "Ví dụ truy vấn phân cấp". Ngoài ra http://www.sitepoint.com/hierarchical-data-database cho khái niệm chung. –

+1

@AndrewEidsness Làm thế nào để làm cho nó hoạt động trong 3.7.2? – kiran

1

Phiên bản đệ quy trên yêu cầu ANSI SQL: 1999 được hỗ trợ bởi DBMS chung trong những ngày đó, nhưng cũng có một phương pháp ANSI SQL-92 để đạt được bị chặn đệ quy. Cách tiếp cận này có thể được mở rộng tùy ý.

Ví dụ dưới đây hỗ trợ tối đa 7 cấp. Nếu bạn muốn nhiều hơn, hãy thêm nhiều hơn nữa.

SELECT DISTINCT 
    I.* 
FROM 
    item I INNER JOIN (
     SELECT 
      I1.itemID as Level1, 
      I2.itemID as Level2, 
      I3.itemID as Level3, 
      I4.itemID as Level4, 
      I5.itemID as Level5, 
      I6.itemID as Level6, 
      I7.itemID as Level7 
     FROM 
      item I1 LEFT JOIN 
      item I2 ON EXISTS (SELECT NULL FROM itemItems II1 WHERE II1.parentItemID = I1.itemID AND I2.itemID = II1.childItemID) LEFT JOIN 
      item I3 ON EXISTS (SELECT NULL FROM itemItems II2 WHERE II2.parentItemID = I2.itemID AND I3.itemID = II2.childItemID) LEFT JOIN 
      item I4 ON EXISTS (SELECT NULL FROM itemItems II3 WHERE II3.parentItemID = I3.itemID AND I4.itemID = II3.childItemID) LEFT JOIN 
      item I5 ON EXISTS (SELECT NULL FROM itemItems II4 WHERE II4.parentItemID = I4.itemID AND I5.itemID = II4.childItemID) LEFT JOIN 
      item I6 ON EXISTS (SELECT NULL FROM itemItems II5 WHERE II5.parentItemID = I5.itemID AND I6.itemID = II5.childItemID) LEFT JOIN 
      item I7 ON EXISTS (SELECT NULL FROM itemItems II6 WHERE II6.parentItemID = I6.itemID AND I7.itemID = II6.childItemID) 
     WHERE 
      I1.itemID = 1 -- root node condition 
    ) D ON I.itemID = D.Level1 OR I.itemID = D.Level2 OR I.itemID = D.Level3 OR I.itemID = D.Level4 OR I.itemID = D.Level5 OR I.itemID = D.Level6 Or I.itemID = D.Level7 
Các vấn đề liên quan