

๐ก ์ฌ๋ฌ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ํ๋๋ก ํฉ์น๋ ์งํฉ ์ฐ์ฐ์ ์ ๋ฆฌํ๋ค.
๋ ๊ฐ ์ด์์ SELECT ๊ฒฐ๊ณผ๋ฅผ ํฉ์น๋ ์ฐ์ฐ.
| ์ฐ์ฐ | ์ค๋ช | ์ํ |
|---|---|---|
| UNION | ํฉ์งํฉ (์ค๋ณต ์ ๊ฑฐ) | A โช B |
| UNION ALL | ํฉ์งํฉ (์ค๋ณต ํฌํจ) | A + B |
| INTERSECT | ๊ต์งํฉ | A โฉ B |
| EXCEPT | ์ฐจ์งํฉ | A - B |
[employees_kr] (ํ๊ตญ ์ง์)
| id | name | dept |
|----|------|------|
| 1 | ๊น์ฒ ์ | ๊ฐ๋ฐ |
| 2 | ์ด์ํฌ | ๋ง์ผํ
|
| 3 | ๋ฐ๋ฏผ์ | ๊ฐ๋ฐ |
[employees_jp] (์ผ๋ณธ ์ง์)
| id | name | dept |
|----|------|------|
| 101 | ็ฐไธญ | ๊ฐ๋ฐ |
| 102 | ้ดๆจ | ์์
|
| 2 | ์ด์ํฌ | ๋ง์ผํ
|
SELECT name, dept FROM employees_kr
UNION
SELECT name, dept FROM employees_jp;
| name | dept |
|---|---|
| ๊น์ฒ ์ | ๊ฐ๋ฐ |
| ์ด์ํฌ | ๋ง์ผํ |
| ๋ฐ๋ฏผ์ | ๊ฐ๋ฐ |
| ็ฐไธญ | ๊ฐ๋ฐ |
| ้ดๆจ | ์์ |
ํฌ์ธํธ: ์ด์ํฌ๋ ์์ชฝ์ ์์ง๋ง ํ ๋ฒ๋ง ๋์ด!
SELECT name, dept FROM employees_kr
UNION ALL
SELECT name, dept FROM employees_jp;
| name | dept |
|---|---|
| ๊น์ฒ ์ | ๊ฐ๋ฐ |
| ์ด์ํฌ | ๋ง์ผํ |
| ๋ฐ๋ฏผ์ | ๊ฐ๋ฐ |
| ็ฐไธญ | ๊ฐ๋ฐ |
| ้ดๆจ | ์์ |
| ์ด์ํฌ | ๋ง์ผํ |
ํฌ์ธํธ: ์ด์ํฌ๊ฐ ๋ ๋ฒ ๋์ด!
| ๋น๊ต | UNION | UNION ALL |
|---|---|---|
| ์ค๋ณต | ์ ๊ฑฐ | ์ ์ง |
| ์ฑ๋ฅ | ๋๋ฆผ (์ ๋ ฌ ํ์) | ๋น ๋ฆ |
| ์ฌ์ฉ ์์ | ์ค๋ณต ์ ๊ฑฐ ํ์ | ์ฑ๋ฅ ์ค์ |
โ ๋๋ถ๋ถ UNION ALL์ด ๋ ๋น ๋ฆ! ์ค๋ณต ์ ๊ฑฐ๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ง UNION ์ฌ์ฉ.
SELECT name, dept FROM employees_kr
INTERSECT
SELECT name, dept FROM employees_jp;
| name | dept |
|---|---|
| ์ด์ํฌ | ๋ง์ผํ |
ํฌ์ธํธ: ์์ชฝ ๋ชจ๋์ ์๋ ๊ฒ๋ง!
์ฃผ์: MySQL์ INTERSECT ๋ฏธ์ง์! ๋์ฒด ๋ฐฉ๋ฒ:
-- MySQL ๋์ฒด: INNER JOIN
SELECT DISTINCT a.name, a.dept
FROM employees_kr a
INNER JOIN employees_jp b
ON a.name = b.name AND a.dept = b.dept;
-- ๋๋ IN
SELECT name, dept FROM employees_kr
WHERE (name, dept) IN (SELECT name, dept FROM employees_jp);
-- PostgreSQL, SQL Server
SELECT name, dept FROM employees_kr
EXCEPT
SELECT name, dept FROM employees_jp;
-- Oracle
SELECT name, dept FROM employees_kr
MINUS
SELECT name, dept FROM employees_jp;
| name | dept |
|---|---|
| ๊น์ฒ ์ | ๊ฐ๋ฐ |
| ๋ฐ๋ฏผ์ | ๊ฐ๋ฐ |
ํฌ์ธํธ: A์๋ง ์๊ณ B์๋ ์๋ ๊ฒ!
MySQL ๋์ฒด:
SELECT name, dept FROM employees_kr
WHERE (name, dept) NOT IN (SELECT name, dept FROM employees_jp);
-- ๋๋ LEFT JOIN
SELECT a.name, a.dept
FROM employees_kr a
LEFT JOIN employees_jp b
ON a.name = b.name AND a.dept = b.dept
WHERE b.name IS NULL;
-- โ ์๋ฌ: ์ปฌ๋ผ ์ ๋ค๋ฆ
SELECT id, name, dept FROM employees_kr
UNION
SELECT name, dept FROM employees_jp;
-- โ
์ปฌ๋ผ ์ ๋ง์ถค
SELECT name, dept FROM employees_kr
UNION
SELECT name, dept FROM employees_jp;
-- โ ์๋ฌ ๊ฐ๋ฅ: ํ์
๋ถ์ผ์น
SELECT id, name FROM employees_kr -- id: INT
UNION
SELECT name, dept FROM employees_jp; -- name: VARCHAR
-- โ
ํ์
๋ง์ถค
SELECT name, dept FROM employees_kr
UNION
SELECT name, dept FROM employees_jp;
SELECT name AS ์ด๋ฆ, dept AS ๋ถ์ FROM employees_kr
UNION
SELECT name AS n, dept AS d FROM employees_jp;
-- ๊ฒฐ๊ณผ ์ปฌ๋ผ๋ช
: ์ด๋ฆ, ๋ถ์ (์ฒซ ๋ฒ์งธ ๊ธฐ์ค)
-- ORDER BY๋ ์ ์ฒด ๊ฒฐ๊ณผ์ ์ ์ฉ
SELECT name, dept FROM employees_kr
UNION ALL
SELECT name, dept FROM employees_jp
ORDER BY name; -- ๋ง์ง๋ง์ ํ ๋ฒ๋ง!
-- โ ์๋ฌ: ๊ฐ SELECT์ ORDER BY
SELECT name FROM employees_kr ORDER BY name
UNION
SELECT name FROM employees_jp;
-- โ
์๋ธ์ฟผ๋ฆฌ๋ก ๊ฐ์ธ๋ฉด ๊ฐ๋ฅ
(SELECT name FROM employees_kr ORDER BY name LIMIT 10)
UNION
(SELECT name FROM employees_jp ORDER BY name LIMIT 10);
-- ์ฌ๋ฌ ์ง์ญ ๋ฐ์ดํฐ ํตํฉ
SELECT 'ํ๊ตญ' AS region, * FROM sales_kr
UNION ALL
SELECT '์ผ๋ณธ' AS region, * FROM sales_jp
UNION ALL
SELECT '๋ฏธ๊ตญ' AS region, * FROM sales_us;
-- ๊ธ์ก ๊ตฌ๊ฐ๋ณ๋ก ๋ผ๋ฒจ ๋ถ์ฌ์ ํฉ์น๊ธฐ
SELECT 'VIP' AS tier, user_id, total_amount
FROM orders
WHERE total_amount >= 1000000
UNION ALL
SELECT '์ผ๋ฐ' AS tier, user_id, total_amount
FROM orders
WHERE total_amount < 1000000;
-- ์ค์ ๋ฐ์ดํฐ + ๋น ๋ ์ง ์ฑ์ฐ๊ธฐ
SELECT date, COUNT(*) as cnt
FROM orders
GROUP BY date
UNION ALL
SELECT date, 0 as cnt
FROM calendar -- ๋ ์ง ํ
์ด๋ธ
WHERE date NOT IN (SELECT DISTINCT date FROM orders);
-- ํ์ ์ด๋ก ๋ณํํ๋ ํจ๊ณผ
SELECT 'A์ํ ๋งค์ถ' AS metric, SUM(amount) AS value
FROM orders WHERE product = 'A'
UNION ALL
SELECT 'B์ํ ๋งค์ถ' AS metric, SUM(amount) AS value
FROM orders WHERE product = 'B';
-- ๋๋ฆผ: ์ค๋ณต ์ ๊ฑฐ ์ํด ์ ๋ ฌ ํ์
SELECT * FROM table_a
UNION
SELECT * FROM table_b;
-- ๋น ๋ฆ: ๊ทธ๋ฅ ๋ถ์ด๊ธฐ๋ง
SELECT * FROM table_a
UNION ALL
SELECT * FROM table_b;
-- ๊ฐ SELECT๊ฐ ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋จ
-- ๊ฐ๊ฐ์ ๋ง๋ ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ์ข์
SELECT * FROM orders_2023 WHERE user_id = 1
UNION ALL
SELECT * FROM orders_2024 WHERE user_id = 1;
์ ๋ต ๋ณด๊ธฐํ๊ตญ๊ณผ ์ผ๋ณธ ์ง์ ์ ์ฒด ๋ช ๋จ์ ์ค๋ณต ์์ด ๊ตฌํ์ธ์.
SELECT name, dept FROM employees_kr
UNION
SELECT name, dept FROM employees_jp;
์ ๋ต ๋ณด๊ธฐ์ ์ฒด ์ง์ ๋ช ๋จ๊ณผ ํจ๊ป ์ด๋ ์ง์ฌ ์์์ธ์ง ํ์ํ์ธ์.
SELECT 'KR' AS country, name, dept FROM employees_kr
UNION ALL
SELECT 'JP' AS country, name, dept FROM employees_jp;
์ ๋ต ๋ณด๊ธฐํ๊ตญ์๋ง ์๊ณ ์ผ๋ณธ์๋ ์๋ ์ง์์ ๊ตฌํ์ธ์. (MySQL)
SELECT name, dept
FROM employees_kr
WHERE (name, dept) NOT IN (
SELECT name, dept FROM employees_jp
);
-- ๋๋ LEFT JOIN
SELECT a.name, a.dept
FROM employees_kr a
LEFT JOIN employees_jp b
ON a.name = b.name AND a.dept = b.dept
WHERE b.name IS NULL;
์ ๋ต ๋ณด๊ธฐํ๊ตญ ๋งค์ถ ์์ 3๊ฐ์ ์ผ๋ณธ ๋งค์ถ ์์ 3๊ฐ๋ฅผ ํฉ์ณ์ ๊ตฌํ์ธ์.
(SELECT 'KR' AS country, product, amount
FROM sales_kr
ORDER BY amount DESC
LIMIT 3)
UNION ALL
(SELECT 'JP' AS country, product, amount
FROM sales_jp
ORDER BY amount DESC
LIMIT 3);
Q: ์ค๋ณต ์ ๊ฑฐ ํ์?
โโโ Yes โ UNION
โโโ No โ UNION ALL (๋ ๋น ๋ฆ!)
Q: ์์ชฝ ๋ค ์๋ ๊ฒ๋ง?
โโโ INTERSECT (MySQL: INNER JOIN)
Q: ํ์ชฝ์๋ง ์๋ ๊ฒ?
โโโ EXCEPT/MINUS (MySQL: NOT IN, LEFT JOIN)
[ํฉ์งํฉ]
UNION: ์ค๋ณต ์ ๊ฑฐ (๋๋ฆผ)
UNION ALL: ์ค๋ณต ์ ์ง (๋น ๋ฆ)
[๊ต์งํฉ]
INTERSECT (MySQL: JOIN์ผ๋ก ๋์ฒด)
[์ฐจ์งํฉ]
EXCEPT/MINUS (MySQL: NOT IN์ผ๋ก ๋์ฒด)
[๊ท์น]
- ์ปฌ๋ผ ์ ๋์ผ
- ํ์
ํธํ
- ์ปฌ๋ผ๋ช
์ ์ฒซ ๋ฒ์งธ SELECT ๊ธฐ์ค
- ORDER BY๋ ๋ง์ง๋ง์ ํ ๋ฒ๋ง
[SQL ์๋ฆฌ์ฆ #10] BigQuery ๋ฌธ๋ฒ โ ์ฑ๋ํก์ด ์ฐ๋ ๊ทธ DB
๐ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ UNION ALL์ด ์ ๋ต์ด๋ค.
์ค๋ณต ์ ๊ฑฐ๊ฐ ์ ๋ง ํ์ํ ๊ฒฝ์ฐ์๋ง UNION์ ์ฐ์!