2015-07-13 60 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

相關問題