한양과학기술고등학교

에듀테크 프로젝트 대시보드

UPSERT (ON CONFLICT)

ON CONFLICT DO UPDATE EXCLUDED DO NOTHING MERGE

'있으면 갱신, 없으면 삽입'을 한 문장·원자적으로 처리합니다.

1. 기본형

INSERT INTO daily_counts (day, hits)
VALUES (current_date, 1)
ON CONFLICT (day)
DO UPDATE SET hits = daily_counts.hits + 1;

충돌 판정 기준((day))에는 유니크 제약 또는 유니크 인덱스가 있어야 합니다.

2. EXCLUDED — 삽입하려던 값

INSERT INTO users (email, name, last_seen)
VALUES ('a@x.com', '김한양', now())
ON CONFLICT (email) DO UPDATE
SET name      = EXCLUDED.name,
    last_seen = EXCLUDED.last_seen
WHERE users.last_seen < EXCLUDED.last_seen;   -- 조건부 갱신도 가능
이름가리키는 것
EXCLUDED.*INSERT 하려다 충돌난 새 값
테이블명.*이미 저장돼 있던 기존 행

3. DO NOTHING

-- 이미 있으면 조용히 무시 (중복 삽입 방지)
INSERT INTO tags (name) VALUES ('sql')
ON CONFLICT DO NOTHING;

-- 삽입된 행만 RETURNING (충돌로 스킵되면 아무것도 안 나옴)
INSERT INTO tags (name) VALUES ('sql')
ON CONFLICT (name) DO NOTHING
RETURNING id;

4. MERGE (PG15+)

MERGE INTO inventory AS t
USING shipments AS s ON t.sku = s.sku
WHEN MATCHED AND s.qty = 0 THEN DELETE
WHEN MATCHED THEN UPDATE SET qty = t.qty + s.qty
WHEN NOT MATCHED THEN INSERT (sku, qty) VALUES (s.sku, s.qty);
선택
  • 단순 upsert 는 ON CONFLICT 가 간결하고 동시성에 강함. MERGE 는 삭제 등 복합 분기가 필요할 때
"VACUUM 은 선택이 아니라 MVCC 가 물리는 세금이다"