web-dev-qa-db-ja.com

後続スペースを重要と見なすPRIMARY KEY / UNIQUE制約を作成するにはどうすればよいですか?

スペースが重要な文字列で識別されるものに関するレコードを保存できるようにしたいと思います。 T-SQLは、文字列比較に関するルールに従って、比較を実行するときにどちらかの文字列の長さまで暗黙的に埋め込むことと、WHERE句でDATALENGTHも比較することで回避できることを知っています。しかし、PRIMARY KEYを同様に動作させる方法がわかりません。データをどのように保存して、

  • sSMSのようなツールは、CASTする必要なく、テキストとして表示します
  • ほとんどの場合、通常のプログラミング言語では文字列型のように扱われます(比較では大文字と小文字が区別されます)
  • UNIQUE/PRIMARY KEY制約付きの列に格納されていますか?

T-SQLが奇妙なpadding-during-comparisonの処理を行わなかった場合は、次のように動作するはずです。

CREATE TABLE #x (
  Id NVARCHAR(16) COLLATE Latin1_General_BIN2 PRIMARY KEY
)
INSERT INTO #x VALUES ('asdf');
INSERT INTO #x VALUES ('Asdf');
INSERT INTO #x VALUES ('asdf '); -- error here
DROP TABLE #x

しかし、3番目の挿入では、次のようになります。

Msg 2627, Level 14, State 1, Line 6
Violation of PRIMARY KEY constraint 'PK__#x________3214EC0761C21167'. Cannot insert duplicate key in object 'dbo.#x'. The duplicate key value is (asdf ).
3
binki

DATALENGTH句でWHEREを使用していると述べたので、これをPRIMARY KEYの作成にも拡張してみます。これを行うには、最初の列のDATALENGTHを含む計算列を追加し、その列をPRIMARY KEYに含めます。

CREATE TABLE #x (
   Id NVARCHAR(16) COLLATE Latin1_General_BIN2 NOT NULL
  ,IdLength AS DATALENGTH(Id) PERSISTED NOT NULL
  ,PRIMARY KEY(Id, IdLength)
)
INSERT INTO #x VALUES ('asdf');
INSERT INTO #x VALUES ('Asdf');
INSERT INTO #x VALUES ('asdf ');
INSERT INTO #x VALUES ('asdf '); -- Error, proving that UNIQUE works
SELECT '"'+Id+'"' QuotedId, * FROM #x;
DROP TABLE #x;

私はこのようなテーブルを手に入れます:

QuotedId           Id               IdLength
------------------ ---------------- -----------
"Asdf"             Asdf             8
"asdf"             asdf             8
"asdf "            asdf             10

'asdf 'を2回挿入しようとするとエラーが発生し、UNIQUEの動作のメリットが引き続き得られることがわかりました。

Msg 2627, Level 14, State 1, Line 9
Violation of PRIMARY KEY constraint 'PK__#x________A3E5142C3CFA2452'. Cannot insert duplicate key in object 'dbo.#x'. The duplicate key value is (asdf , 10).
4
binki

比較中のその奇妙なパディングは、実際のANSI-SQL標準です。何らかの回避策を実行する必要があります。スペースをデータセットにはない固有の文字に置き換え、表示時に文字を削除するか、計算列などを使用します。

あなたがやろうとしていることは、ANSI規格がこれらのものをどのように扱うかに対して一種の反対です。私が知る限り、これらの末尾のスペースを実際に考慮する唯一の演算子はLIKE演算子です。

計算された列と、スペースごとにいくつかの保証されたエスケープ文字(チルダ、パイプなど)を使用して何かを実行したり、主キーとして作成しようとしているものを再考したりできるのではないでしょうか。あなたの主キーは、挿入と更新を潜在的により幸せにするID列のような代理キーである可能性がありますか?それは、一緒に一意である2つの列を持つ複合キーのほうがよいでしょうか?

2
Mike Walsh