Interval 타입
Interval 타입 (Interval Type)
INTERVAL은 시간의 기간(period)을 나타내며, DATE, TIMESTAMP, TIMESTAMPTZ, TIME 값에 더하거나 뺄 수 있어요.
출처: 문서
본문
| Name | Description |
|---|---|
INTERVAL |
시간의 기간 |
INTERVAL은 단위(unit)와 함께 수량을 제공하면 만들 수 있어요. 월(months), 일(days), *마이크로초(microseconds)*가 아닌 단위는 이 세 가지 기준 단위 중 더 작은 단위로 변환된 동일한 수량으로 변환돼요.
SELECT
INTERVAL 1 YEAR, -- 단일 단위: YEAR 키워드 사용; 12개월로 저장됨
INTERVAL (random() * 10) YEAR, -- 가변 수량에는 괄호가 필요함;
-- 정수 개월 수로 저장됨
INTERVAL '1 month 1 day', -- 여러 단위에는 문자열 타입 필요; (1 month, 1 day)로 저장됨
'16 months'::INTERVAL, -- 문자열 캐스트 지원; 16개월로 저장됨
'48:00:00'::INTERVAL, -- HH::MM::SS 문자열 지원; (48 * 60 * 60 * 1e6 마이크로초)로 저장됨
;
경고: 단위 키워드와 함께 사용할 때 소수 값은 정수로 잘려요(단위가
SECONDS나MILLISECONDS인 경우 제외).SELECT INTERVAL '1.5' YEARS; -- 12개월 반환; `to_years(CAST(trunc(1.5) AS INTEGER))`와 동일더 정밀하게 하려면 문자열에 단위를 포함하거나 더 세분화된 단위를 사용해요. 예:
INTERVAL '1.5 years'또는INTERVAL 18 MONTHS.
세 개의 독립적인 기준 단위가 필요한 이유는, 한 달이 고정된 일수에 대응하지 않고(2월은 3월보다 날이 적음), 하루가 고정된 마이크로초 수에 대응하지 않기 때문이에요(일광 절약 시간 때문에 하루가 25시간 또는 23시간이 될 수 있음). 구성 요소로 나뉘는 덕분에 INTERVAL 클래스는 특정 시간 단위를 날짜에 더하거나 빼는 데 적합해요. 예를 들어 다음 SQL 쿼리로 매월 1일을 담은 테이블을 만들 수 있어요.
SELECT DATE '2000-01-01' + INTERVAL (i) MONTH
FROM range(12) t(i);
INTERVAL이 datepart 함수로 분해될 때, months 구성 요소는 추가로 연과 월로 분할되고 microseconds 구성 요소는 시, 분, 마이크로초로 분할돼요. days 구성 요소는 추가 단위로 분할되지 않아요. 이를 보여주기 위해 다음 쿼리는 세 기준 단위의 임의 수량을 합해 period라는 INTERVAL을 생성해요. 그런 다음 period에서 앞서 언급한 여섯 부분을 추출해 다시 합치고, 결과가 항상 원래 period와 같음을 확인해요.
SELECT
period = list_reduce(
[INTERVAL (datepart(part, period) || part) FOR part IN
['year', 'month', 'day', 'hour', 'minute', 'microsecond']
],
(i1, i2) -> i1 + i2
) -- 항상 true
FROM (
VALUES (
INTERVAL (random() * 123_456_789_123) MICROSECONDS
+ INTERVAL (random() * 12_345) DAYS
+ INTERVAL (random() * 12_345) MONTHS
)
) _(period);
경고: microseconds 구성 요소는 시, 분, 초(seconds), 마이크로초가 아니라 시, 분, 마이크로초로만 분할돼요.
다음 표는 datepart가 세 기준 단위의 함수로 이 부분들을 어떻게 추출하는지 공식으로 설명해요.
| Part | Formula |
|---|---|
year |
#months // 12 |
month |
#months % 12 |
day |
#days |
hour |
#microseconds // (60 * 60 * 1_000_000) |
minute |
(#microseconds // (60 * 1_000_000)) % 60 |
microsecond |
#microseconds % (60 * 1_000_000) |
추가로 datepart는 INTERVAL에서 세기(century), 십 년(decade), 분기(quarter), 초(second), 밀리초(millisecond)를 추출하는 데에도 사용할 수 있어요. 그러나 이 부분들은 원래 INTERVAL을 다시 조립할 때는 필요하지 않아요. 사실 이전 쿼리가 이 추가 부분 중 하나라도 추출한다면, 추출된 부분의 합은 일반적으로 원래 period보다 커져요.
| Part | Formula |
|---|---|
century |
datepart('year', interval) // 100 |
decade |
datepart('year', interval) // 10 |
quarter |
datepart('month', interval) // 3 + 1 |
second |
datepart('microsecond', interval) // 1_000_000 |
millisecond |
datepart('microsecond', interval) // 1_000 |
모든 단위는 0-기반 인덱싱을 사용하지만, 분기(quarter)만 1-기반 인덱싱을 사용해요.
예를 들어:
SELECT
datepart('decade', INTERVAL 12 YEARS), -- 1 반환
datepart('year', INTERVAL 12 YEARS), -- 12 반환
datepart('second', INTERVAL 1_234 MILLISECONDS), -- 1 반환
datepart('microsecond', INTERVAL 1_234 MILLISECONDS), -- 1_234_000 반환
;
타임스탬프, 날짜, Interval 간의 산술 (Arithmetic with Timestamps, Dates and Intervals)
INTERVAL은 +와 - 연산자를 사용해 TIMESTAMP, TIMESTAMPTZ, DATE, TIME에 더하거나 뺄 수 있어요.
SELECT
DATE '2000-01-01' + INTERVAL 1 YEAR,
TIMESTAMP '2000-01-01 01:33:30' - INTERVAL '1 month 13 hours',
TIME '02:00:00' - INTERVAL '3 days 23 hours', -- 감싸짐; TIME '03:00:00'과 동일
;
INTERVAL을DATE에 더하면INTERVAL에 마이크로초 구성 요소가 없어도TIMESTAMP가 반환돼요. 결과는INTERVAL을 더하기 전에DATE를TIMESTAMP로 캐스트한(시간 구성 요소를00:00:00으로 설정) 것과 같아요.
반대로 두 TIMESTAMP 또는 두 TIMESTAMPTZ를 서로 빼면 days와 microseconds 구성 요소만 가진, 타임스탬프 간의 차이를 설명하는 INTERVAL이 생성돼요. 예를 들어:
SELECT
TIMESTAMP '2000-02-06 12:00:00' - TIMESTAMP '2000-01-01 11:00:00', -- 36 days 1 hour
TIMESTAMP '2000-02-01' + (TIMESTAMP '2000-02-01' - TIMESTAMP '2000-01-01'), -- '2000-03-03', NOT '2000-03-01'
;
두 DATE를 서로 빼면 INTERVAL이 아니라 주어진 날짜 간의 일수를 정수 값으로 반환해요.
경고: 두
TIMESTAMP의INTERVAL차이에서 부분을 추출하는 것은 해당 단위에 대한 두TIMESTAMP사이의 파티션 경계 수를 계산하는 것과 동일하지 않아요. 후자는datediff함수가 계산해요.SELECT datediff('day', TIMESTAMP '2020-01-01 01:00:00', TIMESTAMP '2020-01-02 00:00:00'), -- 1 datepart('day', TIMESTAMP '2020-01-02 00:00:00' - TIMESTAMP '2020-01-01 01:00:00'), -- 0 ;
동등성과 비교 (Equality and Comparison)
동등성과 정렬 비교만을 위해, INTERVAL의 총 마이크로초 수는 days 기준 단위를 24 * 60 * 60 * 1e6 마이크로초로, months 기준 단위를 30일(30 * 24 * 60 * 60 * 1e6 마이크로초)로 변환해 계산해요.
그 결과 기능적으로 다르더라도 INTERVAL이 동등하게 비교될 수 있고, INTERVAL을 날짜나 타임스탬프에 더할 때 정렬 순서가 항상 보존되지는 않아요.
예를 들어:
INTERVAL 30 DAYS = INTERVAL 1 MONTH- 하지만
DATE '2020-01-01' + INTERVAL 30 DAYS != DATE '2020-01-01' + INTERVAL 1 MONTH
그리고
INTERVAL '30 days 12 hours' > INTERVAL 1 MONTH- 하지만
DATE '2020-01-01' + INTERVAL '30 days 12 hours' < DATE '2020-01-01' + INTERVAL 1 MONTH
함수 (Functions)
INTERVAL과 함께 사용할 수 있는 date part 목록은 Date Part Functions 페이지에서 확인해요.
interval을 조작하는 함수는 Interval Operators 페이지에서 확인해요.