반응형
설치·접속: PostgreSQL 설치와 접속
부제: 구독 기간을 [시작, 종료) 로 저장했더니 종료일과 다음 구독 시작일이 딱 붙어도 겹침 판정이 안 나야 할 때
-- range 는 무조건 반열림 [) 표준형으로 정규화된다
SELECT '[3,7]'::int4range AS closed, -- 7 포함 -> [3,8)
'[3,7)'::int4range AS half, -- [3,7)
'(3,7)'::int4range AS open; -- 3 제외 -> [4,7)
-- 인접 구간은 겹치지 않는다 (경계값 공유해도)
SELECT int4range(10,20) && int4range(20,30) AS overlap, -- 겹침?
int4range(10,20) -|- int4range(20,30) AS adjacent; -- 인접?
-- [4,4) 는 빈 구간으로 정규화
SELECT '[4,4)'::int4range AS r,
isempty('[4,4)'::int4range) AS is_empty,
'[4,4]'::int4range AS one_point; -- 점 하나 -> [4,5)
closed | half | open
--------+-------+-------
[3,8) | [3,7) | [4,7)
overlap | adjacent
---------+----------
f | t
r | is_empty | one_point
-------+----------+-----------
empty | t | [4,5)range 타입은 어떻게 입력하든 하한 포함·상한 제외 [) 형태로 정규화한다. [3,7](양끝 포함)은 [3,8)로, (3,7)(양끝 제외)은 [4,7)로 바뀐다. 그래서 [10,20)과 [20,30)은 경계값 20을 공유하지만 20이 앞 구간엔 안 들어가므로 &&(겹침)은 거짓, -|-(인접)만 참이다. 대부분 "시작~끝을 둘 다 포함"으로 생각해서 이 지점에서 어긋난다. 반열림이 표준형이라 인접 기간을 이어 붙일 때 경계 하루가 이중 계산되지 않는다.
빈 구간 규칙도 여기서 나온다. [4,4)는 하한은 포함인데 상한 4 미만이라 담을 값이 없어 empty로 정규화되고 isempty가 참이다. 반면 [4,4]는 4 하나를 담은 [4,5)가 된다. 구독·예약 기간을 [start, end)로 저장하면 종료일과 다음 시작일이 같은 날이어도 겹침이 안 나서 인접 처리가 깔끔해진다 — 아래 구독 테이블에서 세 기간이 연달아 붙어도 겹치는 쌍이 하나도 없다.
CREATE TABLE sub (user_id int, period daterange);
INSERT INTO sub VALUES
(1, '[2026-01-01,2026-02-01)'),
(1, '[2026-02-01,2026-03-01)'),
(1, '[2026-03-01,2026-04-01)');
SELECT a.period, b.period, a.period && b.period AS overlap
FROM sub a JOIN sub b ON a.ctid < b.ctid;
period | period | overlap
-------------------------+-------------------------+---------
[2026-01-01,2026-02-01) | [2026-02-01,2026-03-01) | f
[2026-01-01,2026-02-01) | [2026-03-01,2026-04-01) | f
[2026-02-01,2026-03-01) | [2026-03-01,2026-04-01) | f이렇게도 쓴다
@> 포함: 특정 값/구간이 범위 안에 있나.
SELECT int4range(1,20) @> 5 AS contains_5; -- t
* 교집합: 두 구간의 겹치는 부분만.
SELECT int4range(1,20) * int4range(10,30) AS intersect; -- [10,20)
lower / upper 로 경계값 추출.
SELECT lower(int4range(10,30)) AS lo, upper(int4range(10,30)) AS hi; -- 10, 30
무한 경계: 종료일 없는 "현재 진행 중" 구독.
SELECT '[2026-07-01,)'::daterange @> current_date AS active_now;
겹침 삽입을 DB가 원천 차단. (조합: EXCLUDE + GiST)
CREATE TABLE booking (room text, during tsrange,
EXCLUDE USING GIST (during WITH &&));
빈 구간 방어: 잘못된 입력을 CHECK 로 거른다.
ALTER TABLE sub ADD CHECK (NOT isempty(period));반응형
'명령어 > DB' 카테고리의 다른 글
| [PostgreSQL] ntile(4) / percent_rank() / cume_dist() — 분위수 버킷으로 나누기 (0) | 2026.07.22 |
|---|---|
| [PostgreSQL] multirange — 불연속 기간을 한 값으로 다룬다 (0) | 2026.07.22 |
| [PostgreSQL] "배열은 집합이 아니다" — 언제 배열, 언제 조인 테이블 (0) | 2026.07.22 |
| [PostgreSQL] array_position 으로 상태값을 커스텀 순서로 정렬한다 (0) | 2026.07.22 |
| [PostgreSQL] 배열 검색 = ANY / && / @> 와 GIN 인덱스 (0) | 2026.07.22 |