使用CHECK约束执行业务规则

2016-02-19 16:05 12 1 收藏

每个人都希望每天都是开心的,不要因为一些琐事扰乱了心情还,闲暇的时间怎么打发,关注图老师可以让你学习更多的好东西,下面为大家推荐使用CHECK约束执行业务规则,赶紧看过来吧!

【 tulaoshi.com - 编程语言 】

  如果你不熟悉CHECK约束,那么习惯上它们通过限制插入到一个字段中的值来执行字段域完整性。我发现CHECK约束很不幸地被用于大多数的数据模型中。在大多数的案例中,我看到使用触发器来执行业务规则,而这本来是应该用一个CHECK约束来执行的。我个人使用CHECK而不是触发器是基于很多个原因的。首先,我不需要浪费时间来写专门的代码。另外,CHECK约束是在数据库修改通过数据库引擎完成之前执行的,然而触发器是事故发生后检查的。使用触发器延长了一个事务的生命,如果检测到一个回滚事件那么代价可能是昂贵的。

  SQL Server允许你定义检查单独字段完整性的字段级别的CHECK约束。此外,SQL Server允许你使用一个表级别CHECK约束来检查多个字段的值。虽然它们被归类为表级别约束,但是这些CHECK约束的类型实际上是在行级别上检查的。最后,CHECK约束通过检查一个定义好的情形来看它的值为TRUE还是FALSE。

  让我们来看看一些例子。我将建立一张示例表EMPLOYEE。作为表定义的一部分,我们将执行一个公司规则:在我们的系统中没有一个员工被允许赚取超过$100,000或者少于$30,000。

   CREATE TABLE DBO.EMPLOYEE
  (
  EMPLOYEEID INT IDENTITY(1,1) NOT NULL,
  FIRSTNAME VARCHAR(50) NOT NULL,
  LASTNAME VARCHAR(50) NOT NULL,
  IS_MANAGER BIT NULL,
  SALARY MONEY NOT NULL,
  BONUSPCT FLOAT NOT NULL
  )
  GO
  ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEEID)
  GO
  ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT DF_EMPLOYEE_BONUSPCT DEFAULT 0.00 FOR BONUSPCT
  GO
  ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT CK_EMPLOYEE_SALARY CHECK (SALARY BETWEEN 30000 AND 100000)
  GO
  EXEC SP_HELPCONSTRAINT EMPLOYEE
  GO

  查看我们表中的约束,我们看到我们简单的字段级别约束已经定义好了:

图一

  尝试把值插入到SALARY字段超出了我们定义的范围,这也被我们的数据库引擎成功捕捉到了。

  INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, SALARY)

  SELECT 'GEORGE', 'WASHINGTON', 110000

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  GO

图二

  到目前为止这些都进展得很顺利。但是,这里还有另外一个公司规则需要我们来执行。我们公司的管理人员可以赚取任何奖金比例但是他们是唯一被允许赚取他们工资5%或者更高比例奖金的员工。非管理人员只能赚取低于5%的任何比例奖金。让我们来试着通过一个表级别的CHECK约束来执行这个公司规则:

   ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT CK_EMPLOYEE_BONUSPCT
  CHECK (IS_MANAGER = 1 AND BONUSPCT = 5.00)
  GO
  INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, IS_MANAGER, SALARY, BONUSPCT)
  SELECT 'GEORGE', 'WASHINGTON', 1, 100000, 5.00
  GO
  INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, IS_MANAGER, SALARY, BONUSPCT)
  SELECT 'BEN', 'FRANKLIN', 0, 75000, 2.50
  GO

图三

  然后发生了什么事呢?员工Washington成功插入但是Franklin插入失败。那么,正如它被定义的,CHECK约束迫使所有的员工成为一个管理人员并且具有一个大于或等于5%的奖金比例。如果所有的员工必须是具有大于或者等于5%的奖金比例的管理人员,那么这就没有什么问题。然而,这不是我们想要执行的业务规则。我们想要确保如果一个员工不是管理人员,那么他就不能执行查果5%奖金的界限。因此我们应该怎样使CHECK约束有条件地执行完整性呢?你可能想使用一个触发器。尽管如此,正如我在开篇提到的,CHECK是用来检查TRUE/FALSE条件的。因此,你可以平衡这两种方法来产生一个可以执行条件检查的CHECK约束。让我们通过使用这些原则来重新创建我们的CHECK并试着重新插入员工Franklin。

   ALTER TABLE DBO.EMPLOYEE
  DROP CONSTRAINT CK_EMPLOYEE_BONUSPCT
  GO
  ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT CK_EMPLOYEE_BONUSPCT
  CHECK (CASE WHEN IS_MANAGER 1 AND BONUSPCT = 5.00 THEN 1 ELSE 0 END = 0)
  GO
  INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, IS_MANAGER, SALARY, BONUSPCT)
  SELECT 'BEN', 'FRANKLIN', 0, 75000, 2.50
  GO

  现在试着使用正确的CHECK约束定义来插入Franklin,结果成功了。

图四

  现在让我们尝试插入一个新的员工Jefferson。

   INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, IS_MANAGER, SALARY, BONUSPCT)
  SELECT 'THOMAS', 'JEFFERSON', NULL, 80000, 7.50
  GO

 

图五

  等待一秒钟,Jefferson没有被标记成一个管理人员但是他的引擎允许他的奖金比例变成7.5%。为什么会发生这种情况呢?再次回顾CHECK约束是用于检查TRUE/FALSE条件的。看看我们的模式,IS_MANAGER被声明成NULL。由于这个字段中的任何空值都会导致CHECK的IS_MANAGER条件等同于不知道的并且导致CASE表达求取我们的默认布尔值为零。当使用等于零的字段时,这是一个需要明白的地方。有很多种方法可以纠正这点。其中一种是把IS_MANAGER标记定义为NOT NULL从而把NULL值转化为零。如果你不能改变这个模式,那么另外的方法就是把CASE重新写到NULL IS_MANAGER 标记的账户中。下面是其中一种重写CASE的方法。(你可能有自己的更改;我的版本是为了达到例证的目的)。

   TRUNCATE TABLE DBO.EMPLOYEE
  GO
  ALTER TABLE DBO.EMPLOYEE
  DROP CONSTRAINT CK_EMPLOYEE_BONUSPCT
  GO
  ALTER TABLE DBO.EMPLOYEE
  ADD CONSTRAINT CK_EMPLOYEE_BONUSPCT
  CHECK (CASE WHEN IS_MANAGER IS NULL AND BONUSPCT = 5.00 THEN 1
  WHEN IS_MANAGER 1 AND BONUSPCT = 5.00 THEN 1
  ELSE 0 END = 0)
  GO
  INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME, IS_MANAGER, SALARY, BONUSPCT)
  SELECT 'JAMES', 'MADISON', NULL, 60000, 5.50
  GO

  执行一个新员工Madison,的脚本,我们可以看到现在这个引擎成功捕捉了这个条件。

图六

  现在你可能在想“我打赌我能写一个纯量函数来读取我整个表并且执行一个真实的表级别CHECK以便检查超过的数目和总量”。你是对的,你可以做到。但是正如SQL Server MVP David Portas所提出的,这里也有风险。

  正如你看到的,CHECK约束是执行单个和多个字段域完整性而不需要写专门的触发器或者存储过程代码的强有力的方法。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

来源:http://www.tulaoshi.com/n/20160219/1611021.html

延伸阅读
ListBox窗口用来列出一系列的文本,每条文本占一行。创建一个列表窗口可以使用成员函数: BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff ); 其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。 LBS_M...
标签: 电脑入门
Linux命令中at命令用于列出已计划的任务,有点类似日历软件的提醒功能,使用at命令你就不需要去特地下载有提醒功能的软件,那么at命令还有那些用途呢?下面图老师小编就给大家介绍下Linux at命令的用法。 在linux系统中你可能已经发现了为什么系统常常会自动的进行一些任务?这些任务到底是谁在支配他们工作的?在linux系统如果你想要让自...
网易云阅读红包使用规则   1.购买时默认先用红包余额抵扣,不足部分再从阅点账户中扣除阅点。 2.同时存在多个红包,可叠加使用,且先过期的优先使用。 3.红包可记余额,可多次使用。如一个500阅点的红包,一次使用扣减200阅点后,还有300阅点,在有效期内都可继续使用。 4.使用限制:根据不同红包性质,可适用客户...
标签: 服务器
哪些行业巨头正在使用Linux操作系统?   亚马逊 亚马逊是大多数人喜欢买书的地方。大型在线零售商Amazon.com的几乎每个业务都由Linux支持。自从转向Linux后,亚马逊节省的技术基础设施成本高达数百万美元。当时亚马逊在向证券管理委员会提交的报表中称,亚马逊的省钱之道关键在于利用便宜的基础技术架构,引入基于Linux的技...
途牛抵用券使用规则   途牛旅游app是一款当下非常好用、功能非常强大、便于大家出行旅游的应用软件,以让旅游更简单为使命,为消费者提供旅游产品预订服务,产品全面,价格透明。为了 吸引更多的用户途牛旅游网有不少优惠券和抵用券可以使用的,小编来给大家介绍途牛抵用券的使用方法。 抵用券可冲抵途牛旅游产品部分金额,...

经验教程

959

收藏

18
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部