Til MySQL 8+: brug den rekursive med
syntaks.
For MySQL 5.x: bruge inline-variabler, sti-id'er eller selv-joins.
MySQL 8+
with recursive cte (id, name, parent_id) as (
select id,
name,
parent_id
from products
where parent_id = 19
union all
select p.id,
p.name,
p.parent_id
from products p
inner join cte
on p.parent_id = cte.id
)
select * from cte;
Værdien angivet i parent_id =19
skal indstilles til id
af den forælder, du vil vælge alle efterkommere af.
MySQL 5.x
For MySQL-versioner, der ikke understøtter almindelige tabeludtryk (op til version 5.7), vil du opnå dette med følgende forespørgsel:
select id,
name,
parent_id
from (select * from products
order by parent_id, id) products_sorted,
(select @pv := '19') initialisation
where find_in_set(parent_id, @pv)
and length(@pv := concat(@pv, ',', id))
Her er en violin .
Her er værdien angivet i @pv :='19'
skal indstilles til id
af den forælder, du vil vælge alle efterkommere af.
Dette vil også fungere, hvis en forælder har flere børn. Det er dog påkrævet, at hver post opfylder betingelsen parent_id
Variable tildelinger i en forespørgsel
Denne forespørgsel bruger specifik MySQL-syntaks:variabler tildeles og ændres under udførelsen. Nogle antagelser er lavet om rækkefølgen af udførelse:
fra klausul vurderes først. Så det er her @pv
bliver initialiseret.-
hvor klausulen evalueres for hver post i rækkefølgen for hentning fra fra
aliaser. Så det er her, en betingelse sættes til kun at inkludere poster, for hvilke forælderen allerede var identificeret som værende i efterkommertræet (alle efterkommere af den primære forælder tilføjes gradvist til@pv
). - Betingelserne i denne
hvor
klausulen evalueres i rækkefølge, og evalueringen afbrydes, når det samlede resultat er sikkert. Derfor skal den anden betingelse være på andenpladsen, da den tilføjerid
til forældrelisten, og dette bør kun ske, hvisid
opfylder den første betingelse.længden
funktionen kaldes kun for at sikre, at denne betingelse altid er sand, selv hvispv
streng ville af en eller anden grund give en falsk værdi.
Alt i alt kan man finde disse antagelser for risikable til at stole på. dokumentationen advarer:
du får muligvis de resultater, du forventer, men dette er ikke garanteret [...] rækkefølgen af evaluering for udtryk, der involverer brugervariable, er udefineret.
Så selvom det fungerer i overensstemmelse med ovenstående forespørgsel, kan evalueringsrækkefølgen stadig ændre sig, for eksempel når du tilføjer betingelser eller bruger denne forespørgsel som en visning eller underforespørgsel i en større forespørgsel. Det er en "funktion", som vil blive fjernet i en fremtid MySQL-udgivelse :
Tidligere udgivelser af MySQL gjorde det muligt at tildele en værdi til en brugervariabel i andre sætninger end SET
. Denne funktionalitet understøttes i MySQL 8.0 for bagudkompatibilitet, men kan fjernes i en fremtidig udgivelse af MySQL.
Som nævnt ovenfor skal du fra MySQL 8.0 og fremefter bruge den rekursive with
syntaks.
Effektivitet
For meget store datasæt kan denne løsning blive langsom, da find_in_set
operation er ikke den mest ideelle måde at finde et tal på en liste på, bestemt ikke på en liste, der når en størrelse i samme størrelsesorden som antallet af returnerede poster.
Alternativ 1:med rekursiv
, tilslut med
Flere og flere databaser implementerer SQL:1999 ISO-standarden MED [RECURSIVE] syntaks
til rekursive forespørgsler (f.eks. Postgres 8.4+
, SQL Server 2005+
, DB2
, Oracle 11gR2+
, SQLite 3.8.4+
, Firebird 2.1+
, H2
, HyperSQL 2.1.0+
, Teradata , MariaDB 10.2.2+
). Og fra version 8.0 understøtter MySQL det
. Se toppen af dette svar for den syntaks, der skal bruges.
Nogle databaser har en alternativ, ikke-standard syntaks til hierarkiske opslag, såsom CONNECT BY
klausul tilgængelig på Oracle
, DB2
, Informix , CUBRID
og andre databaser.
MySQL version 5.7 tilbyder ikke en sådan funktion. Når din databasemotor leverer denne syntaks, eller du kan migrere til en, der gør det, så er det bestemt den bedste mulighed at gå efter. Hvis ikke, så overvej også følgende alternativer.
Alternativ 2:Stilignende identifikatorer
Tingene bliver meget nemmere, hvis du tildeler id
værdier, der indeholder den hierarkiske information:en sti. For eksempel, i dit tilfælde kunne dette se sådan ud:
ID | NAVN |
---|---|
19 | kategori1 |
19/1 | kategori2 |
19/1/1 | kategori3 |
19/1/1/1 | kategori4 |
Derefter vælg
ville se sådan ud:
select id,
name
from products
where id like '19/%'
Alternativ 3:Gentagne selvforbindelser
Hvis du kender en øvre grænse for, hvor dybt dit hierarkitræ kan blive, kan du bruge en standard sql
forespørgsel som denne:
select p6.parent_id as parent6_id,
p5.parent_id as parent5_id,
p4.parent_id as parent4_id,
p3.parent_id as parent3_id,
p2.parent_id as parent2_id,
p1.parent_id as parent_id,
p1.id as product_id,
p1.name
from products p1
left join products p2 on p2.id = p1.parent_id
left join products p3 on p3.id = p2.parent_id
left join products p4 on p4.id = p3.parent_id
left join products p5 on p5.id = p4.parent_id
left join products p6 on p6.id = p5.parent_id
where 19 in (p1.parent_id,
p2.parent_id,
p3.parent_id,
p4.parent_id,
p5.parent_id,
p6.parent_id)
order by 1, 2, 3, 4, 5, 6, 7;
Se denne violin