NULL i aggregeringar, joinar och DISTINCT
Så beter sig NULL olika vid gruppering, joinar och unikhet
NULL i aggregeringar, joinar och DISTINCT är en gratis lektion i Förberedelser inför SQL-intervjun på CoddyKit. Detta är lektion 4 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 Förberedelser inför SQL-intervjun, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Förberedelser inför SQL-intervjun innehåller totalt 4 lektioner.
NULL på tre överraskande ställen
NULL beter sig inte likadant överallt. Den sista lektionen behandlar de tre sammanhang där beteendet oftast överraskar kandidater: aggregat, joinar och DISTINCT / GROUP BY.
Den återkommande överraskningen är att aggregat och filtrering behandlar NULL som »hoppa över mig«, medan gruppering och DISTINCT behandlar NULL som »ett värde som är lika med andra NULL«. Den inkonsekvensen är exakt det intervjuare testar.
Bemästra detta så har du täckt de vanligaste NULL-frågorna i SQL-intervjuer.
Aggregat ignorerar NULL
Grundregeln: aggregatfunktioner hoppar över NULL-värden. SUM, AVG, MIN, MAX och COUNT(column) ignorerar helt NULL-indata i stället för att behandla dem som noll.
Det är därför AVG kan returnera ett annat tal än du förväntar dig. Det dividerar summan av icke-NULL-värden med antalet icke-NULL-värden, inte med det totala antalet rader.
-- bonus values: 100, 200, NULL
SELECT
SUM(bonus) AS total, -- 300 (NULL ignored)
AVG(bonus) AS average, -- 150 = 300 / 2, not / 3
COUNT(bonus) AS cnt -- 2 (NULL not counted)
FROM employees;COUNT(*) jämfört med COUNT(column)
Den vanligaste frågan om aggregat och NULL. COUNT(*) räknar rader, inklusive rader med NULL. COUNT(column) räknar endast rader där kolumnen är icke-NULL.
Skillnaden mellan dem är alltså exakt antalet NULL i den kolumnen. COUNT(DISTINCT column) går ett steg längre och ignorerar också NULL när dubbletter tas bort.
SELECT
COUNT(*) AS rows_total, -- all rows
COUNT(bonus) AS non_null_bonus, -- excludes NULLs
COUNT(DISTINCT bonus) AS distinct_bonus, -- excludes NULLs + dups
COUNT(*) - COUNT(bonus) AS null_bonus
FROM employees;AVG jämfört med SUM/COUNT(*): en klassisk fälla
Intervjuare frågar: »Är AVG(x) samma som SUM(x) / COUNT(*)?« Svaret är nej när NULL finns med.
AVG(x) är lika med SUM(x) / COUNT(x) och dividerar med antalet icke-NULL-värden. Att dividera med COUNT(*) behandlar i stället NULL som om de vore noll, vilket sänker genomsnittet.
Om du faktiskt vill räkna NULL som noll måste du uttryckligen ange det med COALESCE.
-- These differ when bonus has NULLs:
SELECT
AVG(bonus) AS avg_ignoring_nulls,
SUM(bonus) * 1.0 / COUNT(*) AS avg_nulls_as_zero,
AVG(COALESCE(bonus, 0)) AS explicit_nulls_as_zero
FROM employees;Specialfallet när alla aggregatvärden är NULL
Vad returnerar ett aggregat när alla indata är NULL eller när det inte finns några rader? Här är en exakt åtskillnad som intervjuare uppskattar:
SUM,AVG,MINochMAXöver enbart NULL-värden (eller noll rader) returnerar NULL.COUNTreturnerar alltid 0, aldrig NULL.
Om en rapport visar tomma totalsummor är en SUM som bara innehåller NULL ett sannolikt skäl. Omslut den med COALESCE för att visa 0.
-- No matching rows or all bonuses NULL:
SELECT SUM(bonus) FROM employees WHERE 1 = 0; -- NULL
SELECT COUNT(bonus) FROM employees WHERE 1 = 0; -- 0
-- Present a clean zero:
SELECT COALESCE(SUM(bonus), 0) FROM employees;NULL i JOIN-villkor
I joinens ON-sats är NULL = NULL fortfarande UNKNOWN, så NULL-nycklar matchar aldrig i en equi-join. Två rader som båda har en NULL som join-nyckel kopplas inte ihop.
Detta är en vanlig fälla vid joinar på valfria främmande nycklar. Om matchning mellan NULL-värden är det avsedda beteendet behöver du en NULL-säker operator (IS NOT DISTINCT FROM eller <=>) från den tidigare lektionen.
-- Rows with region IS NULL on both sides do NOT match
SELECT *
FROM a JOIN b ON a.region = b.region;
-- To match NULL-to-NULL (ANSI):
SELECT *
FROM a JOIN b ON a.region IS NOT DISTINCT FROM b.region;NULL som skapas av yttre joinar
Yttre joinar skapar NULL för omatchade rader. Efter en LEFT JOIN är varje kolumn på höger sida NULL för vänsterrader som inte hittade någon matchning.
Detta är grunden för anti-join-mönstret: filtrera med WHERE right_table.key IS NULL för att hitta rader utan matchning, till exempel kunder utan beställningar.
Var dock försiktig: att filtrera en kolumn från en yttre join i WHERE kan oavsiktligt omvandla den till en inner join, vilket är ämnet för nästa scen.
-- Find customers who have never ordered (anti-join)
SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;NULL-fällan med WHERE på en yttre join
En klassisk fallgrop. Du gör en LEFT JOIN mot orders och lägger sedan till WHERE o.status = 'shipped'. Plötsligt försvinner kunder utan beställningar, så att den yttre joinen i praktiken blir en inner join.
Varför? För omatchade rader är o.status NULL, och NULL = 'shipped' är UNKNOWN, så WHERE tar bort dem. För att behålla omatchade rader flyttar du i stället villkoret till ON-satsen.
-- Accidental inner join: drops customers with no orders
SELECT c.name, o.status
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'shipped';
-- Correct: keep unmatched customers
SELECT c.name, o.status
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id AND o.status = 'shipped';DISTINCT behandlar alla NULL-värden som lika
Här är inkonsekvensen som överraskar alla. Aggregatfunktioner hoppar över NULL, men DISTINCT behåller exakt ett NULL och behandlar alla NULL-värden som dubbletter av varandra.
Så SELECT DISTINCT bonus över värdena 100, 100, NULL, NULL returnerar tre rader: 100, NULL och inget mer. De två NULL-värdena slås ihop till ett, trots att NULL = NULL ger UNKNOWN i andra sammanhang.
-- bonus: 100, 100, NULL, NULL, 200
SELECT DISTINCT bonus FROM employees;
-- Returns: 100, 200, NULL (the two NULLs become one row)GROUP BY samlar alla NULL-värden i en grupp
GROUP BY följer samma regel som DISTINCT: alla NULL-nycklar samlas i en enda grupp. Detta är motsatsen till jämförelselogiken, där NULL-värden aldrig är lika med varandra.
Att gruppera efter en nullable kolumn ger alltså en rad som representerar alla poster med NULL som nyckel, vilket vanligtvis är det man vill ha i rapporter. Nämn kontrasten mellan gruppering och jämförelse för att visa djupare förståelse.
-- All employees with NULL department form ONE group
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;
-- A single row where department is NULL totals all of themViktiga punkter inför intervjun
Den sammanfattning som förenar allt och imponerar på intervjuare:
- Aggregatfunktioner ignorerar NULL; AVG delar med COUNT(column), inte COUNT(*).
- COUNT(*) räknar rader; COUNT(col) och COUNT(DISTINCT col) hoppar över NULL.
- SUM/AVG/MIN/MAX utan rader returnerar NULL; COUNT returnerar 0.
- Vid joinar matchar NULL-nycklar aldrig; filtrering av en kolumn från en outer join i WHERE blir i praktiken tyst en inner join.
- DISTINCT och GROUP BY behandlar alla NULL-värden som lika, motsatsen till jämförelselogiken.
En mening att komma ihåg: 'NULL ignoreras vid aggregering och jämförelser, men grupperas tillsammans när dubbletter tas bort.'
Snabbtest
Testa kontrasten mellan gruppering och aggregering.
Sammanfattning
Du har nu gått igenom NULL-hantering inför intervjuer:
- Aggregatfunktioner hoppar över NULL; AVG delar med antalet icke-NULL-värden, och en SUM med enbart NULL är NULL medan COUNT är 0.
COUNT(*)inkluderar rader med NULL;COUNT(col)gör det inte, och skillnaden motsvarar antalet NULL-värden.- Joinnycklar som är NULL matchar aldrig; filtrering av kolumner från en outer join i WHERE kan göra att joinen övergår till en inner join.
- DISTINCT och GROUP BY samlar alla NULL-värden i en grupp, motsatsen till jämförelselogiken.
Kom ihåg tumregeln: NULL ignoreras vid aggregering och jämförelser, men grupperas tillsammans när dubbletter tas bort. Denna enda insikt besvarar de flesta intervjufrågor om NULL.
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
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”NULL i aggregeringar, joinar och DISTINCT” gratis?
Ja – hela texten till ”NULL i aggregeringar, joinar och DISTINCT” 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 Förberedelser inför SQL-intervjun, kan Ni uppgradera till CoddyKit PRO. Kursen i Förberedelser inför SQL-intervjun innehåller totalt 4 lektioner.
Vad lär jag mig i ”NULL i aggregeringar, joinar och DISTINCT”?
Så beter sig NULL olika vid gruppering, joinar och unikhet Ni övar på Förberedelser inför SQL-intervjun 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 Förberedelser inför SQL-intervjun?
Du behöver inga förkunskaper. Utbildningen i Förberedelser inför SQL-intervjun 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 4 av 4.
Hur lång tid tar lektionen ”NULL i aggregeringar, joinar och DISTINCT”?
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 Förberedelser inför SQL-intervjun-lektionen?
Ja. Varje Förberedelser inför SQL-intervjun-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
- Tre värden i logiken och UNKNOWN
- IS NULL, IS NOT NULL och NULL-säker likhet
- COALESCE, NULLIF och ISNULL
- NULL i aggregeringar, joinar och DISTINCT