반응형

서브쿼리(Subquery)의 모든 것
: 복잡한 데이터도 쉽게 다루는 SQL 비법

SQL 초보자라면 꼭 알아야 할 핵심 스킬! 서브쿼리만 잘 써도 데이터 조회, 갱신, 삭제가 훨씬 쉬워집니다!

 

 

안녕하세요, 데이터베이스를 처음 배우시는 분들께 정말 중요한 주제를 들고 왔습니다.

바로 서브쿼리(Subquery)입니다!

처음에는 좀 헷갈릴 수도 있지만, 개념만 제대로 잡고 나면 생각보다 쉽게 활용할 수 있답니다.

특히 오늘은 단순한 이론 설명에 그치지 않고, 실무에서 바로 써먹을 수 있는 실습 예제까지 준비했어요.

서브쿼리는 단일행/다중행 서브쿼리부터 시작해, 평균보다 비싼 상품 찾기, 데이터 갱신/삭제까지 아주 유용한 기능들을 갖추고 있습니다.

이번 글에서는 실제 SQL 쿼리와 결과를 함께 보면서 여러분이 서브쿼리를 완전히 이해할 수 있도록 도와드릴게요.

그럼 지금부터 하나씩 차근차근, 함께 살펴볼까요? 😊

1. 서브쿼리란? 기본 개념과 종류 정리

SQL을 공부하다 보면 이런 상황 한 번쯤은 겪게 됩니다.

“조건에 맞는 데이터를 조회하고 싶은데, 조건 자체가 또 다른 쿼리 결과여야 한다?”
이럴 때 서브쿼리(Subquery)가 등장하죠.

쉽게 말해,

쿼리 안에 또 다른 쿼리를 넣는 것입니다.

말 그대로 ‘하위 쿼리’라고도 불러요.

서브쿼리의 정의

서브쿼리는 SELECT, INSERT, UPDATE, DELETE 문의 내부에 포함되어 실행되는 SQL 쿼리입니다.

보통 괄호(()) 안에 위치하며, 외부 쿼리(Main Query)의 조건을 보조하는 역할을 해요.

서브쿼리의 위치별 분류

  • WHERE 절 서브쿼리: 특정 조건에 맞는 데이터를 필터링할 때 사용
  • FROM 절 서브쿼리: 서브쿼리를 테이블처럼 사용
  • SELECT 절 서브쿼리: 컬럼 값으로 서브쿼리 결과를 가져올 때 사용

서브쿼리의 종류: 단일행 vs 다중행

구분 설명 사용 예
단일행 서브쿼리 결과가 한 행만 반환됨 =, >, < 등의 연산자 사용
다중행 서브쿼리 결과가 여러 행을 반환함 IN, ANY, ALL 연산자 사용

✅ 실전에서 어떤 걸 써야 할까?

단일 결과가 필요한 조건(예: 평균, 최대값, 특정 ID)이라면 단일행 서브쿼리가 적합하고,

여러 조건 중 하나라도 일치하는 경우(예: 다수의 ID 목록, 특정 그룹)라면 다중행 서브쿼리가 필요합니다.

 

다음 단계에서는 이 두 가지 서브쿼리를 예제 중심으로 비교해보고, 실무에서 어떻게 활용되는지를 구체적으로 살펴볼게요. 🚀

 

 

2. 단일행 vs 다중행 서브쿼리 비교하기

서브쿼리를 사용하다 보면 가장 먼저 마주치는 갈림길이 바로 이것입니다.

"이 서브쿼리는 단일행일까, 다중행일까?" 이 둘은 쓰는 문법도 다르고, 오류 발생 가능성도 달라요.

그러니까 잘 구분해서 사용해야 합니다!

📌 단일행 서브쿼리

단일행 서브쿼리는 결과가 딱 하나만 나오는 경우입니다.

주로 집계 함수(AVG, MAX, MIN)를 쓴 서브쿼리에서 많이 볼 수 있어요.

 

💡 예제: 평균 급여보다 높은 급여를 받는 사원 찾기

SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

 

서브쿼리 (SELECT AVG(salary) ...)는 하나의 숫자(평균 급여)만 반환하죠?

그래서 외부 쿼리에서 salary > 평균 조건으로 비교할 수 있어요.

📌 다중행 서브쿼리

다중행 서브쿼리는 결과가 여러 행 나올 수 있는 경우예요.

이럴 땐 IN, ANY, ALL 같은 연산자를 사용해야 합니다.

 

💡 예제: 서울에 있는 고객에게만 상품을 판매한 직원 찾기

SELECT name
FROM employees
WHERE region_id IN (SELECT region_id FROM regions WHERE city = 'Seoul');

 

SELECT region_id ... 서브쿼리는 여러 개의 지역 ID를 반환할 수 있어요.

그럼 외부 쿼리는 IN (여러 값) 형태로 처리해야죠.

🎯 단일/다중행 서브쿼리, 이렇게 구분하세요!

항목 단일행 서브쿼리 다중행 서브쿼리
결과 수 1행 (1개 값) 여러 행
대표 연산자 =, >, <, >= 등 IN, ANY, ALL
예외 발생 다중 결과시 오류 발생 단일 연산자 사용시 오류

 

정리하자면,

결과 행의 수를 기준으로 서브쿼리를 판단하고, 그에 맞는 연산자를 선택해야 합니다.

 

다음 장에서는 이 개념을 바탕으로 실제로 서브쿼리를 활용해서 복잡한 데이터 조회를 어떻게 수행하는지 보여드릴게요!

 

 

3. 복잡한 데이터 조회에 서브쿼리 활용하기

서브쿼리를 진짜 멋지게 활용할 수 있는 타이밍이 바로 복잡한 조건의 데이터 조회입니다.

단일 테이블에서 끝나는 단순한 SELECT 쿼리는 물론, 두 개 이상의 테이블을 연결하거나 특정 조건을 가진 집계 데이터를 찾을 때도 서브쿼리는 빛을 발하죠.

🎯 활용 예 1: 평균보다 높은 급여를 받는 부서의 사원 목록

SELECT name, department_id, salary
FROM employees
WHERE salary > (
  SELECT AVG(salary)
  FROM employees
);

 

이 쿼리는 모든 직원의 평균 급여를 먼저 계산한 후, 그보다 높은 급여를 받는 직원만 조회합니다.

복잡해 보이지만, 서브쿼리 하나로 매우 직관적인 쿼리를 완성할 수 있어요!

🎯 활용 예 2: 최근 주문한 고객 정보 조회

SELECT customer_id, name
FROM customers
WHERE customer_id IN (
  SELECT customer_id
  FROM orders
  WHERE order_date >= CURDATE() - INTERVAL 30 DAY
);

 

orders 테이블에서 최근 30일 내 주문한 고객 ID만 추출한 후, 그 ID들을 바탕으로 customers 테이블에서 상세 정보를 가져오는 방식입니다.

이중 조회가 필요한 케이스에서 아주 강력한 무기예요.

🎯 활용 예 3: 가장 많이 주문한 상품 조회

SELECT product_name
FROM products
WHERE product_id = (
  SELECT product_id
  FROM order_items
  GROUP BY product_id
  ORDER BY COUNT(*) DESC
  LIMIT 1
);

 

이 쿼리는 서브쿼리 안에서 ORDER BY + LIMIT를 사용해 가장 많이 팔린 상품 하나를 찾고, 그 상품의 이름을 외부 쿼리로 가져오는 방식입니다.

💡 FROM 절에 쓰는 인라인 서브쿼리도 있다?

서브쿼리는 WHERE절에만 사용하는 게 아니에요.

FROM 절에 서브쿼리를 넣으면, 그것 자체가 하나의 가상 테이블처럼 작동합니다.

SELECT dept_summary.department_id, dept_summary.total_salary
FROM (
  SELECT department_id, SUM(salary) AS total_salary
  FROM employees
  GROUP BY department_id
) AS dept_summary
WHERE total_salary > 1000000;

 

이런 방식은 복잡한 그룹 연산을 미리 처리하고, 그 결과를 다시 필터링하거나 정렬할 때 정말 유용해요.

📌 Tip: JOIN보다 서브쿼리가 유리한 상황

  • 집계 결과로 필터링해야 할 때 (ex. 평균, 최대값 기반 조건)
  • 조건에 맞는 특정 값만 필요할 때 (ex. 최신 데이터 1건만)
  • 중첩 필터링이 필요한 복잡한 조건문 구성 시

이제 서브쿼리를 어떻게 응용하면 복잡한 조건에서도 깔끔하게 원하는 데이터를 뽑을 수 있는지 감이 좀 오셨죠?

다음은 바로 실습 시간입니다! 😊

AVG를 활용해 평균보다 비싼 상품만 골라보는 예제로 넘어가 보죠!

 

 

4. 실습예제 ① : 평균보다 비싼 상품 조회

실습 예제를 통해 서브쿼리를 직접 써보면 확실히 개념이 잘 잡히죠!

이번 예제에서는 상품 테이블(products)에서 전체 평균 가격보다 비싼 상품들만 골라보겠습니다.

🎯 목표

  • 전체 상품의 평균 가격을 계산한다.
  • 평균보다 높은 가격의 상품들만 조회한다.

📋 사용 테이블 구조 (products)

컬럼명 데이터 타입 설명
product_id INT 상품 고유 ID
product_name VARCHAR 상품명
price DECIMAL 상품 가격

💻 실습 SQL

SELECT product_name, price
FROM products
WHERE price > (
  SELECT AVG(price) FROM products
);

 

이 쿼리는 단일행 서브쿼리를 사용한 대표적인 예입니다.

내부 쿼리 SELECT AVG(price)는 하나의 평균값을 반환하고, 외부 쿼리는 그 값을 기준으로 조건을 걸어줍니다.

💬 실습 팁

  • 서브쿼리가 먼저 실행되고, 그 결과를 외부 쿼리가 이용해 조건 비교합니다.
  • 테이블에 따라 AVG 결과가 소수점이 나오기 때문에 ROUND() 함수를 함께 사용해도 좋습니다.

이제 서브쿼리를 직접 써봤으니 감이 조금 오시죠? 😎

 

다음은 서브쿼리로 데이터를 갱신하거나 삭제하는 예제로 이어가 볼게요.

 

 

5. 실습예제 ② : 서브쿼리로 데이터 갱신/삭제하기

서브쿼리는 단순히 데이터를 조회하는 데만 쓰이는 게 아닙니다!

UPDATEDELETE에도 아주 효과적으로 활용할 수 있어요.

이번엔 데이터를 바꾸거나 지울 때 서브쿼리를 어떻게 활용하는지 실습 예제를 통해 익혀볼게요.

🎯 예제 1: 가장 적게 팔린 상품의 가격 10% 인하

UPDATE products
SET price = price * 0.9
WHERE product_id = (
  SELECT product_id
  FROM order_items
  GROUP BY product_id
  ORDER BY COUNT(*) ASC
  LIMIT 1
);

 

위 쿼리는 order_items 테이블에서 가장 적게 팔린 상품을 찾아내고, 해당 상품의 가격을 10% 인하하는 업데이트 작업을 수행합니다.

서브쿼리를 통해 조건 대상을 정하고, 외부 쿼리에서 그 값을 기반으로 갱신하는 방식이죠.

🎯 예제 2: 주문한 적 없는 고객 삭제

DELETE FROM customers
WHERE customer_id NOT IN (
  SELECT DISTINCT customer_id
  FROM orders
);

 

이번엔 삭제입니다!

orders 테이블에 등장하지 않은 고객 ID만 찾아내서, customers 테이블에서 해당 고객들을 제거합니다.

NOT IN과 서브쿼리 조합은 이런 "조건부 삭제"에 자주 사용됩니다.

💬 실무 꿀팁

  • UPDATE/DELETE에 서브쿼리를 쓸 때는 SELECT 먼저 테스트 해보는 게 안전합니다.
  • 서브쿼리가 다중 결과를 반환할 가능성이 있다면 IN, EXISTS를 고려해 보세요.
  • DELETE 전에 항상 백업을! 데이터는 소중하니까요 😥

서브쿼리를 단순 조회뿐 아니라 갱신과 삭제에도 유용하게 활용할 수 있다는 것, 이제 확실히 느끼셨을 거예요.

 

 

6. 마무리 

지금까지 서브쿼리의 개념부터 다양한 활용 예제까지 쭉 따라오신 여러분, 정말 고생 많으셨어요!

처음엔 다소 낯설고 복잡하게 느껴질 수 있지만, 막상 실무에 들어가 보면 서브쿼리를 얼마나 자주 쓰는지 놀라실 거예요.

이제는 단순한 SELECT 문을 넘어서 데이터를 요리하듯 다룰 수 있는 능력이 생긴 겁니다!

📌 실무 활용 꿀팁 요약

  • 서브쿼리 결과는 꼭 행 수를 예측하고 연산자를 선택해야 합니다 (= vs IN).
  • SELECT문 외에도 UPDATE, DELETE에도 서브쿼리를 적극 활용해보세요.
  • FROM 절에서 사용하는 인라인 뷰도 실무에서 많이 등장합니다.
  • 서브쿼리로 처리 가능한 로직은 JOIN보다 더 깔끔하고 효율적일 수 있음!

끝으로 하나만 더 강조드릴게요.

서브쿼리는 조건을 동적으로 만들 수 있는 강력한 도구입니다.

SQL 초보 단계에서 서브쿼리를 자유자재로 다룰 수 있게 되면, 그 자체로 실력자라고 불릴 만한 자격이 충분해요! 🔥

오늘 배운 예제들, 꼭 실습하면서 손에 익혀보시길 추천드릴게요.

 

반응형
반응형

다양한 JOIN 활용하기: 테이블 관계를 한눈에!

"이런 데이터를 어떻게 뽑지?"
JOIN을 이해하면, 테이블 간 데이터 연결이 보입니다.
실무에서 가장 많이 쓰이는 SQL JOIN의 모든 것을 쉽게 알려드릴게요!

 

 

안녕하세요, 여러분 😊

개발자든 데이터 분석가든, SQL을 다루다 보면 언젠가는 반드시 마주치는 벽이 있죠. 바로 JOIN입니다!

JOIN은 데이터베이스에서 테이블 간 관계를 연결하고 원하는 데이터를 통합할 수 있게 해주는 정말 강력한 기능인데요.

하지만 처음 배우는 분들에게는 그 개념이 꽤나 헷갈릴 수 있어요.

그래서 오늘은 JOIN의 개념부터 실무 예제까지, 실전 중심으로 하나하나 친절하게 설명해드리려고 해요.

특히 회원, 주문, 상품 테이블을 JOIN해서 판매 리포트까지 만드는 실습을 함께 해볼 거예요!

1. INNER JOIN, LEFT JOIN, RIGHT JOIN 개념 정리 ✨

SQL에서 JOIN은 두 개 이상의 테이블을 연결해 하나의 결과로 만들어주는 기능이에요.

이 JOIN은 데이터베이스 관계형 모델의 핵심 개념 중 하나로, 테이블 간의 관계(Relation)를 활용해 데이터를 종합하는 데 사용되죠.

JOIN의 종류는 다양하지만, 그중에서도 가장 자주 사용하는 세 가지가 바로

INNER JOIN, LEFT JOIN, RIGHT JOIN입니다.

1-1. INNER JOIN 🧩

INNER JOIN은 두 테이블에서 공통된 값이 존재하는 행만 결과로 가져와요.

즉, 교집합을 구한다고 생각하면 편해요.

SELECT *
FROM orders
INNER JOIN members ON orders.member_id = members.id;

→ 주문한 회원만 조회하고 싶을 때 자주 사용합니다.

1-2. LEFT JOIN 🧭

LEFT JOIN은 왼쪽 테이블은 모두 가져오고, 오른쪽 테이블에 매칭되는 값이 있으면 같이 보여줘요.

즉, 왼쪽 기준 전체 데이터 + 오른쪽 매칭되는 데이터!

SELECT *
FROM members
LEFT JOIN orders ON members.id = orders.member_id;

→ 주문하지 않은 회원까지 모두 조회해야 할 때 유용합니다.

1-3. RIGHT JOIN ➡️

RIGHT JOIN은 LEFT JOIN의 반대 개념이에요.

오른쪽 테이블은 모두 보여주고, 왼쪽 테이블과 매칭되는 데이터를 함께 보여줍니다.

SELECT *
FROM orders
RIGHT JOIN members ON orders.member_id = members.id;

→ 오른쪽 테이블 중심으로 보고 싶을 때 쓰지만, 대부분 LEFT JOIN으로 처리하는 경우가 많아요.

1-4. JOIN 비교 요약표 📊

JOIN 종류 결과 설명 대표 사용 예
INNER JOIN 양쪽 모두에 일치하는 데이터만 실제로 주문한 회원만 조회
LEFT JOIN 왼쪽 테이블 전체 + 오른쪽 매칭 모든 회원 + 주문 여부 확인
RIGHT JOIN 오른쪽 테이블 전체 + 왼쪽 매칭 모든 주문 기록 + 회원 여부 확인

 

이제 JOIN의 기본 개념이 조금은 명확해지셨죠? 😊

다음 파트에서는 "왜 실무에서 이렇게까지 JOIN을 많이 쓰는지" 그 이유를 살펴볼 거예요.

실제 현업에서는 데이터 연결 없이는 아무것도 할 수 없거든요.

그럼 계속해서 다음 목차로 넘어가 볼게요!

 

 

2. 실무에서 JOIN을 활용하는 이유 💡

JOIN이 실무에서 왜 이렇게 중요할까요?

간단히 말해,

현실 세계의 데이터는 대부분 하나의 테이블에 담기지 않기 때문이에요.

회원 정보는 `members` 테이블, 주문 정보는 `orders`, 상품 정보는 `products`에 따로 저장돼 있죠.

그럼 결국, 우리가 원하는 "의미 있는 데이터 분석"을 하려면 이 테이블들을 묶어주는 JOIN이 필수라는 뜻이에요.

2-1. 실제 서비스는 '관계형' 데이터 구조로 설계된다

예를 들어볼게요. 여러분이 쿠팡 같은 쇼핑몰을 만든다고 가정해 봅시다.

  • 회원은 여러 번 주문할 수 있고,
  • 하나의 주문에는 여러 상품이 들어갈 수 있으며,
  • 상품은 다른 주문에도 포함될 수 있어요.

→ 이처럼 실제 서비스는 '하나의 테이블'로 해결되지 않으며, 테이블 간의 관계를 표현하고 연결해주는 JOIN이 꼭 필요해요.

2-2. JOIN이 필요한 실전 사례들 🔍

상황 JOIN 이유
회원별 총 주문 금액 조회 회원 + 주문 테이블을 JOIN해서 합계 계산
상품별 판매 실적 분석 주문 상세 + 상품 테이블을 JOIN
로그인한 사용자 주문 내역 조회 세션 기반 사용자 ID로 JOIN하여 조회

2-3. JOIN을 모르면 겪게 되는 문제들 ⚠️

  • 단일 테이블에 모든 데이터를 저장하려고 함 → DB 설계 실패
  • 필요한 데이터를 뽑지 못해 리포트, 분석 등 무력해짐
  • 성능 저하를 유발하는 서브쿼리 반복

JOIN을 자유자재로 활용하는 사람과 그렇지 않은 사람의 실력 차이는, 데이터를 문장으로 이해하느냐, 실제로 활용할 수 있느냐의 차이라고 생각해요.

 

그럼 다음은 본격적인 실습을 위한 준비! 회원-주문-상품 테이블의 구조를 먼저 이해해보도록 할게요.

구조를 모르고 JOIN하면 의미가 없으니까요 😉

 

 

3. 회원-주문-상품 테이블 구조 이해 🧱

자, 이제 JOIN 실습을 하기 전에 먼저 어떤 테이블이 존재하고, 이들 사이에 어떤 관계가 있는지부터 명확하게 이해해야 해요.

우리가 사용할 데이터베이스에는 총 3개의 테이블이 있습니다:

  1. 회원 테이블 (members)
  2. 주문 테이블 (orders)
  3. 상품 테이블 (products)

이 세 테이블은 각각 독립적으로 존재하지만, 외래 키(Foreign Key)를 통해 서로 연결됩니다.

3-1. 테이블 구조 및 관계도 📘

테이블 주요 컬럼 설명
members id, name, email 회원 정보 저장
orders id, member_id, product_id, quantity 주문 정보 저장, 회원/상품과 연결됨
products id, name, price 상품 정보 저장

 

이 구조에서 핵심은 orders 테이블이 중간 다리 역할을 한다는 거예요.

이 테이블 덕분에 "어떤 회원이 어떤 상품을 주문했는가?"를 알 수 있죠.

3-2. 관계형 데이터 ERD 도식화 🔗

간단한 관계도를 텍스트로 나타내면 다음과 같아요:

members (1) ──── (N) orders (N) ──── (1) products

→ 회원 1명이 여러 주문 가능,

→ 하나의 주문은 하나의 상품을 가리킴,

→ 같은 상품이 여러 주문에 포함될 수 있음!

3-3. 실습을 위한 샘플 데이터 📦

실습을 위해 아래와 같은 샘플 데이터를 구성해둘게요.

테이블 샘플 데이터 예시
members (1, '홍길동', 'hong@example.com')
orders (1001, 1, 2001, 2)
products (2001, 'USB 메모리', 12000)

→ 이제 이 데이터를 JOIN해서 "누가 어떤 상품을 몇 개 샀는지"를 알 수 있겠죠?

 

자, 테이블 구조도 이해했고 준비는 끝났습니다.

다음 파트에서는 본격적으로 JOIN을 활용한 실습을 시작해볼게요!

궁금했던 JOIN의 실제 동작 방식, 이제 직접 눈으로 확인할 시간입니다 🔥

 

 

4. JOIN으로 테이블 관계 조회하기 🔍

자, 이제 본격적인 실습 시간이에요!

앞서 소개한 회원(members), 주문(orders), 상품(products) 테이블을 JOIN해서 데이터를 조회해볼게요. 이 실습을 통해 실제 서비스에서 JOIN이 어떻게 활용되는지 체감할 수 있어요.

4-1. 회원 + 주문 정보 조회 (INNER JOIN)

SELECT m.id AS member_id, m.name, o.id AS order_id, o.quantity
FROM members m
INNER JOIN orders o ON m.id = o.member_id;

→ 주문을 한 회원만 조회됩니다. (주문하지 않은 회원은 결과에 포함되지 않음)

4-2. 주문 + 상품 정보 조회 (INNER JOIN)

SELECT o.id AS order_id, p.name AS product_name, p.price, o.quantity
FROM orders o
INNER JOIN products p ON o.product_id = p.id;

→ 주문 내역에 포함된 상품의 이름과 가격까지 확인 가능해요.

4-3. 회원 + 주문 + 상품 전체 JOIN (3개 테이블 연결)

SELECT m.name AS member_name, p.name AS product_name, p.price, o.quantity
FROM members m
INNER JOIN orders o ON m.id = o.member_id
INNER JOIN products p ON o.product_id = p.id;

회원이 어떤 상품을 얼마나 주문했는지를 정확히 알 수 있어요.

4-4. LEFT JOIN으로 주문 없는 회원까지 조회

SELECT m.name AS member_name, o.id AS order_id
FROM members m
LEFT JOIN orders o ON m.id = o.member_id;

모든 회원을 보여주되, 주문이 있는 경우만 주문 번호가 함께 나옵니다. (주문이 없는 회원은 NULL로 표시됨)

4-5. 실습 결과 예시 🎯

회원명 상품명 가격 수량
홍길동 USB 메모리 12000 2

여기까지 진행하셨다면, 이제 JOIN의 기본적인 사용법은 거의 마스터하신 거예요! 👏

이제 다음 파트에서는 JOIN을 활용한 리포트 생성이라는 한 단계 높은 실습으로 넘어가볼게요.

단순 조회를 넘어서, 집계, 분석, 정렬까지 같이 경험해봐야 진짜 실무 활용이 되니까요!

 

 

5. 실습: 다양한 JOIN으로 리포트 만들기 📊

지금부터 JOIN을 활용해서 판매 실적 리포트를 만들어보겠습니다.

단순 조회를 넘어서서, 집계(SUM), 그룹핑(GROUP BY), 정렬(ORDER BY)까지 함께 써볼 거예요.

이게 바로 진짜 실무에서 매일 하는 SQL이에요.

5-1. 상품별 총 판매 수량 리포트

SELECT p.name AS product_name, SUM(o.quantity) AS total_sold
FROM orders o
INNER JOIN products p ON o.product_id = p.id
GROUP BY p.name
ORDER BY total_sold DESC;

→ 어떤 상품이 얼마나 많이 팔렸는지 순서대로 확인할 수 있어요.

5-2. 회원별 총 구매 금액 리포트

SELECT m.name AS member_name, SUM(p.price * o.quantity) AS total_spent
FROM members m
INNER JOIN orders o ON m.id = o.member_id
INNER JOIN products p ON o.product_id = p.id
GROUP BY m.name
ORDER BY total_spent DESC;

→ 어떤 회원이 가장 많이 결제했는지 알 수 있어요.

     마케팅 타깃 추출이나 VIP 등급 관리에 바로 써먹을 수 있어요!

5-3. 월별 판매 실적 리포트

이번엔 날짜가 저장되어 있다고 가정하고, 주문일 기준으로 월별 실적도 만들어볼게요.

아래는 주문 테이블에 order_date 컬럼이 있는 경우입니다.

SELECT DATE_FORMAT(o.order_date, '%Y-%m') AS month, SUM(p.price * o.quantity) AS monthly_revenue
FROM orders o
INNER JOIN products p ON o.product_id = p.id
GROUP BY month
ORDER BY month ASC;

→ 월별 매출 분석! 보고서, 대시보드, 매출 트렌드 예측 등에 사용됩니다.

5-4. 리포트 실전 응용 팁 💡

  • 집계 함수 + GROUP BY 조합은 실무에서 필수!
  • 리포트용 쿼리는 항상 ORDER BY로 정렬까지!
  • 복잡해지면 서브쿼리 또는 CTE로 나누기

여기까지 잘 따라오셨다면,

이제 단순 SELECT 쿼리를 넘어서 데이터 분석 실무에서 필요한 JOIN 활용 능력을 갖추셨다고 볼 수 있어요!

이제 마지막으로 JOIN 마스터를 위한 실전 꿀팁만 정리하고 마무리할게요 😉

 

 

6. JOIN 마스터를 위한 실전 팁 🔧

JOIN을 이론으로만 배웠다면 아직 반쪽짜리예요.

실제 프로젝트, 운영 서버, 대용량 데이터에서 JOIN은 성능, 구조, 가독성 등 다양한 고민이 함께 따라옵니다.

이 파트에서는 JOIN을 잘 쓰는 사람들의 실무 노하우를 공유할게요!

6-1. JOIN 성능 최적화 핵심 포인트

  • ON 절의 컬럼은 반드시 인덱스가 있는지 확인할 것!
  • 필요한 컬럼만 SELECT 해서 속도와 메모리 낭비 줄이기
  • WHERE 조건은 JOIN보다 아래쪽에 두는 게 가독성에 좋음

6-2. 실무에서 자주 쓰는 JOIN 패턴

JOIN은 다음과 같은 실무 시나리오에서 자주 사용됩니다:

JOIN 활용 시나리오 예시
회원별 주문 내역 조회 members + orders
상품별 누적 판매 집계 orders + products + GROUP BY
접속 로그 기반 행동 분석 users + logs + actions

6-3. JOIN 쿼리 디버깅 꿀팁

  • JOIN 결과가 비정상일 때는 테이블 별 단독 SELECT로 먼저 확인하기
  • WHERE 조건이 NULL과 연관된 경우에는 IS NULL 주의
  • 쿼리 복잡할수록 CTE(Common Table Expression) 활용 추천

🚀 마무리하며

JOIN은 단순히 문법만 익히는 것이 아니라, "데이터 구조를 연결해서 의미를 찾아내는 능력"입니다.

기본 개념 → 실습 → 리포트 → 최적화까지 익히셨다면, 이제 JOIN은 여러분의 강력한 무기가 될 거예요.

 

다음에 더 복잡한 관계형 쿼리나 성능 튜닝, 실시간 분석 쿼리까지도 도전해보세요!

JOIN은 처음이 어렵지, 익숙해지면 누구보다 유용한 툴이 될 거예요 😉

반응형
반응형

관계형 데이터베이스 정규화 이론 완전 정복!

여러분 혹시, 엑셀처럼 막 복사해서 만든 테이블이 왜 문제가 되는지 고민해 본 적 있나요?
데이터가 반복되고 수정도 어렵고…
그거, 정규화로 해결할 수 있어요!

 

 

안녕하세요 😊

오늘은 관계형 데이터베이스(RDBMS)를 다룰 때 절대 빼놓을 수 없는 이론,

바로 정규화(Normalization)에 대해 제대로 파헤쳐 보려고 해요.

처음엔 조금 어려워 보여도, 한 번 개념이 잡히면 나중에 설계나 개발할 때 정말 큰 무기가 되거든요.

특히, 1NF → 2NF → 3NF의 흐름과 함께 직접 실습해보는 과정까지!

데이터가 어떻게 더 깔끔하고 효율적으로 변하는지 직접 확인할 수 있을 거예요.

그럼 같이 출발해 볼까요? 🚀

1. 정규화란 무엇인가요? 개념과 등장 배경 🔍

데이터베이스를 설계하다 보면, 데이터를 어떻게 분리하고 어떤 식으로 테이블을 나눠야 할지 고민될 때가 있어요.

바로 이때! 정규화(Normalization)라는 개념이 등장합니다.

정규화는 데이터 중복을 줄이고, 데이터 무결성을 높이기 위한 데이터베이스 설계 원칙이에요.

💡 정규화란?

정규화는 데이터를 체계적으로 분해해 논리적 구조로 만드는 과정입니다.

쉽게 말해,

"테이블 안에 들어 있는 정보들이 서로 충돌하거나 불필요하게 반복되지 않도록" 정리하는 거죠.

  • 데이터를 중복 없이 저장하고
  • 삽입, 수정, 삭제 시 오류가 없도록 만들고
  • 각 데이터가 '한 곳'에서만 관리되도록 하기 위해 존재합니다

📜 정규화의 등장 배경

정규화는 1970년대에 E.F. Codd라는 천재 수학자 겸 컴퓨터 과학자에 의해 제안되었습니다.

그는 관계형 데이터베이스의 개념을 처음 정의하면서, 데이터의 논리적 일관성유지 보수의 편의성을 위해 정규형(Normal Forms)을 도입했죠.

처음에는 단순한 규칙이었지만, 점점 데이터의 복잡도가 높아지면서 1NF, 2NF, 3NF, BCNF, 4NF, 5NF처럼 여러 단계로 발전하게 되었습니다.

이번 글에서는 그 중에서도 가장 핵심이 되는 1NF, 2NF, 3NF에 초점을 맞춰 소개할게요!

🎯 정규화의 핵심 목표

목표 설명
중복 최소화 같은 정보를 여러 번 저장하지 않도록 테이블을 나눔
무결성 유지 데이터 간 논리적 오류나 불일치 방지
유연한 구조 변경이 쉽게 가능한 설계로 확장성 향상

자, 이제 정규화의 개념과 역사, 목적까지 알아봤으니… 다음은 왜 이게 중요한지,

정규화를 하지 않았을 때 어떤 일이 벌어지는지 살펴볼 차례입니다!

 

 

2. 왜 정규화가 필요할까요? 비정규형의 문제점들 🤔

정규화가 중요한 이유를 한 문장으로 정리하자면, 데이터의 혼란을 방지하고 효율적으로 관리하기 위해서입니다.

비정규형 테이블은 언뜻 보면 한눈에 들어오고 관리가 쉬워 보일 수 있지만, 실제 운영에서는 심각한 문제를 야기합니다.

⚠️ 비정규형 테이블의 예시

예를 들어, 아래와 같은 학생 수강 테이블이 있다고 해볼게요.

학번 이름 수강과목
2023001 김지민 데이터베이스, 운영체제
2023002 이수현 프로그래밍언어

위처럼 수강과목을 쉼표로 나열하게 되면, 과목별로 검색하기가 어려워지고, 특정 과목을 삭제하거나 수정하려면 문자열 전체를 분석해야 하죠.

이게 바로 비정규형의 대표적인 문제입니다.

🧨 비정규형이 일으키는 대표적 문제들

  1. 📌 중복 발생 – 같은 정보가 여러 행에 중복 저장됨
  2. 📌 삽입 이상 – 특정 데이터를 삽입하려 해도 다른 정보가 필요함
  3. 📌 삭제 이상 – 하나의 데이터를 지우면 관련 없는 정보까지 삭제됨
  4. 📌 수정 이상 – 같은 데이터를 여러 곳에서 동시에 수정해야 함

즉, 정규화가 안 된 상태에서는 데이터의 일관성을 유지하기가 매우 어려워지고, 유지보수 비용도 급증합니다.

💬 현실 속 사례

예전에 학사 시스템을 관리할 때, 수강신청 내역이 전부 하나의 테이블에 ‘CSV 문자열’로 저장되어 있었어요.

검색은 느리고, 수정을 잘못해서 다른 과목까지 삭제되는 사태도 발생했죠.

그 경험 이후, 정말 간절히 정규화의 필요성을 절감했습니다 😅

그럼 이제 정규화를 적용하면 구체적으로 어떻게 바뀌는지, 1NF부터 살펴보도록 할게요!

 

 

3. 제1정규형(1NF)의 개념과 예시 ✨

정규화의 첫 단계인 제1정규형(1NF)은 모든 정규화의 시작점이에요.

이 단계에서는 모든 컬럼이 원자값(Atomic Value)을 갖도록 만드는 것이 핵심입니다.

🔍 제1정규형(1NF)의 정의

  • 모든 컬럼이 **단일 값(Atomic Value)**만 가져야 함
  • 반복 그룹이나 리스트 형태로 저장된 값은 허용하지 않음

즉, 열마다 하나의 값만 존재하도록 테이블을 구성해야 한다는 뜻이에요.

📌 예시로 살펴보는 1NF 적용

앞서 등장했던 비정규형 테이블을 다시 불러와 볼게요:

학번 이름 수강과목
2023001 김홍도 데이터베이스, 운영체제

이 테이블은 1NF를 만족하지 못합니다.

이유는 수강과목이라는 컬럼에 두 개의 값이 들어있기 때문이에요.

이를 1NF로 바꾸면 아래처럼 각 과목을 분리한 행 단위로 나눠야 합니다:

학번 이름 수강과목
2023001 김홍도 데이터베이스
2023001 김홍도 운영체제

이제야 진정한 1NF 정규화 테이블이 되었죠?

이렇게 함으로써 검색, 필터링, 수정이 훨씬 쉬워지고, SQL 쿼리도 깔끔하게 동작합니다.

✅ 1NF의 핵심 요약

요소 설명
원자성 모든 컬럼 값은 더 이상 나눌 수 없는 원자값이어야 함
중복 제거 여러 개의 값을 하나의 셀에 저장하지 않음
정규화 시작점 2NF와 3NF를 위한 전제 조건

그럼 다음 단계인 2NF에서는 어떤 일이 벌어질까요?

여기서부터 본격적으로 ‘의미의 분리’가 시작됩니다!

 

 

4. 제2정규형(2NF)의 개념과 예시 🔄

제2정규형(2NF)은 1NF를 만족한 상태에서 부분 함수 종속을 제거하는 단계예요.

여기서 중요한 개념이 바로 ‘복합 기본키’와 ‘부분 종속성’입니다.

📌 제2정규형(2NF)의 조건

  • 테이블이 1NF를 만족해야 함
  • 기본키가 복합키인 경우, 부분적으로만 종속되는 속성을 제거해야 함

즉, 기본키 전체가 아닌 일부 컬럼에만 의존하는 데이터를 다른 테이블로 분리해야 해요.

📚 예시로 살펴보기

1NF를 만족한 아래의 테이블을 보세요. 기본키는 (학번, 과목명) 입니다.

학번 이름 과목명 성적
2023001 김지민 데이터베이스 A
2023001 김지민 운영체제 B+

여기서 이름은 과목과는 무관하게 학번에만 종속되죠?

이게 바로 부분 종속입니다.

🔧 2NF 적용 후 테이블 분리

이럴 땐 아래처럼 두 개의 테이블로 나누어야 해요:

[학생 테이블]

학번 이름
2023001 김지민

[성적 테이블]

학번 과목명 성적
2023001 데이터베이스 A
2023001 운영체제 B+

이렇게 나누면 부분 종속성이 제거되고, 하나의 데이터가 두 번 이상 등장하는 일이 줄어들게 됩니다.

📌 핵심 요약: 2NF

요소 설명
1NF 기반 1NF를 만족한 테이블만 2NF로 정규화 가능
부분 종속 제거 복합키의 일부에만 의존하는 속성 제거
테이블 분리 의미 단위별 테이블로 나누어 관리

자, 이제 2NF까지 잘 정리되었어요.

그럼 다음은 마지막 정규형 중 가장 많이 쓰이는 제3정규형(3NF)에 대해 알아볼 차례입니다!

 

 

5. 제3정규형(3NF)의 개념과 예시 🧹

드디어 도달했습니다.

정규화의 핵심 중 핵심, 바로 제3정규형(3NF)입니다.

이 단계에 도달하면 대부분의 테이블은 정상적인 관계형 구조로 볼 수 있어요.

🧩 제3정규형(3NF)이란?

  • 테이블이 2NF를 만족해야 함
  • 이행적 함수 종속(Transitive Dependency)을 제거해야 함

좀 더 쉽게 말하면, 기본키가 아닌 다른 컬럼에 종속된 컬럼이 존재하면 안 된다는 뜻이에요.

📚 예제로 이해하는 3NF

다음 테이블을 살펴보세요. 기본키는 학번입니다.

학번 학생명 학과코드 학과명
2023001 김지민 CS101 컴퓨터공학과

여기서 학과명학번이 아니라 학과코드에 종속되어 있어요.

즉, 이행적 종속이 발생하고 있는 거죠!

🔧 3NF로 변환하기

이럴 땐 학과 테이블을 분리해서 종속성을 제거해야 합니다!

[학생 테이블]

학번 학생명 학과코드
2023001 김지민 CS101

[학과 테이블]

학과코드 학과명
CS101 컴퓨터공학과

이제 학생 테이블은 학과명에 대해 알지 못하고, 학과 테이블이 그 역할을 맡게 되었어요.

이게 바로 3NF의 핵심입니다

모든 비기본키 속성은 기본키에만 종속되어야 한다는 원칙!

📝 핵심 요약: 3NF

요소 설명
2NF 기반 3NF는 2NF를 만족한 테이블을 대상으로 함
이행 종속 제거 기본키가 아닌 컬럼이 다른 컬럼에 의존하지 않도록 분리
의미 단위 분리 테이블마다 명확한 의미와 책임을 갖도록 구조화

정규화는 여기까지가 실무에서 가장 자주 활용되는 단계예요.

이제 실제 테이블을 직접 정규화하는 실습으로 넘어가 볼까요? 😎

 

 

6. 실전! 비정규 테이블을 3NF까지 정규화하기 실습 💻

이제까지 배운 정규화 이론들을 바탕으로,

실제 예시 테이블을 1NF → 2NF → 3NF로 직접 정규화해보는 실습을 해볼게요.

이해를 위해 간단하면서도 실무에서 자주 나오는 학생-수업-학과 정보를 활용하겠습니다.

🧾 Step 0. 비정규 테이블 예시

학생ID 학생이름 학과명 수강과목 교수명
1001 홍길동 컴퓨터공학과 데이터베이스, 운영체제 김교수

문제가 무엇일까요?

수강과목이 여러 개로 원자값이 아님은 물론, 교수명도 과목별로 다를 수 있는데 하나의 셀에 통합되어 있어서 데이터 무결성에 위협이 됩니다.

✅ Step 1. 1NF 적용

수강과목을 각각 행으로 나누어 원자값을 만족시킵니다.

학생ID 학생이름 학과명 수강과목 교수명
1001 홍길동 컴퓨터공학과 데이터베이스 김교수
1001 홍길동 컴퓨터공학과 운영체제 김교수

✅ Step 2. 2NF 적용

기본키가 (학생ID, 수강과목)인 경우, 학과명은 학생ID에만 종속되므로 학생 정보를 별도의 테이블로 분리합니다.

[학생 테이블]

학생ID 학생이름 학과명
1001 홍길동 컴퓨터공학과

[수강 테이블]

학생ID 수강과목 교수명
1001 데이터베이스 김교수
1001 운영체제 김교수

✅ Step 3. 3NF 적용

교수명은 과목에 따라 결정되므로,

이행 종속을 없애기 위해 교수 정보를 분리합니다.

[교과목 테이블]

과목명 교수명
데이터베이스 김교수
운영체제 김교수

이제 테이블 간 종속성이 모두 제거되었고,

각 테이블은 하나의 주제와 역할만을 담당하게 되었어요.

이것이 바로 3NF 정규화의 완성입니다! 🎉

 

 

🎯 데이터 설계의 기초 체력!

정규화는 단순한 이론이 아니라, 모든 데이터베이스 설계의 근간입니다.

이번 글에서 1NF부터 3NF까지 개념을 정리하고, 실전 예제까지 적용해보면서 느끼셨겠지만, 정규화를 통해 데이터 구조를 '깔끔하고, 안전하게' 만들어두면 향후 유지보수, 검색 속도, 무결성 관리에서 엄청난 차이를 만들어냅니다.

 

데이터가 많은 시대, 정규화는 데이터 정리정돈의 첫걸음이에요.

하지만 때론 과한 정규화는 성능 저하를 부를 수도 있다는 점도 기억해두세요.

실전에서는 정규화와 비정규화(denormalization)를 적절히 병행하는 것이 핵심이랍니다.

 

🧠 앞으로 데이터베이스를 설계하거나 테이블을 만들 때, 정규화의 관점에서 구조를 한 번 더 점검해보세요.

      여러분의 데이터가 훨씬 더 강력해질 거예요!

반응형

+ Recent posts