8. SQL - null

Jasonยท2026๋…„ 1์›” 12์ผ

SQL

๋ชฉ๋ก ๋ณด๊ธฐ
8/47




SQL NULL ์ฒ˜๋ฆฌ โ€” ์‹ค์ˆ˜ํ•˜๊ธฐ ์‰ฌ์šด ํ•จ์ •๋“ค

๐Ÿ’ก NULL ๋•Œ๋ฌธ์— ํ‹€๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ๋งŽ๋‹ค. ์™„๋ฒฝํ•˜๊ฒŒ ์ •๋ฆฌํ•œ๋‹ค.


๐Ÿค” NULL์ด ๋ญ์•ผ?

"๊ฐ’์ด ์—†์Œ" ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํŠน์ˆ˜ํ•œ ์ƒํƒœ.

  • 0๊ณผ ๋‹ค๋ฆ„ (0์€ ๊ฐ’์ž„)
  • ๋นˆ ๋ฌธ์ž์—ด('')๊ณผ ๋‹ค๋ฆ„
  • FALSE์™€ ๋‹ค๋ฆ„
NULL โ‰  0
NULL โ‰  ''
NULL โ‰  FALSE
NULL = "์•Œ ์ˆ˜ ์—†์Œ"

โš ๏ธ NULL์˜ ํŠน์ดํ•œ ์„ฑ์งˆ

1. ๋น„๊ต ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ NULL

SELECT 
    NULL = NULL,      -- NULL (TRUE ์•„๋‹˜!)
    NULL = 1,         -- NULL
    NULL != 1,        -- NULL
    NULL > 0,         -- NULL
    1 + NULL,         -- NULL
    'hello' || NULL   -- NULL (PostgreSQL)
;

์ค‘์š”: NULL๊ณผ์˜ ๋ชจ๋“  ๋น„๊ต๋Š” NULL์„ ๋ฐ˜ํ™˜!

2. WHERE์—์„œ NULL์€ ํ†ต๊ณผ ๋ชปํ•จ

-- ์ด ์ฟผ๋ฆฌ๋Š” NULL์ธ ํ–‰์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Œ!
SELECT * FROM users WHERE age != 30;

-- NULL์ธ ํ–‰๋„ ์›ํ•˜๋ฉด ๋ช…์‹œ์ ์œผ๋กœ
SELECT * FROM users WHERE age != 30 OR age IS NULL;

๐Ÿ“Š ์˜ˆ์ œ ํ…Œ์ด๋ธ”

[users]
| user_id | name | age | email |
|---------|------|-----|-------|
| 1 | ๊น€์ฒ ์ˆ˜ | 30 | kim@test.com |
| 2 | ์ด์˜ํฌ | NULL | lee@test.com |
| 3 | ๋ฐ•๋ฏผ์ˆ˜ | 25 | NULL |
| 4 | ์ตœ์ง€์€ | NULL | NULL |


1๏ธโƒฃ IS NULL / IS NOT NULL

NULL ์ฒดํฌ

-- โŒ ํ‹€๋ฆฐ ๋ฐฉ๋ฒ•
SELECT * FROM users WHERE age = NULL;    -- ๊ฒฐ๊ณผ ์—†์Œ!

-- โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
SELECT * FROM users WHERE age IS NULL;   -- ์ด์˜ํฌ, ์ตœ์ง€์€

NULL์ด ์•„๋‹Œ ๊ฒƒ

SELECT * FROM users WHERE age IS NOT NULL;  -- ๊น€์ฒ ์ˆ˜, ๋ฐ•๋ฏผ์ˆ˜

์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ ์ฒดํฌ

-- age ๋˜๋Š” email์ด NULL์ธ ์œ ์ €
SELECT * FROM users 
WHERE age IS NULL OR email IS NULL;

2๏ธโƒฃ COALESCE โ€” NULL ๋Œ€์ฒด

๊ธฐ๋ณธ ์‚ฌ์šฉ

SELECT 
    name,
    age,
    COALESCE(age, 0) AS age_or_zero,     -- NULL์ด๋ฉด 0
    COALESCE(email, '์—†์Œ') AS email_or_default
FROM users;
nameageage_or_zeroemail_or_default
๊น€์ฒ ์ˆ˜3030kim@test.com
์ด์˜ํฌNULL0lee@test.com
๋ฐ•๋ฏผ์ˆ˜2525์—†์Œ
์ตœ์ง€์€NULL0์—†์Œ

์—ฌ๋Ÿฌ ๊ฐ’ ์ค‘ ์ฒซ ๋ฒˆ์งธ NOT NULL

SELECT COALESCE(NULL, NULL, 'hello', 'world');
-- ๊ฒฐ๊ณผ: 'hello' (์ฒซ ๋ฒˆ์งธ NOT NULL)

SELECT COALESCE(phone, mobile, email, '์—ฐ๋ฝ์ฒ˜ ์—†์Œ') AS contact
FROM users;

3๏ธโƒฃ IFNULL / NVL โ€” ๊ฐ„๋‹จ ๋Œ€์ฒด

MySQL - IFNULL

SELECT 
    name,
    IFNULL(age, 0) AS age
FROM users;

Oracle - NVL

SELECT 
    name,
    NVL(age, 0) AS age
FROM users;

๋น„๊ต

ํ•จ์ˆ˜DBํŒŒ๋ผ๋ฏธํ„ฐ
COALESCEํ‘œ์ค€ SQL์—ฌ๋Ÿฌ ๊ฐœ ๊ฐ€๋Šฅ
IFNULLMySQL2๊ฐœ๋งŒ
NVLOracle2๊ฐœ๋งŒ
ISNULLSQL Server2๊ฐœ๋งŒ

โ†’ COALESCE๊ฐ€ ๊ฐ€์žฅ ๋ฒ”์šฉ์ !


4๏ธโƒฃ NULLIF โ€” ํŠน์ • ๊ฐ’์„ NULL๋กœ

SELECT NULLIF(10, 10);  -- NULL (๊ฐ™์œผ๋ฉด NULL)
SELECT NULLIF(10, 20);  -- 10 (๋‹ค๋ฅด๋ฉด ์ฒซ ๋ฒˆ์งธ ๊ฐ’)

ํ™œ์šฉ: 0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ ๋ฐฉ์ง€

-- โŒ ์—๋Ÿฌ ๊ฐ€๋Šฅ (0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ)
SELECT revenue / count AS avg_revenue;

-- โœ… ์•ˆ์ „ (count๊ฐ€ 0์ด๋ฉด NULL ๋ฐ˜ํ™˜)
SELECT revenue / NULLIF(count, 0) AS avg_revenue;

5๏ธโƒฃ ์ง‘๊ณ„ ํ•จ์ˆ˜์™€ NULL

์ง‘๊ณ„ ํ•จ์ˆ˜๋Š” NULL ๋ฌด์‹œ

SELECT 
    COUNT(*) AS total_rows,      -- 4 (์ „์ฒด ํ–‰)
    COUNT(age) AS age_count,     -- 2 (NULL ์ œ์™ธ)
    SUM(age) AS age_sum,         -- 55 (NULL ๋ฌด์‹œ)
    AVG(age) AS age_avg          -- 27.5 (55/2, NULL ์ œ์™ธ)
FROM users;

์ฃผ์˜: AVG๋Š” NULL์„ ์ œ์™ธํ•˜๊ณ  ๊ณ„์‚ฐ!

NULL ํฌํ•จํ•ด์„œ ํ‰๊ท  ๊ตฌํ•˜๊ธฐ

-- NULL์„ 0์œผ๋กœ ์น˜ํ™˜ ํ›„ ํ‰๊ท 
SELECT AVG(COALESCE(age, 0)) AS avg_with_null_as_zero;
-- ๊ฒฐ๊ณผ: 13.75 (55/4)

6๏ธโƒฃ GROUP BY์™€ NULL

SELECT age, COUNT(*) 
FROM users 
GROUP BY age;
ageCOUNT(*)
301
251
NULL2

ํฌ์ธํŠธ: NULL๋„ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์ž„!


7๏ธโƒฃ ORDER BY์™€ NULL

NULL ์ •๋ ฌ ์œ„์น˜ (DB๋งˆ๋‹ค ๋‹ค๋ฆ„)

DBNULL ์œ„์น˜
MySQL์˜ค๋ฆ„์ฐจ์ˆœ ์‹œ ๋งจ ์•ž
PostgreSQL์˜ค๋ฆ„์ฐจ์ˆœ ์‹œ ๋งจ ๋’ค
Oracle์˜ค๋ฆ„์ฐจ์ˆœ ์‹œ ๋งจ ๋’ค

๋ช…์‹œ์  ์ œ์–ด

-- MySQL: NULL์„ ๋งจ ๋’ค๋กœ
SELECT * FROM users
ORDER BY age IS NULL, age;

-- PostgreSQL/Oracle: NULLS FIRST/LAST
SELECT * FROM users
ORDER BY age NULLS LAST;

8๏ธโƒฃ JOIN๊ณผ NULL

NULL ๊ฐ’์€ JOIN๋˜์ง€ ์•Š์Œ!

-- users.department_id๊ฐ€ NULL์ธ ํ–‰์€ ๊ฒฐ๊ณผ์— ์—†์Œ
SELECT u.*, d.name
FROM users u
JOIN departments d ON u.department_id = d.id;

NULL๋„ ํฌํ•จํ•˜๋ ค๋ฉด LEFT JOIN

SELECT u.*, COALESCE(d.name, '๋ฏธ๋ฐฐ์ •') AS dept_name
FROM users u
LEFT JOIN departments d ON u.department_id = d.id;

9๏ธโƒฃ CASE WHEN๊ณผ NULL

NULL ๋น„๊ต ์ฃผ์˜

-- โŒ ์ž‘๋™ ์•ˆ ํ•จ
CASE age
    WHEN NULL THEN '๋ฏธ์ž…๋ ฅ'  -- ์ด ์กฐ๊ฑด์€ ์ ˆ๋Œ€ TRUE ์•ˆ ๋จ!
    ELSE '์ž…๋ ฅ๋จ'
END

-- โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
CASE 
    WHEN age IS NULL THEN '๋ฏธ์ž…๋ ฅ'
    ELSE '์ž…๋ ฅ๋จ'
END

๐ŸŽฏ ์‹ค์ „ ๋ฌธ์ œ

๋ฌธ์ œ 1: NULL ์นด์šดํŠธ

์ด๋ฉ”์ผ์ด NULL์ธ ์œ ์ € ์ˆ˜๋ฅผ ๊ตฌํ•˜์„ธ์š”.

์ •๋‹ต ๋ณด๊ธฐ
SELECT COUNT(*) AS null_email_count
FROM users
WHERE email IS NULL;

๋ฌธ์ œ 2: NULL ๋Œ€์ฒด ์ง‘๊ณ„

๋‚˜์ด์˜ ํ‰๊ท ์„ ๊ตฌํ•˜์„ธ์š”. NULL์€ 0์œผ๋กœ ์ฒ˜๋ฆฌ.

์ •๋‹ต ๋ณด๊ธฐ
SELECT AVG(COALESCE(age, 0)) AS avg_age
FROM users;

๋ฌธ์ œ 3: NULL ํฌํ•จ ํ•„ํ„ฐ

๋‚˜์ด๊ฐ€ 30์ด ์•„๋‹Œ ๋ชจ๋“  ์œ ์ €๋ฅผ ๊ตฌํ•˜์„ธ์š”. (NULL ํฌํ•จ)

์ •๋‹ต ๋ณด๊ธฐ
SELECT *
FROM users
WHERE age != 30 OR age IS NULL;

-- ๋˜๋Š”
SELECT *
FROM users
WHERE COALESCE(age, -1) != 30;

๋ฌธ์ œ 4: 0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ ๋ฐฉ์ง€

๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ‰๊ท  ์ฃผ๋ฌธ ๊ธˆ์•ก์„ ๊ตฌํ•˜์„ธ์š”. (์ฃผ๋ฌธ์ด ์—†๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋„ ํฌํ•จ)

์ •๋‹ต ๋ณด๊ธฐ
SELECT 
    category,
    SUM(amount) AS total,
    COUNT(*) AS cnt,
    SUM(amount) / NULLIF(COUNT(*), 0) AS avg_amount
FROM orders
GROUP BY category;

๐Ÿ’ก NULL ์ฒ˜๋ฆฌ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

์ฝ”๋”ฉํ…Œ์ŠคํŠธ ์ „ ํ™•์ธ

  • WHERE์—์„œ = NULL ๋Œ€์‹  IS NULL ์ผ๋‚˜?
  • NULL๋„ ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ์กฐ๊ฑด์ธ๊ฐ€?
  • ์ง‘๊ณ„ ํ•จ์ˆ˜์—์„œ NULL ์ฒ˜๋ฆฌ ํ•„์š”ํ•œ๊ฐ€?
  • JOIN์—์„œ NULL ๋•Œ๋ฌธ์— ๋ˆ„๋ฝ๋˜๋Š” ํ–‰ ์—†๋‚˜?
  • ๋‚˜๋ˆ„๊ธฐ์—์„œ 0 ๋ฐฉ์ง€ํ–ˆ๋‚˜?

๐Ÿ“ ํ•ต์‹ฌ ์ •๋ฆฌ

[NULL ์ฒดํฌ]
IS NULL / IS NOT NULL (= NULL ์‚ฌ์šฉ ๊ธˆ์ง€!)

[NULL ๋Œ€์ฒด]
COALESCE(๊ฐ’1, ๊ฐ’2, ...) โ€” ์ฒซ ๋ฒˆ์งธ NOT NULL
IFNULL(๊ฐ’, ๋Œ€์ฒด๊ฐ’) โ€” MySQL

[NULL ์ƒ์„ฑ]
NULLIF(๊ฐ’1, ๊ฐ’2) โ€” ๊ฐ™์œผ๋ฉด NULL

[์ง‘๊ณ„์™€ NULL]
COUNT(*)๋Š” NULL ํฌํ•จ
COUNT(์ปฌ๋Ÿผ)์€ NULL ์ œ์™ธ
SUM, AVG ๋“ฑ์€ NULL ๋ฌด์‹œ

[์ฃผ์˜์‚ฌํ•ญ]
NULL๊ณผ์˜ ๋น„๊ต๋Š” ํ•ญ์ƒ NULL
JOIN ์‹œ NULL์€ ๋งค์นญ ์•ˆ ๋จ

๐Ÿ”— ๋‹ค์Œ ํฌ์ŠคํŠธ

[SQL ์‹œ๋ฆฌ์ฆˆ #9] UNION & ์ง‘ํ•ฉ ์—ฐ์‚ฐ โ€” ๋ฐ์ดํ„ฐ ํ•ฉ์น˜๊ธฐ


๐Ÿ“ NULL์€ "์•Œ ์ˆ˜ ์—†์Œ"์ด๋‹ค.
= NULL ๋Œ€์‹  IS NULL, ๊ทธ๋ฆฌ๊ณ  COALESCE๋ฅผ ์Šต๊ด€์ฒ˜๋Ÿผ ์“ฐ์ž!

profile
Data Analyst | Thoughts Become Things. ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํ•  ์ˆ˜ ์—†๋‹ค. | www.linkedin.com/in/๋ช…์ˆ˜-์ œ-7ab843200

0๊ฐœ์˜ ๋Œ“๊ธ€