我需要一个表,其中CHECK将检查值是否以相同的方式排序(是单调的)。例如:
CREATE TABLE test
(
ID int identity primary key,
ID_foreignkey int references something,
order int,
value int
)
我需要的效果是,对于相同的ID_foreign键,订单会增长并且值也会增长,例如:
(1,1,4), (1,2,5), (1,3,9), (1,4,12), (1,5,13), (1,6,18)
是否可以使用约束轻松完成,或者必须使用某个程序?也许检查插入的值是否大于测试中的select max(value)?
答案 0 :(得分:1)
你可以创建一个这样的函数来返回预期的下一个值
create FUNCTION [dbo].[test](@id integer, @typeKey integer)
RETURNS int
AS
BEGIN
DECLARE @retval int
if @typeKey=1
begin
SELECT @retval = max([order]) + 1 FROM table where ID_foreignkey = @id
end
else
begin
/*next value i don't understand the logic*/
SELECT @retval = max([value]) + 1 FROM table where ID_foreignkey = @id
end
RETURN @retval
END
然后在检查约束
dbo.test(ID_foreignkey, 1) = order
和
dbo.test(ID_foreignkey, 2) = value
答案 1 :(得分:1)
我认为您应该编写一个FOR INSERT, UPDATE
触发器,其验证方式如下:
if exists (
select 1
from (
select ID_foreignkey
, row_number() over (partition by ID_foreignkey order by [order]) as num_order
, row_number() over (partition by ID_foreignkey order by value) as num_value
from test
where ID_foreignkey in (
select ID_foreignkey
from inserted
)
) t
where num_order <> num_value
)
raiserror('Error', 16, 1);
答案 2 :(得分:1)
如果我们可以强制order
从1开始并且没有间隙,那么我们可以声明性地实现大多数的要求:
CREATE TABLE test
(
ID int not null identity,
ID_foreignkey int not null,
[order] int not null,
value int not null,
prev_order as CASE WHEN [order] > 1 THEN [order]-1 END persisted,
prev_value int null,
constraint PK_test PRIMARY KEY (ID),
constraint UQ_test_backref UNIQUE (ID_foreignkey,[order]),
constraint CK_test_orders CHECK ([order] >= 1),
constraint CK_test_prevpopulated CHECK ([order]=1 or prev_value is not null),
constraint FK_test_backref FOREIGN KEY (ID_foreignkey,prev_order)
references test (ID_foreignkey,[order]),
--Finally, we can actually write the constraint you wanted
constraint CK_test_increase_only CHECK (value > prev_value)
)
不幸的是,我们确实需要添加一个触发器,以便在prev_value
s 1 期间正确设置INSERT
:
create trigger T_test on test
instead of insert
as
set nocount on;
insert into test (ID_foreignkey,[order],value,prev_value)
select i.ID_foreignkey,i.[order],i.value,COALESCE(p.value,i2.value)
from inserted i
left join
test p
on
i.ID_foreignkey = p.ID_foreignkey and
i.[order] = p.[order]+1
left join
inserted i2
on
i.ID_foreignkey = i2.ID_foreignkey and
i.[order] = i2.[order]+1
现在我们可以做一些示例插入:
insert into test (ID_foreignkey,[order],value) values
(1,1,4), (1,2,5), (1,3,9)
go
insert into test (ID_foreignkey,[order],value) values
(1,4,12), (1,5,13)
现在失败了:
insert into test (ID_foreignkey,[order],value) values
(1,6,12)
Msg 547,Level 16,State 0,Procedure T_test,Line 4
INSERT语句与CHECK约束“CK_test_increase_only”冲突。冲突发生在数据库“X”,表“dbo.test”。
声明已经终止。
只有值得一提的其他事情 - 如果你想稍后调整value
,你不需要做很多事情就可以做到这一点,并且仍然要强制执行约束 - 你只需要添加ON UPDATE CASCADE
至FK_text_backref
。
1 但请注意,声明性约束会强制 时应填充数据并且必须包含正确的数据。因此,没有把触发器弄错的危险,比如说,并且在表中以错误的数据结束。