简体   繁体   English

用于检查约束的条件

[英]Condidate for Check Constraint

I have a table that holds Tasks for a particular person. 我有一个表格,可以保存特定人员的任务。

TaskID INT PK
PersonID INT (FK to Person Table)
TaskStatusID INT (FK To list of Statuses)
Deleted DATETIME NULL

The business rule is that a person can not have more than one active task at a time. 业务规则是一个人一次不能有多个活动任务。 A task is 'Active' based on it's TaskStatusID. 基于TaskStatusID的任务是“活动”。 The statuses are: 状态是:

'5=New, 6=In 7=Progress, 8=Under 9=Review, 10=Complete, 11=Cancelled' '5 =新,6 =在7 =进度,8 =低于9 =评论,10 =完成,11 =已取消'

These are values in my Status table. 这些是我的状态表中的值。

So, 5,6,7,8 and 9 are Active tasks. 因此,5,6,7,8和9是活动任务。 These rest are finalised. 这些休息已经完成。

A person can only have one task which is in an active state. 一个人只能有一个处于活动状态的任务。

So, to test if I can add a task for this person, I would do: 所以,为了测试我是否可以为这个人添加任务,我会这样做:

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

The table has a lot of rows. 该表有很多行。 Around 200,000. 大约20万。

I was thinking of adding a Check Constraint on this table, so on update/insert, I make that query to see if the row being added/edited will break the data integrity with regards the business rules. 我想在这个表上添加一个Check Constraint,所以在更新/插入时,我进行查询以查看添加/编辑的行是否会破坏业务规则的数据完整性。

Is a check constraint suitable for this, or is there a more efficient way to keep the data integral. 检查约束是否适用于此,或者是否有更有效的方法来保持数据的积分。

Something like: 就像是:

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

You can't easily do it with a check constraint because they only (naturally) can make assertions about columns within the same row. 您不能轻易地使用检查约束来执行此操作,因为它们(自然地)只能对同一行中的列进行断言。 There are some kludgy ways to get around that by using a UDF to query other rows but most implementations I've seen have odd edge cases where it's possible to work around the UDF and end up with invalid rows after all. 通过使用UDF查询其他行,有一些方法可以解决这个问题,但是我见过的大多数实现都有奇怪的边缘情况,可以解决UDF并最终导致无效行。

What you can do is to create an indexed view that maintains the constraint: 您可以做的是创建一个维护约束的索引视图

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)

And now this insert succeeds (because there's only one row with an active status for person 1: 现在这个插入成功(因为只有一行具有人1的活动状态:

insert into dbo.Tasks (TaskID,PersonID,TaskStatusID)
values (1,1,5),(2,1,1),(3,1,4)

But this insert fails: 但是这个插入失败了:

insert into dbo.Tasks (TaskID,PersonID,TaskStatusID)
values (4,2,6),(5,2,8)

With the message: 随着消息:

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

If you are using SQL Server 2008 or later version, you could create a unique filtered index: 如果您使用的是SQL Server 2008或更高版本,则可以创建唯一的筛选索引:

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

It would act as a unique constraint specifically for rows with the specified statuses. 它将作为唯一约束,专门用于具有指定状态的行。 You would only be able to have one of the specified statuses per person. 您每人只能拥有一个指定的状态。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM