SQL 함수 정리- 기본 함수부터 윈도우 함수까지

차지예·2026년 5월 3일

SQL

목록 보기
1/1

목차

  1. 기본 SQL 함수
  2. CONVERT() 함수
  3. 윈도우 함수란?
  4. PARTITION BY
  5. ORDER BY (윈도우 함수에서)
  6. ROWS BETWEEN
  7. LAST_VALUE와 ROWS BETWEEN의 관계

1. 기본 SQL 함수

문자열 함수

SELECT
  UPPER('hello')               -- 'HELLO'  (대문자 변환)
  LOWER('WORLD')               -- 'world'  (소문자 변환)
  LENGTH('SQL')                -- 3        (문자열 길이)
  SUBSTRING('Hello', 1, 3)     -- 'Hel'   (문자열 자르기)
  CONCAT('Hello', ' ', 'World')-- 'Hello World' (문자열 합치기)
  TRIM('  hello  ')            -- 'hello'  (공백 제거)

숫자 함수

SELECT
  ROUND(3.567, 2)  -- 3.57  (반올림)
  CEIL(3.2)        -- 4     (올림)
  FLOOR(3.9)       -- 3     (내림)
  ABS(-10)         -- 10    (절댓값)
  MOD(10, 3)       -- 1     (나머지)
  POWER(2, 3)      -- 8     (제곱)

날짜 함수

SELECT
  NOW()                                 -- 현재 날짜 + 시간
  CURDATE()                             -- 현재 날짜
  YEAR('2024-05-03')                    -- 2024
  MONTH('2024-05-03')                   -- 5
  DAY('2024-05-03')                     -- 3
  DATEDIFF('2024-12-31', '2024-01-01') -- 365 (날짜 차이)

집계 함수

SELECT
  COUNT(*)    -- 전체 행 수
  SUM(salary) -- 급여 합계
  AVG(salary) -- 급여 평균
  MAX(salary) -- 최고 급여
  MIN(salary) -- 최저 급여
FROM employees;

GROUP BY와 함께 사용:

SELECT department, AVG(salary) AS 평균급여
FROM employees
GROUP BY department;

조건 함수

-- IF
SELECT IF(score >= 60, '합격', '불합격') FROM students;

-- CASE
SELECT
  name,
  CASE
    WHEN score >= 90 THEN 'A'
    WHEN score >= 80 THEN 'B'
    WHEN score >= 70 THEN 'C'
    ELSE 'F'
  END AS grade
FROM students;

-- COALESCE: NULL이면 대체값 반환
SELECT COALESCE(phone, '번호 없음') FROM customers;

변환 함수

SELECT
  CAST('123' AS INT)             -- 문자 → 숫자
  CAST(3.14 AS CHAR)             -- 숫자 → 문자
  DATE_FORMAT(NOW(), '%Y-%m-%d') -- 날짜 형식 변환

2. CONVERT() 함수

CONVERT()는 두 가지 용도로 사용된다.

데이터 타입 변환

SELECT CONVERT('123', UNSIGNED INTEGER) -- 문자 → 정수: 123
SELECT CONVERT(3.14, CHAR)              -- 숫자 → 문자: '3.14'
SELECT CONVERT('2024-05-03', DATE)      -- 문자 → 날짜
SELECT CONVERT(NOW(), TIME)             -- 날짜시간 → 시간만

문자셋(인코딩) 변환

SELECT CONVERT('안녕하세요' USING utf8mb4);
SELECT CONVERT('hello' USING latin1);

한글 깨짐 같은 인코딩 이슈 해결 시 유용하다.

CAST vs CONVERT 비교

CASTCONVERT
문법CAST(값 AS 타입)CONVERT(값, 타입)
문자셋 변환❌ 불가✅ 가능
SQL 표준✅ 표준⚠️ 비표준 (MySQL 등)

타입 변환만 할 거라면 표준인 CAST()를, 문자셋 변환이 필요하면 CONVERT()를 쓰는 게 일반적이다.


3. 윈도우 함수란?

집계 함수 vs 윈도우 함수

집계 함수와 윈도우 함수의 가장 큰 차이는 행의 수다.

집계 함수윈도우 함수
결과 행 수줄어듦그대로 유지
사용 키워드GROUP BYOVER()
용도그룹별 요약행 유지하며 계산

예를 들어 아래 테이블이 있다고 할 때:

namesalary
철수500
영희600
민준400
지수350

집계 함수 (GROUP BY 사용):

SELECT AVG(salary) FROM employees;
-- 결과: 1행 (462.5)
-- 철수, 영희, 민준, 지수 정보가 사라짐

윈도우 함수 (OVER() 사용):

SELECT name, salary, AVG(salary) OVER() AS avg_salary
FROM employees;
namesalaryavg_salary
철수500462.5
영희600462.5
민준400462.5
지수350462.5

4행이 그대로 유지되면서 평균값 컬럼이 추가된다. "철수의 급여가 전체 평균보다 높은지" 같은 비교가 필요할 때 윈도우 함수가 필수다.

기본 문법

함수명() OVER (
  PARTITION BY 그룹기준컬럼  -- 그룹 나누기 (생략 가능)
  ORDER BY 정렬기준컬럼      -- 정렬 기준 (생략 가능)
)

주요 윈도우 함수 종류

순위 함수:

SELECT name, score,
  RANK()       OVER (ORDER BY score DESC) AS rank,       -- 1,2,2,4
  DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank, -- 1,2,2,3
  ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num     -- 1,2,3,4
FROM students;
namescoreRANKDENSE_RANKROW_NUMBER
철수95111
영희90222
민준90223
지수85434

행 참조 함수:

SELECT name, month, sales,
  LAG(sales, 1)  OVER (ORDER BY month) AS 전월매출,
  LEAD(sales, 1) OVER (ORDER BY month) AS 다음달매출
FROM monthly_sales;

분위 함수:

SELECT name, score,
  NTILE(4)       OVER (ORDER BY score DESC) AS 사분위,
  PERCENT_RANK() OVER (ORDER BY score DESC) AS 백분위
FROM students;

4. PARTITION BY

PARTITION BY부서별 울타리를 치는 것이다. 각 울타리 안에서만 계산이 이루어진다.

SELECT name, department, salary,
  AVG(salary) OVER (PARTITION BY department) AS 부서_평균급여
FROM employees;
namedepartmentsalary부서_평균급여
철수개발500550
영희개발600550
민준영업400375
지수영업350375
  • 개발팀 평균: (500 + 600) / 2 = 550
  • 영업팀 평균: (400 + 350) / 2 = 375

PARTITION BY가 없으면 전체 평균(462.5)이 나오지만, PARTITION BY department를 쓰면 부서별로 분리해서 계산한다.


5. ORDER BY (윈도우 함수에서)

ORDER BY는 파티션 안에서 행을 순서대로 세우고, 위에서부터 누적해서 계산한다.

SELECT name, salary,
  SUM(salary) OVER (ORDER BY salary) AS 누적합계
FROM employees;

ORDER BY salary로 정렬 후 누적 계산:

namesalary누적합계
지수350350
민준400750
철수5001250
영희6001850

PARTITION BY + ORDER BY 함께 쓰기

SELECT name, department, salary,
  SUM(salary) OVER (
    PARTITION BY department
    ORDER BY salary
  ) AS 부서내_누적합
FROM employees;

부서별로 나누고(PARTITION BY), 그 안에서 급여 순으로 누적(ORDER BY)한다.


6. ROWS BETWEEN

ROWS BETWEEN A AND B는 계산할 행의 범위(프레임) 를 직접 지정한다.

함수명() OVER (
  ORDER BY 컬럼
  ROWS BETWEEN 시작 AND)

주요 키워드

키워드의미
UNBOUNDED PRECEDING맨 처음 행
UNBOUNDED FOLLOWING맨 마지막 행
CURRENT ROW현재 행
N PRECEDING현재 행에서 N행 앞
N FOLLOWING현재 행에서 N행 뒤

자주 쓰는 패턴

누적합 (기본 패턴):

SUM(sales) OVER (
  ORDER BY month
  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
-- 맨 처음부터 현재 행까지 누적

전체 합계:

SUM(sales) OVER (
  ORDER BY month
  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
-- 항상 전체 합계 (현재 행 위치 무관)

이동 평균 (3개월):

AVG(sales) OVER (
  ORDER BY month
  ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
-- 직전 2행 + 현재 행, 총 3개 행의 평균

기본값 주의: ROWS BETWEEN을 생략하면 기본값은 UNBOUNDED PRECEDING AND CURRENT ROW다. LAST_VALUE() 같은 함수에서 의도치 않은 결과가 나올 수 있으므로 항상 명시하는 것이 좋다.


7. LAST_VALUE와 ROWS BETWEEN의 관계

LAST_VALUE(컬럼)범위 안에서 가장 마지막 행의 값을 가져온다.

문제: 기본값을 쓰면 왜 이상하게 나올까?

-- 잘못된 예
SELECT month, sales,
  LAST_VALUE(sales) OVER (ORDER BY month) AS 마지막달매출
FROM monthly_sales;

ROWS BETWEEN을 생략하면 기본 범위가 UNBOUNDED PRECEDING ~ CURRENT ROW다. 그러면 2월 행에서 범위는 "1월~2월"이고, 그 범위의 마지막은 2월 자신이 된다. 즉 LAST_VALUE가 그냥 현재 행 값을 돌려줘서 아무 의미가 없어진다.

해결: UNBOUNDED FOLLOWING 명시

-- 올바른 예
SELECT month, sales,
  LAST_VALUE(sales) OVER (
    ORDER BY month
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS 마지막달매출
FROM monthly_sales;

범위가 "맨 처음 ~ 맨 끝" 전체로 고정되므로, 현재 행이 1월이든 3월이든 상관없이 항상 마지막 달(12월)의 값을 가져온다.

monthsales마지막달매출
1월100180
2월150180
3월120180
4월200180
5월180180

정리

윈도우 함수 = 집계 함수처럼 계산하지만 행을 줄이지 않는다

OVER (
  PARTITION BY → 어느 그룹 안에서 계산할지 (울타리)
  ORDER BY     → 어떤 순서로 누적할지
  ROWS BETWEEN → 정확히 몇 번째 행까지 범위로 볼지
)
개념한 줄 요약
집계 함수여러 행 → 1행으로 줄임
윈도우 함수행 유지하며 계산 결과 컬럼 추가
PARTITION BY그룹별 울타리 치기
ORDER BY순서 정해서 위에서부터 누적
UNBOUNDED PRECEDING맨 처음 행
UNBOUNDED FOLLOWING맨 마지막 행
CURRENT ROW지금 이 행
LAST_VALUE범위 내 마지막 행의 값

0개의 댓글