2015-07-13 31 views
1

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

Widget Version Latest 
XYZ  1.0  0 
XYZ  1.1  0 
XYZ  1.2  1 
ABC  1.0  1 

有没有一种方法来创建一个约束,说

每个插件版本的组合可以有任意数量的0为 最新版本的标志,但必须有确切1发生在哪里 最新标志是1

还是我必须使用触发器或类似的?

+0

问题:当您插入新行(用最新版本),你必须把最新的。例如,'小工具:XYZ','版本:1.3'。所以这一个必须有最新= 1,但是'XYZ/1.2'必须更新以使最新= 0,因为它不再是最新值。有一段时间,您需要接受两条最新= 1(通过窗口小部件)或没有最新= 1的线...... –

+0

在我的s/p中,我先删除所有现有窗口小部件版本上的最新标志,我认为这符合上面的约束。 – Ryan

+0

那么,当你删除标志,有一个而当'必须恰好1 occurence其中最新的标志是1'不再有效...... –

回答

1

我看到两种方法(第三个是使用视图,但它是相当类似于第二溶液)

首先,有检查约束

东西(这个人是丑陋,但你的想法):

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在存储过程中停用约束,然后重新激活它。您可能需要锁定你的表以避免任何插入/更新,而约束是停用...


另一种方式将使用计算科拉姆 n表示Latest

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语句将花费更多...可依您的数据更大小。

+0

真棒答案 - 学会两个伟大的事情。谢谢。 – Ryan

相关问题