Sql 检查约束条件

Sql 检查约束条件,sql,sql-server,tsql,constraints,Sql,Sql Server,Tsql,Constraints,我有一张桌子,上面放着某个人的任务 TaskID INT PK PersonID INT (FK to Person Table) TaskStatusID INT (FK To list of Statuses) Deleted DATETIME NULL 业务规则是一个人一次不能有多个活动任务。任务根据其TaskStatusID处于“活动”状态。状态为: ‘5=新,6=在7=进展中,8=在9=审查中,10=完成,11=取消’ 这些是我的状态表中的值 因此,5、6、7、8和9是主动任务。其余

我有一张桌子,上面放着某个人的任务

TaskID INT PK
PersonID INT (FK to Person Table)
TaskStatusID INT (FK To list of Statuses)
Deleted DATETIME NULL
业务规则是一个人一次不能有多个活动任务。任务根据其TaskStatusID处于“活动”状态。状态为:

‘5=新,6=在7=进展中,8=在9=审查中,10=完成,11=取消’

这些是我的状态表中的值

因此,5、6、7、8和9是主动任务。其余部分已完成

一个人只能有一个处于活动状态的任务

因此,为了测试我是否可以为此人添加任务,我将执行以下操作:

CASE EXISTS(SELECT * FROM Task WHERE PersonID = 123 AND TaskStatusIN IN (5,6,7,8,9)) THEN 0 ELSE 1 END AS CanAdd
这张桌子有很多行。大约20万

我正在考虑在这个表上添加一个检查约束,所以在update/insert上,我进行该查询,以查看正在添加/编辑的行是否会破坏业务规则方面的数据完整性

检查约束是否适用于此,或者是否有更有效的方法来保持数据的完整性

比如:

ADD CONSTRAINT chk_task CHECK (
    EXISTS(SELECT * FROM Task WHERE PersonID = ?? AND TaskStatusIN IN (5,6,7,8,9)))

您可以使用上面的检查约束,但我建议最好的方法是在insert/update之前编写dml触发器,即发出语句。

使用检查约束很难做到这一点,因为它们(自然)只能对同一行中的列进行断言。通过使用UDF查询其他行,有一些笨拙的方法可以解决这个问题,但我看到的大多数实现都有一些奇怪的边缘情况,在这种情况下,可以绕过UDF,最终得到无效的行

您可以做的是创建一个用于维护约束的:

create table dbo.Tasks (
TaskID INT not null primary key,
PersonID INT not null,
TaskStatusID INT not null,
Deleted DATETIME NULL
)
go
create view dbo.DRI_Tasks_OneActivePerPerson
with schemabinding
as
    select PersonID from dbo.Tasks
    where TaskStatusID IN (5,6,7,8,9)
go
create unique clustered index UX_DRI_Tasks_OneActivePerPerson
on dbo.DRI_Tasks_OneActivePerPerson (PersonID)
现在,此插入成功(因为只有一行具有person 1的活动状态:

insert into dbo.Tasks (TaskID,PersonID,TaskStatusID)
values (1,1,5),(2,1,1),(3,1,4)
但该插入失败:

insert into dbo.Tasks (TaskID,PersonID,TaskStatusID)
values (4,2,6),(5,2,8)
我谨此致辞:

Cannot insert duplicate key row in object 'dbo.DRI_Tasks_OneActivePerPerson'
with unique index 'UX_DRI_Tasks_OneActivePerPerson'.
The duplicate key value is (2).

如果您使用的是SQL Server 2008或更高版本,则可以创建唯一的筛选索引:

CREATE UNIQUE INDEX UQ_ActiveStatus
ON dbo.Task (PersonID)
WHERE TaskStatusID IN (5, 6, 7, 8, 9);

它将专门作为具有指定状态的行的唯一约束。每个人只能有一个指定状态。

这并不能回答问题。若要评论作者或要求作者澄清,请在其帖子下方留下评论。他在征求建议。因此我建议D你应该在回答中加入一些相关的代码。仅仅在上面加上注释是不可接受的。我对此做了一些阅读,但似乎使用约束比使用触发器更有效,更“最佳实践”。@Craig-是的,如果你不能以更“声明性”的方式强制约束,你应该只使用触发器时尚。安德烈的答案和我的答案都展示了实现这一点的方法。如果你在2008年或更高版本,安德烈的答案可能是首选。也许检查
已删除的
列也合适?如果已删除的任务仍然在表中处于活动状态…啊。我尝试创建一个计算列,并在该列上放置一个过滤索引,然后它就消失了生病了,所以我放弃了筛选索引,转而使用索引视图。我永远记不起您在筛选中被/不被允许做什么。