检查约束的候选人

时间:2014-08-28 04:02:04

标签: 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是活动任务。这些休息已经完成。

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

所以,为了测试我是否可以为这个人添加任务,我会这样做:

CASE EXISTS(SELECT * FROM Task WHERE PersonID = 123 AND TaskStatusIN IN (5,6,7,8,9)) THEN 0 ELSE 1 END AS CanAdd

该表有很多行。大约200,000。

我想在这个表上添加一个Check Constraint,所以在更新/插入时,我进行查询以查看正在添加/编辑的行是否会破坏业务规则的数据完整性。

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

类似的东西:

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

3 个答案:

答案 0 :(得分:2)

您无法使用检查约束轻松执行此操作,因为它们(自然地)只能对同一行中的列进行断言。通过使用UDF查询其他行,有一些方法可以解决这个问题,但我见过的大多数实现都有奇怪的边缘情况,它们可以解决UDF并最终导致无效行。

您可以做的是创建一个维持约束的indexed view

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)

现在这个插入成功(因为只有一行具有人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).

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

你可以使用上面的检查约束,但是我建议在插入/更新之前编写dml触发器的最佳方法是提高语句。