DB 구현시 많이 쓰는 패턴중에 하나가 해당 row가 있으면 update, 없으면 insert를 하는 패턴일 것이다. Oracle의 경우는 merge ~ into 구문을 통해 한번의 명령으로 해당 로직을 구현할 수 있다. Postgres에서도 동일한 명령이 있지 않을까?
아래와 같이 insert ~ on conflict 구문을 활용하면 구현할 수 있다.
문법은 다음과 같다.
INSERT INTO [TABLE] (COLUMN1, COLUMN2, ...)
VALUES (VALUE1, VALUE2, ...)
ON CONFLICT ([column_name / ON CONSTRAINT constraint_name/ WHERE predicate])
[DO NOTHING]
[DO UPDATE SET column1 = value1, ...]
ON CONFLICT column_name : 특정 컬럼명을 기준으로 체크를하며 컬럼을 여러개 넣을수도 있다.(pk기준)
ON CONFLICT ON CONSTRAINT ~ : 테이블 생성시 만든 constraint명을 기준으로 체크한다.
ON CONFLICT WHERE predicate : UNIQUE INDEX 생성 시 사용.
action 에서는 다음과 같은 구문을 사용할 수 있다.
- DO NOTHING : 기존에 존재하는 row가 있는 경우 아무런 동작을 하지 않는다.
- DO UPDATE SET column_1 = value_1, .. WHERE condition : 기존 row를 update 한다.
단일 row upsert
아래와 같이 테스트 용 테이블과 초기데이터가 있다고 해보자.
CREATE TABLE users (
user_id serial PRIMARY KEY,
NAME VARCHAR(20)
)
SELECT * FROM users ORDER BY user_id asc;
on conflict를 이용한 insert 테스트
-- id 6에 대해서 conflict가 발생하지만 아무것도 안함
insert into users (user_id, name) VALUES (6, '홍길동2') ON CONFLICT (user_id) DO NOTHING;
-- id 6에 대해서 conflict가 발생하고 해당 row의 name을 '홍길동2' 로 업데이트 함
insert into users (user_id, name) VALUES (6, '홍길동2') ON CONFLICT (user_id) DO UPDATE SET NAME = '홍길동3'
위 upsert를 수행한 결과 6번 id의 name값이 홍길동3로 바뀌었음을 알 수 있다.
conflict 에 지정한 컬럼(단 여기에 나오는 컬럼은 pk 로 사용되는 컬럼 이어야 함)의 충돌이 있고 DO UPDATE를 명시하였을 경우 해당 row가 업데이트 됨을 볼 수 있다.
Multiple row upsert
만일 multiple row insert 시에도 동작을 제대로 할까? 답은 동일하게 동작한다 이다. 단 on conflict 절에서 충돌난 row의 update 지정 시 insert 시에 사용한 값을 활용하기 위해 excluded.변수명 형식으로 지정해 주면 된다.
현재 초기 값은 다음과 같다고 가정하고
-- insert 구문시의 변수값을 그대로 활용하려면 DO UPDATE절에 excluded 키워드를 붙여준다.
insert into users (user_id, name) VALUES (6, '홍길동4'), (8, '컴퓨터4') ON CONFLICT (user_id) DO UPDATE SET NAME = excluded.name;
결과는 다음과 같다. id 출돌이 난 6,8번 row에 대해서 각각의 insert 시 값으로 갱신되어 있음을 알 수 있다.
-- The end --
'Database > Postgresql' 카테고리의 다른 글
[Postgresql] Sql 쿼리 수행 시간 늘리기 (0) | 2022.09.25 |
---|---|
[Postgresql] max_connection 늘리기, 현재 connection 확인 (windows) (0) | 2022.08.17 |
[Postgresql] RETURNING 활용 예제 (0) | 2022.05.09 |
[Postgresql] auto increment, sequence 처리방법 (0) | 2022.04.28 |
[Postgresql] Postgres db dump, restore (0) | 2022.01.14 |