sql >> Databasteknik >  >> RDS >> Mysql

MySQL:gå med i många bord på ett uttalande

Hur får man alla ättlingar från en trädnod med rekursiv fråga i MySql?

Det är verkligen ett problem för MySql, och det är en nyckelfråga i den här frågan, men du har fortfarande några valmöjligheter.

Förutsatt att du har sådana exempeldata, inte lika mycket som ditt prov men tillräckligt för att visa:

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

Första val:nivåkod

Som exempeldata för namnkolumnen i treeNode-tabellen. (Jag vet inte hur man säger det på engelska, kommentera mig om det korrekta uttrycket för level code .)

För att få alla ättlingar till C1 eller G1 kan vara enkelt så här:

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

Jag föredrar detta tillvägagångssätt mycket, behöver till och med att vi genererar denna kod innan treeNode sparas i applikationen. Det kommer att vara mer effektivt än rekursiv fråga eller procedur när vi har ett stort antal poster. Jag tror att detta är ett bra denormaliseringssätt.

Med detta tillvägagångssätt, påståendet du vill med join kan vara:

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öt, eller hur?

Andra val:nivånummer

Lägg till en nivåkolumn till treeNode-tabellen, som visas i DDL.

Nivånummer är mycket lättare att underhålla än nivåkod i ansökan.

Med nivånummer för att få alla ättlingar till C1 eller G1 behöver ett litet trick som detta:

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

Detta tillvägagångssätt är långsammare än det första, men fortfarande snabbare än rekursiv fråga.

Hela sql till frågan har utelämnats. Behöver bara ersätta dessa två underfrågor av C och G med två frågor ovan.

Obs!

Det finns många liknande tillvägagångssätt som här , här , eller till och med här . De fungerar inte om de inte beställs efter nivånummer eller nivåkod. Du kan testa den sista frågan i denna SqlFiddle genom att ändra order by level för att order by id för att se skillnaderna.

Ett annat val:The Nested Set Model

Vänligen hänvisa till den här bloggen , jag har inte testat ännu. Men jag tror att det liknar de två senaste valen.

Det behöver du lägga till ett vänsternummer och ett högernummer i treenode-tabellen för att omsluta alla ättlingars ID mellan dem.



  1. Variabel i SQL -> FEL PLS-00103:Påträffade symbolen SELECT

  2. php infoga flera rader i MYSQL-databasen

  3. Returnera alla filgrupper för den aktuella databasen i SQL Server

  4. Hierarkisk rekursionsmeny med PHP/MySQL