[SQL 쿡북/09장] 9절. 지정 분기의 시작일 및 종료일 알아내기

정은아·2025년 5월 23일

[도서] SQL 쿡북

목록 보기
8/13
post-thumbnail

09장. 날짜 조작 기법


🎨 DB2

  • SUBSTR 함수를 사용하여 인라인 뷰 X에서 연도를 반환합니다.
  • MOD 함수를 사용하여 분기를 결정합니다.
SELECT (q_end - 2 MONTH) q_start,
       (q_end + 1 MONTH) - 1 DAY q_end
FROM (
  SELECT DATE(
           SUBSTR(CAST(yrq AS CHAR(4)), 1, 4) || '-' ||
           RTRIM(CAST(MOD(yrq, 10) * 3 AS CHAR(2))) || '-1'
         ) q_end
  FROM (
    SELECT 20051 yrq FROM t1
    UNION ALL
    SELECT 20052 yrq FROM t1
    UNION ALL
    SELECT 20053 yrq FROM t1
    UNION ALL
    SELECT 20054 yrq FROM t1
  ) x
) y

✅ 해석


  1. 내부 서브쿼리 x

    SELECT 20051 AS yrq
    UNION ALL SELECT 20052
    UNION ALL SELECT 20053
    UNION ALL SELECT 20054
    • 분기 정보를 의미하는 숫자 코드 yrq를 나열
    • yrqYYYYQ 형식으로 구성됨
      • 예: 20051 → 2005년 1분기 (Q1)
  2. MOD(yrq, 10) * 3

    • yrq에서 분기 숫자 추출 후 3을 곱해 해당 분기의 마지막 달 계산
      • Q1 → 1 × 3 = 3 (3월)
      • Q2 → 2 × 3 = 6 (6월)
      • Q3 → 3 × 3 = 9 (9월)
      • Q4 → 4 × 3 = 12 (12월)
  3. SUBSTR(...), || '-' || ..., || '1'

    • 문자열을 연결하여 날짜 형식의 문자열 'YYYY-MM-1' 생성
    • 예: 20052"2005-6-1"
    • 이는 해당 분기 종료월의 첫째 날을 의미
  4. DATE(...)q_end

    • 문자열을 날짜 형식으로 변환
    • q_end는 해당 분기 종료월의 1일
  5. 바깥 SELECT

    SELECT
      (q_end - INTERVAL 2 MONTH) AS q_start,
      (q_end + INTERVAL 1 MONTH - INTERVAL 1 DAY) AS q_end
    • q_start: q_end 기준 2개월 전 → 분기 시작일
    • q_end: q_end의 다음 달 첫날에서 하루를 빼서 → 분기 종료일

    예시:

    • q_end = 2005-04-01이면
      • q_start = 2005-02-01
      • q_end = 2005-04-30
      • 따라서 실제 분기 기간: 2005-01-01 ~ 2005-03-31

✅ 결과 예시

q_startq_end
2005-01-012005-03-31
2005-04-012005-06-30
2005-07-012005-09-30
2005-10-012005-12-31

🎨 Oracle

  • SUBSTR함수를 사용하여 인라인 뷰 X에서 연도를 반환합니다.
  • MOD 함수를 사용하여 분기를 결정합ㄴ디ㅏ.
SELECT ADD_MONTHS(q_end, -2) q_start,
       LAST_DAY(q_end) q_end
FROM (
  SELECT TO_DATE(SUBSTR(yrq, 1, 4) || MOD(yrq, 10) * 3, 'YYYYMM') q_end
  FROM (
    SELECT 20051 yrq FROM dual
    UNION ALL
    SELECT 20052 yrq FROM dual
    UNION ALL
    SELECT 20053 yrq FROM dual
    UNION ALL
    SELECT 20054 yrq FROM dual
  ) x
) y

✅ 해석


  1. SELECT 20051, 20052, ..., 20054 FROM dual

    • 분기 코드(yrq)를 나열
    • 코드 구조: YYYYQ
      • 20051 → 2005년 1분기
      • 20054 → 2005년 4분기
  2. MOD(yrq, 10) * 3

    • yrq에서 분기 숫자 추출 후 3을 곱해 해당 분기의 종료 월 계산
      • Q1 → 1 × 3 = 3 → 3월
      • Q2 → 2 × 3 = 6 → 6월
      • Q3 → 3 × 3 = 9 → 9월
      • Q4 → 4 × 3 = 12 → 12월
  3. SUBSTR(yrq, 1, 4) || ...'YYYYMM'

    • 문자열 결합:
      • 연도 부분: SUBSTR(yrq, 1, 4)"2005"
      • 종료 월: MOD(...) * 3"06"
    • 예: 20052'200506'
    • 결과: 해당 분기의 종료 월을 나타내는 문자열
  4. TO_DATE(..., 'YYYYMM')

    • 문자열 'YYYYMM'날짜형(YYYY-MM-01) 으로 변환
    • 예: '200506'2005-06-01
  5. q_end = 종료 월의 1일

    • TO_DATE 결과를 q_end로 사용
    • 예: q_end = 2005-06-01
  6. ADD_MONTHS(q_end, -2)분기 시작일

    • q_end에서 2개월을 빼면 분기 시작월의 1일
    • 예: 2005-06-012005-04-01
    • ✅ 출력 컬럼: q_start
  7. LAST_DAY(q_end)분기 종료일

    • 종료 월의 마지막 날을 계산
    • 예: LAST_DAY(2005-06-01)2005-06-30
    • ✅ 출력 컬럼: q_end

✅ 결과 예시

q_startq_end
2005-01-012005-03-31
2005-04-012005-06-30
2005-07-012005-09-30
2005-10-012005-12-31

🎨 PostgreSQL

  • SUBSTR 함수를 사용하여 인라인 뷰 X 에서 연도를 반환합니다.
  • MOD 함수를 사용하여 분기를 결정합니다.
SELECT DATE(q_end - (2 * INTERVAL '1 month')) q_start,
       DATE(q_end + INTERVAL '1 month' - INTERVAL '1 day') q_end
FROM (
  SELECT TO_DATE(SUBSTR(yrq, 1, 4) || MOD(yrq, 10) * 3, 'YYYYMM') q_end
  FROM (
    SELECT 20051 yrq FROM t1
    UNION ALL
    SELECT 20052 yrq FROM t1
    UNION ALL
    SELECT 20053 yrq FROM t1
    UNION ALL
    SELECT 20054 yrq FROM t1
  ) x
) y

✅ 해석

  1. 내부 쿼리: SELECT 20051, ..., 20054 FROM t1

    • yrq 형식의 분기 코드 나열
      • 예: 20051 = 2005년 1분기, 20054 = 2005년 4분기
  2. MOD(yrq, 10) * 3`

    • 분기 번호 추출 후 종료 월 계산
      • Q1 → 1 × 3 = 3 (3월)
      • Q2 → 2 × 3 = 6 (6월)
      • Q3 → 3 × 3 = 9 (9월)
      • Q4 → 4 × 3 = 12 (12월)
  3. SUBSTR(yrq, 1, 4) || ...'YYYYMM'

    • 연도(YYYY)와 분기 종료 월(MM)을 문자열로 결합
      • 예: 20052'200506'
  4. TO_DATE(..., 'YYYYMM')q_end

    • 해당 문자열을 날짜로 변환 → 종료 월의 1일
      • 예: '200506'2005-06-01
  5. 바깥 SELECT

    DATE(q_end - (2 * INTERVAL '1 month')) AS q_start,
    DATE(q_end + INTERVAL '1 month' - INTERVAL '1 day') AS q_end
    • q_start: 종료 월 기준 -2개월 → 분기 시작일
      • 예: 2005-06-01 - 2개월 → 2005-04-01
    • q_end: 종료 월 기준 +1개월 후 하루 전 → 분기 종료일
      • 예: 2005-06-01 + 1개월 - 1일 → 2005-06-30

✅ 결과 예시

q_startq_end
2005-01-012005-03-31
2005-04-012005-06-30
2005-07-012005-09-30
2005-10-012005-12-31

🎨 MySQL

  • SUBSTR 함수를 사용하여 인라인 뷰 X 에서 연도를 반환합니다.
  • MOD 함수를 사용하여 분기를 결정합니다.
SELECT DATE_ADD(
         ADDDATE(q_end, -DAY(q_end) + 1),
         INTERVAL -2 MONTH
       ) q_start,
       q_end
FROM (
  SELECT LAST_DAY(
           STR_TO_DATE(
             CONCAT(
               SUBSTR(yrq, 1, 4),
               LPAD(MOD(yrq, 10) * 3, 2, '0')
             ),
             '%Y%m'
           )
         ) q_end
  FROM (
    SELECT 20051 yrq FROM t1
    UNION ALL
    SELECT 20052 yrq FROM t1
    UNION ALL
    SELECT 20053 yrq FROM t1
    UNION ALL
    SELECT 20054 yrq FROM t1
  ) x
) y;

✅ 해석

  1. 내부 서브쿼리

    SELECT 20051, 20052, 20053, 20054 FROM t1
    • 분기 코드 yrq 나열 (형식: YYYYQ)
  2. MOD(yrq, 10) * 3

    • 분기 번호(1~4)를 추출한 뒤 3을 곱해 해당 분기의 종료 월 계산
      • Q1 → 3, Q2 → 6, Q3 → 9, Q4 → 12
    • LPAD(..., 2, '0')를 사용해 '06', '09'처럼 두 자리 문자열로 보정
  3. STR_TO_DATE(..., '%Y%m')

    • 연도 + 월 문자열을 날짜로 변환
      • 예: '200506'2005-06-01
  4. LAST_DAY(...)q_end

    • 해당 월의 마지막 날을 구함
      • 예: 2005-06-012005-06-30
  5. 바깥 SELECT

    DATE_ADD(ADDDATE(q_end, -DAY(q_end) + 1), INTERVAL -2 MONTH) AS q_start,
    q_end
    • DAY(q_end) → 종료일의 "일" 숫자 추출 (예: 30)
    • q_end - 일자 + 1 → 해당 월의 1일 (예: 6월 30일 → 6월 1일)
    • 그로부터 2개월 전 → 분기 시작일
      • 예: 2005-06-01 - 2개월2005-04-01

    결과:

    • q_start = 2005-04-01
    • q_end = 2005-06-30

✅ 결과 예시

q_startq_end
2005-01-012005-03-31
2005-04-012005-06-30
2005-07-012005-09-30
2005-10-012005-12-31

🎨 SQL Server

  • SUBSTRING 함수를 사용하여 인라인 뷰 X에서 연도를 반환합니다.
  • 절댓값 함수(%)를 사용하여 찾고 있는 분기를 결정합니다.
SELECT DATEADD(m, -2, q_end) q_start,
       DATEADD(d, -1, DATEADD(m, 1, q_end)) q_end
FROM (
  SELECT CAST(
           SUBSTRING(CAST(yrq AS VARCHAR), 1, 4) + '-' +
           CAST(yrq % 10 * 3 AS VARCHAR) + '-1'
         AS DATETIME) q_end
  FROM (
    SELECT 20051 yrq FROM t1
    UNION ALL
    SELECT 20052 yrq FROM t1
    UNION ALL
    SELECT 20053 yrq FROM t1
    UNION ALL
    SELECT 20054 yrq FROM t1
  ) x
) y;

✅ 해석

  1. SELECT 20051~20054 AS yrq FROM t1

    • yrq는 분기 코드를 의미하는 값 (형식: YYYYQ)
      • 예: 20052 → 2005년 2분기
  2. yrq % 10 * 3

    • yrq에서 마지막 자리를 이용해 분기 숫자(1~4) 추출
    • 여기에 3을 곱해 종료 월 계산
      • Q1 → 3월, Q2 → 6월, Q3 → 9월, Q4 → 12월
  3. SUBSTRING(...) + '-' + ... + '-1'

    • yrq를 문자열로 변환하여 'YYYY-M-1' 형식 생성
      • 예: 20052'2005-6-1'
    • 이는 종료 월의 1일을 의미하는 문자열
  4. CAST(... AS DATETIME)q_end

    • 위 문자열을 날짜형(DATETIME) 으로 변환
    • q_end는 해당 분기의 종료 월의 1일
  5. 바깥 SELECT

    DATEADD(m, -2, q_end) AS q_start,
    DATEADD(d, -1, DATEADD(m, 1, q_end)) AS q_end
    • q_start: q_end 기준 2개월 전 → 분기 시작일
      • 예: 2005-06-01 - 2개월 = 2005-04-01
    • q_end: q_end 기준 +1개월 후 -1일 → 분기 종료일
      • 예: 2005-06-01 + 1개월 - 1일 = 2005-06-30

✅ 예시 결과

q_startq_end
2005-01-012005-03-31
2005-04-012005-06-30
2005-07-012005-09-30
2005-10-012005-12-31
profile
꾸준함의 가치를 믿는 개발자

0개의 댓글