私はこれを理解する上でおならをしている。次の2つのテーブルがあります。
Table: parts
part_id INT IDENTITY(1,1) NOT NULL,
part_number VARCHAR(50) UNIQUE NOT NULL,
part_description VARCHAR(MAX) NOT NULL,
information VARCHAR(MAX) NULL,
manufacturer_id INT NOT NULL,
subcategory_id INT NOT NULL
Table: part_temp
part_num VARCHAR(50) NOT NULL,
part_desc VARCHAR(MAX) NULL,
info VARCHAR(MAX) NULL,
man_id INT NULL,
sub_id INT NULL
part_temp
は、CSVファイルからのデータを含む一時テーブルです。そのため、NOT NULL
に設定されている列は1つだけです。 part_temp
からparts
にデータを挿入する必要があります。
テーブルのデータを適切にクリーンアップしたので、値を必要とするnull値が行に挿入されないようにしています。しかし、私の問題は、UNIQUE
テーブルのpart_number
列のparts
制約にあります。 part_temp
テーブル内に重複する値があるため、挿入中にそれらをスキップできる方法が必要です。これは私がこれまでに試したことですが、うまくいきません:
INSERT INTO parts
SELECT DISTINCT pt.part_num, pt.part_desc, pt.info, m.manufacturer_id, s.subcategory_id
FROM part_temp AS pt
FULL OUTER JOIN man_temp AS mt ON pt.man_id = mt.man_id
INNER JOIN manufacturers AS m ON mt.man_name = m.manufacturer_name
FULL OUTER JOIN cat_temp AS ct ON pt.sub_id = ct.category_id
INNER JOIN subcategories AS s ON ct.category_name = s.subcategory_name
WHERE NOT EXISTS(SELECT part_number FROM parts WHERE part_number = pt.part_num)
これらは、上記にリストされていない結合に含まれるテーブルです
Table: man_temp
man_id INT NOT NULL,
man_name VARCHAR(100) NOT NULL
Table: manufacturers
manufacturer_id INT IDENTITY(1,1) NOT NULL,
manufacturer_name VARCHAR(100) NOT NULL
Table: cat_temp
category_id INT NOT NULL,
category_name VARCHAR(100) NOT NULL
Table: subcategories
subcategory_id INT IDENTITY(1,1) NOT NULL,
subcategory_name VARCHAR(100) NOT NULL
INSERT
クエリの何が問題になっていますか?
私が得ている特定のエラーは:
メッセージ2627、レベル14、状態1、行1
UNIQUE KEY制約の違反。オブジェクト 'dbo.parts'に重複するキーを挿入することはできません。重複するキーの値は(31335A11)です
part_num 31335A11
はcsvファイルに複数回出現します。そのため、part_temp
テーブルに複数回出現します。このエントリだけでも簡単ですが、1,000を超えるリピートエントリがあるため、すべての重複を削除するには永久に時間がかかります。 parts
には何も存在しません。これは、値を入れようとしている真新しい空のテーブルだからです。
Violation of UNIQUE KEY constraint
に遭遇した場合、私が最初に行うことは、次の質問を自分に問うことです。
上記に答えることで、重複する値がどこから取得されているのか、そして原因の合理的な考えがわかります。可能性の例は次のとおりです。
問題の重複する値があるので、最終的にはこの問題を基本に戻す必要があります。問題の重複値があるので、データを掘り下げ、ソースクエリに細心の注意を払う必要があります。幸いにもあなたの例ではそれは単純なクエリであり、簡単に結合を取り除いてそれらのいずれかが重複を導入しているかどうか、または実際に非キー属性が異なるために重複が存在し、そのためDISTINCT
があなたが期待することをしないでください。
私が言おうとしているのは、この種の問題には必ずしもすぐに成功するわけではなく、SQLによって提供される手掛かりを使用して、古き良きファッション探偵の仕事をする必要があるということです。
Mootポイントですが、ターゲットテーブルの列の順序がソースクエリの列の順序と異なる場合でも何も壊れないように、挿入の列を明示的にリストするのが好きです。
まず、SQL SERVERにはCONFLICTコマンドがありません。
第二:
DISTINCTとWHERE NOT EXISTSを使用して間違った方向に進んでいます。どちらのコマンドでも、データの重複を防ぐことはできません。
part_temp
に関する次のデータがあるとします。
part_num part_desc info man_id sub_id
============================================================
000345 something1 some info 2 1
000345 something2 some info1 4 6
000345 something3 some info2 5 8
Part_num 000345がparts
テーブルに存在しないとします。クエリは、3つのレコード(互いに異なるレコード)を挿入しようとします。
最後に:
あなたが望むものを達成するために。 SQL ServerはMERGE
というコマンドを提供します
MERGEを使用すると、競合が発生するたびに何を行うかを決定できます。これは、前に挿入されたレコードをupdateするか、または単にskip挿入の新しい候補
競合ケースの挿入をスキップするには、次のコードを使用します。
MERGE INTO parts A
USING (
--YOUR SELECT QUERY HERE; NO NEED TO USE DISTINCT / WHERE
) B
ON(A.part_num = B.part_num)
WHEN MATCHED THEN UPDATE SET A.part_num=A.part_num
WHEN NOT MATCHED THEN INSERT(part_number,part_description,....)
VALUES(B.part_num,B.part_desc,....);
幸運を!
繰り返しデータを2番目のテーブルに格納する場合は、UPDATE文の最後にOUTPUT句を含めます(これは実際にはDO NOTHINGとして機能します)。..
...
WHEN MATCHED THEN
UPDATE SET A.part_num=A.part_num
OUTPUT DELETED.part_id, B.* INTO part_duplicates
WHEN NOT MATCHED THEN
INSERT(part_number,part_description,....)
VALUES(B.part_num,B.part_desc,....);