programing

행이 아직 없는 경우에만 해당 행 삽입

telecom 2023. 6. 24. 08:45
반응형

행이 아직 없는 경우에만 해당 행 삽입

저는 항상 다음과 유사한 것을 사용하여 이를 달성했습니다.

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)

하지만 제가 잠금장치를 잘못 사용하거나 너무 많은 잠금장치를 사용하고 있는 것 같습니다.

저는 stackoverflow.com 에서 "IF(SELECT COUNT(*) ... INSERT" 등을 제안하는 다른 질문들을 보았지만, 저는 항상 단일 SQL 문이 원자적일 것이라는 (매우 잘못된) 가정하에 있었습니다.

아이디어 있는 사람?

"JFDI" 패턴은 어떻습니까?

BEGIN TRY
   INSERT etc
END TRY
BEGIN CATCH
    IF ERROR_NUMBER() <> 2627
      RAISERROR etc
END CATCH

특히 대용량의 경우 잠금이 없는 것이 가장 빠르고 동시에 가능합니다.UPDLOCK이 에스컬레이션되어 전체 테이블이 잠기면 어떻게 합니까?

4과를 읽습니다.

4과: 인덱스를 조정하기 전에 업서트 프로세스를 개발할 때, 저는 먼저 다음과 같은 것을 믿었습니다.If Exists(Select…)라인은 모든 항목에 대해 작동하고 중복을 금지합니다.Nada. 짧은 시간에 수천 개의 중복 항목이 발생했습니다. 동일한 항목이 동일한 밀리초 단위로 상승하고 두 트랜잭션 모두 존재하지 않는 것으로 확인되어 삽입을 수행하기 때문입니다.많은 테스트를 거친 후 해결책은 고유 인덱스를 사용하여 오류를 감지한 후 트랜잭션이 행을 보고 삽입 대신 업데이트를 수행할 수 있도록 다시 시도하는 것이었습니다.

원래 없던 HOLD LOCK을 추가했습니다.이 힌트가 없는 버전은 무시하십시오.

제가 아는 한, 이 정도면 충분할 것 같습니다.

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)

먼저, 지역사회에 기여한 우리 남성 @gbn에게 큰 함성을 지릅니다.제가 얼마나 자주 그의 충고를 따르는지 설명할 수조차 없습니다.

어쨌든, 팬보이링은 충분합니다.

그의 대답에 약간 덧붙이자면, 아마도 그것을 "강화"할 것입니다.나처럼, 무엇을 해야 할지 불안하게 남은 사람들을 위해.<> 2627 빈 " "는 .")CATCH옵션이 아님).테크넷에서 이 작은 덩어리를 찾았습니다.

    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

이게 "공식적인" 방법인지는 모르겠지만, 당신은 그것을 시도할 수 있습니다.INSERT 되아다가돌로다▁to▁back.UPDATE실패할 경우에는

승인된 답변 JFDI 패턴 외에도 오류를 무시하고 싶을있습니다.2627)는 "의 위반이라는 뜻으로 "고유지수의 위반"이라는 뜻입니다

...
IF ERROR_NUMBER() NOT IN (2601, 2627) THROW
...

이미 과 .6.0 신 C#을 사용하여 SQL 없이 할 수 있는 방법은 다음과 NET을 사용하고 있다면 간단한 C# 6.0을 사용하여 복잡한 SQL 코드 없이 깔끔하게 처리할 수 있는 방법은 다음과 같습니다.when문:

try
{
    connection.Execute("INSERT INTO etc");
}
catch (SqlException ex) when (ex.Number == 2601 || ex.Number == 2627)
{
    //ignore "dup key" errors
}

그건 그렇고, 여기 이 주제에 대한 좋은 읽을거리가 있습니다: https://michaeljswart.com/2017/07/sql-server-upsert-patterns-and-antipatterns/ .

저는 이전에 다른 방법을 사용하여 비슷한 작업을 수행한 적이 있습니다.먼저 기본 키를 보유할 변수를 선언합니다.그런 다음 해당 값을 가진 레코드를 찾는 select 문의 출력으로 변수를 채웁니다.그리고 나서 나는 하고 만약 진술합니다.기본 키가 null이면 삽입을 수행하고, 그렇지 않으면 오류 코드를 반환합니다.

     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

반응형