web-dev-qa-db-ja.com

SQL UNIQUE制約を使用して複数の値を挿入する

MS SQL Server 2012と次の表があります。

CREATE TABLE dzp.contractid (
id bigint PRIMARY KEY IDENTITY(1,1),
VNR char(18) NOT NULL,
CONSTRAINT UC_VNR UNIQUE (VNR))

コンテキストについては、VNRは一意の契約番号を文字列形式で表します。

契約ごとに複数の行が含まれる可能性のある契約情報を含むcsvファイルをインポートしたい。 char(18)に対するクエリを回避するために、ステージングテーブルのINSERT-Triggerを使用して、ロード時にデータを正規化しようとしています。

フローは:

csv-file --> staging table --> insert trigger --> normalized tables

私のトリガーでは、私は次のことを試みています:

BEGIN TRY
    INSERT INTO dzp.contractid(VNR)
    SELECT VNR
    FROM dzp.accounts_stage
END TRY

BEGIN CATCH
-- ignore unique constraint violation error, raise otherwise
IF ERROR_NUMBER() <> 2627
    RAISERROR ('blah', 16, 1)
END CATCH

だから私が達成したいのは基本的に:

  1. ステージングテーブルからすべての契約番号を取得する
  2. これらすべての数値を正規化されたテーブルに追加します
  3. 一意制約に違反したときにスローされるエラーを無視します
  4. 正しく機能している場合は、すべての一意のVNRを含むテーブルができました

問題:

一意性制約は、実際に重複している値だけでなく、INSERT全体をブロックしているようです。

行ごとにデータを挿入する方法はありますか、または行ごとにデータを処理するように制約に指示しますか?

これは正しいアプローチですか?この問題が最初に発生するとは思えないので、アプローチを完全に変更できてうれしいです...コンテキストでは、これは基本的に、1日に1回バッチフィードされるレポートデータベースであり、合計で約100万行になります。 (csv-tableから)、時々クエリを実行している最大5人のユーザーがいます。

ご協力ありがとうございます。

2
zuiqo

SQL制約違反はステートメント全体に影響し、個々の行を無視することはできません。

canを実行すると、制約に違反していない行のみが挿入されます。たとえば、いくつかの方法があります。

INSERT INTO dzp.contractid(vnr)
SELECT DISTINCT vnr FROM dzp.accounts_stage s 
WHERE NOT EXISTS (SELECT 1 FROM dzp.contractid WHERE vnr = s.vnr)

MERGEを使用することもできます:

MERGE dzp.contractid AS t
USING dzp.accounts_stage AS s
ON (t.vnr = s.vnr) 
WHEN NOT MATCHED BY TARGET 
THEN INSERT(vnr) VALUES(s.vnr)
4
mustaccio