단일 쿼리를 사용하여 삽입하거나 업데이트하는 방법은 무엇입니까?


25

기본 키와 자동 증가 및 이름이있는 열 id가있는 테이블 테스트가 있습니다. 레코드가없는 경우에만 annd 인 경우 새 레코드를 삽입하고 싶습니다.

입력은 id = 30122이고 name = john

ID가 30122 인 레코드가 있으면 이름 열을 john으로 업데이트하고 레코드가없는 경우 새 레코드를 삽입합니다.

나는 2 개의 쿼리를 사용하여 할 수있다

select * from test where id=30122

레코드가 있으면 사용할 수 있습니다. update test set name='john' where id=3012

또는 기록이 없으면 사용할 수 있습니다.

insert into test(name) values('john')

그러나 단일 쿼리를 사용하고 싶습니까?

누군가 가능하다면 말할 수 있습니까?


1
But I wanted to use single query?왜?
Aaron Bertrand

@AaronBertrand 내 백엔드는 java를 사용하여 개발되었으므로 2 개의 쿼리를 사용하면 DB를 두 번 두 드려야합니다. 따라서 단일 쿼리를 사용하여 수행 할 수있는 경우 2 개의 쿼리를 사용해야하는 이유
SpringLearner

1
Java는 저장 프로 시저 또는 데이터베이스에 하나의 히트 만 요구하는 두 개의 명령문이있는 단일 배치를 지원하지 않습니까?
Aaron Bertrand

@AaronBertrand SQL Server 2008 이상에서 어떻게 처리하는지 예를 들어 줄 수 있습니까?
eaglei22

1
@ eaglei22 아래 vijayp의 답변에서 두 번째 예를 사용합니다. MERGESQL Server 2019조차도 어떤 버전에서도 선택하지 않을 것 입니다. 여기에 대한 배경 지식이 있습니다 .
Aaron Bertrand

답변:


41

당신은 이것을 시도 할 수 있습니다

IF EXISTS(select * from test where id=30122)
   update test set name='john' where id=3012
ELSE
   insert into test(name) values('john');

더 나은 성능을위한 다른 방법은

update test set name='john' where id=3012
IF @@ROWCOUNT=0
   insert into test(name) values('john');

또한 스키마 접두사에 킥이 나쁜 습관을 읽고


4
첫 번째 예는 낭비이며 교착 상태로 이어질 수 있습니다. 전혀 제안하지 않습니다.
Aaron Bertrand

@AaronBertrand가 정교하게 신경써? 감사합니다
Hexo

5
@SlapY 물론, 첫 번째 예에서 "이봐, SQL Server,이 ID를 가진 행이 있습니까?"라고 말합니다. SQL Server는 아마도 스캔을 사용하여 행을 찾은 다음 응답으로 돌아옵니다. "왜 그래, 사용자, 나는 그 ID를 가진 행을 가지고있다!" 그런 다음 "알겠습니다. SQL Server, 해당 행을 다시 찾으십시오 . 그러나 이번에는 업데이트하십시오!" 탐색 또는 스캔을 두 번 수행하는 것이 얼마나 낭비 적인지 알고 있습니까? 다른 사용자가 행의 존재에 대해 같은 질문을한다면 어떤 일을하기 전에 어떻게되는지 상상할 수 있습니까?
Aaron Bertrand

고마워, 나는 왜 첫 번째가 교착 상태에 빠질 때 왜 두 번째가 아닌지 알지 못합니까? 둘 다 전체 잠금으로 실행되지 않으면 가로 챌 수있는 여러 명령문으로 구성됩니다. 내가 잘못?
Hexo

2
@ 0x25b3 하나는 교착 상태에 의해 위협받지 않고 다른 하나는 위협받지 않으며, 첫 번째 예는 훨씬 더 취약합니다. 두 경우 모두 완전하고 적절한 거래로 포장해야하지만 사람들은 그렇지 않습니다.
Aaron Bertrand

17

SQL Server 2008 이상을 가정하면 다음을 사용할 수 있습니다 MERGE.

CREATE TABLE dbo.Test
(
    id integer NOT NULL,
    name varchar(30) NULL,

    CONSTRAINT PK_dbo_Test__id
        PRIMARY KEY CLUSTERED (id)
);

질문

MERGE dbo.Test WITH (SERIALIZABLE) AS T
USING (VALUES (3012, 'john')) AS U (id, name)
    ON U.id = T.id
WHEN MATCHED THEN 
    UPDATE SET T.name = U.name
WHEN NOT MATCHED THEN
    INSERT (id, name) 
    VALUES (U.id, U.name);

SERIALIZABLE힌트에 필요한 높은 동시성 하에서 정확한 동작 .

Michael J. Swart의 일반적인 방법 비교는 다음과 같습니다.

추론 : 동시 업데이트 / 삽입 솔루션


8
병합에는 몇 가지 문제있습니다 .
vonPryz

신화 붕괴 링크가 우수합니다. 좋은 것!
JonnyRaa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.