시간 및 버전 관리 행
유효 시간 및 특정 시점 기준 쿼리를 배웁니다
시간 및 버전 관리 행은(는) CoddyKit의 무료 SQL Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 SQL Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
시간 테이블이란 무엇인가요
시간 테이블을 사용하면 시간이 지나며 데이터가 어떻게 변하는지 추적할 수 있습니다. 무언가 변경될 때 행을 덮어쓰는 대신, 시간 테이블은 해당 행의 모든 버전을 보존하고 각 버전에 유효했던 기간을 표시합니다.
핵심 개념은 두 가지입니다. 유효 시간(실제 세계에서 사실이었던 시점)과 트랜잭션 시간(데이터베이스가 그 사실을 기록한 시점)입니다. 두 개념을 결합하면 완전한 이중 시간 테이블을 만들 수 있습니다.
유효 시간과 트랜잭션 시간 비교
유효 시간은 사실이 실제 세계에서 유효했던 시점을 나타냅니다. 예를 들어 직원의 급여가 2020-01-01부터 2022-06-30까지였던 기간입니다. 트랜잭션 시간은 데이터베이스의 행이 삽입되거나 만료된 시점입니다. 두 시간을 함께 사용하면 다음 두 질문에 답할 수 있습니다. 무엇이 사실이었는가? 그리고 언제 그것을 알게 되었는가?
대부분의 실용적인 사용 사례는 유효 시간 추적부터 시작하며, valid_from과 valid_to 열을 사용해 직접 구현할 수 있습니다.
유효 시간 테이블 만들기
버전이 관리되는 행을 저장하는 가장 간단한 방법은 valid_from과 valid_to 타임스탬프 열을 추가하는 것입니다. valid_to가 NULL이거나 9999-12-31과 같은 먼 미래의 기준값이면 해당 행이 현재 활성 상태임을 의미합니다.
CREATE TABLE employee_salary (
id SERIAL PRIMARY KEY,
employee_id INT NOT NULL,
salary NUMERIC(12, 2) NOT NULL,
valid_from DATE NOT NULL,
valid_to DATE
);
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES
(1, 50000, '2020-01-01', '2022-06-30'),
(1, 60000, '2022-07-01', NULL);현재 버전 조회하기
각 직원의 현재 활성 행을 찾으려면 valid_to IS NULL인 행(종료 시점이 정해지지 않은 행)을 필터링하거나, 오늘 날짜가 유효 범위 안에 포함되는지 확인하세요. '9999-12-31'과 같은 기준값을 사용하면 범위 비교가 간단해집니다.
SELECT employee_id, salary
FROM employee_salary
WHERE valid_to IS NULL
ORDER BY employee_id;특정 시점 기준 조회
특정 시점 기준 조회는 다음과 같은 질문을 합니다. 특정 시점의 데이터는 무엇이었는가? 주어진 타임스탬프가 유효 기간 안에 포함되는 행만 필터링하면 됩니다. 이는 시간 테이블의 가장 강력한 기능 중 하나입니다.
-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_from, valid_to
FROM employee_salary
WHERE employee_id = 1
AND valid_from <= '2021-03-15'
AND (valid_to IS NULL OR valid_to > '2021-03-15');버전 관리 행 업데이트하기
사실이 변경될 때 기존 행을 그 자리에서 UPDATE하지 않습니다. 대신 현재 행을 종료하고 valid_to를 설정한 다음, 새 값이 담긴 행을 INSERT합니다. 이렇게 하면 전체 이력이 보존됩니다.
-- Employee 1 gets a raise effective 2023-01-01
BEGIN;
-- Close the current open row
UPDATE employee_salary
SET valid_to = '2022-12-31'
WHERE employee_id = 1
AND valid_to IS NULL;
-- Insert the new version
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES (1, 72000, '2023-01-01', NULL);
COMMIT;유효 기간에 daterange 사용하기
PostgreSQL의 daterange 유형은 유효 기간을 하나의 열로 우아하게 표현합니다. @>(포함) 연산자를 사용해 날짜가 범위에 포함되는지 확인하고, 동일한 엔터티의 기간이 겹치지 않도록 배제 제약 조건을 추가할 수 있습니다.
CREATE TABLE employee_salary_v2 (
id SERIAL PRIMARY KEY,
employee_id INT NOT NULL,
salary NUMERIC(12, 2) NOT NULL,
valid_period DATERANGE NOT NULL,
EXCLUDE USING GIST (employee_id WITH =, valid_period WITH &&)
);
INSERT INTO employee_salary_v2 (employee_id, salary, valid_period)
VALUES
(1, 50000, '[2020-01-01, 2022-07-01)'),
(1, 60000, '[2022-07-01, infinity)');daterange를 사용한 특정 시점 기준 조회
daterange 방식을 사용하면 특정 시점 기준 조회를 매우 읽기 쉽게 작성할 수 있습니다. @> 연산자는 주어진 날짜가 범위 안에 포함되어 있는지 확인하고 하한과 상한을 자동으로 처리합니다.
-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_period
FROM employee_salary_v2
WHERE employee_id = 1
AND valid_period @> '2021-03-15'::date;시스템 버전 관리 테이블(SQL 표준)
SQL:2011 표준에서는 시스템 버전 관리 시간 테이블을 도입했습니다. 데이터베이스가 row_start와 row_end 트랜잭션 시간 열을 자동으로 관리합니다. PostgreSQL에서는 이를 흉내 내야 하지만, SQL 서버와 MariaDB에서는 SYSTEM VERSIONING으로 기본 제공됩니다.
아래 예제는 개념을 참고할 수 있도록 SQL 서버 / MariaDB 구문을 보여 줍니다.
-- SQL Server / MariaDB syntax (reference)
CREATE TABLE dbo.Product (
ProductID INT PRIMARY KEY,
Name VARCHAR(100),
Price DECIMAL(10,2),
SysStart DATETIME2 GENERATED ALWAYS AS ROW START,
SysEnd DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (SysStart, SysEnd)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Product_History));시간 조인: 두 테이블의 시간 맞추기
흔히 발생하는 문제는 일치하는 시간 범위를 기준으로 두 시간 테이블을 조인하는 것입니다. 예를 들어 유효 시간이 서로 겹치는 직원 급여와 부서 배정을 조인할 수 있습니다. 엔터티 키 AND 겹침 조건을 기준으로 조인하며, 범위에는 &&를 사용하고 명시적인 날짜 비교를 사용할 수도 있습니다.
CREATE TABLE dept_assignment (
employee_id INT,
department VARCHAR(50),
valid_period DATERANGE
);
INSERT INTO dept_assignment VALUES
(1, 'Engineering', '[2020-01-01, infinity)'),
(1, 'Marketing', '[2019-01-01, 2020-01-01)');
-- Periods where employee 1 was in Engineering AND had salary > 55000
SELECT s.salary, d.department,
s.valid_period * d.valid_period AS overlap_period
FROM employee_salary_v2 s
JOIN dept_assignment d
ON s.employee_id = d.employee_id
AND s.valid_period && d.valid_period
WHERE s.employee_id = 1
AND s.salary > 55000;공백과 겹침 방지하기
시간 테이블에서 흔히 발생하는 데이터 품질 문제는 공백(기록이 없는 기간)과 겹침(두 행이 동시에 유효한 상태)입니다. &&를 사용하는 배제 제약 조건은 데이터베이스 수준에서 겹침을 방지합니다. 공백을 감지하려면 조회를 통해 누락된 범위를 확인해야 합니다.
-- Find gaps in salary history for employee 1
-- (periods where upper(prev) < lower(next))
SELECT
upper(a.valid_period) AS gap_start,
lower(b.valid_period) AS gap_end
FROM employee_salary_v2 a
JOIN employee_salary_v2 b
ON a.employee_id = b.employee_id
AND upper(a.valid_period) < lower(b.valid_period)
WHERE a.employee_id = 1
AND NOT EXISTS (
SELECT 1 FROM employee_salary_v2 c
WHERE c.employee_id = 1
AND lower(c.valid_period) > upper(a.valid_period)
AND lower(c.valid_period) < lower(b.valid_period)
)
ORDER BY gap_start;이해도 확인
시간 테이블과 특정 시점 기준 조회를 얼마나 이해했는지 확인해 보세요.
복습: 시간 및 버전 관리 행
이 레슨에서는 유효 시간 열과 PostgreSQL의 daterange 유형을 사용해 시간에 따라 변하는 데이터를 모델링하는 방법을 배웠습니다. 핵심 내용:
- 이력 행을 절대 덮어쓰지 마세요. 기존 행을 종료하고 새 버전을 삽입하세요.
- 특정 시점 기준 조회(
valid_from <= target AND valid_to > target)를 사용하면 과거 어느 시점에서든 데이터를 가져올 수 있습니다. @>연산자와 함께 사용하는daterange유형은 시간 관련 조회를 간결하고 읽기 쉽게 만듭니다.&&(범위 겹침)에 대한 배제 제약 조건은 데이터베이스 수준에서 데이터 무결성을 보장합니다.- 시간 조인은 유효 기간을 교차하여 두 이력을 맞춥니다.
이러한 패턴은 이벤트 소싱, 감사 기록, 그리고 이력의 정확성이 중요한 모든 시스템의 토대입니다.
자주 묻는 질문
“시간 및 버전 관리 행” 강의는 무료인가요?
네 — “시간 및 버전 관리 행” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 SQL Academy 강의 전체를 잠금 해제할 수 있습니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“시간 및 버전 관리 행”에서 뭘 배우나요?
유효 시간 및 특정 시점 기준 쿼리를 배웁니다 브라우저에서 직접 실행하는 실습 코드로 SQL Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
SQL Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 SQL Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“시간 및 버전 관리 행” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 SQL Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 SQL Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 이력을 보관해야 하는 이유
- 추가 전용 이벤트 테이블
- 시간 및 버전 관리 행
- 이벤트에서 상태 재구성하기