행이없는 경우에만 삽입
나는 그것을 달성하기 위해 항상 다음과 비슷한 것을 사용했습니다.
INSERT INTO TheTable
SELECT
@primaryKey,
@value1,
@value2
WHERE
NOT EXISTS
(SELECT
NULL
FROM
TheTable
WHERE
PrimaryKey = @primaryKey)
...하지만 일단로드되면 기본 키 위반이 발생했습니다. 이것은이 테이블에 전혀 삽입하는 유일한 명령문입니다. 그렇다면 이것은 위의 진술이 원자가 아니라는 것을 의미합니까?
문제는 이것이 마음대로 다시 만드는 것이 거의 불가능하다는 것입니다.
아마도 다음과 같이 변경할 수 있습니다.
INSERT INTO TheTable
WITH
(HOLDLOCK,
UPDLOCK,
ROWLOCK)
SELECT
@primaryKey,
@value1,
@value2
WHERE
NOT EXISTS
(SELECT
NULL
FROM
TheTable
WITH
(HOLDLOCK,
UPDLOCK,
ROWLOCK)
WHERE
PrimaryKey = @primaryKey)
비록 내가 잘못된 잠금 장치를 사용하거나 너무 많은 잠금 장치를 사용하고있을 수 있습니다.
나는 답변이 "IF (SELECT COUNT (*) ... INSERT"등을 제안하는 다른 질문을 stackoverflow.com에서 보았지만, 저는 항상 단일 SQL 문이 원자적일 것이라는 (아마도 틀린) 가정하에있었습니다.)
누구에게 아이디어가 있습니까?
무엇에 대해 "JFDI" 패턴?
BEGIN TRY
INSERT etc
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
RAISERROR etc
END CATCH
진지하게, 이것은 특히 높은 볼륨에서 잠금없이 가장 빠르고 가장 동시 적입니다. UPDLOCK이 에스컬레이션되고 전체 테이블이 잠겨 있으면 어떻게됩니까?
레슨 4 : 인덱스를 조정하기 전에 upsert proc을 개발할 때 먼저
If Exists(Select…)
라인이 모든 항목에 대해 실행되고 중복을 금지 할 것이라고 믿었습니다 . 나다. 짧은 시간에 동일한 항목이 동일한 밀리 초에 upsert에 도달하고 두 트랜잭션 모두 존재하지 않음을 확인하고 삽입을 수행하기 때문에 수천 개의 중복이있었습니다. 많은 테스트 후 솔루션은 고유 인덱스를 사용하고 오류를 포착 한 다음 트랜잭션이 행을보고 삽입 대신 업데이트를 수행 할 수 있도록 재 시도하는 것이 었습니다.
원래 존재하지 않았던 HOLDLOCK을 추가했습니다. 이 힌트가없는 버전은 무시하십시오.
내가 아는 한 이것으로 충분할 것입니다.
INSERT INTO TheTable
SELECT
@primaryKey,
@value1,
@value2
WHERE
NOT EXISTS
(SELECT 0
FROM TheTable WITH (UPDLOCK, HOLDLOCK)
WHERE PrimaryKey = @primaryKey)
또한 실제로 행이있는 경우 업데이트하고 그렇지 않은 경우 삽입하려는 경우이 질문이 유용 할 수 있습니다 .
MERGE를 사용할 수 있습니다.
MERGE INTO Target
USING (VALUES (@primaryKey, @value1, @value2)) Source (key, value1, value2)
ON Target.key = Source.key
WHEN MATCHED THEN
UPDATE SET value1 = Source.value1, value2 = Source.value2
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, ReasonType) VALUES (@primaryKey, @value1, @value2)
이것이 "공식적인"방법인지는 모르겠지만을 시도하고 실패하면 INSERT
다시 돌아갈 수 UPDATE
있습니다.
첫째, 커뮤니티에 대한 그의 공헌에 대해 @gbn 남자에게 큰 외침을 보냅니다. 내가 얼마나 자주 그의 충고를 따르는 지 설명 할 수 없다.
어쨌든 충분히 팬보이.
그의 대답에 약간 추가하려면 아마도 "강화"하십시오. 저와 같은 사람들에게는 <> 2627
시나리오 에서해야 할 일에 대해 불안한 느낌이 들었습니다 (비어있는 CATCH
것은 선택 사항이 아닙니다). 나는 technet 에서이 작은 너겟을 찾았다 .
BEGIN TRY
INSERT etc
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
BEGIN
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (
@ErrorMessage,
@ErrorSeverity,
@ErrorState
);
END
END CATCH
I've done a similar operation in past using a different method. First, I declare a variable to hold the primary key. Then I populate that variable with the output of a select statement which looks for a record with those values. Then I do and IF statement. If primary key is null, then do insert, else, return some error code.
DECLARE @existing varchar(10)
SET @existing = (SELECT primaryKey FROM TABLE WHERE param1field = @param1 AND param2field = @param2)
IF @existing is not null
BEGIN
INSERT INTO Table(param1Field, param2Field) VALUES(param1, param2)
END
ELSE
Return 0
END
참고URL : https://stackoverflow.com/questions/3407857/only-inserting-a-row-if-its-not-already-there
'developer tip' 카테고리의 다른 글
테이블 행의 마지막 셀이 나머지 모든 너비를 차지하도록 만드는 방법 (0) | 2020.11.15 |
---|---|
Form의 Closing 이벤트에서 BackgroundWorker를 중지하는 방법은 무엇입니까? (0) | 2020.11.15 |
MVC 3 jQuery 유효성 검사 / 숫자 / 십진수 필드의 전역 화 (0) | 2020.11.15 |
배열의`length` 속성을 읽는 것이 자바 스크립트에서 그렇게 비싼 작업입니까? (0) | 2020.11.15 |
Zookeeper 3.4.6과 함께 Kafka 0.8.1을 사용할 때 LeaderNotAvailableException으로 실행 (0) | 2020.11.15 |