내일배움캠프에서 제공하는 데이터를 사용했습니다.

 

🎯 수업 목표 (오늘 “반드시” 가져갈 것)

세션 종료 후 수강생이 혼자 할 수 있어야 하는 것:

  1. UNION vs UNION ALL 차이를 설명하고, 목적에 맞게 선택한다. (중복 제거/유지)
  2. UNION이 성립하기 위한 규칙(컬럼 개수/순서, 데이터 타입, ORDER BY 위치)을 이해한다.
  3. JOIN을 하기 위해 공통 컬럼을 찾고, 그 컬럼이 PK인지 FK인지를 관계 관점에서 설명할 수 있다.
  4. INNER/LEFT/RIGHT JOIN의 결과 차이를 이해하고, “내가 보고 싶은 모수(기준 테이블)가 무엇인지”에 따라 JOIN 종류를 선택한다.
  5. LEFT JOIN + NULL 체크로 “~가 없는 대상”을 찾을 수 있다.
  6. 3개 이상 테이블 다중 JOIN에서 어떤 조인이 1:N이라서 결과가 늘어나는지를 설명하고, COUNT(DISTINCT)로 검증할 수 있다.

*테이블 파악 능력 중요!

- 추후 Today I Learne에 데이터명세서 방법론 기입!

 

4회차 선요약!

테이블 결합의 두 축!

  • UNION: 결과를 세로로 쌓기(수직 결합)
  • JOIN: 테이블을 옆으로 붙이기(수평 결합)

Part 1. UNION / UNION ALL

UNION은 여러 SELECT 결과를 하나로 합쳐서 보고 싶을 때 사용한다.

대표적인 상황은 다음과 같다.

  • 11월 신청자 목록이 있고, 12월 신청자 목록이 따로 있을 때
  • 웹 유입 로그와 앱 유입 로그가 따로 있고 “전체 유입”을 보고 싶을 때
  • “학생 목록”과 “강사 목록”을 합쳐서 “전체 사람 목록”을 만들고 싶을 때

UNION 핵심!

열(컬럼) 수가 늘어나지 않고 행(레코드)이 늘어남

💡 UNION은 “테이블 결합”이라기보단 "결과 결합"

즉, SELECT 결과를 세로로 붙여서 하나로 만든다!

 

1_2) UNION vs UNION ALL

✅ 기본은 “중복 제거” (UNION = DISTINCT가 기본)
MySQL set operation은 기본적으로 중복 행을 제거 (`DISTINCT`가 기본)

✅ UNION ALL은 “중복 유지”
`ALL`을 붙이면 중복 제거를 하지 않고 그대로 다 포함

 

1_3) UNION 규칙 3가지

  1. 각 SELECT는 같은 개수의 컬럼을 반환해야 한다.
    - 컬럼 수가 다르면 UNION 불가
  2. 같은 위치의 컬럼끼리 데이터 타입이 호환되어야 한다
    (숫자 ↔ 숫자, 문자열 ↔ 문자열 등)
  3. 결과 컬럼명은 첫 번째 SELECT 기준
    컬럼명이 꼭 똑같아야 하나?
    ❌. 컬럼명은 달라도 되지만, UNION 결과의 컬럼명은 첫 번째 SELECT의 컬럼명(또는 별칭)을 따른다.
UNION 기본 문법

SELECT col1, col2
FROM table_a
UNION [ALL]
SELECT col1, col2
FROM table_b;

 

1_4) UNION에서 ORDER BY는 어디에?

UNION 결과 전체를 정렬하고 싶다면 맨 마지막에 ORDER BY를 사용한다.

Part 2. JOIN

 

💡 JOIN은 SQL의 꽃
UNION이 “세로로 붙이기”였다면, JOIN은 옆으로 붙이기다.

 

JOIN의 성패는 결국 이 3단계로 결정된다.

  1. 공통컬럼 찾기
  2. PK/FK 관계 이해
  3. 적절한 JOIN 방식 선택

0) 먼저 어떤 목적으로 join을 할려고 하는건가?

JOIN을 하기로 마음먹었다면, 관련된 모든 테이블의 역할과 의미를 먼저 이해해야 한다.
무작정 JOIN부터 치면 거의 100% 결과가 꼬인다. 그렇기에 JOIN 전에 스스로에게 질문해야 한다.

 

 “최종적으로 무엇을 보고 싶은가?”

 

예를 들어, 최종 테이블은 학생 단위 당 결재 총액을 보고 싶다. 라고하면...

필요한 정보는

student

enrollments

payments

테이블이 필요할것이다. 그 뒤 확인을 해보자!

 

 

1) JOIN을 하기 전에 헤야할것: 공통 컬럼 찾기?

JOIN은 테이블을 연결하는 고리(키) 가 반드시 필요하다.
이 고리는 보통:

  • ID 컬럼
  • PK / FK 관계

JOIN은 결국 이렇게 말하는 것과 같다.
“이 행은, 저 테이블의 이 행과 같은 대상이다”

 

ex)
students.student_id ↔ enrollments.student_id
enrollments.enrollment_id ↔ payments.enrollment_id

 

2) PK / FK를 0부터 설명

PK(Primary Key, 기본키)

  • 한 테이블에서 각 행을 유일하게 식별하는 컬럼
  • 중복되면 안 됨
  • NULL이면 안 됨

👉 “이 테이블의 주민등록번호”

 

FK(Foreign Key, 외래키)

  • 다른 테이블의 PK를 참조하는 컬럼
  • “이 행이 누구/무엇과 연결되는지” 알려주는 값

👉 “우리 테이블에서, 저 테이블의 누구를 가리키는가”

 

 

 

3) 관계(카디널리티) 감각

1:1 / 1:N 이 왜 중요한가?

JOIN이 어려운 진짜 이유는
👉 문법이 아니라, 결과 행이 늘어나는 방식 때문이다.

 

 

🔹 1:1 관계 👉 비교적 안전한 JOIN

  • 한 행 ↔ 한 행
  • JOIN해도 행 수가 늘어나지 않음

 

🔹 1:N 관계 (가장 중요) 👉 JOIN하면 행이 N배로 늘어난다

  • 1쪽 테이블의 한 행
  • N쪽 테이블의 여러 행과 매칭

 

그래서 어떻게 해야 하나? (How?)

JOIN 전에 반드시 이 순서를 거친다.

  1. 최종 결과의 행 단위(grain)를 먼저 선언
  2. N쪽 테이블은
    → JOIN 전에 집계하거나 한 행으로 줄인다
  3. JOIN 후 결과를 반드시 확인한다

👉 “JOIN은 붙이는 기술이 아니라, 결과를 설계하는 과정”

 

 

4) JOIN의 종류 & 기본 문법(패턴)

조인 종류 설명 반환 데이터 범위 MySQL 지원 여부
INNER JOIN
(가장 많이 사용)
두 테이블에서 일치하는 값을 가진 행만 반환 (교집합) 두 테이블의 교집합 지원
LEFT JOIN
(가장 많이 사용)
왼쪽 테이블의 모든 행 + 오른쪽 테이블에서 일치하는 행 반환. 일치하지 않으면 오른쪽 컬럼은 NULL 왼쪽 전체 + 교집합 지원
RIGHT JOIN 오른쪽 테이블의 모든 행 + 왼쪽 테이블에서 일치하는 행 반환. 일치하지 않으면 왼쪽 컬럼은 NULL 오른쪽 전체 + 교집합 지원
FULL OUTER JOIN 양쪽 테이블의 모든 행 반환 (합집합). 일치하지 않는 컬럼은 NULL로 채움 합집합 (교집합 + 왼쪽/오른쪽 단독 데이터) MySQL 기본적으로 미지원
→ LEFT JOIN 과 RIGHT JOIN 의 합집합으로 계산해야 함.

 

JOIN 기본문법

SELECT
a.col1,
b.col2
FROM table_a AS a
JOIN table_b AS b
ON a.key= b.key;

 

5) INNER JOIN (교집합)

언제 쓰나?

“양쪽 테이블에 모두 존재하는 데이터만 보고 싶을 때”

  • 매칭 안 되는 행은 전부 제거됨

예)

  • 실제로 수강신청이 있는 학생만 보고 싶다
  • 주문이 있는 고객만 보고 싶다
SELECT
e.enrollment_id,
e.enroll_date,
s.student_id,
s.student_name,
s.region,
s.segment
FROM basic.enrollments AS e
INNER JOIN basic.students AS s
ON e.student_id= s.student_id
ORDER BY e.enroll_date;

 

 

 

6) LEFT JOIN (왼쪽 기준 + 매칭 없으면 NULL)

언제 쓰나?

기준(모수)을 유지하고 싶을 때

  • 왼쪽 테이블은 무조건 남김
  • 오른쪽에 매칭이 없으면 NULL

예)

 

  • 전체 학생 중 수강신청 안 한 사람 찾기
  • 전체 고객 대비 주문 여부 확인

 

사용 예시
SELECT
s.student_id,
s.student_name,
e.enrollment_id
FROM basic.students AS s
LEFT JOIN basic.enrollments AS e
ON s.student_id = e.student_id;

(null 활용)
SELECT
s.student_id,
s.student_name
FROM basic.students AS s
LEFT JOIN basic.enrollments AS e
ON s.student_id= e.student_id
WHERE e.enrollment_id IS NULL;

7) RIGHT JOIN (오른쪽 기준)

MySQL 공식 문서에서도:

  • RIGHT JOIN은 LEFT JOIN과 기능적으로 동일
  • 이식성(portability)을 위해 LEFT JOIN 사용 권장

그래서 수업에서는:

  • RIGHT JOIN은 개념만 이해
  • 실제 작성은 LEFT JOIN으로 통일 추천

 

8) ON vs WHERE (LEFT JOIN에서 자주 터지는 함정)

MySQL 문서:

ON: 조인을 “어떻게 붙일지” 조건
WHERE: 결과에서 “어떤 행을 남길지” 필터

⚠️ 흔한 실수: 

LEFT JOIN을 했는데 WHERE 때문에 INNER JOIN처럼 되어버림

 

오늘 JOIN 파트 회상 요약

  • JOIN은 “옆으로 붙이기”
  • 먼저 목적과 최종 단위(grain) 를 정해야 한다
  • 공통 컬럼 + PK/FK 이해가 핵심
  • 1:N 관계에서 행이 늘어나는 걸 항상 의식
  • LEFT JOIN에서는 ON / WHERE 위치에 특히 주의

쿼리문 요약

-- 1) UNION / UNION ALL (세로 결합: 행이 늘어남)
SELECT col1, col2
FROM t1
UNION-- 기본: 중복 제거
SELECT col1, col2
FROM t2;


SELECT col1, col2
FROM t1
UNION ALL-- 중복 유지
SELECT col1, col2
FROM t2;


-- 2) UNION 결과 정렬은 "맨 마지막"에
SELECT col1, col2 FROM t1
UNION ALL
SELECT col1, col2 FROM t2
ORDER BY col1;


-- 3) INNER JOIN (가로 결합: 공통키로 매칭되는 것만)
SELECT
a.key, a.col A, b.col B
FROM A a
INNER JOIN B b
ON a.key= b.key;


-- 4) LEFT JOIN (왼쪽 모수 유지 + 매칭 없으면 오른쪽은 NULL)
SELECT
a.key, a.col A, b.col B
FROM A a
LEFT JOIN B b
ON a.key= b.key;


-- 5) "B에 없는 A" 찾기 (LEFT JOIN + NULL 체크 = anti-join)
SELECT a.*
FROM A a
LEFT JOIN B b
ON a.key= b.key
WHERE b.key IS ULL;


-- 6) LEFT JOIN에서 오른쪽 조건은 ON에 두기 (WHERE에 두면 모수 유실 위험)
-- 모수 유지(결제 없는 신청도 남김)
SELECT e.enrollment_id, p.payment_status
FROM enrollments e
LEFT JOIN payments p
ON e.enrollment_id= p.enrollment_id
AND p.payment_status='paid';

 

 

Part 3. 다중 JOIN + 결과 검증 루틴

복습 때 정리

 

Part 4. UNION vs JOIN + 함께 쓰는 패턴

복습 때 정리

'A.Today I Learne > SQL' 카테고리의 다른 글

[TIL] SQL 라이브세션 6회차  (0) 2025.12.31
[TIL] SQL 라이브세션 5회차  (0) 2025.12.30
데이터 딕셔너리에 관하여  (0) 2025.12.29
포메팅 습관  (0) 2025.12.28

+ Recent posts