Mysql
 sql >> Baza danych >  >> RDS >> Mysql

MySQL:łącz wiele stołów na jednej instrukcji

Jak pobrać wszystkich potomków z węzła drzewa za pomocą zapytania rekurencyjnego w MySql?

To naprawdę problem dla MySql i jest to kluczowy punkt tego pytania, ale nadal masz kilka możliwości.

Zakładając, że masz takie przykładowe dane, nie tyle, co próbka, ale wystarczająco dużo, aby zademonstrować:

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);

Pierwszy wybór:kod poziomu

Podobnie jak przykładowe dane kolumny nazwy w tabeli treeNode. (Nie wiem, jak to powiedzieć po angielsku, skomentuj mi poprawne wyrażenie level code .)

Aby pobrać wszystkich potomków C1 lub G1 może być tak proste:

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

Bardzo wolę to podejście, nawet musimy wygenerować ten kod przed zapisaniem treeNode w aplikacji. Będzie bardziej wydajne niż rekurencyjne zapytanie lub procedura, gdy mamy dużą liczbę rekordów. Myślę, że to dobre podejście do denormalizacji.

Przy takim podejściu oświadczenie chcesz z dołączeniem może być:

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

Słodko, prawda?

Drugi wybór:numer poziomu

Dołącz kolumnę poziomu do tabeli treeNode, jak pokazano w DDL.

Numer poziomu jest znacznie łatwiejszy w utrzymaniu niż kod poziomu w aplikacji.

Z numerem poziomu, aby uzyskać wszystkich potomków C1 lub G1 potrzebujesz takiej sztuczki:

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) ;

To podejście jest wolniejsze niż pierwsze, ale wciąż szybsze niż zapytanie rekurencyjne.

Pominięto pełny sql do pytania. Wystarczy zastąpić te dwa podzapytania C i G dwoma powyższymi zapytaniami.

Uwaga:

Istnieje wiele podobnych podejść, takich jak tutaj , tutaj , a nawet tutaj . Nie będą działać, jeśli nie zostaną uporządkowane według numeru poziomu lub kodu poziomu. Możesz przetestować ostatnie zapytanie w tym SqlFiddle zmieniając order by level do order by id aby zobaczyć różnice.

Inny wybór:model zestawu zagnieżdżonego

Proszę odnieść się do tego bloga , jeszcze nie testowałem. Ale myślę, że jest podobny do dwóch ostatnich wyborów.

Musisz dodać lewą i prawą liczbę do tabeli treenode, aby zawrzeć między nimi wszystkie identyfikatory potomków.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kolejność zagnieżdżenia SQL według?

  2. Policz liczbę odrębnych wierszy dla wielu wartości

  3. Zwróć klucz obcy za pomocą zapytania DQL

  4. Uzyskaj maksymalną długość dozwoloną w kolumnie, mysql

  5. MYSQL Konwertuj znacznik czasu na miesiąc