Gå igenom ett kategoriträd
Expandera träd med överordnade och underordnade noder helt.
Gå igenom ett kategoriträd är en gratis lektion i SQL Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för SQL Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i SQL Academy innehåller totalt 4 lektioner.
Vad är ett kategoriträd?
Många verkliga datamängder har en förälder-barn-relation. En produktkatalog kan ha kategorier som Elektronik → Telefoner → Smartphones. Varje nod har en förälder, vilket bildar en trädstruktur.
I SQL lagras detta vanligtvis i en självrefererande tabell: varje rad har ett id och ett parent_id som pekar på en annan rad i samma tabell.
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT REFERENCES categories(id)
);Exempeldata för kategorier
Låt oss fylla i ett litet kategoriträd. Rotnoden har parent_id = NULL eftersom den saknar förälder. Alla andra noder pekar på sin förälder med ett parent_id som inte är NULL.
INSERT INTO categories (id, name, parent_id) VALUES
(1, 'Electronics', NULL),
(2, 'Phones', 1),
(3, 'Laptops', 1),
(4, 'Smartphones', 2),
(5, 'Feature Phones', 2),
(6, 'Gaming Laptops', 3),
(7, 'Ultrabooks', 3);Problemet med enkla frågor
En vanlig SELECT-sats kan bara hämta en nivå i taget. För att nå tre nivåer på djupet skulle ni behöva tre separata frågor eller tre self joins, vilket blir ohanterligt när trädet växer.
WITH RECURSIVE löser detta genom att låta en fråga referera till sitt eget resultat och gå igenom trädet nivå för nivå tills inga nya rader hittas.
-- This only shows direct children of Electronics (level 1)
SELECT id, name
FROM categories
WHERE parent_id = 1;Anatomin hos WITH RECURSIVE
En rekursiv CTE består av två delar som separeras av UNION ALL:
1. Ankardel — en vanlig SELECT-fråga som tillhandahåller startraderna.
2. Rekursiv del — en SELECT-fråga som kopplar tillbaka CTE:n till sig själv och genererar nästa nivå vid varje iteration.
Databasmotorn upprepar den rekursiva delen tills den inte returnerar några rader.
WITH RECURSIVE cte AS (
-- Anchor: starting rows
SELECT ...
UNION ALL
-- Recursive: join cte to base table
SELECT ... FROM base_table JOIN cte ON ...
)
SELECT * FROM cte;Gå igenom hela trädet från roten
Börja vid roten (där parent_id IS NULL) och gå nedåt till alla efterkommande noder. Den rekursiva delen kopplar varje ackumulerad rad till categories igen utifrån förälder-barn-relationen.
WITH RECURSIVE category_tree AS (
-- Anchor: root nodes
SELECT id, name, parent_id, 1 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
-- Recursive: children of current level
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, depth
FROM category_tree
ORDER BY depth, id;Spåra sökvägen
Det är praktiskt att registrera hela sökvägen från roten till varje nod. Vi kan bygga en sträng i path genom att sammanfoga anfädernas namn när vi går djupare i rekursionen.
Då blir det enkelt att visa brödsmulespår som Elektronik / Telefoner / Smartphones.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id,
name AS path
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
ct.path || ' / ' || c.name
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, path
FROM category_tree
ORDER BY path;Börja från en specifik nod
Ni behöver inte börja vid roten. Genom att ändra ankardelens WHERE-villkor kan ni gå igenom underträdet för vilken nod som helst. Här börjar vi från Telefoner (id = 2) och hämtar alla dess efterkommande noder.
WITH RECURSIVE subtree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE id = 2 -- start at Phones
UNION ALL
SELECT c.id, c.name, c.parent_id, s.depth + 1
FROM categories c
JOIN subtree s ON s.id = c.parent_id
)
SELECT id, name, depth
FROM subtree
ORDER BY depth, id;Gå uppåt: hitta alla anfäder
Trädet kan även traverseras i motsatt riktning — uppåt från ett löv till roten. Vänd helt enkelt på kopplingen så att ni följer parent_id uppåt i stället för nedåt. Det är användbart när ni behöver hela brödsmulespåret för en känd lövnod.
WITH RECURSIVE ancestors AS (
SELECT id, name, parent_id
FROM categories
WHERE id = 4 -- start at Smartphones
UNION ALL
SELECT c.id, c.name, c.parent_id
FROM categories c
JOIN ancestors a ON a.parent_id = c.id
)
SELECT id, name
FROM ancestors
ORDER BY id;Lägg till en indenterad visning
Ett vanligt mönster i användargränssnitt är att visuellt indentera barnnoder. Vi kan använda REPEAT (eller LPAD) tillsammans med kolumnen depth för att lägga till inledande blanksteg före varje namn och skapa en textbaserad trädvy.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
REPEAT(' ', depth) || name AS indented_name,
depth
FROM category_tree
ORDER BY path;Skydda mot oändliga loopar
Om era data innehåller en cykel (A är förälder till B och B är förälder till A) kommer rekursionen att fortsätta för evigt och krascha. Ni kan skydda mot detta genom att spåra besökta ID:n i en array och stoppa när det aktuella ID:t redan finns med.
WITH RECURSIVE safe_tree AS (
SELECT id, name, parent_id,
ARRAY[id] AS visited
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
st.visited || c.id
FROM categories c
JOIN safe_tree st ON st.id = c.parent_id
WHERE c.id <> ALL(st.visited) -- stop if already seen
)
SELECT id, name FROM safe_tree;Räkna efterkommande noder per nod
När ni har hela trädet kan ni aggregera det. Här räknar vi hur många efterkommande noder varje nod har genom att gruppera barnraderna mot listan över anfäder. Det är användbart när ni vill visa antal objekt bredvid kategorinamnen i en navigeringsmeny.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, id AS root_id
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.root_id
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
root_id,
COUNT(*) - 1 AS descendant_count
FROM category_tree
GROUP BY root_id
ORDER BY root_id;Snabbtest
Testa er förståelse av rekursiva frågor för kategoriträd.
Sammanfattning av lektionen
I den här lektionen lärde ni er att gå igenom en självrefererande kategoritabell med WITH RECURSIVE.
Viktiga lärdomar:
- Ankardelen väljer startnoderna (vanligtvis roten).
- Den rekursiva delen kopplar tillbaka CTE:n till bastabellen för att hitta nästa nivå.
- Lägg till en kolumn för depth för att spåra hur många nivåer ned varje nod ligger.
- Bygg en sträng i path för att skapa brödsmulespår.
- Gå uppåt genom att följa parent_id i omvänd riktning för att hitta alla anfäder.
- Använd en array i visited för att skydda mot cykler i bristfälliga data.
Lär dig SQL med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 46
- Lektioner
- 183
Vanliga frågor
Är lektionen ”Gå igenom ett kategoriträd” gratis?
Ja – hela texten till ”Gå igenom ett kategoriträd” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i SQL Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i SQL Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Gå igenom ett kategoriträd”?
Expandera träd med överordnade och underordnade noder helt. Ni övar på SQL Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig SQL Academy?
Du behöver inga förkunskaper. Utbildningen i SQL Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Gå igenom ett kategoriträd”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här SQL Academy-lektionen?
Ja. Varje SQL Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Så fungerar rekursiva CTE:er
- Gå igenom ett kategoriträd
- Skapa serier och sekvenser
- Undvika oändliga loopar