web-dev-qa-db-ja.com

単一の列を持つ複合主キーへの外部キーを作成するにはどうすればよいですか?

Microsoft SQL Server 2012で(設計ではなく)複合主キーを持つ、既に配置されている「ルックアップ」スタイルのテーブルを使用しています。別のテーブルの外部キーを追加したいのですが、単一の列、そして私は、どれほど不合理であっても(CLRベースのカスタムライブラリやdllハイジャックであっても)、どれだけの作業が必要かを確認するための回避策を探しています。

次に例を示します。

CREATE TABLE dbo.Lookup (
    FieldName VARCHAR(100) NOT NULL,
    Value VARCHAR(100) NOT NULL,
    PRIMARY KEY (FieldName, Value)
)

INSERT INTO Lookup (FieldName, Value)
SELECT 'This', 'A' UNION ALL
SELECT 'This', 'B' UNION ALL
SELECT 'That', 'A'

CREATE TABLE dbo.OtherTable (
    ID INT PRIMARY KEY IDENTITY(1,1),
    Blah VARCHAR(100)
)

ALTER TABLE dbo.OtherTable WITH CHECK ADD CONSTRAINT [FK__OtherTable__Blah] 
FOREIGN KEY(Blah) REFERENCES Lookup (Value)

--Cannot create this: 
--"There are no primary or candidate keys in the referenced table 'Lookup' 
--that match the referencing column list in the foreign key 'FK__OtherTable__Blah'."

これはやや予想されます。これを処理するためのSQL標準は、外部キーを作成するためにFieldNameを格納する別の列をdbo.OtherTableに含める必要があることを強く認識しています。

ただし、dbo.OtherTableFieldNameの 'This'のみを使用していることを事前に知っている場合はどうなりますか?次に、そのチェックにFieldNameに「This」を使用する外部キーを追加できないのはなぜですか?

別の列を追加し、すべての値を「This」に設定して、次に進むことができることはわかっています。このルートに行くのは面白くない。私が知りたいのは、これを提出に巻き込むことがどれほど可能かということです。独自の外部キーのような整合性チェックを作成することは可能でしょうか?または、組み込みの外部キー実装をハイジャックしますか?

基本的に、私が探しているのは次のようなものです:

ALTER TABLE dbo.OtherTable WITH CHECK ADD CONSTRAINT [FK__OtherTable__Blah] 
FOREIGN KEY('This', Blah) REFERENCES Lookup (FieldName, Value)

この機能は他のSQL実装(MySQL、Postgres、Oracleなど)で利用できますか?

6
Ehryk

はい、COMPUTED columnを使用してこれを行うことができます。これは実際に列が行う必要がある回避策ですbePERSISTEDを外部キー制約に使用して、ストレージスペースを消費します。

CREATE TABLE dbo.OtherTable (
    ID INT PRIMARY KEY IDENTITY(1,1),
    Blah VARCHAR(100),
    FieldName AS CAST('This' AS VARCHAR(100)) PERSISTED NOT NULL
) ;

ALTER TABLE dbo.OtherTable WITH CHECK 
  ADD CONSTRAINT [FK__OtherTable__Blah] 
    FOREIGN KEY (FieldName, Blah) 
    REFERENCES Lookup (FieldName, Value) ;

SQL-Fiddleでテストされています。

その後、FieldNameが存在しないかのようにテーブルを使用できます。この列を含まないビューを定義して、アプリケーションでそのビューを使用することもできます。 SQL-Fiddle-2


あなたが望んだ構文は、見た目はきれいですが、私が知っているどのDBMSにも実装されていません。

ALTER TABLE dbo.OtherTable WITH CHECK 
  ADD CONSTRAINT [FK__OtherTable__Blah] 
    FOREIGN KEY('This', Blah) 
    REFERENCES Lookup (FieldName, Value) ;

ただし、SQL-Serverのみが将来的に永続化列のみを使用するという制限を削除した場合、計算列の回避策はこの構文と100%等価になることに注意してください。リクエストに接続アイテムを追加できます。

これを可能にする他のDBMSがあるかどうかという質問に対しては、いいえ、ありません。関連する質問も確認してください:

ベーステーブルだけでなく、ビューを参照する外部キーを許可するDBMSはありますか?


本当にこのメソッドを使用したくない場合(追加のストレージ要件のため、代替パスは、プロシージャまたはトリガーを介して制約を適用することです(関係する両方のテーブルにプロシージャまたはトリガーを作成する必要があることに注意してください)。

9
ypercubeᵀᴹ