sql >> Database teknologi >  >> RDS >> Mysql

MySQL:slutte sig til mange tabeller på én erklæring

Hvordan får man alle efterkommere fra en træknude med rekursiv forespørgsel i MySql?

Det er virkelig et problem for MySql, og det er et nøglepunkt i dette spørgsmål, men du har stadig nogle valgmuligheder.

Hvis du antager, at du har sådanne prøvedata, ikke så meget som din prøve, men nok til at demonstrere:

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ørstevalg:niveaukode

Ligesom eksempeldataene for navnekolonnen i treeNode-tabellen. (Jeg ved ikke, hvordan man siger det på engelsk, kommenter mig om det korrekte udtryk for level code .)

For at få alle efterkommere af C1 eller G1 kunne være enkelt sådan her:

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

Jeg foretrækker denne tilgang meget, har endda brug for, at vi genererer denne kode, før treeNode gemmes i applikationen. Det vil være mere effektivt end rekursiv forespørgsel eller procedure, når vi har et stort antal poster. Jeg synes, det er en god denormaliseringstilgang.

Med denne tilgang, erklæringen du ønsker med join kunne være:

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ødt, ikke?

Andet valg:niveaunummer

Tilføj en niveaukolonne til treeNode-tabellen, som vist i DDL.

Niveaunummer er meget nemmere at vedligeholde end niveaukode i ansøgning.

Med niveaunummer for at få alle efterkommere af C1 eller G1 brug for et lille trick som dette:

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

Denne tilgang er langsommere end den første, men stadig hurtigere end rekursiv forespørgsel.

Den fulde sql til spørgsmålet er udeladt. Behøver kun at erstatte de to underforespørgsler af C og G med to forespørgsler ovenfor.

Bemærk:

Der er mange lignende tilgange såsom her , her , eller endda her . De virker ikke, medmindre de er bestilt efter niveaunummer eller niveaukode. Du kan teste den sidste forespørgsel i denne SqlFiddle ved at ændre order by level for at order by id for at se forskellene.

Et andet valg:The Nested Set Model

Henvis venligst til denne blog , jeg har ikke testet endnu. Men jeg tror, ​​det ligner sidste to valg.

Det skal du tilføje et venstre tal og et højre tal til trænode-tabellen for at omslutte alle efterkommeres id'er mellem dem.



  1. spring jpa application.properties useSSL

  2. Indsæt sætning med hvor klausul ikke kører på nodejs mysql

  3. Hvordan vælger man rækker med 4-byte UTF-8-tegn i Oracle DB?

  4. Få fat i data fra MySQL ved hjælp af PHP i realtid?