0

これは悪い考えであり、一意の制約を使用する代わりに、データベースにないデータのみを常に使用する必要があることについて話している投稿がここにあります。INSERT現在、私のテーブル構造は次のとおりです。

CREATE TABLE [dbo].[TEST](
    [ColA] [varchar](255) NULL,
    [ColB] [datetime] NULL,
    [ColC] [datetime] NULL,
    [ColD] [int] NOT NULL,
) ON [PRIMARY]

一意の行のみが期待されるため、一意の制約を次のように設定することは理にかなっています。

ALTER TABLE dbo.TEST
  ADD CONSTRAINT uniqueRows UNIQUE (ColA, ColB, ColC, ColD) WITH (IGNORE_DUP_KEY = ON)

新しい情報が消費されると、多くの理由で重複データが処理される可能性があります。これは、私のコードが状態を維持していないためです。したがって、少なくとも私にとっては、重複データを無視することが理にかなっています。

ただし、リンクされた投稿では、@ PhilipKelley の回答で、これは悪い考えであり、次の行に沿って何かをチェックする必要があると述べています。

INSERT INTO X 
VALUES(Y,Z)    
WHERE Y  NOT IN (SELECT Y FROM X)

私の場合、これは次のように変換されます。

INSERT INTO dbo.TEST 
VALUES(ValA,ValB,ValC,ValD) 
WHERE (Some complicated check)

または、派手な主キーを作成することもできます。ここでの回答は、これが実際に機能として使用されていることがわかっている場合は、先に進んでIGNORE_DUP_KEYオプションを使用すれば問題ないことを示唆しています。私の場合、推奨されるパスは何ですか?

4

1 に答える 1

1

個人的には、次の3つのことを行う必要があると思います。

  1. 最も基本的なレベルでデータを保護するための一意の制約が絶対に必要です。
  2. 行をやみくもに挿入する前に、違反の可能性をチェックしてください。
  3. チェックが失敗した例外からユーザーを保護するために、最終的な挿入を TRY/CATCH で囲みます。

単一行の挿入の場合、これは次のように簡単です。

BEGIN TRY
  INSERT dbo.TEST(ValA, ValB, ValC, ValD)
    SELECT @ValA, @ValB, @ValC, @ValD
    WHERE NOT EXISTS
    (SELECT 1 FROM dbo.TEST
      WHERE ValA = @ValA AND ValB = @ValB AND ValC = @ValC AND ValD = @ValD);
END TRY
BEGIN CATCH
  PRINT 'Move along, nothing to see here...';
END CATCH

これらの列の一部またはすべてが null 可能である場合は、もう少し複雑になります。

複数行の挿入の場合、さまざまな方法でこれを処理できます。一意でない値がある場合 (バッチ内に単独で、またはテーブルと競合している場合)、バッチ全体を失敗させるか、成功した行だけをテーブルに入れることができます。状況 A:

  IF EXISTS (SELECT 1 FROM @SourceOfMultipleRows AS r
    WHERE EXISTS (SELECT 1 FROM dbo.Test AS t WHERE t.ValA = r.ValA AND ...))
  OR EXISTS (SELECT 1 FROM @SourceOfMultipleRows
    GROUP BY ValA, ValB, ValC, ValD HAVING COUNT(*) > 1)
  BEGIN
    PRINT 'Not proceeding at all.';
  END
  ELSE
  BEGIN
    BEGIN TRY
      INSERT dbo.TEST(ValA, ValB, ValC, ValD)
        SELECT ValA, ValB, ValC, ValD
        FROM @SourceOfMultipleRows AS r
        WHERE NOT EXISTS (SELECT 1 FROM dbo.Test AS t
          WHERE t.ValA = r.ValA AND ...)
        GROUP BY ValA, ValB, ValC, ValD;
    END TRY
    BEGIN CATCH
      PRINT 'Move along, nothing to see here...';
    END CATCH
  END

適切な行を保持し、重複を無視するシナリオ B:

BEGIN TRY
  INSERT dbo.TEST(ValA, ValB, ValC, ValD)
    SELECT ValA, ValB, ValC, ValD
    FROM @SourceOfMultipleRows AS r
    WHERE NOT EXISTS (SELECT 1 FROM dbo.Test AS t
      WHERE t.ValA = r.ValA AND ...)
    GROUP BY ValA, ValB, ValC, ValD;
END TRY
BEGIN CATCH
  PRINT 'Move along...';
END CATCH
于 2012-07-02T01:24:17.047 に答える