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

Sắp xếp cây con trong cấu trúc dữ liệu phân cấp bảng đóng

Câu hỏi này xuất hiện thường xuyên không chỉ đối với Bảng đóng mà còn đối với các phương pháp lưu trữ dữ liệu phân cấp khác. Nó không dễ dàng trong bất kỳ thiết kế nào.

Giải pháp mà tôi đã đưa ra cho Bảng đóng cửa liên quan đến một phép nối bổ sung. Mọi nút trong cây đều tham gia vào chuỗi tổ tiên của nó, giống như một truy vấn kiểu "breadcrumbs". Sau đó, sử dụng GROUP_CONCAT () để thu gọn breadcrumbs thành một chuỗi được phân tách bằng dấu phẩy, sắp xếp các số id theo độ sâu trong cây. Bây giờ bạn có một chuỗi để bạn có thể sắp xếp.

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(breadcrumb.ancestor ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,3         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,3,4       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,3,7       |
|  6 | Cat 1.2    |      1 |       1 | 1,6         |
+----+------------+--------+---------+-------------+

Lưu ý:

  • Các giá trị id phải có độ dài đồng nhất, vì việc sắp xếp "1,3" và "1,6" và "1,327" có thể không đưa ra thứ tự bạn muốn. Nhưng sắp xếp "001,003" và "001,006" và "001,327" sẽ. Vì vậy, bạn cần bắt đầu các giá trị id của mình ở 1000000+ hoặc nếu không, hãy sử dụng ZEROFILL cho tổ tiên và con cháu trong bảng Category_closure.
  • Trong giải pháp này, thứ tự hiển thị phụ thuộc vào thứ tự số của id danh mục. Thứ tự số của các giá trị id có thể không đại diện cho thứ tự bạn muốn hiển thị cây. Hoặc bạn có thể muốn tự do thay đổi thứ tự hiển thị bất kể giá trị id số. Hoặc bạn có thể muốn dữ liệu danh mục giống nhau xuất hiện trong nhiều cây, mỗi cây có thứ tự hiển thị khác nhau.
    Nếu bạn cần tự do hơn, bạn cần lưu trữ các giá trị thứ tự sắp xếp riêng biệt với id và giải pháp sẽ thậm chí còn phức tạp hơn. Tuy nhiên, trong hầu hết các dự án, có thể chấp nhận sử dụng short-cut, làm nhiệm vụ kép của id danh mục làm thứ tự hiển thị cây.

Nhận xét lại của bạn:

Có, bạn có thể lưu trữ "thứ tự sắp xếp anh chị em" dưới dạng một cột khác trong bảng đóng, sau đó sử dụng giá trị đó thay vì ancestor để xây dựng chuỗi breadcrumbs. Nhưng nếu bạn làm điều đó, bạn sẽ có rất nhiều dữ liệu dư thừa. Có nghĩa là, một tổ tiên nhất định được lưu trữ trên nhiều hàng, một cho mỗi đường đi xuống từ nó. Vì vậy, bạn phải lưu trữ cùng một giá trị cho thứ tự sắp xếp anh chị em trên tất cả các hàng đó, điều này gây ra nguy cơ bất thường.

Cách thay thế sẽ là tạo một bảng khác, chỉ có một hàng cho mỗi tổ tiên riêng biệt trong cây và tham gia vào bảng đó để nhận thứ tự anh chị em.

CREATE TABLE category_closure_order (
  ancestor INT PRIMARY KEY,
  sibling_order SMALLINT UNSIGNED NOT NULL DEFAULT 1
);

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(o.sibling_order ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
JOIN category_closure_order AS o ON breadcrumb.ancestor = o.ancestor
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,1         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,1,1       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,1,2       |
|  6 | Cat 1.2    |      1 |       1 | 1,2         |
+----+------------+--------+---------+-------------+



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. LỖI 1045 (28000):Quyền truy cập bị từ chối đối với người dùng 'root' @ 'localhost' (sử dụng mật khẩu:KHÔNG)

  2. Cách viết truy vấn HQL JOIN cho nhiều Cột đã chọn của bảng bằng cách sử dụng Khối mã lệnh trong Mệnh đề Chọn

  3. Bất ngờ đạt đến giới hạn bộ nhớ PHP chỉ với một truy vấn PDO?

  4. Nhận ngày gần nhất từ ​​bảng MySQL

  5. 2 Hàm trả về Tên tháng từ Ngày trong MySQL