공공부하자개발 · 영어 학습 노트
SQL
SQL 실무페이징·검색·이력·통계·채번·이관0/9 완료
  • 01페이징 쿼리
  • 02동적 검색 조건
  • 03이력 테이블과 시점 조회
  • 04기간별 통계 보고서
  • 05중복 데이터 찾기와 정리
  • 06트랜잭션 기초
  • 07채번과 순번 관리
  • 08저장 프로시저·함수 기초
  • 09데이터 이관·검증 쿼리
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › SQL 실무 › 03 / 9

이력 테이블과 시점 조회

유효 기간, 최신 상태, 특정 날짜의 상태, 기간 겹침
섹션 6진행 0 / 9
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6정리‹ 이전다음 ›

3. 코드 예제

소스: sql-src/work_03_history/01_current_point.sql. 이력 표 emp_hist 는 사원 4명(1 김대표, 2 김개발, 3 남개발, 4 이영업)의 11행이고 현재 행만 valid_to = 9999-12-31 입니다. 주문 표 orders 는 7행입니다.

예제 1: 현재 상태와 특정 날짜의 상태

sql
SELECT
       emp_id
     , dept
     , grade
     , valid_from
  FROM emp_hist
 WHERE valid_to = DATE '9999-12-31'
 ORDER BY emp_id;
text
EMP_ID | DEPT   | GRADE | VALID_FROM
-------+--------+-------+-----------
1      | 경영   | 임원  | 2023-01-01
2      | 개발   | 과장  | 2025-09-01
3      | 인프라 | 대리  | 2024-01-01
4      | 마케팅 | 과장  | 2025-04-01
(4행)

4명 모두 현재 행이 한 개씩입니다. 같은 사원들의 2024-06-30 상태는 시작 조건과 끝 조건을 함께 씁니다.

sql
SELECT
       emp_id
     , dept
     , grade
  FROM emp_hist
 WHERE valid_from <= DATE '2024-06-30'
   AND DATE '2024-06-30' < valid_to
 ORDER BY emp_id;
text
EMP_ID | DEPT   | GRADE
-------+--------+------
1      | 경영   | 임원
2      | 개발   | 대리
3      | 인프라 | 대리
4      | 마케팅 | 대리
(4행)

김개발은 과장이 되기 전이라 대리이고, 이영업은 마케팅으로 옮긴 뒤의 대리입니다. 날짜 값은 바인드 변수 하나로 받아 재사용합니다.

예제 2: 경계일과 BETWEEN 의 함정

김개발의 사원 행은 valid_to = 2023-03-01, 대리 행은 valid_from = 2023-03-01 입니다. 경계일 자체를 조회합니다.

sql
SELECT
       emp_id
     , grade
  FROM emp_hist
 WHERE emp_id = 2
   AND valid_from <= DATE '2023-03-01'
   AND DATE '2023-03-01' < valid_to;
text
EMP_ID | GRADE
-------+------
2      | 대리
(1행)

반개구간이라 경계일은 새 행이 가져가고 정확히 1행입니다. 이 조건을 BETWEEN valid_from AND valid_to 로 쓰면 끝을 포함하게 됩니다.

sql
SELECT
       emp_id
     , grade
  FROM emp_hist
 WHERE emp_id = 2
   AND DATE '2023-03-01' BETWEEN valid_from AND valid_to;
text
EMP_ID | GRADE
-------+------
2      | 사원
2      | 대리
(2행)

경계일에 사원과 대리가 동시에 나옵니다. 시점 조인에서 이런 행이 생기면 그날의 주문이 두 번 집계됩니다.

주의

이력 조회에 BETWEEN 을 쓰지 않습니다. 양쪽 끝을 포함하므로 반개구간과 맞지 않아 경계일에 두 행이 나옵니다.

예제 3: 최신 1건을 ROW_NUMBER 로 고르기

sql
SELECT
       emp_id
     , dept
     , grade
  FROM (
        SELECT
               emp_id
             , dept
             , grade
             , ROW_NUMBER() OVER (PARTITION BY emp_id ORDER BY valid_from DESC) AS rn
          FROM emp_hist
       ) t
 WHERE rn = 1
 ORDER BY emp_id;
text
EMP_ID | DEPT   | GRADE
-------+--------+------
1      | 경영   | 임원
2      | 개발   | 과장
3      | 인프라 | 대리
4      | 마케팅 | 과장
(4행)

예제 1 의 현재 상태와 같은 결과입니다. 이 방식은 9999-12-31 이라는 약속에 기대지 않는 장점이 있지만 사원마다 정렬해야 합니다. 현재 행 조건은 valid_to 인덱스로 바로 찾을 수 있어 대개 더 빠릅니다.

예제 4: 주문일 당시의 부서와 직급

sql
SELECT
       o.id
     , o.emp_id
     , o.ord_date
     , h.dept
     , h.grade
  FROM orders o
  JOIN emp_hist h ON h.emp_id = o.emp_id
                 AND h.valid_from <= o.ord_date
                 AND o.ord_date < h.valid_to
 ORDER BY o.id;
text
ID | EMP_ID | ORD_DATE   | DEPT   | GRADE
---+--------+------------+--------+------
1  | 2      | 2022-11-15 | 개발   | 사원
2  | 2      | 2024-05-20 | 개발   | 대리
3  | 3      | 2023-06-10 | 개발   | 사원
4  | 3      | 2025-03-02 | 인프라 | 대리
5  | 4      | 2022-01-25 | 영업   | 대리
6  | 4      | 2024-11-30 | 마케팅 | 대리
7  | 4      | 2025-04-01 | 마케팅 | 과장
(7행)

주문 7건이 각각 정확히 한 행에 붙었습니다. 7번 주문은 이영업이 과장으로 승진한 2025-04-01 당일이라 과장으로 붙습니다. 소스 파일에는 이 조인으로 부서별 매출을 구하는 쿼리도 있습니다. 개발 3건 1600, 마케팅 2건 1500, 영업 1건 450, 인프라 1건 700 입니다.

예제 직접 실행

아래 폴더의 SQL 파일을 Git Bash 에서 H2 메모리 DB 로 실행합니다. 방언은 파일 안의 SET MODE 로 바꿉니다.

cd sql-src/work_03_history
ls *.sql
bash ../run.sh <파일>.sql
코드 예제
  • 예제 1: 현재 상태와 특정 날짜의 상태
  • 예제 2: 경계일과 BETWEEN 의 함정
  • 예제 3: 최신 1건을 ROW_NUMBER 로 고르기
  • 예제 4: 주문일 당시의 부서와 직급
이전 섹션2 핵심 원리3 / 6다음 섹션4 응용 변형 예제