SQL Server-条件/过滤的外键。另一种方式

时间:2018-12-19 15:33:09

标签: sql-server foreign-keys

通常我们只想从Table2引用Table1中满足某些谓词的行。像这样:

create table dbo.Table1 
(
    Id int not null primary key clustered,
    IsActive bit not null
);

create table dbo.Table2 
(
    Id int not null, 
    Table1Id int not null
);

alter table dbo.Table2 
    add constraint FK_Table2_Table1 
        foreign key (Table1Id) references Table1(Id) 
        where IsActive = 1; -- unsupported

但是此代码不起作用。通常,在这种情况下,建议在IsActive中添加列Table2(始终等于1)并添加FK:

alter table dbo.Table2 
    add constraint FK_Table2_Table1 
        foreign key (Table1Id, IsActive) references Table1(Id, IsActive);

此问题的示例:https://dba.stackexchange.com/questions/188379/filtered-foreign-keys

但是,如果我们在Table1中有10行,在Table2中有10亿行,则应该存储许多冗余数据。

我们可以解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

这里是解决此问题的另一种方法:

create table dbo.Table1 (
    Id int not null primary key clustered,
    IsActive bit not null,
    ActiveIdForForeignKey as iif(IsActive = 1, Id, -Id) persisted not null,
    constraint UQ_ActiveIdForForeignKey unique (ActiveIdForForeignKey)
);
go
create table dbo.Table2 (Id int not null, Table1Id int not null);
go
alter table dbo.Table2 add constraint FK_Table2_Table1 foreign key (Table1Id) references Table1(Id);
alter table dbo.Table2 add constraint FK_Table2_Table1_Active foreign key (Table1Id) references Table1(ActiveIdForForeignKey);
go
insert into dbo.Table1(Id, IsActive) values (1, 0);
insert into dbo.Table1(Id, IsActive) values (2, 1);
insert into dbo.Table1(Id, IsActive) values (3, 0);
go
insert into dbo.Table2(Id, Table1Id) values (1, 2); -- success
insert into dbo.Table2(Id, Table1Id) values (2, 1); -- fail
go

看起来很肮脏,但这没有数据存储开销。

我很高兴听到您的评论。