SQL Server에 업데이트 저장 프로 시저 삽입
레코드가 있으면 업데이트를 수행하는 저장된 proc을 작성했습니다. 그렇지 않으면 삽입을 수행합니다. 다음과 같이 보입니다.
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
이런 식으로 작성하는 논리는 업데이트가 where 절을 사용하여 암시 적 선택을 수행하고 0을 반환하면 삽입이 발생한다는 것입니다.
이 방법의 대안은 선택을 수행 한 다음 반환 된 행 수에 따라 업데이트 또는 삽입을 수행하는 것입니다. 업데이트를 수행하면 두 번의 선택이 발생하기 때문에 비효율적이라고 생각했습니다 (첫 번째 명시 적 선택 호출과 업데이트 위치에 두 번째 암시 적). 프로세서가 삽입을한다면 효율성에 차이가 없을 것입니다.
내 논리가 여기에 있습니까? 이것이 저장된 proc에 삽입 및 업데이트를 결합하는 방법입니까?
귀하의 가정이 맞습니다. 이것이 최선의 방법이며 upsert / merge 라고 합니다.
UPSERT의 중요성-sqlservercentral.com에서 :
위에서 언급 한 경우의 모든 업데이트에 대해 EXISTS 대신 UPSERT를 사용하면 테이블에서 하나의 추가 읽기를 제거합니다. 안타깝게도 Insert의 경우 UPSERT 및 IF EXISTS 메서드는 모두 테이블에서 동일한 수의 읽기를 사용합니다. 따라서 존재 확인은 추가 I / O를 정당화 할 매우 타당한 이유가있을 때만 수행되어야합니다. 작업을 수행하는 최적화 된 방법은 DB에서 가능한 한 거의 읽지 않도록하는 것입니다.
가장 좋은 전략은 업데이트를 시도하는 것입니다. 업데이트의 영향을받는 행이 없으면 삽입하십시오. 대부분의 경우 행은 이미 존재하며 하나의 I / O 만 필요합니다.
편집 : 이 패턴의 문제와 안전하게 작동하는 방법에 대해 알아 보려면 이 답변 과 링크 된 블로그 게시물을 확인하십시오.
사용할 수있는 좋고 안전한 패턴에 대해서는 내 블로그 의 게시물을 읽으십시오 . 많은 고려 사항이 있으며이 질문에 대한 대답은 안전하지 않습니다.
빠른 답변을 위해 다음 패턴을 시도하십시오. SQL 2000 이상에서 잘 작동합니다. SQL 2005는 다른 옵션을 여는 오류 처리를 제공하고 SQL 2008은 MERGE 명령을 제공합니다.
begin tran
update t with (serializable)
set hitCount = hitCount + 1
where pk = @id
if @@rowcount = 0
begin
insert t (pk, hitCount)
values (@id,1)
end
commit tran
SQL Server 2000/2005와 함께 사용하려면 데이터가 동시 시나리오에서 일관되게 유지되도록 원본 코드를 트랜잭션에 포함시켜야합니다.
BEGIN TRANSACTION Upsert
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
COMMIT TRANSACTION Upsert
이로 인해 추가 성능 비용이 발생하지만 데이터 무결성이 보장됩니다.
이미 제안한대로 가능한 경우 MERGE를 사용해야합니다.
MERGE는 SQL Server 2008의 새로운 기능 중 하나입니다.
트랜잭션에서 실행해야 할뿐만 아니라 높은 격리 수준도 필요합니다. 사실 기본 격리 수준은 Read Commited이며이 코드에는 Serializable이 필요합니다.
SET transaction isolation level SERIALIZABLE
BEGIN TRANSACTION Upsert
UPDATE myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
begin
INSERT into myTable (ID, Col1, Col2) values (@ID @col1, @col2)
end
COMMIT TRANSACTION Upsert
@@ error 검사 및 롤백을 추가하는 것도 좋은 생각 일 수 있습니다.
SQL 2008에서 병합을 수행하지 않는 경우 다음으로 변경해야합니다.
@@ rowcount = 0이고 @@ error = 0 인 경우
그렇지 않으면 어떤 이유로 업데이트가 실패하면 실패한 명령문의 행 개수가 0이므로 나중에 삽입을 시도합니다.
UPSERT의 열렬한 팬은 관리 할 코드를 정말로 줄여줍니다. 다른 방법은 다음과 같습니다. 입력 매개 변수 중 하나는 ID이고, ID가 NULL 또는 0이면 INSERT이고 그렇지 않으면 업데이트입니다. 응용 프로그램이 ID가 있는지 알고 있다고 가정하므로 모든 상황에서 작동하지는 않지만 그렇게 할 경우 실행을 절반으로 줄입니다.
귀하의 논리는 소리가 나지만 특정 기본 키를 전달한 경우 삽입을 방지하기 위해 코드를 추가하는 것을 고려할 수 있습니다.
그렇지 않고 업데이트가 레코드에 영향을주지 않는 경우 항상 삽입을 수행하는 경우 "UPSERT"가 실행되기 전에 누군가 레코드를 삭제하면 어떻게됩니까? 이제 업데이트하려는 레코드가 존재하지 않으므로 대신 레코드가 생성됩니다. 그것은 아마도 당신이 찾던 행동이 아닐 것입니다.
수정 된 Dima Malenko 게시물 :
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION UPSERT
UPDATE MYTABLE
SET COL1 = @col1,
COL2 = @col2
WHERE ID = @ID
IF @@rowcount = 0
BEGIN
INSERT INTO MYTABLE
(ID,
COL1,
COL2)
VALUES (@ID,
@col1,
@col2)
END
IF @@Error > 0
BEGIN
INSERT INTO MYERRORTABLE
(ID,
COL1,
COL2)
VALUES (@ID,
@col1,
@col2)
END
COMMIT TRANSACTION UPSERT
You can trap the error and send the record to a failed insert table.
I needed to do this because we are taking whatever data is send via WSDL and if possible fixing it internally.
참고URL : https://stackoverflow.com/questions/13540/insert-update-stored-proc-on-sql-server
'Programming' 카테고리의 다른 글
호출이 하나의 개체 만 반환 할 때 Powershell에서 배열을 반환하도록하려면 어떻게해야합니까? (0) | 2020.08.20 |
---|---|
파일 병합을 완료하는 방법은 무엇입니까? (0) | 2020.08.20 |
Java Regex 스레드는 안전합니까? (0) | 2020.08.20 |
Go 명령 줄 호출에서 세 개의 점 "./…"은 무엇을 의미합니까? (0) | 2020.08.20 |
사용자가 로그 아웃 후 이전에 방문한 보안 페이지를 보지 못하도록 방지 (0) | 2020.08.20 |