我想约束它,所以整个FKID = 2失败,因为它加起来等于1.1。
当前我的约束是
FUNCTION[dbo].[CheckSumTarget](@ID bigint)
RETURNS bit
AS BEGIN
DECLARE @Res BIT
SELECT @Res = Count(1)
FROM dbo.Test AS t
WHERE t.FKID = @ID
GROUP BY t.FKID
HAVING Sum([t.Value])<>1
RETURN @Res
END
GO
ALTER TABLE dbo.Test WITH CHECK ADD CONSTRAINT [CK_Target_Sum] CHECK (([dbo].[CheckSumTarget]([FKID])<>(1)))
,但是在第一次插入时失败,因为它尚未累加到1。我希望同时添加它们,但事实并非如此。
答案 0 :(得分:2)
这种方法似乎充满了问题。
我建议另一种方法,从两个表开始:
aggregates
,因此“ fkid”应为aggregate_id
components
然后,在aggregates
中,使用触发器累积分量值的sum()
。维护计算出的另一个标志:
alter table aggregates add is_valid as ( sum_value = 1.0 )
然后,在两个表上创建视图以仅显示is_valid = 1
处的记录。例如:
create view v_aggregates as
select c.*
from aggregates a join
components c
on a.aggregate_id = c.aggregate_id
where a.is_value = 1;
答案 1 :(得分:1)
这是解决方案的有效版本
这是表DDL
create table dbo.test(
id int,
fkid bigint,
value decimal(4,2)
);
函数定义
CREATE FUNCTION[dbo].[CheckSumTarget](@ID bigint)
RETURNS bit
AS BEGIN
DECLARE @Res decimal(4,2)
SELECT @Res = case when sum(value) > 1 then 1 else 0 end
FROM dbo.Test AS t
WHERE t.FKID = @ID
RETURN @Res
END
和约束定义
ALTER TABLE dbo.Test WITH CHECK ADD CONSTRAINT [CK_Target_Sum] CHECK ([dbo].[CheckSumTarget]([FKID]) <> 1)
在您的示例中
insert into dbo.test values (1, 2, 0.5);
insert into dbo.test values (1, 2, 0.4);
-- The following insert will fail, like you expect
insert into dbo.test values (1, 2, 0.2);
注意:此解决方案将被UPDATE语句(如“ Daniel Brughera”指出的)破坏,但这是已知的行为。一种更好的通用方法是使用触发器。您可能想探索一下。
答案 2 :(得分:1)
您的实际方法将以这种方式工作.....
由于您的约束只处理FKID列,因此有可能,并且您可能认为这是可行的。...
但是....如果您在步骤3中离开了该过程,则您的总和不等于1,并且约束无法预见是否要插入下一个值,甚至更糟的是,您可以更新任何值大于1,它将被接受。
如果将value列添加到约束中,它将阻止这些更新,但是您将永远无法超越步骤1。
我个人不会这样做,但是在这里您可以找到一种方法
注意,因为您可以看到函数中未使用id和value参数,但是在创建约束时我需要它们调用它们,这样约束也将验证更新>
CREATE TABLE ttest (id int, fkid int, value float)
go
create FUNCTION [dbo].[CheckSumTarget](@id int, @fkid int, @value float)
RETURNS FLOAT
AS BEGIN
DECLARE @Res float
SELECT @Res = sum(value)
FROM dbo.ttest AS t
WHERE t.FKID = @fkid
RETURN @Res
END
GO
ALTER TABLE dbo.ttest WITH CHECK ADD CONSTRAINT [CK_Target_Sum] CHECK (([dbo].[CheckSumTarget](id,[FKID],value)<=(1.0)))