SQL Server - условный / отфильтрованный внешний ключ.По-другому - PullRequest
0 голосов
/ 19 декабря 2018

Часто мы хотим ссылаться из 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

Но если у нас есть 10 строк в Table1 и 1 миллиард строк в Table2, мы должны хранить много избыточных данных.

Можем ли мы решить эту проблему без этих накладных расходов?

1 Ответ

0 голосов
/ 19 декабря 2018

Вот еще один способ решения этой проблемы:

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

Выглядит как подвох, но это работает без накладных расходов на хранилище данных.

Буду рад услышать ваши комментарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...