Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

MySQL:nối nhiều bảng trên một câu lệnh

Làm cách nào để lấy tất cả con cháu từ một nút cây bằng truy vấn đệ quy trong MySql?

Đó thực sự là một vấn đề đối với MySql và đó là điểm mấu chốt của câu hỏi này, nhưng bạn vẫn có một số lựa chọn.

Giả sử bạn có dữ liệu mẫu như vậy, không nhiều bằng mẫu của bạn nhưng đủ để chứng minh:

create table treeNode(
id int, parent_id  int,  name varchar(10), type varchar(10),level int);
insert into treeNode 
(id, parent_id, name, type, level) values 
( 1,  0,  'C1    ', 'CATEGORY', 1),
( 2,  1,  'C1.1  ', 'CATEGORY', 2),
( 3,  2,  'C1.1.1', 'CATEGORY', 3),
( 4,  1,  'C1.2  ', 'CATEGORY', 2),
( 5,  4,  'C1.2.1', 'CATEGORY', 3),
( 3,  8,  'G1.1.1',    'GROUP', 3),
( 4,  9,  'G1.2  ',    'GROUP', 2),
( 5,  4,  'G1.2.1',    'GROUP', 3),
( 8,  9,  'G1.1  ',    'GROUP', 2),
( 9,  0,  'G1    ',    'GROUP', 1);

Lựa chọn đầu tiên: mã cấp

Giống như dữ liệu mẫu của cột tên trong bảng treeNode. ( Tôi không biết phải nói thế nào bằng tiếng Anh, hãy bình luận cho tôi về cách diễn đạt đúng của level code .)

Để nhận tất cả các con của C1 hoặc G1 có thể đơn giản như thế này:

select * from treeNode where type = 'CATEGORY' and name like 'C1%' ;
select * from treeNode where type = 'GROUP' and name like 'G1%' ;

Tôi rất thích cách tiếp cận này, thậm chí cần chúng tôi tạo những đoạn mã này trước khi treeNode được lưu trong ứng dụng. Nó sẽ hiệu quả hơn truy vấn hoặc thủ tục đệ quy khi chúng ta có số lượng lớn các bản ghi. Tôi nghĩ đây là một cách tiếp cận không chuẩn hóa tốt.

Với cách tiếp cận này, tuyên bố bạn muốn với tham gia có thể là:

SELECT distinct p.* --if there is only one tree node for a product, distinct is not needed
FROM product p
JOIN product_type pt
     ON pt.id= p.parent_id -- to get product type of a product
JOIN linked_TreeNode LC
     ON LC.product_id= p.id -- to get tree_nodes related to a product
JOIN (select * from treeNode where type = 'CATEGORY' and name like 'C1%' ) C --may replace C1% to concat('$selected_cat_name','%')
     ON LC.treeNode_id = C.id
JOIN (select * from treeNode where type = 'GROUP' and name like 'G1%' ) G --may replace G1% to concat('$selected_group_name','%')
     ON LC.treeNode_id = G.id
WHERE pt.name = '$selected_type'  -- filter selected product type, assuming using product.name, if using product.parent_id, can save one join by pt like your original sql

Ngọt ngào phải không?

Lựa chọn thứ hai:số cấp

Nối cột mức vào bảng treeNode, như được hiển thị trong DDL.

Số cấp dễ duy trì hơn nhiều so với mã cấp trong ứng dụng.

Với số cấp để nhận tất cả các con của C1 hoặc G1 cần một mẹo nhỏ như sau:

SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids 
  FROM (select * from treeNode where type = 'CATEGORY' order by level) as t
  JOIN (select @pv:='1')tmp
 WHERE find_in_set(parent_id,@pv)
    OR find_in_set(id,@pv);
 -- get all descendants of `C1`

SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids 
  FROM (select * from treeNode where type = 'GROUP' order by level) as t
  JOIN (select @pv:=',9,')tmp
 WHERE find_in_set(parent_id,@pv)
    OR find_in_set(id,@pv) ;

Cách tiếp cận này chậm hơn cách tiếp cận đầu tiên, nhưng vẫn nhanh hơn truy vấn đệ quy.

Đã bỏ qua sql đầy đủ cho câu hỏi. Chỉ cần thay thế hai truy vấn con C và G bằng hai truy vấn trên.

Lưu ý:

Có nhiều cách tiếp cận tương tự như tại đây , tại đây hoặc thậm chí tại đây . Chúng sẽ không hoạt động trừ khi được sắp xếp theo số cấp hoặc mã cấp. Bạn có thể kiểm tra truy vấn cuối cùng trong SqlFiddle này bằng cách thay đổi order by level đến order by id để thấy sự khác biệt.

Lựa chọn khác:Mô hình tập hợp lồng nhau

Vui lòng tham khảo blog này , Tôi đã không thử nghiệm được nêu ra. Nhưng tôi nghĩ nó tương tự như hai lựa chọn cuối cùng.

Bạn cần thêm một số bên trái và một số bên phải vào bảng treenode để bao gồm tất cả các id của con cháu giữa chúng.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chèn cùng một giá trị cố định vào nhiều hàng

  2. jQuery Xác thực cách sử dụng phương pháp từ xa để kiểm tra xem tên người dùng đã tồn tại chưa

  3. Làm cách nào để tạo nhóm kết nối mysql bằng công cụ asadmin trong máy chủ GlassFish?

  4. Hiển thị số hàng trùng lặp

  5. Laravel Ngày so sánh thường xuyên từ trường datetime