ํต์ฌ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ, ๋ค์ฑ๋ก์ด JOIN ๊ตฌ๋ฌธ, ์ง๊ณ ๋ฐ ์๋์ฐ ํจ์, ์ธ๋ฑ์ค ์ต์ ํ์ ํธ๋์ญ์
๊ฒฉ๋ฆฌ
## 1. ๊ธฐ๋ณธ ์กฐํ & ํํฐ๋ง (SELECT & WHERE)
```sql
-- ์กฐ๊ฑด ํํฐ๋ง ๋ฐ ํ์ด์ง
SELECT id, username, email, created_at
FROM users
WHERE status = 'ACTIVE'
AND created_at >= NOW() - INTERVAL '30 days'
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
-- NULL ์์ ๊ฒ์ฌ ๋ฐ ํจํด ๋งค์นญ
SELECT * FROM products
WHERE description IS NOT NULL
AND name ILIKE '%keyboard%'; -- ๋์๋ฌธ์ ๋ฌด์ ๊ฒ์ (Postgres)
```
## 2. ํ
์ด๋ธ ๊ฒฐํฉ (JOIN ๋ง์คํฐ)
```sql
-- INNER JOIN: ์์ชฝ์ ๋งค์นญ๋๋ ํ๋ง ๋ฐํ
SELECT u.username, o.total_amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- LEFT JOIN: ์ผ์ชฝ(users) ํ
์ด๋ธ์ ๋งค์นญ์ด ์์ด๋ NULL๋ก ๋ชจ๋ ๋ณด์กด
SELECT u.username, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;
-- ์ฃผ๋ฌธ ๋ด์ญ์ด ํ ๋ฒ๋ ์๋ ์ฌ์ฉ์ ์ฐพ๊ธฐ (Anti-Join)
SELECT u.id, u.username
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
```
## 3. ์ง๊ณ & ๊ทธ๋ฃนํ (GROUP BY & HAVING)
```sql
-- ๊ทธ๋ฃนํ ์ง๊ณ ๋ฐ ์กฐ๊ฑด ํํฐ (WHERE vs HAVING)
-- HAVING์ ์ง๊ณ๋ ๊ฒฐ๊ณผ(SUM, COUNT ๋ฑ)์ ๋ํ ํํฐ๋ง
SELECT category_id, COUNT(*) AS item_count, AVG(price) AS avg_price
FROM products
WHERE is_deleted = false
GROUP BY category_id
HAVING COUNT(*) >= 5;
```
## 4. ์๋์ฐ ํจ์ (์์ ๋ฐ ๋์ ํฉ)
```sql
-- ๋ถ์๋ณ ๊ธ์ฌ ์์ (RANK / DENSE_RANK / ROW_NUMBER)
SELECT
name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank_in_dept
FROM employees;
-- ์๋ณ ๋งค์ถ ๋ฐ ๋์ ๋งค์ถ(Cumulative Sum) ๊ณ์ฐ
SELECT
order_date, daily_revenue,
SUM(daily_revenue) OVER (ORDER BY order_date) AS running_total
FROM daily_sales;
```
## 5. UPSERT (์ฝ์
๋๋ ๊ธฐ์กด ๋ฐ์ดํฐ ์์ )
```sql
-- PostgreSQL ON CONFLICT
INSERT INTO user_settings (user_id, theme, notifications)
VALUES (101, 'dark', true)
ON CONFLICT (user_id)
DO UPDATE SET theme = EXCLUDED.theme, updated_at = NOW();
-- MySQL ON DUPLICATE KEY UPDATE
INSERT INTO user_settings (user_id, theme)
VALUES (101, 'dark')
ON DUPLICATE KEY UPDATE theme = VALUES(theme);
```
## 6. ์ธ๋ฑ์ค ์์ฑ ๋ฐ ์คํ ๊ณํ ๋ถ์ (EXPLAIN)
```sql
-- ์์ฃผ ๊ฒ์ํ๋ ๋ณตํฉ ์ธ๋ฑ์ค ์์ฑ
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
-- ์ฟผ๋ฆฌ ์คํ ๊ณํ ๋ฐ ์ค์ ์์ ์๊ฐ ๋ถ์
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE user_id = 42 AND status = 'COMPLETED';
```
`Seq Scan`(์ ์ฒด ํ
์ด๋ธ ์ค์บ) ๋์ `Index Scan`์ด ์ ์ฉ๋๋์ง ํ์ธํ๋ ๊ฒ์ด ์ฑ๋ฅ ํ๋์ ๊ธฐ๋ณธ์
๋๋ค.
## 7. ํธ๋์ญ์
์ ์ด (ACID)
```sql
BEGIN; -- ๋๋ START TRANSACTION;
UPDATE accounts SET balance = balance - 5000 WHERE id = 1;
UPDATE accounts SET balance = balance + 5000 WHERE id = 2;
-- ๋ชจ๋ ์์
์ด ์ ์์ผ ๋ ์ต์ข
๋ฐ์
COMMIT;
-- ์ค๊ฐ์ ์์ธ ๋ฐ์ ์ ์ด์ ์ํ๋ก ๋ณต์
-- ROLLBACK;
```
์๊ฒฌ ๋ฐ ์ง๋ฌธ
0์์ง ๋ฑ๋ก๋ ์๊ฒฌ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋๊ธ์ ๋จ๊ฒจ๋ณด์ธ์!
๋๊ธ ์์
๋๊ธ ์ญ์