SQL约束检查还是触发器?
我一直在网上寻找答案。但我得到的只是简单的答案 我的数据库中有一些列应该对它们的最大值有一个约束,但如果另一列设置为false,则没有约束 我在表中有以下值SQL约束检查还是触发器?,sql,sql-server-2005,triggers,constraints,Sql,Sql Server 2005,Triggers,Constraints,我一直在网上寻找答案。但我得到的只是简单的答案 我的数据库中有一些列应该对它们的最大值有一个约束,但如果另一列设置为false,则没有约束 我在表中有以下值 ROW ValueA TRUE/FALSE ValueB 0 3750 TRUE 0 1 5000 TRUE 0 2 5000 FALSE
ROW ValueA TRUE/FALSE ValueB
0 3750 TRUE 0
1 5000 TRUE 0
2 5000 FALSE 0 [INITIAL VALUES PROVIDED]
2 3750 FALSE 1250 [ACTUAL VALUES ACCEPTED]
在此表中,第2行由外部程序提供,其中ValueA最初为5000,但该行的值设置为FALSE,因此将该值限制为3750,并将1250添加到ValueB
现在的想法是,如果设置为true,它可以绕过检查。
但是,如果该行的值设置为false,并且该值大于3750,则应将ValueA减回到3750,并将剩余值放入ValueB中
这可能与约束检查表达式有关,还是更谨慎地使用更新前触发器?我认为,这听起来像是“复杂”的业务逻辑 所谓复杂,我指的是一些if检查,以及一些基于规则的不同行为
在本例中,我将在触发器中进行检查。您需要一个触发器,因为约束无法根据条件设置另一列的值(正如您在这里所做的那样)我建议您有两个表:一个用于保存外部程序原始数据的暂存表,另一个用于应用业务规则的表。第二个表可能只是一个
视图
,它通过应用规则来查询数据,例如(我使用CTE用示例数据模拟暂存表;另外,SQL Server没有真正的布尔类型,所以我使用字符(1)模拟它)
列中的名称将我的头部插入,因此我将其更改为某些标志
!):
然后,您可以使用上面的查询将数据从暂存表复制到基表,同时不违反任何约束,但要知道,如果查询错误,过程将失败 谢谢你的switft回复,我自己也倾向于使用触发器,只是不确定使用触发器是否不好,因为我读到了很多关于触发器的负面信息。这种类型的使用非常好-人们在埋葬会降低性能的巨大程序行为时会遇到麻烦。谢谢,那么我就有了我需要的答案!当然,不要忘记编写(和测试)触发器,以便它能够处理多个记录插入/更新。SQL Server不会在触发器中循环遍历批处理中的每条记录。。。这里可能也有一个潜在的规范化问题。谢谢,我想不出一个更好的名称来表示真-假位,它确实是一个包含t或F的字符字段。谢谢您的见解。我将此标记为我的答案,因为它包含一个示例。
WITH Staging
AS
(
SELECT *
FROM (
VALUES (0, 3750, 'T'),
(1, 5000, 'T'),
(2, 5000, 'F')
) AS T (ROW, ValueA, some_flag)
)
SELECT ROW, ValueA, some_flag,
0 AS ValueB
FROM Staging
WHERE ( ValueA <= 3750 OR some_flag = 'T' )
UNION
SELECT ROW, 3750 AS ValueA, some_flag,
( ValueA - 3750 ) AS ValueB
FROM Staging
WHERE ValueA > 3750 AND some_flag = 'F';
IF some_flag = 'F' THEN ValueA <= 3750
IF some_flag = 'T' THEN ValueB = 0
IF some_flag = 'F' AND ValueA < 3750 THEN ValueB = 0
CREATE TABLE MyTable
(
ROW INTEGER NOT NULL UNIQUE,
ValueA INTEGER NOT NULL CHECK ( ValueA > 0 ),
some_flag CHAR(1) NOT NULL CHECK ( some_flag IN ( 'T', 'F' ) ),
ValueB INTEGER NOT NULL CHECK ( ValueB >= 0 ),
CHECK ( some_flag <> 'F' OR ValueA <= 3750 ),
CHECK ( some_flag <> 'T' OR ValueB = 0 ),
CHECK ( some_flag <> 'F' OR ValueA >= 3750 OR ValueB = 0 )
);