Der*_*sar 15 foreign-key database-design sql-server constraint sql-server-2014
假设我有一个表 A,它有两列:一列是 的 ID ThingA
,另一列是 的 ID ThingB
。主键是(ThingA, ThingB)
.
接下来,我有第二个表,但这次它仅限于表A
中具有ThingB = 3
. 主键是ThingA
,因为ThingB
是 3 的常数。
最初,我以为我可以简单地:
FOREIGN KEY (ThingA, 3) REFERENCES A(ThingA, ThingB)
Run Code Online (Sandbox Code Playgroud)
但我了解到事实并非如此,我必须为以下内容创建一个列ThingB
:
ThingB INT NOT NULL DEFAULT(3) CHECK(ThingB = 3)
Run Code Online (Sandbox Code Playgroud)
然后,
FOREIGN KEY (ThingA, ThingB) REFERENCES A (ThingA, ThingB)
Run Code Online (Sandbox Code Playgroud)
有没有不需要额外列的替代方法,或者DEFAULT + CHECK
?一种选择是持久化的计算列,但我也讨厌这个想法,因为它基本上是一种作弊,并且仍然添加了一个具有物理存储的新列。虽然它本身INT
不会很大,但在几个表中有几百万行需要它,我宁愿不维护额外的列。
下面是示例 DDL 来说明这种情况:
CREATE TABLE Test1
(
ThingA INT NOT NULL,
ThingB INT NOT NULL,
PRIMARY KEY (ThingA, ThingB)
);
CREATE TABLE Test2
(
ThingAVal INT NOT NULL,
ThingBVal INT NOT NULL DEFAULT(3) CHECK(ThingBVal = 3),
Val INT NOT NULL,
FOREIGN KEY (ThingAVal, ThingBVal) REFERENCES Test1 (ThingA, ThingB)
);
Run Code Online (Sandbox Code Playgroud)
我创建了一个 db<>fiddle 来演示我的(当前)解决方案:
如果答案是“否”,我会接受,但我很好奇是否还有其他选择。
dbo.Test1
我认为代理键和在and语句之后执行的触发器的组合,特别是触发器,就是这里的答案。INSERT
UPDATE
INSTEAD OF
可能看起来像这样(小提琴):
create table dbo.Test1 (
Id int identity primary key,
ThingA int not null,
ThingB int not null
);
create table dbo.Test2 (
Id int identity primary key,
Test1Id int not null foreign key references Test1 (Id),
Val int not null
);
Run Code Online (Sandbox Code Playgroud)
INSERT
触发后create trigger test2ThingBCheck_Insert
on dbo.Test2
instead of INSERT
as
begin
insert into dbo.Test2 (Test1Id, Val)
select
t.Id
,i.Val
from
Test1 t
join
inserted i
on i.Test1Id = t.Id
where
t.ThingB = 3;
end;
Run Code Online (Sandbox Code Playgroud)
UPDATE
触发后create trigger test2ThingBCheck_Update
on dbo.Test2
instead of Update
as
begin
update
t2
set
Val = i.Val
from
dbo.Test2 t2
join
inserted i
on i.Id = t2.Id
join
dbo.Test1 t1
on t1.Id = i.Test1Id
where
t1.ThingB = 3;
end;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2733 次 |
最近记录: |