フィルター処理された一意のインデックスは素晴らしいアイデアですが、WHERE identity_column > <current value>
条件を使用するか、またはWHERE identity_column NOT IN (<list of ids for duplicate values here>)
。
最初のアプローチでは、今後も既存の(現在の)データの複製である重複データを挿入できます。たとえば、現在1行しかない場合でもCompanyName = 'Software Inc.'
、行は同じ会社名でもう1行挿入することを禁止しません。2回試行した場合にのみ禁止されます。
2番目のアプローチでは改善がありますが、上記は機能しません(これは良いことです)。しかし、さらに多くの重複または既存の重複を挿入できます。たとえば、で(2つ以上の)行があるCompanyName = 'DoubleData Co.'
場合、インデックスは同じ会社名の行をもう1つ挿入することを禁止しません。2回試行した場合にのみ禁止されます。
(更新)重複する名前ごとに、1つのIDを除外リストに含めない場合、これを修正できます。上記の例のように、重複CompanyName = DoubleData Co.
とIDを持つ4つの行がある場合、4,6,8,9
除外リストにはこれらのIDが3つしかありません。
2番目のアプローチでは、SQL-Server がフィルター選択されたインデックスの一部でNOT IN
演算子をサポートしていないように見えるため、面倒な状態(最初の場所にある重複の数に依存する面倒さ)も欠点ですWHERE
。SQL-Fiddleを参照してください。の代わりにWHERE (CompanyID NOT IN (3,7,4,6,8,9))
、WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
何百もの重複した名前がある場合、そのような条件に効率的な影響があるかどうかわからないようなものを持っている必要があります。
別の解決策(@Alex Kuznetsovに類似)は、別の列を追加し、ランク番号を入力して、この列を含む一意のインデックスを追加します。
ALTER TABLE Company
ADD Rn TINYINT DEFAULT 1;
UPDATE x
SET Rn = Rnk
FROM
( SELECT
CompanyID,
Rn,
Rnk = ROW_NUMBER() OVER (PARTITION BY CompanyName
ORDER BY CompanyID)
FROM Company
) x ;
CREATE UNIQUE INDEX CompanyName_UQ
ON Company (CompanyName, Rn) ;
次に、DEFAULT 1
プロパティと一意のインデックスのために、重複した名前の行の挿入は失敗します。これはまだ100%絶対確実なものではありません(アレックスのものはそうです)。Rn
がINSERT
ステートメントで明示的に設定されている場合、またはRn
値が悪意を持って更新された場合、複製は引き続きスリップします。
SQL-フィドル-2