代码之家  ›  专栏  ›  技术社区  ›  Ruslan K.

SQL Server-条件/筛选的外键。另一种方式

  •  0
  • Ruslan K.  · 技术社区  · 6 年前

    我们经常想引用 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 在里面 表2 (始终等于 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

    但是如果我们有10排 表1 10亿行 表2 我们应该存储许多冗余数据。

    我们能在没有这种开销的情况下解决这个问题吗?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Ruslan K.    6 年前

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

    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
    

    看起来像是一个肮脏的把戏,但这是在没有数据存储开销的情况下工作的。

    我很高兴听到你的评论。