3. Frågor som omfattar flera tabeller
Tabellreferenser
En central idé inom databaser är att en rad i en tabell kan referera till en rad i en annan tabell. Således kan man skapa frågor som samlar data från flera tabeller utifrån dessa referenser. I praktiken består en sådan referens oftast av ID-numret för raden i den andra tabellen.
Exempel
Låt oss som exempel titta på en situation där databasen innehåller data om kurser och deras lärare. Vi antar att varje kurs har en lärare, och att samma lärare kan undervisa flera kurser.
Vi sparar information om lärarna i tabellen Teachers. Varje lärare har ett ID-nummer som vi kan referera till.
CREATE TABLE Teachers (
id INTEGER PRIMARY KEY,
name TEXT
);
Tabellen kan exempelvis se ut på följande sätt:
id name
-- ----------
1 Kaila
2 Luukkainen
3 Kivinen
4 Laaksonen
Tabellen Courses innehåller data om kurserna. För varje kurs finns en referens till kursens lärare.
CREATE TABLE Courses (
id INTEGER PRIMARY KEY,
name TEXT,
teacher_id INTEGER REFERENCES Teachers
);
Här refererar kolumnen teacher_id till ID-numret för en rad i tabellen Teachers, vilket anges med REFERENCES Teachers.
Tabellen kan exempelvis se ut på följande sätt:
id name teacher_id
-- ---------------- ----------
1 Beräkningsmodeller 3
2 Datanätverk 1
3 Seminarium 1
4 PHP-programmering 4
5 Neuronnät 3
Detta innebär att till exempel kursen Beräkningsmodeller undervisas av läraren med ID-numret 3. Från tabellen Teachers framgår att detta är lärare Kivinen.
Vi kan nu hämta kurserna med deras lärare med följande fråga som samtidigt hämtar information från tabellerna Courses och Teachers:
SELECT
Courses.name, Teachers.name
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id;
Eftersom frågan involverar flera tabeller anger vi vilken tabell varje kolumn tillhör. Till exempel refererar Courses.name till kolumnen name i tabellen Courses.
Frågan ger följande svar:
name name
---------------- ---------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
PHP-programmering Laaksonen
Neuronnät Kivinen
Vad händer i exemplet ovan?
Frågan ovan omfattar flera tabeller (FROM Courses, Teachers). Vad innebär det egentligen?
Idén är att när en fråga omfattar flera tabeller är utgångspunkten för resultattabellen alla de olika möjliga sätten att kombinera rader från tabellerna. Därefter kan man med villkoren i WHERE-delen bestämma vilka radkombinationer som är av intresse.
Ett bra sätt för att förstå hur en fråga med flera tabeller fungerar är att först titta på en fråga som hämtar alla kolumner och som inte innehåller någon WHERE-del. I exemplet ovan är en sådan fråga följande:
SELECT * FROM Courses, Teachers;
Eftersom tabellen Courses har 5 rader och tabellen Teachers har 4 rader blir svaret en resultattabell på 5 * 4 = 20 rader. Resultattabellen innehåller alla möjliga sätt att först välja en rad från tabellen Courses och sedan en rad från tabellen Teachers:
id name teacher_id id name
-- ---------------- ---------- -- ---------
1 Beräkningsmodeller 3 1 Kaila
1 Beräkningsmodeller 3 2 Luukkainen
1 Beräkningsmodeller 3 3 Kivinen
1 Beräkningsmodeller 3 4 Laaksonen
2 Datanätverk 1 1 Kaila
2 Datanätverk 1 2 Luukkainen
2 Datanätverk 1 3 Kivinen
2 Datanätverk 1 4 Laaksonen
3 Seminarium 1 1 Kaila
3 Seminarium 1 2 Luukkainen
3 Seminarium 1 3 Kivinen
3 Seminarium 1 4 Laaksonen
4 PHP-programmering 4 1 Kaila
4 PHP-programmering 4 2 Luukkainen
4 PHP-programmering 4 3 Kivinen
4 PHP-programmering 4 4 Laaksonen
5 Neuronnät 3 1 Kaila
5 Neuronnät 3 2 Luukkainen
5 Neuronnät 3 3 Kivinen
5 Neuronnät 3 4 Laaksonen
De flesta resultatrader är dock inte av intresse eftersom deras information inte hör ihop sinsemellan. Till exempel berättar den första resultatraden bara att det finns en kurs som heter Beräkningsmodeller och att det finns en lärare som heter Kaila.
För att filtrera fram de rader som ger oss användbar information begränsar vi sökningen så att lärarens id-nummer ska vara samma i båda tabellerna:
SELECT
*
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id;
Nu ger frågan ett mer intressant svar:
id name teacher_id id name
-- ---------------- ---------- -- ---------
1 Beräkningsmodeller 3 3 Kivinen
2 Datanätverk 1 1 Kaila
3 Seminarium 1 1 Kaila
4 PHP-programmering 4 4 Laaksonen
5 Neuronnät 3 3 Kivinen
Vi kan ytterligare precisera svarstabellen genom att endast välja de kolumner som är av intresse:
SELECT
Courses.name, Teachers.name
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id;
På så sätt kommer vi fram till samma svar som tidigare:
name name
---------------- ---------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
PHP-programmering Laaksonen
Neuronnät Kivinen
Flera villkor
I frågor som involverar flera tabeller kopplar WHERE-delen ihop de rader i tabellerna som är av intresse. Vi kan också lägga till andra villkor i WHERE-delen på samma sätt som tidigare. Till exempel kan vi ställa följande fråga:
SELECT
Courses.name, Teachers.name
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id AND Teachers.name = 'Kivinen';
Vi får då fram de kurser där Kivinen är lärare:
name name
---------------- -------
Beräkningsmodeller Kivinen
Neuronnät Kivinen
Förkortade tabellnamn
Vi kan göra frågor som involverar flera tabeller mer lättlästa genom att ge tabellerna alternativa kortare namn som vi sedan kan hänvisa till. Exempelvis frågan
SELECT
Courses.name, Teachers.name
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id;
kan förkortas:
SELECT
C.name, T.name
FROM
Courses AS C, Teachers AS T
WHERE
C.teacher_id = T.id;
Ordet AS är inte heller nödvändigt att använda. Vi kan alltså förkorta frågan ytterligare:
SELECT
C.name, T.name
FROM
Courses C, Teachers T
WHERE
C.teacher_id = T.id;
Att upprepa samma tabell
I en fråga som involverar flera tabeller kan samma tabell också förekomma flera gånger så länge varje tabell som upprepas får ett annat namn. Till exempel hämtar följande fråga alla sätt att välja ett par av två lärare:
SELECT A.name, B.name FROM Teachers A, Teachers B;
Frågan ger följande svar:
name name
---------- ----------
Kaila Kaila
Kaila Luukkainen
Kaila Kivinen
Kaila Laaksonen
Luukkainen Kaila
Luukkainen Luukkainen
Luukkainen Kivinen
Luukkainen Laaksonen
Kivinen Kaila
Kivinen Luukkainen
Kivinen Kivinen
Kivinen Laaksonen
Laaksonen Kaila
Laaksonen Luukkainen
Laaksonen Kivinen
Laaksonen Laaksonen
Länkningstabeller
Mellan tabeller finns det i allmänhet två typer av relationer:
-
En-till-många-relation: En rad i tabell A är kopplad till högst en rad i tabell B. En rad i tabell B kan vara kopplad till flera rader i tabell A.
-
Många-till-många-relation: En rad i tabell A kan vara kopplad till flera rader i tabell B. En rad i tabell B kan vara kopplad till flera rader i tabell A.
I fall 1 kan vi lägga till en kolumn i tabell A som refererar till tabell B precis som vi gjorde i exemplet i föregående avsnitt. Fall 2 är däremot mer komplicerat eftersom en enskild referens i någon av tabellraderna inte räcker. Lösningen är att skapa en tredje kopplingstabell (join table) som innehåller datan om referenserna.
Exempel
Låt oss som exempel titta på en situation där en webbutik har produkter och kunder, och varje kund har valt vissa produkter till sin köpkorg. I en viss köpkorg kan det finnas flera produkter, och en viss produkt kan finnas i flera köpkorgar.
Vi skapar en databas som består av tre tabeller: Products, Customers och Purchases. Kopplingstabellen Purchases anger vilka produkter som finns i varje köpkorg. Varje rad i kopplingstabellen motsvarar ett par i formen “Kunden id har produkten id i sin köpkorg”.
Vi antar att tabellerna ser ut på följande sätt:
| id | name | price |
|---|---|---|
| 1 | rädisa | 7 |
| 2 | morot | 5 |
| 3 | rova | 4 |
| 4 | kålrot | 8 |
| 5 | selleri | 4 |
| id | name |
|---|---|
| 1 | Uolevi |
| 2 | Maija |
| 3 | Aapeli |
| customer_id | product_id |
|---|---|
| 1 | 2 |
| 1 | 5 |
| 2 | 1 |
| 2 | 4 |
| 2 | 5 |
Detta betyder att Uolevis köpkorg innehåller en morot och en selleri. Maijas köpkorg innehåller en rädisa, en kålrot och en selleri. Aapelis köpkorg är tom.
Vi kan nu hämta kunderna och produkterna på följande sätt:
SELECT
Customers.name, Products.name
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND
Products.id = Purchases.product_id;
Syftet med frågan är att hämta information från tabellerna Customers och Products som motsvarar raderna i tabellen Purchases. För att få fram relevanta svar kopplar vi ihop raderna med hjälp av två villkor. Frågan ger som svar följande resultattabell:
name name
------ --------
Uolevi morot
Uolevi selleri
Maija rädisa
Maija kålrot
Maija selleri
Hur fungerar frågan?
Vi kan återigen undersöka hur frågan fungerar genom att hämta alla kolumner och ta bort villkoren:
SELECT * FROM Customers, Products, Purchases;
Resultattabellen från denna fråga innehåller alla möjliga kombinationer av kund, produkt och köp. Resultattabellen har 5 * 3 * 5 = 75 rader och börjar på följande sätt:
id name id name price customer_id product_id
-- ------ -- -------- ----- ----------- ----------
1 Uolevi 1 rädisa 7 1 2
1 Uolevi 1 rädisa 7 1 5
1 Uolevi 1 rädisa 7 2 1
1 Uolevi 1 rädisa 7 2 4
1 Uolevi 1 rädisa 7 2 5
1 Uolevi 2 morot 5 1 2
1 Uolevi 2 morot 5 1 5
1 Uolevi 2 morot 5 2 1
1 Uolevi 2 morot 5 2 4
1 Uolevi 2 morot 5 2 5
1 Uolevi 3 rova 4 1 2
1 Uolevi 3 rova 4 1 5
1 Uolevi 3 rova 4 2 1
1 Uolevi 3 rova 4 2 4
1 Uolevi 3 rova 4 2 5
...
När vi sedan lägger till villkoren i frågan kan vi begränsa oss till de rader som vi är intresserade av:
SELECT
*
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND
Products.id = Purchases.product_id;
id name id name price customer_id product_id
-- ------ -- -------- ----- ----------- ----------
1 Uolevi 2 morot 5 1 2
1 Uolevi 5 selleri 4 1 5
2 Maija 1 rädisa 7 2 1
2 Maija 4 kålrot 8 2 4
2 Maija 5 selleri 4 2 5
När vi därtill specificerar de önskade kolumnerna får vi den slutgiltiga frågan:
SELECT
Customers.name, Products.name
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND
Products.id = Purchases.product_id;
name name
------ --------
Uolevi morot
Uolevi selleri
Maija rädisa
Maija kålrot
Maija selleri
Flera villkor i frågan
Vi kan lägga till flera villkor i frågan om vi vill få reda på mer om köpkorgarna. Till exempel hämtar följande fråga de produkter som finns i Maijas köpkorg:
SELECT
Products.name
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND
Products.id = Purchases.product_id AND
Customers.name = 'Maija';
name
----------
rädisa
kålrot
selleri
Följande fråga visar vilka kunder som har selleri i sin köpkorg:
SELECT
Customers.name
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND
Products.id = Purchases.product_id AND
Products.name = 'selleri';
name
----------
Uolevi
Maija
Sammanfattning av tabellerna
Vi kan också använda aggregeringsfunktioner och gruppering i frågor som omfattar flera tabeller. De behandlar resultattabellen på samma sätt som i frågor som använder endast en tabell.
Vi betraktar fortsättningsvis databasen som innehåller produkter, kunder och köp:
| id | name | price |
|---|---|---|
| 1 | rädisa | 7 |
| 2 | morot | 5 |
| 3 | rova | 4 |
| 4 | kålrot | 8 |
| 5 | selleri | 4 |
| id | name |
|---|---|
| 1 | Uolevi |
| 2 | Maija |
| 3 | Aapeli |
| customer_id | product_id |
|---|---|
| 1 | 2 |
| 1 | 5 |
| 2 | 1 |
| 2 | 4 |
| 2 | 5 |
Följande fråga sammanfattar varje kunds totala antal produkter i köpkorgen och det totala priset för produkterna.
SELECT
Customers.name, COUNT(Products.id), SUM(Products.price)
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND Products.id = Purchases.product_id
GROUP BY
Customers.id;
Frågan ger följande svar:
name COUNT(Products.id) SUM(Products.price)
------ ------------------ -------------------
Uolevi 2 9
Maija 3 19
Uolevis köpkorg innehåller 2 produkter med ett totalt pris på 9. Maijas köpkorg innehåller 3 produkter med ett totalt pris på 19.
Hur fungerar frågan?
Frågan utgår från följande:
SELECT
*
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND Products.id = Purchases.product_id;
id name id name price customer_id product_id
-- ------ -- -------- ----- ----------- ----------
1 Uolevi 2 morot 5 1 2
1 Uolevi 5 selleri 4 1 5
2 Maija 1 rädisa 7 2 1
2 Maija 4 kålrot 8 2 4
2 Maija 5 selleri 4 2 5
Om vi i frågan lägger till grupperingen GROUP BY Customers.id delas raderna upp i två grupper baserat på kolumnen Customers.id:
Grupp 1:
id name id name price customer_id product_id
-- ------ -- -------- ----- ----------- ----------
1 Uolevi 2 morot 5 1 2
1 Uolevi 5 selleri 4 1 5
Grupp 2:
id name id name price customer_id product_id
-- ----- -- ------- ----- ----------- ----------
2 Maija 1 rädisa 7 2 1
2 Maija 4 kålrot 8 2 4
2 Maija 5 selleri 4 2 5
För dessa grupper beräknas sedan antalet produkter med COUNT(Products.id) samt det totala priset för köpen med SUM(Products.price).
Observera att grupperingen sker enligt kolumnen Customers.id men att frågan hämtar kolumnen Customers.name. Detta är logiskt eftersom det är kolumnen Customers.id som definierar Customers.name. Medan denna fråga fungerar i exempelvis SQLite, kräver vissa andra databaser att alla kolumner som hämtas direkt också finns med i grupperingen. I sådana fall ska grupperingen skrivas som GROUP BY Customers.id, Customers.name.
Problem med en rad som saknas
Frågan ovan fungerar i och för sig bra, men något saknas:
name COUNT(Products.id) SUM(Products.price)
------ ------------------ -------------------
Uolevi 2 9
Maija 3 19
Ett problem med frågan ovan är att svaret inte innehåller den tredje kunden i databasen, alltså Aapeli. Eftersom Aapelis köpkorg är tom kopplas hans rad inte ihop med någon annan rad och kommer därför inte med i resultattabellen.
Som tur är så har vi snart en lösning på detta problem.
JOIN-syntaxen
Hittills har vi hämtat information från tabellerna genom att lista dem i frågans FROM-del, vilket i regel fungerar bra. Ibland är det dock nödvändigt att använda JOIN-syntaxen, vilket är användbart när det ser ut som om viss information saknas i frågans svar.
Sätt att ställa frågan på
Nedan visas två sätt att ställa samma fråga på. Först ställs frågan på det redan bekanta sättet och sedan med hjälp av JOIN-syntaxen.
SELECT
Courses.name, Teachers.name
FROM
Courses, Teachers
WHERE
Courses.teacher_id = Teachers.id;
SELECT
Courses.name, Teachers.name
FROM
Courses JOIN Teachers ON Courses.teacher_id = Teachers.id;
I JOIN-syntaxen står ordet JOIN mellan tabellnamnen. Villkoret som kopplar ihop tabellraderna anges i en separat ON-del.
I exemplet ovan tillför JOIN-syntaxen inget nytt, utan är bara ett alternativt sätt att ställa frågan på. Vi ska i nästa exempel se hur vi kan utvidga syntaxen så att den ger oss nya möjligheter i frågorna.
Exempel
Låt oss som exempel titta på en situation där databasen innehåller de bekanta tabellerna Courses och Teachers men där en kurs i tabellen Courses saknar en lärare.
id name teacher_id
-- ---------------- ----------
1 Beräkningsmodeller 3
2 Datanätverk 1
3 Seminarium 1
4 PHP-programmering NULL
5 Neuronnät 3
I rad 4 har kolumnen teacher_id värdet NULL. Om vi kör någon av de tidigare frågorna uppstår problemet att rad 4 inte matchar någon rad i tabellen Teachers. Detta leder till att resultattabellen inte innehåller någon rad för kursen PHP-programmering:
name name
---------------- -------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
Neuronnät Kivinen
Lösningen på problemet är att använda LEFT JOIN-syntaxen, vilket innebär att om en rad i den vänstra tabellen inte kopplas till någon rad i den högra tabellen, skapas en rad i resultattabellen där varje kolumn som hör till den tabellen då får värdet NULL.
Vi kan här ställa frågan på följande sätt:
SELECT
Courses.name, Teachers.name
FROM
Courses LEFT JOIN Teachers ON Courses.teacher_id = Teachers.id;
Nu visas även kursen PHP-programmering utan lärare i resultattabellen.
name name
---------------- -------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
PHP-programmering NULL
Neuronnät Kivinen
Hur fungerar frågan?
Återigen är ett bra sätt att förstå hur frågan fungerar att förenkla den:
SELECT
*
FROM
Courses LEFT JOIN Teachers ON Courses.teacher_id = Teachers.id;
id name teacher_id id name
-- ---------------- ---------- ---- -------
1 Beräkningsmodeller 3 3 Kivinen
2 Datanätverk 1 1 Kaila
3 Seminarium 1 1 Kaila
4 PHP-programmering NULL NULL NULL
5 Neuronnät 3 3 Kivinen
Här ser man att eftersom rad 4 i den vänstra tabellen inte matchar någon rad i den högra tabellen, blir det en rad i resultattabellen för den vänstra raden där varje kolumn som hör till den högra tabellen har värdet NULL.
Mera om JOIN
Det finns fyra olika varianter av JOIN-frågan:
JOINalltsåINNER JOIN: fungerar som en vanlig fråga med två tabellerLEFT JOIN: om en rad i den vänstra tabellen inte matchar någon rad i den högra tabellen, tas den ändå med som en egen rad.RIGHT JOIN: om en rad i den högra tabellen inte matchar någon rad i den vänstra tabellen, tas den ändå med som en egen rad.FULL JOIN: både från den vänstra och den högra tabellen tas de rader som inte matchar någon rad i den andra tabellen med som egna rader.
En begränsning i SQLite var länge att endast JOIN och LEFT JOIN var möjliga, men från och med version 3.39.0 är även RIGHT JOIN och FULL JOIN tillgängliga. I materialet för denna kurs använder vi LEFT JOIN-syntax när vi vill att resultatet även ska innehålla rader som inte kopplas ihop med rader i den andra tabellen.
ON vs. WHERE
Ordet ON är centralt i en LEFT JOIN-fråga eftersom det anger villkoret som gör att även de extra raderna i den vänstra tabellen tas med:
SELECT
Courses.name, Teachers.name
FROM
Courses LEFT JOIN Teachers ON Courses.teacher_id = Teachers.id;
name name
---------------- -------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
PHP-programmering NULL
Neuronät Kivinen
Om vi i stället använder ordet WHERE faller de extra raderna i den vänstra tabellen bort:
SELECT
Courses.name, Teachers.name
FROM
Courses LEFT JOIN Teachers
WHERE
Courses.teacher_id = Teachers.id;
name name
---------------- -------
Beräkningsmodeller Kivinen
Datanätverk Kaila
Seminarium Kaila
Neuronnät Kivinen
Både ON och WHERE kan förekomma i samma fråga:
SELECT
Courses.name, Teachers.name
FROM
Courses LEFT JOIN Teachers ON Courses.teacher_id = Teachers.id
WHERE
Courses.name <> 'Datanätverk';
I sådant fall sköter ON-delen sammanslagningen av tabellerna medan WHERE-delen begränsar resultaten ytterligare:
name name
---------------- -------
Beräkningsmodeller Kivinen
Seminarium Kaila
PHP-Programmering NULL
Neuronnät Kivinen
I det här fallet gör WHERE-delen att resultattabellen inte innehåller någon rad för kursen Datanätverk.
Om båda villkoren istället finns i ON-delen förändras resultatet:
SELECT
Courses.name, Teachers.name
FROM
Courses LEFT JOIN Teachers
ON Courses.teacher_id = Teachers.id AND
Courses.name <> 'Datanätverk';
name name
---------------- -------
Beräkningsmodeller Kivinen
Datanätverk NULL
Seminarium Kaila
PHP-programmering NULL
Neuronät Kivinen
I det här fallet blir raderna för kurserna Datanätverk och PHP-programmering kvar som extra rader i den vänstra tabellen eftersom de inte kan kopplas till någon rad i den högra tabellen enligt ON-villkoret.
Lösning för sammanfattningen
Vi återgår till det tidigare problemet där frågan som sammanfattar saknade data. I vår databas finns fortfarande följande tabeller:
| id | name | price |
|---|---|---|
| 1 | rädisa | 7 |
| 2 | morot | 5 |
| 3 | rova | 4 |
| 4 | kålrot | 8 |
| 5 | selleri | 4 |
| id | name |
|---|---|
| 1 | Uolevi |
| 2 | Maija |
| 3 | Aapeli |
| customer_id | product_id |
|---|---|
| 1 | 2 |
| 1 | 5 |
| 2 | 1 |
| 2 | 4 |
| 2 | 5 |
Vi sammanfattade köpkorgarna med följande fråga:
SELECT
Customers.name, COUNT(Products.id), SUM(Products.price)
FROM
Customers, Products, Purchases
WHERE
Customers.id = Purchases.customer_id AND Products.id = Purchases.product_id
GROUP BY
Customers.id;
Problemet var att Aapeli inte fanns med i sammanfattningen:
name COUNT(Products.id) SUM(Products.price)
------ ------------------ -------------------
Uolevi 2 9
Maija 3 19
Orsaken till problemet är att Aapelis köpkorg är tom. När frågan väljer kombinationer av rader från tabellerna finns det ingen rad som innehåller Aapeli. Lösningen på problemet är att använda LEFT JOIN-syntaxen på följande sätt:
SELECT
Customers.name, COUNT(Products.id), SUM(Products.price)
FROM
Customers LEFT JOIN Purchases ON Customers.id = Purchases.customer_id
LEFT JOIN Products ON Products.id = Purchases.product_id
GROUP BY
Customers.id;
Nu finns också Aapeli med i sammanfattningen:
name COUNT(Products.id) SUM(Products.price)
------ ------------------ -------------------
Uolevi 2 9
Maija 3 19
Aapeli 0 NULL
Eftersom Aapelis köpkorg inte innehåller några produkter blir summan av produkternas priser NULL. Vi kan förbättra frågan ytterligare genom att använda IFNULL.
SELECT
Customers.name, COUNT(Products.id), IFNULL(SUM(Products.price), 0)
FROM
Customers LEFT JOIN Purchases ON Customers.id = Purchases.customer_id
LEFT JOIN Products ON Products.id = Purchases.product_id
GROUP BY
Customers.id;
Då blir NULL istället 0:
name COUNT(Products.id) IFNULL(SUM(Products.price), 0)
------ ------------------ ------------------------------
Uolevi 2 9
Maija 3 19
Aapeli 0 0
Hur fungerar frågan?
När frågan innehåller flera LEFT JOIN-delar tolkas det som att tabellerna slås ihop från vänster till höger. I frågan ovan kan vi tänka oss att det första steget slår ihop tabellerna Customers och Purchases:
SELECT
*
FROM
Customers LEFT JOIN Purchases ON Customers.id = Purchases.customer_id;
id name customer_id product_id
-- ------ ----------- ----------
1 Uolevi 1 2
1 Uolevi 1 5
2 Maija 2 1
2 Maija 2 4
2 Maija 2 5
3 Aapeli NULL NULL
I det andra steget slås resultattabellen från det första steget ihop med tabellen Products:
SELECT
*
FROM
Customers LEFT JOIN Purchases ON Customers.id = Purchases.customer_id
LEFT JOIN Products ON Products.id = Purchases.product_id;
id name customer_id product_id id name price
-- ------ ----------- ---------- ---- -------- -----
1 Uolevi 1 2 2 morot 5
1 Uolevi 1 5 5 selleri 4
2 Maija 2 1 1 rädisa 7
2 Maija 2 4 4 kålrot 8
2 Maija 2 5 5 selleri 4
3 Aapeli NULL NULL NULL NULL NULL
I båda stegen inkluderas Aapeli i resultattabellen eftersom hans rad inte matchar någon rad i den högra tabellen.