Okee, ik kom er even niet meer uit en ChatGPT weet het ook even niet meer
Ik voel me in elk geval niet alleen in het probleem.
Ik heb twee tabellen in een MySQL-database (of: mariadb): b_taxonomy en b_taxonomy_terms. Zoals gebruikelijk bij een taxonomy dient die ertoe om een hierarchische structuur te herbergen. De tabel b_taxonomy bevat wat gegevens als "naam" etc, maar is voor het probleem niet van belang. De tabel b_taxonomy_terms ziet er zo uit:
Ik wil de taxonomy op een website op hierarchische wijze weergeven. Maar het kunnen flinke lijsten worden, met tot enkele tienduizenden geneste termen. Er moet dus een pager in komen. Bij voorkeur haal ik om te beginnen al een beperkte set op uit de database. Daarvoor heb ik de volgende query bedacht:
Die werkt, in zoverre dat 'ie de tabel weergeeft als hierboven. Maar de sortering is daarbij dus onjuist, want niet-hierarchisch. De laatste rij (id=2) had een rij hoger moeten staan, want is een child van parent_id 3. Hier bereikt mijn hobby-sql zijn grenzen; daarom zocht ik samen met ChatGPT naar een oplossing. ChatGPT stelde voor:
Goed om te weten dat ik niet de grootste n00b-fout ooit heb gemaakt: kennelijk is het best een lastige vraag. Heeft iemand een idee?
Ik heb twee tabellen in een MySQL-database (of: mariadb): b_taxonomy en b_taxonomy_terms. Zoals gebruikelijk bij een taxonomy dient die ertoe om een hierarchische structuur te herbergen. De tabel b_taxonomy bevat wat gegevens als "naam" etc, maar is voor het probleem niet van belang. De tabel b_taxonomy_terms ziet er zo uit:
code:
1
2
3
4
5
| id taxonomy_id parent_id machine_name term_full term_short 1 7 NULL zwart zwart zwart 3 7 1 wit wit wit 4 7 1 paars paars paars 2 7 3 grijs grijs grijs |
Ik wil de taxonomy op een website op hierarchische wijze weergeven. Maar het kunnen flinke lijsten worden, met tot enkele tienduizenden geneste termen. Er moet dus een pager in komen. Bij voorkeur haal ik om te beginnen al een beperkte set op uit de database. Daarvoor heb ik de volgende query bedacht:
SQL:
1
2
3
4
5
6
7
8
9
10
| WITH RECURSIVE tree AS ( SELECT * FROM b_taxonomy_terms WHERE taxonomy_id = 7 AND parent_id = 0 UNION ALL SELECT t.* FROM b_taxonomy_terms AS t, tree WHERE tree.id = t.parent_id ) SELECT * FROM tree |
Die werkt, in zoverre dat 'ie de tabel weergeeft als hierboven. Maar de sortering is daarbij dus onjuist, want niet-hierarchisch. De laatste rij (id=2) had een rij hoger moeten staan, want is een child van parent_id 3. Hier bereikt mijn hobby-sql zijn grenzen; daarom zocht ik samen met ChatGPT naar een oplossing. ChatGPT stelde voor:
Om de uitvoer te sorteren op basis van de hiërarchische structuur, kunt u de volgende query gebruiken:
SQL:
1 2 3 4 5 6 7 8 9 10 11 WITH RECURSIVE taxonomy_tree AS ( SELECT id, taxonomy_id, parent_id, machine_name, term_full, term_short, created, updated, 1 AS level FROM b_taxonomy_terms WHERE parent_id IS NULL UNION ALL SELECT t.id, t.taxonomy_id, t.parent_id, t.machine_name, t.term_full, t.term_short, t.created, t.updated, tt.level + 1 FROM b_taxonomy_terms t INNER JOIN taxonomy_tree tt ON t.parent_id = tt.id ) SELECT * FROM taxonomy_tree ORDER BY COALESCE(parent_id, id), level, id;
[...]
Nu staan de rijen in de juiste volgorde, waarbij de rij met id "2" tussen de rijen met id "3" en "4" in staat, omdat deze als kind van rij "3" wordt beschouwd en een niveau dieper in de hiërarchie staat.
Dat zou inderdaad juist zijn, maar de rij met id "2" staat als laatste.
Het spijt me dat de aangepaste query nog niet de gewenste resultaten oplevert. In dat geval kunnen we proberen een andere aanpak te gebruiken, namelijk door gebruik te maken van een LEFT JOIN om de ouderrijen aan de kindrijen te koppelen. Dit zou er als volgt uit kunnen zien:
SQL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 WITH RECURSIVE taxonomy_tree AS ( SELECT id, taxonomy_id, parent_id, machine_name, term_full, term_short, created, updated, 1 AS level FROM b_taxonomy_terms WHERE parent_id IS NULL UNION ALL SELECT t.id, t.taxonomy_id, t.parent_id, t.machine_name, t.term_full, t.term_short, t.created, t.updated, tt.level + 1 FROM b_taxonomy_terms t LEFT JOIN taxonomy_tree tt ON t.parent_id = tt.id ) SELECT * FROM taxonomy_tree ORDER BY COALESCE(parent_id, id), -- sorteer eerst op de bovenliggende rij of de huidige rij indien het een hoofdrij is level, -- sorteer vervolgens op het niveau in de hiërarchie id; -- tenslotte sorteer op de id om te voorkomen dat er een willekeurige volgorde ontstaat
[...]
Deze query zou de rijen in de juiste volgorde moeten ophalen, waarbij de rij met id "2" tussen de rijen met id "3" en "4" in staat, omdat deze als kind van rij "3" wordt beschouwd en een niveau dieper in de hiërarchie staat.
Rij 2 staat nog steeds onderaan.
Dat is vervelend om te horen. Ik zie echter geen enkele reden waarom de query die ik heb gegeven de rijen niet in de juiste volgorde zou moeten ophalen. Ik vermoed dat er ergens anders in de code of in de database iets aan de hand is waardoor de query niet het gewenste resultaat oplevert.
In ieder geval zou je kunnen proberen om de volgende aanpak te gebruiken om de rijen in de juiste volgorde op te halen. Deze aanpak maakt gebruik van de MySQL-specifieke GROUP_CONCAT-functie om de volledige hiërarchie van elke rij op te halen en vervolgens de rijen te sorteren op basis van die hiërarchie. Hier is de query:
code:
1 2 3 4 5 6 SELECT t1.*, GROUP_CONCAT(t2.id ORDER BY t2.parent_id SEPARATOR '/') AS hierarchy FROM b_taxonomy_terms AS t1 LEFT JOIN b_taxonomy_terms AS t2 ON t1.parent_id = t2.id GROUP BY t1.id ORDER BY hierarchy;
Met deze query zou de uitvoer als volgt moeten zijn:
Python:
1 2 3 4 5 id taxonomy_id parent_id machine_name term_full term_short hierarchy 1 7 NULL zwart zwart zwart 1 3 7 1 wit wit wit 1/3 4 7 1 paars paars paars 1/4 2 7 3 grijs grijs grijs 1/3/2
In dit resultaat is te zien dat de rijen nu gesorteerd zijn op basis van hun hiërarchie, zoals aangegeven in de hierarchy-kolom. Dit zou de rij met id "2" tussen de rijen met id "3" en "4" in moeten plaatsen, omdat deze als kind van rij "3" wordt beschouwd en een niveau dieper in de hiërarchie staat.
Hopelijk helpt dit je om de rijen in de juiste volgorde op te halen. Als dit niet het geval is, laat het me dan gerust weten, dan kunnen we verder kijken wat er misgaat.
Vervolgens werd een brakke PHP-functie uitgespuugd die evenmin werkteOok hier staat id 2 onderaan. Schrijf een PHP-functie die de rijen ophaalt en in hierarchische volgorde plaatst.
Goed om te weten dat ik niet de grootste n00b-fout ooit heb gemaakt: kennelijk is het best een lastige vraag. Heeft iemand een idee?
Privacy-adepten vinden op AVGtekst.nl de Nederlandse AVG-tekst voorzien van uitspraken en besluiten.