DB

[DataBase/MySQL] MySQL 문법 정리

ayeongjin 2025. 12. 4. 08:53

0. SQL 기본 구조와 실행 순서

SQL 쿼리의 기본 구조는 다음과 같이 이루어진다.

SELECT  컬럼/표현식
FROM    테이블명 AS t
WHERE   조건
GROUP BY 그룹핑 기준
HAVING  그룹핑 이후 조건
ORDER BY 정렬 기준
LIMIT   개수 [OFFSET 시작위치]

SQL 실행 순서

코드는 위에서 아래로 보이지만 실제로는 아래 순서로 실행된다.

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

이 실행 순서를 이해하면 WHERE/HAVING 차이, 그룹 연산, 정렬 오류 등을 쉽게 해결할 수 있다.

 

 

1. SELECT / FROM / WHERE

1-1. 컬럼 선택 및 별칭(AS)

SELECT
    e.emp_no AS 직원번호,
    e.salary * 12 AS 연봉
FROM employees e;
  • AS는 생략 가능 (e.emp_no 직원번호)
  • select 목록의 연산 결과에도 별칭을 붙일 수 있음

1-2. WHERE 조건식

SELECT *
FROM employees
WHERE salary >= 3000                    -- 비교 연산자: =, !=, <>, >, <, >=, <=
  AND dept_no = 'D001'                  -- 논리 연산자: AND, OR, NOT
  AND hire_date BETWEEN '2020-01-01' AND '2020-12-31'
  AND job IN ('DEV', 'QA');             -- IN / NOT IN
  • BETWEEN a AND b : a 이상, b 이하
  • IN (...) / NOT IN (...) : 여러 값 비교 시 유용
  • 문자열, 날짜 비교 모두 가능

 

 

2. ORDER BY와 LIMIT

2-1. ORDER BY

SELECT name, age, score
FROM students
ORDER BY score DESC, age ASC;
  • 여러 컬럼 조합 정렬 가능
  • ASC는 생략 가능

2-2. LIMIT / OFFSET

SELECT *
FROM students
ORDER BY score DESC
LIMIT 5;        -- 상위 5개

SELECT *
FROM students
ORDER BY score DESC
LIMIT 5 OFFSET 5;  -- 6~10번째

 

 

3. 집계 함수 + GROUP BY + HAVING

3-1. 집계 함수

자주 쓰는 집계 함수:

  • COUNT(*), COUNT(col)
  • SUM(col), AVG(col)
  • MIN(col), MAX(col)
SELECT
    dept_no,
    COUNT(*) AS 인원수,
    AVG(salary) AS 평균연봉
FROM employees
GROUP BY dept_no;

 

💡GROUP BY 시 주의
- 표준 SQL에서는 SELECT 문에 다음 두 종류의 컬럼만 포함해야 한다.
- 그룹 기준 컬럼 (GROUP BY에 있는 것)집계 함수로 감싼 컬럼
  (MySQL은 기본 설정에서 예외를 허용하기도 함)

3-2. HAVING vs WHERE

  • WHERE : 그룹핑 이전의 행 필터링
  • HAVING : 그룹핑 이후의 집계 결과 필터링
SELECT dept_no, COUNT(*) AS 인원수
FROM employees
WHERE hire_date >= '2020-01-01'
GROUP BY dept_no
HAVING COUNT(*) >= 5;

 

 

4. JOIN (조인)

4-1. INNER JOIN

SELECT
    o.order_id,
    c.name AS customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.id;
  • 두 테이블 모두에서 조건이 만족하는 행만 반환 (교집합)

4-2. LEFT JOIN

SELECT
    c.id,
    c.name,
    o.order_id
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id;
  • 왼쪽(customers)은 모든 행 유지
  • 오른쪽(orders) 데이터가가 없으면 NULL
  • “주문 이력이 없는 고객도 포함” 같은 문제에서 자주 사용

4-3. 자기 자신 조인 (Self Join)

SELECT
    e1.emp_no,
    e1.name AS 직원,
    e2.name AS 매니저
FROM employees e1
JOIN employees e2 ON e1.manager_id = e2.emp_no;

 

 

5. 서브쿼리 (Subquery)

5-1. SELECT 안에서 쓰는 스칼라 서브쿼리

SELECT
    name,
    salary,
    (SELECT AVG(salary) FROM employees) AS 평균연봉
FROM employees;

모든 행에 대해 같은 값(전체 평균)을 붙이고 싶을 때.

5-2. WHERE 절에서 IN

SELECT *
FROM employees
WHERE dept_no IN (
    SELECT dept_no
    FROM departments
    WHERE location = 'SEOUL'
);

서울에 있는 부서에 속한 직원

5-3. FROM 절 서브쿼리 (인라인 뷰)

SELECT dept_no, avg_salary
FROM (
    SELECT dept_no, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY dept_no
) AS t
WHERE avg_salary >= 3000;

한 번 집계한 결과를 다시 필터링할 때 자주 사용한다

 

 

6. NULL 처리

6-1. NULL 비교

WHERE col IS NULL
WHERE col IS NOT NULL
  • col = NULL → 불가능
  • 반드시 IS (NOT) NULL

6-2. IFNULL / COALESCE

SELECT IFNULL(phone, '없음') AS phone FROM customers;
SELECT COALESCE(phone, '없음') AS phone FROM customers;
  • IFNULL(expr, alt) : expr이 NULL이면 alt 반환
  • COALESCE(a, b, c, ...) : 왼쪽부터 첫 NULL 아닌 첫 값 반환 (표준 함수)
SELECT
    dept_no,
    IFNULL(SUM(bonus), 0) AS 총보너스
FROM employees
GROUP BY dept_no;
  • 위와 같이 집계에서 자주 사용한다

 

 

7. 문자열 관련 함수

SELECT
    CONCAT(first_name, ' ', last_name) AS full_name,
    SUBSTRING(email, 1, 5) AS prefix,
    LEFT(phone, 3) AS 국번,
    RIGHT(phone, 4) AS 끝4자리,
    LENGTH(name) AS 바이트길이,
    CHAR_LENGTH(name) AS 글자수,
    UPPER(name),      -- 대문자
    LOWER(name)       -- 소문자
FROM customers;

7-1. LIKE 패턴 매칭

WHERE name LIKE '김%'      -- 김으로 시작
WHERE name LIKE '%민'      -- 민으로 끝남
WHERE name LIKE '%철수%'   -- 철수 포함
WHERE email LIKE '%@gmail.com'
  • % : 0글자 이상
  • _ : 정확히 1글자

 

 

8. 날짜/시간 함수

SELECT
    order_id,
    order_date,
    YEAR(order_date) AS 연도,
    MONTH(order_date) AS 월,
    DAY(order_date) AS 일,
    DATE_FORMAT(order_date, '%Y-%m-%d') AS 날짜포맷,
    DATE_ADD(order_date, INTERVAL 7 DAY) AS 일주일후,
    DATEDIFF(NOW(), order_date) AS 경과일수
FROM orders;
-- 특정 연/월 필터
WHERE YEAR(order_date) = 2024
  AND MONTH(order_date) = 11;

-- 최근 3개월
WHERE order_date >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH);
  • 위와 같이 자주 사용한다

 

 

9. 수치 함수

SELECT
    price,
    ROUND(price, 0) AS 반올림,
    FLOOR(price) AS 내림,
    CEIL(price) AS 올림
FROM products;
-- 백분율
SELECT
    category,
    ROUND(100.0 * sales / total_sales, 2) AS 비율
FROM ...;
  • 위와 같이 정수/백분율 계산 문제에서 사용한다

 

 

10. CASE WHEN (조건 분기)

SELECT
    name,
    score,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        ELSE 'D'
    END AS grade
FROM students;
  • 조건에 따라 값을 변환해야 할 때
  • 구간(연령대, 점수대, 금액대) 분류에서 필수

 

 

11. DISTINCT / UNION

11-1. DISTINCT

SELECT DISTINCT dept_no
FROM employees;
  • 중복 제거

11-2. UNION vs UNION ALL

SELECT name FROM students
UNION
SELECT name FROM teachers;
  • UNION : 합치면서 중복 제거
  • UNION ALL : 중복 유지

 

 

12. 윈도우 함수

12-1. 기본 형태

SELECT
    emp_no,
    dept_no,
    salary,
    ROW_NUMBER() OVER (PARTITION BY dept_no ORDER BY salary DESC) AS rn,
    RANK()       OVER (PARTITION BY dept_no ORDER BY salary DESC) AS rnk,
    DENSE_RANK() OVER (PARTITION BY dept_no ORDER BY salary DESC) AS drnk,
    SUM(salary)  OVER (PARTITION BY dept_no) AS dept_total
FROM employees;
  • PARTITION BY : 그룹 나누는 기준 (GROUP BY와 비슷한 개념)
  • ORDER BY : 그룹 안에서 순서를 정함
  • ROW_NUMBER() : 동일 값이어도 고유 번호
  • RANK() : 동일한 값은 같은 순위, 다음 순위 건너뜀
  • DENSE_RANK() : 동일 순위 후 다음 순위를 건너뛰지 않음

12-2. 활용 예시

1. 부서별 연봉 1등 직원만 뽑기

SELECT *
FROM (
    SELECT
        emp_no,
        dept_no,
        salary,
        ROW_NUMBER() OVER (PARTITION BY dept_no ORDER BY salary DESC) AS rn
    FROM employees
) t
WHERE rn = 1;

 

2. 누적 합

SELECT
    order_date,
    amount,
    SUM(amount) OVER (ORDER BY order_date) AS 누적금액
FROM orders;

 

 

13. SQL 패턴별 정리

  1. 단순 조회/정렬
    • SELECT, WHERE, ORDER BY, LIMIT, LIKE
  2. 집계/그룹 문제
    • GROUP BY, COUNT/SUM/AVG, HAVING, DISTINCT
  3. 두 개 이상 테이블 연관 문제
    • INNER JOIN, LEFT JOIN, ON 조건, 다중 조인
  4. 특정 조건을 만족하는 그룹만
    • HAVING COUNT(*) >= N, MAX/MIN, 서브쿼리
  5. 날짜 기준 필터 & 포맷팅
    • DATE_FORMAT, YEAR/MONTH, BETWEEN, DATE_ADD/SUB
  6. 구간/등급/라벨링
    • CASE WHEN, BETWEEN, 나이/점수 구간화
  7. “n등”, “가장 많이/적게 주문한 ~”
    • 윈도우 함수 (ROW_NUMBER/RANK)
    • 또는 서브쿼리로 WHERE col = (SELECT MAX(col) ...)

'DB' 카테고리의 다른 글

[Database/DBMS] 트랜잭션과 ACID  (3) 2025.10.11
[Database] 데이터베이스 기본 개념  (1) 2025.10.10