要精心制作,
是否可以强制执行一条规则,其中只有一个记录条目可以将名为“IsPrimaryUser”的列设置为true,而将按其他列分组的所有其他列设置为false。决定哪个条目具有真正的'IsPrimaryUser'字段的条件将是CompanyId列。
我只对使用检查约束是否可以完成感兴趣。显然,有一种类似于此的SQL方法。
示例:
用户表
int UserId | int CompanyId |位IsPrimaryUser
数据:
UserId | CompanyId | IsPrimaryUser
1 1 1
2 1 0
3 1 0
4 1 0
5 2 1
6 2 0
7 2 0
8 2 0
答案 0 :(得分:3)
检查约束仅适用于单行,但您可以在约束内使用标量UDF。
您可以使用检查表中其他行的UDF来破坏单行检查。虽然与可以单独访问DELETED虚拟表和进程的触发器不同,但SQL Server似乎在某种事务中保存记录,并在更改后在EACH行执行CHECK,然后最终批量接受或中止CRUD。
查看此测试用例
创建表
create table usertable (UserId int,
CompanyId int, IsPrimaryUser int)
填充
insert usertable select
1, 1, 1 union all select
2, 1, 0 union all select
3, 1, 0 union all select
4, 1, 0 union all select
5, 2, 1 union all select
6, 2, 0 union all select
7, 2, 0 union all select
8, 2, 0
标量函数助手
create function dbo.anyprimaryuser(@userid int, @company int) returns bit as
begin
return
case when exists (
select * from usertable
where companyid=@company and isprimaryuser=1 and userid<>@userid)
then 1 else 0 end
end
CHECK约束
alter table usertable add constraint usertable_ck1
check (isprimaryuser=0 or dbo.anyprimaryuser(userid,companyid)=0)
测试
insert usertable select 9,2,1 -- fail
insert usertable select 9,2,0 -- ok
insert usertable select 19,4,1 union all select 20,4,0 -- ok
insert usertable select 19,3,1 union all select 20,3,0 union all select 21,3,1
-- not ok, accepting the multi-row insert will breach the constraint
update usertable set IsPrimaryUser=1-IsPrimaryUser where CompanyId=4
-- ok! sets one and unsets the other in one go
(注意)我在Martin的评论
之后更新了答案