2013-01-31 39 views
1

我有一個數據庫結構,其包括如下表:使用外鍵,我可以在複合主鍵中引用固定值嗎?

CREATE TABLE dbo.PaymentProvidersForEntities 
(
    PaymentProviderId SMALLINT NOT NULL, 
    EntityId BIGINT NOT NULL, 
    CONSTRAINT PK_PaymentProvidersForEntities 
     PRIMARY KEY (PaymentProviderId, EntityId), 
    CONSTRAINT FK_PaymentProvidersForEntities_PaymentProviders 
     FOREIGN KEY (PaymentProviderId) 
     REFERENCES PaymentProviders(PaymentProviderId) 
     ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT FK_PaymentProvidersForEntities_Entities 
     FOREIGN KEY (EntityId) 
     REFERENCES Entities(EntityId) 
     ON DELETE CASCADE ON UPDATE CASCADE 
) 

顯然,這是用一個複合主鍵的簡單多到許多鏈接表。我想要另一個引用該表的表,但僅爲一個PaymentProvider提供數據(即PaymentProviderId =固定值)。喜歡的東西:

CREATE TABLE dbo.SpecificPaymentProviderExtraDetails 
(
    EntityId BIGINT NOT NULL, 
    ExtraDetails NVARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_PaymentProviderExtraDetails 
     PRIMARY KEY (EntityId), 
    CONSTRAINT FK_PaymentProviderExtraDetails_PaymentProvidersForEntities 
     FOREIGN KEY (EntityId, 1) 
     REFERENCES PaymentProvidersForEntities(EntityId, PaymentProviderId) 
     ON DELETE CASCADE ON UPDATE CASCADE 
) 

很顯然,我可以只添加一個可空「ExtraDetails」字段中PaymentProvidersForEntities表,但我沒有發現,很優雅一樣會有幾種不同類型的支付提供者,每個需要不同類型的額外的細節。有沒有一種優雅的方式來做我想做的事?如果不是,那麼實現同樣目標的更好方法是什麼?

+0

級聯刪除和更新可能會給經驗豐富的DBA帶來問題。我會建議你刪除它們並手動執行需要級聯的更新/刪除 – gh9

+1

你能提供參考嗎?我將自己形容爲「經驗豐富」的DBA,目前我對他們沒有任何問題......但我有興趣瞭解他們導致他人的問題。 –

回答

2

最簡單的方法是存儲支付提供商ID,並使用CHECK()約束來確保它是您想要的。讓我們假設你想將支付提供商ID總是等於13

CREATE TABLE dbo.PaymentProviderExtraDetails 
(
    PaymentProviderID SMALLINT NOT NULL DEFAULT 13 CHECK(PaymentProviderID = 13), 
    EntityId BIGINT NOT NULL, 
    ExtraDetails NVARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_PaymentProviderExtraDetails 
     PRIMARY KEY (PaymentProviderID, EntityId), 
    CONSTRAINT FK_PaymentProviderExtraDetails_PaymentProvidersForEntities 
     FOREIGN KEY (PaymentProviderID, EntityID) 
     REFERENCES PaymentProvidersForEntities(PaymentProviderId, EntityId) 
     ON DELETE CASCADE ON UPDATE CASCADE 
); 

我喜歡這種方式,以持久列,因爲這種方法如下principle of least surprise。擴展到支持兩個,三個或四個支付提供商而不是一個支付提供商也更簡單。

如果我是你,我會重新考慮表名。它可能應該以您正在記錄數據的單一付款提供商命名。

+0

這看起來像是一個更好的解決方案。謝謝!是的,這個想法本來就是有不同名稱的表 - 比如PayPalExtraDetails或GoogleCheckoutExtraDetails。我已經更新了這個問題來反映這一點。 –

+0

此外,它還不如您可以使用我在問題中提出的語法那麼優雅。我想知道是否會有更好的解決方案? –

-1

如果你的第二個表的主鍵是一個代理鍵,並且你對你想要的組合鍵的一部分做了一個外鍵。

例如,pseudosql


酒吧INT的PrimaryKey
foobar的INT的PrimaryKey

測試
命名爲testFoo INT的PrimaryKey
foobar的INT foriengkey

只要確保你只放您想要的測試項目。如果你真的想成爲安全的,你可以把一個約束上foobar確保它不僅具有價值你想

+0

我不知道這是否有效,但我可能會誤解。你能澄清你的意思嗎?也許真正的SQL? –

+1

*「如果第二個表的主鍵是代理鍵,並且爲組合鍵的一部分創建了一個外鍵,那麼將爲您執行該操作。」*首先,在任何符合條件的SQL dbms中與SQL標準。外鍵引用的目標在其列上必須具有主鍵約束或唯一約束。其次,即使它有效,也不能解決OP的問題。「第二個」表格需要引用一個且唯一的一個支付提供商ID。 –

1

您可以將持久化計算列添加到引用列的列表:

CREATE TABLE dbo.p(i1 INT, i2 INT, CONSTRAINT p_pk PRIMARY KEY CLUSTERED (i1,i2)); 
CREATE TABLE dbo.c(id INT PRIMARY KEY CLUSTERED,i1 INT, i2 AS 1 PERSISTED, CONSTRAINT c_fk FOREIGN KEY (i1,i2) REFERENCES dbo.p(i1,i2)); 
INSERT INTO dbo.p(i1,i2)VALUES(42,1); 
INSERT INTO dbo.c(id,i1)VALUES(111,42); 
+0

似乎是一個很好的解決方案,謝謝! –

+0

是這個標準的sql嗎?還是特定於某些數據庫? – jambriz

+0

這是在Microsoft SQL Server上測試的。這可能不是標準。 –