在SQL Server插入期间强制执行业务规则(检查约束?)

时间:2014-12-11 21:33:55

标签: sql-server tsql check-constraints

我们有一些业务规则强制执行诸如Employee之类的东西只能有一个当前活动(Todo,In-Progress),而所有其他活动必须是不同的状态(已完成,已移除)

我们注意到有时我们会在数据库中输入重复的活动,即使我们的业务规则应该阻止它(我们在插入之前检查一个活动的活动)。我们认为这是一个很小的时间问题(两者都是从两个不同的来源同时添加)

我们能否使用支票约束?

业务规则是:

  • 活动状态为活动状态(0或1)的每个活动类型(ActivityId)的一名员工(Id)

因此,每个员工可以进行一项活动并使其处于活动状态,或者一个员工可以拥有多个相同的活动,只要其中只有一个活动一次(其他人可以处于状态2/3)

  • EmployeeId 1活动1状态1存在于数据库
  • 添加EmployeeId 1活动1状态0将失败
  • 添加EmployeeId 1活动2状态0将成功
  • 添加EmployeeId 2活动1状态0将成功

一旦现有记录更新到状态2或3,那么员工将再次能够在待办事项/进行中状态中添加新记录。

那么这种类型的逻辑是否可以放在SQL Server检查约束中,或者我们是否需要使用触发器或事后删除这些“重复”?

编辑:

这是我的函数,但它在我尝试插入的所有内容上出错(在约束之外运行时正确返回1或0):

我不得不改变函数以接受Id忽略,因为检查约束失败,因为它找到了它正在插入的记录!

ALTER FUNCTION [dbo].[ActiveEmployeeActivitiyExists] 
(
    -- Add the parameters for the function here
    @ActivityId nvarchar(5),
    @EmployeeId int,
    @IgnoreId int,
)
RETURNS int
AS
BEGIN
  DECLARE @Id int

  SELECT Top(1) @Id = Id
  FROM [dbo].[EmployeeActivities]
  WHERE EmployeeId = @EmployeeId and ActivityId = @ActivityId and ActivityState < 2 and Id <> @IgnoreId

  RETURN CASE WHEN(@Id IS NULL) THEN 0 ELSE 1 END
END

1 个答案:

答案 0 :(得分:0)

您可以使用Check Constraint或触发器。检查约束的缺点是,如果索引违反约束,则会引发错误。在约束中没有其他选项可以处理它。您必须在执行插入的代码中处理错误。

如果您选择使用检查约束,那么实现它的最佳选择可能是编写一个udf来测试您的业务规则并返回一个简单的通过/失败(1或0),并让约束只是测试{ {1}}

在触发器中,您可以选择编写代码来处理插件违反业务规则时要执行的操作。但是,当然,触发器会产生其他并发症,这些并发症已在interwebz中得到充分记录。

如果您有两个名为EmployeeId和ActivityId的列,并希望在检查约束函数中将它们作为参数传递,那么您的检查约束将是:

dbo.MyFunction(SomeColumn or Columns)=1

因为检查约束在运行之前写入插入,所以您需要忽略Id并将其传递给您的函数:

dbo.MyFunction(EmployeeId, ActivityId) = 1