我可以使用嵌入式业务逻辑创建高级 SQL 约束吗?
Can I Create Advanced SQL Constraints with Embedded Business Logic?
如果我有table
Widget Version Latest
XYZ 1.0 0
XYZ 1.1 0
XYZ 1.2 1
ABC 1.0 1
有没有办法创建一个约束
each widget-version combination can have any number of 0s for the
latest version flag but must have exactly 1 occurrence where the
latest flag is 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 时,您必须停用约束,然后重新激活它。您可能需要锁定 table 以避免在禁用约束时进行任何插入/更新...
另一种方法 将使用计算列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
语句会花费更多...可能取决于您的数据大小。
如果我有table
Widget Version Latest
XYZ 1.0 0
XYZ 1.1 0
XYZ 1.2 1
ABC 1.0 1
有没有办法创建一个约束
each widget-version combination can have any number of 0s for the latest version flag but must have exactly 1 occurrence where the latest flag is 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 时,您必须停用约束,然后重新激活它。您可能需要锁定 table 以避免在禁用约束时进行任何插入/更新...
另一种方法 将使用计算列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
语句会花费更多...可能取决于您的数据大小。