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

Ngăn kết nối vòng tròn, tìm kiếm đệ quy

Nếu bạn sử dụng MySQL 8.0 hoặc MariaDB 10.2 (hoặc cao hơn) bạn có thể thử CTE đệ quy (biểu thức bảng phổ biến) .

Giả sử lược đồ và dữ liệu sau:

CREATE TABLE `list_relation` (
  `child_id`  int unsigned NOT NULL,
  `parent_id` int unsigned NOT NULL,
  PRIMARY KEY (`child_id`,`parent_id`)
);
insert into list_relation (child_id, parent_id) values
    (2,1),
    (3,1),
    (4,2),
    (4,3),
    (5,3);

Bây giờ bạn thử chèn một hàng mới với child_id = 1parent_id = 4 . Nhưng điều đó sẽ tạo ra các quan hệ tuần hoàn ( 1-> 4-> 2-> 1 1-> 4-> 3-> 1 ), mà bạn muốn ngăn chặn. Để tìm hiểu xem mối quan hệ ngược đã tồn tại chưa, bạn có thể sử dụng truy vấn sau, truy vấn này sẽ hiển thị tất cả các bậc cha mẹ của danh sách 4 (bao gồm cả cha mẹ thừa kế / lai):

set @new_child_id  = 1;
set @new_parent_id = 4;

with recursive rcte as (
  select *
  from list_relation r
  where r.child_id = @new_parent_id
  union all
  select r.*
  from rcte
  join list_relation r on r.child_id = rcte.parent_id
)
select * from rcte

Kết quả sẽ là:

child_id | parent_id
       4 |         2
       4 |         3
       2 |         1
       3 |         1

Bản trình diễn

Bạn có thể thấy trong kết quả, danh sách 1 là một trong những bậc cha mẹ của danh sách 4 và bạn sẽ không chèn bản ghi mới.

Vì bạn chỉ muốn biết nếu danh sách 1 là kết quả, bạn có thể thay đổi dòng cuối cùng thành

select * from rcte where parent_id = @new_child_id limit 1

hoặc để

select exists (select * from rcte where parent_id = @new_child_id)

BTW:Bạn có thể sử dụng cùng một truy vấn để ngăn các quan hệ thừa. Giả sử bạn muốn chèn bản ghi với child_id = 4parent_id = 1 . Điều này sẽ là thừa, vì danh sách 4 đã kế thừa danh sách 1 qua danh sách 2 danh sách 3 . Truy vấn sau sẽ cho bạn thấy rằng:

set @new_child_id  = 4;
set @new_parent_id = 1;

with recursive rcte as (
  select *
  from list_relation r
  where r.child_id = @new_child_id
  union all
  select r.*
  from rcte
  join list_relation r on r.child_id = rcte.parent_id
)
select exists (select * from rcte where parent_id = @new_parent_id)

Và bạn có thể sử dụng một truy vấn tương tự để nhận tất cả các mục được kế thừa:

set @list = 4;

with recursive rcte (list_id) as (
  select @list
  union distinct
  select r.parent_id
  from rcte
  join list_relation r on r.child_id = rcte.list_id
)
select distinct i.*
from rcte
join item i on i.list_id = rcte.list_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. MySQL:Cắt ngắn Bảng so với Xóa khỏi Bảng

  2. Sự cố với các ký tự cyrillic trong url thân thiện

  3. Cách tạo API đồ thị không máy chủ cho MySQL, Postgres và Aurora

  4. Tìm kiếm toàn văn bản trên mysql với một từ gồm 3 chữ cái

  5. Thiết kế cơ sở dữ liệu để phát triển ứng dụng web 'Quiz' bằng PHP và MySQL