Sql 对于外键,我可以引用复合主键中的固定值吗?
我有一个数据库结构,包括下表:Sql 对于外键,我可以引用复合主键中的固定值吗?,sql,sql-server,sql-server-2008,tsql,sql-server-2012,Sql,Sql Server,Sql Server 2008,Tsql,Sql Server 2012,我有一个数据库结构,包括下表: CREATE TABLE dbo.PaymentProvidersForEntities ( PaymentProviderId SMALLINT NOT NULL, EntityId BIGINT NOT NULL, CONSTRAINT PK_PaymentProvidersForEntities PRIMARY KEY (PaymentProviderId, EntityId), CONSTRAINT F
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”字段,但我觉得这不是很优雅,因为会有几种不同类型的支付提供商,每种都需要不同类型的额外详细信息。有没有一种优雅的方式来做我想做的事?如果不是,那么实现相同功能的更好方法是什么呢?如果第二个表的主键是代理键,并且您为所需的组合键部分创建了一个外键,这将为您实现 例如,伪SQL Foo
bar int primarykey
foobar int primarykey
测试
testFoo int primarykey
foobar int foriengkey
只要确保你只把你想要的项目放在测试中。如果您确实希望安全,可以在
foobar
上设置一个约束,确保它只包含您想要的值您可以向引用列列表添加一个持久化计算列:
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);
最简单的方法是存储支付提供商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
);
与持久化列相比,我更喜欢这种方法,因为这种方法遵循。扩展到支持两个、三个或四个支付提供商(而不是一个)也要简单得多
如果我是你,我会重新考虑桌名。它可能应该以您记录数据的单一支付提供商的名字命名。级联删除和更新可能会给经验丰富的DBA带来问题。我建议您删除它们,并手动执行需要更新/删除的操作。您能提供参考吗?我会把自己描述成一个“经验丰富”的DBA,目前我和他们没有任何问题。。。但我很想知道他们给别人带来了什么问题。我不知道这是否有效,但我可能是误解了。你能澄清你的意思吗?可能是使用真正的SQL?“如果第二个表的主键是代理键,并且您为所需的复合键部分创建了一个外键,这将为您提供帮助。”首先,这在任何符合SQL标准的SQL dbms中都不起作用。外键引用的目标必须在其列上具有主键约束或唯一约束。第二,即使有效,也无法解决OP的问题。“第二个”表只需要引用一个支付提供商ID。这看起来是一个更好的解决方案。谢谢是的,我们的想法是使用不同名称的表,比如PayPalExtraDetails或GoogleCheckoutExtraDetails。我已经更新了这个问题来反映这一点。而且,它仍然不像我在问题中建议的语法那样优雅。我想知道是否会出现更好的解决方案?这是标准sql吗?还是特定于某个数据库?这是在Microsoft SQL Server上测试的。这可能不是标准。