我有一个数据库结构,其中包括下表:
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
)
显然我可以在PaymentProvidersForEntities表中添加一个可以为空的'ExtraDetails'字段,但我发现它并不优雅,因为会有几种不同类型的支付提供商,每种提供商都需要不同类型的额外细节。做一个我想要的优雅方式吗?如果没有,那么实现相同目标的更好方法是什么?
答案 0 :(得分: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。扩展到支持两个,三个或四个支付提供商而不是一个支持提供商也简单得多。
如果我是你,我会重新考虑表名。 可能应该以您为其记录数据的单一支付提供商命名。
答案 1 :(得分: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);
答案 2 :(得分:-1)
如果您的第二个表的主键是代理键,并且您为所需的复合键部分创建了一个外键,那么它将为您完成。
例如,pseudosql
Foo
bar int primarykey
foobar int primarykey
测试
testFoo int primarykey
foobar int foriengkey
确保只放置测试中的项目。如果您真的想要安全,可以在foobar
上设置约束,确保它只有您想要的值