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

Tôi nên sử dụng mô hình phân cấp nào? Liền kề, Lồng nhau hay Được liệt kê?

Thông thường, có ba loại truy vấn trong phân cấp gây ra sự cố:

  1. Trả lại tất cả tổ tiên
  2. Trả lại tất cả các con cháu
  3. Trả lại tất cả các con (con cháu trực tiếp).

Đây là một bảng nhỏ hiển thị hiệu suất của các phương thức khác nhau trong MySQL :

                        Ancestors  Descendants  Children        Maintainability InnoDB
Adjacency list          Good       Decent       Excellent       Easy            Yes
Nested sets (classic)   Poor       Excellent    Poor/Excellent  Very hard       Yes
Nested sets (spatial)   Excellent  Very good    Poor/Excellent  Very hard       No
Materialized path       Excellent  Very good    Poor/Excellent  Hard            Yes

Trong children , poor/excellent có nghĩa là câu trả lời phụ thuộc vào việc bạn có đang trộn phương thức với danh sách kề hay không, i. e. lưu trữ parentID trong mỗi bản ghi.

Đối với nhiệm vụ của mình, bạn cần cả ba truy vấn:

  1. Tất cả tổ tiên để chỉ cho Trái đất / Vương quốc Anh / Devon vật
  2. Tất cả trẻ em để hiển thị "Các điểm đến ở Châu Âu" (các mục)
  3. Tất cả các phần tử con để hiển thị "Các điểm đến ở Châu Âu" (số lượng)

Tôi sẽ đi theo những con đường cụ thể hóa, vì loại thứ bậc này hiếm khi thay đổi (chỉ trong trường hợp chiến tranh, nổi dậy, v.v.).

Tạo một cột varchar có tên là path , lập chỉ mục nó và điền vào nó với giá trị như sau:

1:234:6345:45454:

trong đó các số là khóa chính của cha mẹ thích hợp, theo đúng thứ tự (1 đối với Châu Âu, 234 cho Vương quốc Anh, v.v.)

Bạn cũng sẽ cần một bảng có tên là levels để giữ các số từ 1 thành 20 (hoặc bất kỳ mức lồng ghép tối đa nào bạn muốn).

Để chọn tất cả tổ tiên:

SELECT   pa.*
FROM     places p
JOIN     levels l
ON       SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN     places pa
ON       pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':') 
WHERE    p.id = @id_of_place_in_devon

Để chọn tất cả trẻ em và số lượng địa điểm trong chúng:

SELECT  pc.*, COUNT(pp.id)
FROM    places p
JOIN    places pc
ON      pc.parentId = p.id
JOIN    places pp
ON      pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
        AND pp.id NOT IN
        (
        SELECT  parentId
        FROM    places
        )
WHERE   p.id = @id_of_europe
GROUP BY
        pc.id


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bảng MySQL của Schrödingers:tồn tại, nhưng nó không

  2. Lỗi MYSQL:1045 (28000):Quyền truy cập bị từ chối đối với người dùng 'root' @ 'localhost'

  3. Spring Mvc Hibernate Encoding / Multi-line import sql

  4. SQLSTATE [HY000] [2002] php_network_getaddresses:getaddrinfo không thành công:Không xác định được tên hoặc dịch vụ

  5. MySQL Trigger chỉ sau khi cập nhật nếu hàng đã thay đổi