我可以使用嵌入式业务逻辑创建高级SQL约束吗?

时间:2015-07-13 09:17:29

标签: sql sql-server-2008 constraints

如果我有桌子

{{1}}

有没有办法创建一个说

的约束
  

每个widget-version组合可以包含任意数量的0   最新版本的标志但必须恰好有1次出现在哪里   最新的旗帜是1

或者我是否必须使用触发器或类似物?

1 个答案:

答案 0 :(得分:1)

我看到两种方式(第三种方式是使用View,但它与第二种解决方案非常相似)

首先,带有检查约束

某事(这个很难看,但你已经明白了):

create function [dbo].[checkLatest](@widget varchar(3))
returns bit

as
begin
declare @numOfLatest int;
declare @lastValue int;
declare @maxVersion decimal(18,2);
select @maxVersion = MAX([Version]) from Table1 where Widget = @widget;
--check if there's only one Latest = 1 by Widget
select @numOfLatest = COUNT(*) from Table1 where Widget = @widget and Latest = 1;
--check if Latest = 1 for max version
select @lastValue = Latest from Table1 where [Version] = @maxVersion and Widget = @widget;

return case when @numOfLatest = 1 and @lastValue = 1 then 1 else 0 end
end
GO

然后

ALTER TABLE Table1 
WITH CHECK ADD CONSTRAINT CK_LAtest
    CHECK (checkLatest(Widget) = 1)

注意:当您在存储过程中将所有最新标志设置为0时,您必须停用约束,然后重新激活它。您可能需要锁定表以避免在禁用约束时进行任何插入/更新...

另一种方式是为Latest使用计算的colum n:

create function setLatest(@Widget varchar(3), @Version decimal(18,2))
returns bit
as 
begin
declare @result bit = 0;

with cte as (select  [Version], ROW_NUMBER() over(PARTITION by [Widget] order by [Version] desc) rn from dbo.Table1 where Widget = @Widget)
select @result = case when @Version = [Version] then 1 else 0 end from 
cte where rn = 1
and @Version = [Version]
return @result;
end

然后删除最新列

alter table Table1 drop column Latest;

并将其重新添加为计算列

alter table Table1 add Latest as setLatest(Widget, [Version]);

按照它的计算,它永远不会出错,但...... SELECT语句会花费更多......可能取决于数据的大小。