WHERE절( 조건 - 필터링)
1. 비교 연산자

- 예시) ryan 유저 찾기
SELECT *
FROM USERS
WHERE username = 'ryan';
2. 논리 연산자
- AND: 두 조건 모두 만족해야 할 때
SELECT *
FROM POSTS
WHERE user_id = 1 AND post_type = 'video';
- OR: 두 조건 중 하나라도 만족할 때
SELECT *
FROM POSTS
WHERE user_id = 1 OR post_type = 'video';
- NOT: 특정 조건을 제외하고 싶을 때
3. BETWEEN, IN, LIKE, IS NULL
1) BETWEEN a AND b : 특정 범위에 있는 데이터를 찾을 때
- 예시) 2022년 1월 1일부터 2022년 12월 31일 사이에 가입한 사용자 찾기
SELECT username, registration_date
FROM USERS
WHERE registration_date BETWEEN '2022-01-01' AND '2022-12-31';
2) IN (list) : 여러 값 중 하나라도 일치하는 데이터를 찾을 때(OR처리)
- user_id가 1, 9, 21 중 하나에 해당하는 사용자 정보 찾기
SELECT *
FROM USERS
WHERE user_id IN (1, 9, 21);
==
SELECT *
FROM USERS
WHERE user_id = 1
OR users.user_id = 9
OR users.user_id = 21
;
3) LIKE '패턴' : 문자열 패턴으로 데이터를 찾을 때
- %(0개 이상의 모든 문자)와 _(딱 1개의 문자) 기호를 사용
- p'로 시작하는 모든 사용자 찾기
SELECT username
FROM USERS
WHERE username LIKE 'p%';
- #일상 해시테그 게시물 찾기
SELECT post_id, content
FROM POSTS
WHERE content LIKE '%#일상%';
4) IS NULL : 값이 비어 있는 데이터를 찾을 때
- ~가 아닌 것: NOT
NULL이 아닌 것: IS NOT NULL
JOIN
1. CROSS JOIN
- 가능한 모든 경우의 수를 조합
- 가로로 조인 / 5열 12행
SELECT *
FROM EMPLOYEES
CROSS JOIN DEPARTMENTS
;
>> 같은 ID로 부서 필터링 필요
2. INNER JOIN ~ ON
- 매칭되는 데이터만 포함
- 올바른 조인
SELECT *
FROM EMPLOYEES
JOIN DEPARTMENTS
ON EMPLOYEES.dept_id = DEPARTMENTS.id
;
- 식별자 추가
SELECT EMPLOYEES.id, EMPLOYEES.name, DEPARTMENTS.name
FROM EMPLOYEES
JOIN DEPARTMENTS
ON EMPLOYEES.dept_id = DEPARTMENTS.id
;
- 별칭 쓰기
SELECT E.id, E.name, D.name
FROM EMPLOYEES E
JOIN DEPARTMENTS D
ON E.dept_id = D.id
;
- user_id가 1인 유저가 쓴 피드의 작성자명, 피드내용, 피드작성일 조회
SELECT U.username,P.content, p.creation_date
FROM POSTS P
JOIN USERS U
ON P.user_id = U.user_id
WHERE P.user_id = 1
;
3. OUTER JOIN: 데이터 매칭 안 되어도 다 보여줌
1) 이너 조인 단점: 배달 예시 / 배달 주문 안 한 회원을 찾을 수 없음
2) LEFT (OUTER) JOIN
- 왼쪽 차집합 +오른쪽과 교집합
SELECT U.user_id, U.username, UP.bio
FROM USERS U
LEFT OUTER JOIN USER_PROFILES UP
ON U.user_id = UP.user_id
ORDER BY U.user_id
- 프로필 안 쓴 애만 찾기
SELECT U.user_id, U.username, UP.bio
FROM USERS U
LEFT OUTER JOIN USER_PROFILES UP
ON U.user_id = UP.user_id
WHERE UP.bio IS NULL
ORDER BY U.user_id
;
4. RIGHT와 FULL
- RIGHT OUTER JOIN: 오른쪽 데이터 포함
- FULL OUTER JOIN: 양쪽 테이블 모든 데이터 포함
명령어 지원x : LEFT JOIN과 RIGHT JOIN을 UNION으로 합치는 방식
SELECT * FROM USERS u LEFT JOIN USER_PROFILES p ON u.user_id = p.user_id
UNION
SELECT * FROM USERS u RIGHT JOIN USER_PROFILES p ON u.user_id = p.user_id;
5. SELF JOIN
- 테이블이 자기 자신과 조인: 테이블 안에 계층적인 관계
- EX) 팔로우 = USERS 2번 조인
SELECT U.user_id, U.username, U.manager_id, M.username
FROM USERS U
JOIN USERS M
ON U.manager_id = M.user_id
;
Subquery절
1. 단일 행 서브쿼리
- 오직 하나의 행, 하나의 컬럼 (즉, 하나의 값)
- 예시) 우리는 '라이언'의 username은 알지만 user_id는 모르는 상황입니다. '라이언'이 작성한 모든 게시물을 찾아주세요
SELECT
post_id,
content
FROM
POSTS
WHERE
user_id = (SELECT user_id -- 1. 이 서브쿼리가 먼저 실행됩니다.
FROM USERS
WHERE username = 'ryan'); -- 결과: 1 이라는 단일 값
- 예시) 우리 서비스의 평균 조회수보다 더 높은 조회수를 기록한 게시물은 무엇?
SELECT
post_id,
view_count
FROM
POSTS
WHERE
view_count > (SELECT AVG(view_count) FROM POSTS); -- 1. 전체 게시물의 평균 조회수를 먼저 계산
2. 다중 행 서브쿼리
- 실행 결과가 여러 개의 행
- IN: 목록에 있는 값 중 하나라도 일치하면 참
- ANY: 목록에 있는 값 중 하나라도 조건을 만족하면 참 (예: `< ANY` -> 최댓값보다 작으면)
- ALL: 목록에 있는 모든 값을 만족해야만 참 (예: `> ALL` -> 최댓값보다 크면)
- 예시) '카카오프렌즈' 그룹에 속한 모든 사용자들의 ID 목록을 알려주기 > 그 ID를 가진 사용자들이 작성한 모든 게시물을 찾기
SELECT
post_id,
user_id,
content
FROM
POSTS
WHERE
user_id IN (SELECT user_id -- 1. 이 서브쿼리가 먼저 실행됩니다.
FROM USERS
WHERE manager_id = 1) -- 결과: (2, 3, 5, 7...) 이라는 여러 개의 값
;
- 예시) '#포켓몬' 해시태그가 달린 모든 게시물의 내용을 보여주세요 = 중첩 서브쿼리
SELECT
post_id,
content
FROM
POSTS
WHERE
post_id IN (SELECT post_id -- 2. #포켓몬 태그가 달린 post_id 목록을 찾는다
FROM POST_TAGS
WHERE tag_id = (SELECT tag_id -- 1. '#포켓몬'의 tag_id를 먼저 찾는다
FROM HASHTAGS
WHERE tag_name = '#포켓몬'))
;
3. FROM절 서브쿼리: 인라인 뷰
- 서브쿼리의 실행 결과는 쿼리가 실행되는 동안에만 존재하는 임시 가상 테이블
- 예시) 모든 사용자의 username과 함께, 각 사용자가 작성한 총 게시물 수를 나란히 보여주세요
SELECT
u.username,
post_info.post_count -- 2. 인라인 뷰에서 계산된 '게시물 수' 컬럼
FROM
USERS u
INNER JOIN
(SELECT user_id, COUNT(*) AS post_count -- 1. '사용자별 게시물 수'라는 가상 테이블을 생성
FROM POSTS
GROUP BY user_id) post_info -- 반드시 별명(Alias)을 붙여줘야 합니다!
ON
u.user_id = post_info.user_id; -- 3. USERS 테이블과 가상 테이블을 조인
4. SELECT절의 서브쿼리: 스칼라 서브쿼리
- 하나의 값만 반환(단일 행, 단일 컬럼)
- 모든 사용자의 username을 조회하면서, 바로 옆에 각 사용자가 작성한 총 게시물 수를 계산해서 보여주세요
SELECT
u.username,
(SELECT COUNT(*)
FROM POSTS p
WHERE p.user_id = u.user_id) AS "작성 게시물 수" -- 1. 바깥 쿼리의 u.user_id를 참조
FROM
USERS u
;
- 예시) 모든 게시물의 content와 함께, 각 게시물별 '좋아요' 수와 '댓글' 수를 각각 계산해서 보여주세요
- 방법 1: 스칼라 서브쿼리 사용 (간결하고 직관적인 방법)
SELECT
p.post_id,
p.content,
(SELECT COUNT(*) FROM LIKES l WHERE l.post_id = p.post_id) AS "좋아요 수",
(SELECT COUNT(*) FROM COMMENTS c WHERE c.post_id = p.post_id) AS "댓글 수"
FROM
POSTS p
;
- 방법 2: JOIN과 인라인 뷰 사용
SELECT
p.post_id,
p.content,
COALESCE(lc.like_count, 0) AS "좋아요 수",
COALESCE(cc.comment_count, 0) AS "댓글 수"
FROM
POSTS p
LEFT JOIN
(SELECT post_id, COUNT(*) AS like_count FROM LIKES GROUP BY post_id) lc
ON p.post_id = lc.post_id -- '좋아요 수' 요약 테이블을 조인
LEFT JOIN
(SELECT post_id, COUNT(*) AS comment_count FROM COMMENTS GROUP BY post_id) cc
ON p.post_id = cc.post_id -- '댓글 수' 요약 테이블을 조인
;
5. 비연관 서브쿼리 vs 연관 서브쿼리
1) 비연관 서브쿼리
- 서브쿼리 독자적 실행 가능, 안쪽 먼저 실행 > 밖 실행
- 예시)
SELECT *
FROM POSTS
WHERE user_id = (
SELECT user_id
FROM USERS
WHERE username = 'ryan'
)
;
2) 연관 서브쿼리
- 밖 > 안쪽 / 단독실행X
- 메인쿼리 1번 실행당 서브쿼리도 1번씩 반복실행
- 예시)
SELECT
u.username,
(
SELECT COUNT(*)
FROM POSTS p
WHERE p.user_id = u.user_id) AS "작성 게시물 수" -- 1. 바깥 쿼리의 u.user_id를 참조
FROM
USERS u
6. 존재 여부만 확인: EXISTS, NOT EXISTS
- EXISTS 예시) 게시물을 한 번이라도 작성한 적이 있는 모든 사용자의 이름을 알려주세요
SELECT
u.username
FROM
USERS u
WHERE
EXISTS (SELECT 1 -- SELECT 절에 무엇이 오든 상관없어요. 존재 여부만 체크!
FROM POSTS p
WHERE p.user_id = u.user_id); -- 바깥 쿼리의 사용자가 쓴 게시물이 있는지 확인
- NOT EXISTS 예시) 가입은 했지만, 게시물은 단 한 개도 작성하지 않은 '유령 회원'을 찾아주세요
SELECT
u.username
FROM
USERS u
WHERE
NOT EXISTS (SELECT 1
FROM POSTS p
WHERE p.user_id = u.user_id);
ORDER BY절
1. ORDER BY 기본
1) 오름차순 정렬: ASC > 기본값
- 예시) USERS 테이블에서 모든 사용자를 가입일이 빠른 순서(오래된 순)로 정렬해서 보여주세요
-- registration_date를 기준으로 오름차순 정렬합니다.
-- ASC는 기본값이므로 생략할 수 있습니다.
SELECT
username,
registration_date
FROM
USERS
ORDER BY
registration_date ASC; -- 또는 registration_date; 라고만 써도 동일하게 동작

2) 내림차순 정렬: DESC
- 예시) 인스타그램 피드처럼, POSTS 테이블의 게시물들을 가장 최신순으로 정렬해서 보여주세요
-- creation_date를 기준으로 내림차순 정렬합니다.
SELECT
post_id,
user_id,
content,
creation_date
FROM
POSTS
ORDER BY
creation_date DESC;

3) 여러 기준으로 정렬하기
- 예시) 모든 게시물을 종류(post_type)별로 먼저 정렬하고, 만약 종류가 같다면 그 안에서는 최신순(creation_date 내림차순)으로 다시 정렬
-- 1차: post_type 오름차순, 2차: creation_date 내림차순으로 정렬
SELECT
post_id,
post_type,
creation_date
FROM
POSTS
ORDER BY
post_type ASC, -- 1차 정렬 기준 (ASC는 생략 가능)
creation_date DESC; -- 2차 정렬 기준

2. ORDER BY 고급
1) 별명(Alias)으로 정렬
- 각 사용자별로 게시물 수를 계산해서 '게시물수'라는 별명을 붙이고, 그 '게시물수'가 많은 순서대로 정렬
-- 5강에서 배운 GROUP BY를 활용해 사용자별 게시물 수를 구하고,
-- 그 결과(별명: post_count)를 기준으로 내림차순 정렬합니다.
SELECT
user_id,
COUNT(*) AS post_count
FROM
POSTS
GROUP BY
user_id
ORDER BY
post_count DESC;

2) 컬럼 위치 번호로 정렬
- 예시) USERS 테이블에서 username, email, registration_date를 순서대로 조회한 다음, 세 번째 컬럼인 registration_date를 기준으로 최신순 정렬
SELECT
username, -- 1번째 컬럼
email, -- 2번째 컬럼
registration_date -- 3번째 컬럼
FROM
USERS
ORDER BY
3 DESC; -- SELECT 절의 3번째 컬럼인 registration_date를 기준으로 내림차순 정렬

3) CASE 표현식으로 내 마음대로 정렬
- 예시) 모든 게시물을 조회하는데, 다른 건 다 최신순으로 정렬하되 '라이언(user_id=1)'이 작성한 게시물만 무조건 가장 위로 올려서 보여주세요
-- user_id가 1이면 1순위, 나머지는 2순위로 정렬 우선순위를 부여하고,
-- 같은 순위 내에서는 creation_date를 기준으로 내림차순 정렬합니다.
SELECT
post_id,
user_id,
content,
creation_date
FROM
POSTS
ORDER BY
CASE
WHEN user_id = 1 THEN 1 -- user_id가 1이면 1순위
ELSE 2 -- 나머지는 2순위
END, -- 1차 정렬 기준: CASE 표현식
creation_date DESC; -- 2차 정렬 기준: 작성일
'🔌 SPARTA > Courses' 카테고리의 다른 글
| [숙련 Spring] Spring Data JPA (0) | 2026.02.11 |
|---|---|
| [숙련 Spring] Spring Boot 활용하기 (0) | 2026.02.10 |
| 스탠다드반 2회차: 데이터 베이스 모델링 (0) | 2026.02.05 |
| 스탠다드반 1회차: MVC & REST API (0) | 2026.02.02 |
| Spring MVC / Data JPA (0) | 2026.01.30 |