假设一个业务规则规定某些情况不允许存在.并且不允许使用外键进行限制,此时Instead of 触发器可以作为备选答案,但是通常这类触发器在以后带来的麻烦会多于其带来的便利。还有一种解决方式是使用包含唯一索引的索引视图与只有一个两行的dummy table进行连接。

假设你有如下两个表,地区和办事处

Region表

RegionId RegionName IsActive EffectiveDate ExpirationDate
1 East 1 1/1/2009 NULL
2 West 1 1/1/2009 NULL
3 North 1 1/1/2009 NULL
4 South 1 1/1/2009 NULL
5 Antarctica 1 1/1/2009 NULL

Office表

RegionId RegionId OfficeName IsActive EffectiveDate ExpirationDate
1 1 New York 1 1/1/2009 NULL
2 2 Los Angeles 1 1/1/2009 NULL
3 3 Minneapolis 1 1/1/2009 NULL
4 4 Atlanta 1 1/1/2009 NULL
5 5 Byrd Station 1 1/1/2009 NULL

你如何保证活动的(IsActive=1)的Office只属于活动的Region?

上面提到的表需要某种参照完整性.RegionId是Office表的外键,Check约束保证了在ExpirationDate不为Null的情况下,永远不会是1.但是我们如何防止IsActive的的Office属于IsActive=0的Region呢?我们可以重新设计表或是使用Instead of触发器,但更方便的做法是使用一个含有唯一索引的索引视图与一个两行的哑表进行连接。

DuplicateRows table

DuplicateRows表包含两行,如下

DuplicateRowIndex DuplicateRowValue
1 Duplicate Row
2 Duplicate Row

对于这个表的唯一要求是这个表至少含有两行,其结构和内容并不重要。这个表甚至也可以是只有一列的表并且每行的值不一样。而我这里用这种方式命名是因为“Duplicate Row”这个名字看起来不容易产生混淆,并且这样的命名也不会使得其它DBA删除这个表。

InvalidRegionIsInactiveButOfficeIsActiveView视图

业务规则是如果区域(Region)是不活动的,不能存在活动的办事处(Office)与其关联。换句话说,不能在属于某个区域的办事处还是active的情况下关闭这个区域,除非设置IsActive为0或是将这个办事处分到其它区域(Region),下面的View显示了显示了Region的IsActive为0并且属于它的offce的IsActive为1的例子。这违背了预设的业务规则.与dbo.DuplicateRows进行Cross Join是为了实现如果Where子句满足条件,最少返回两行。

CREATE View dbo.InvalidRegionIsInactiveButOfficeIsActiveView With SchemaBindingAsSELECT     dbo.Region.RegionId
FROM       dbo.Region
INNER JOIN dbo.Office
ON         dbo.Region.RegionId = dbo.Office.RegionId
CROSS JOIN dbo.DuplicateRows
WHERE      dbo.Region.IsActive = Convert(bit, 0)
AND        dbo.Office.IsActive = Convert(bit, 1)

最后的画龙点睛之笔是创建唯一索引,唯一索引是为了防止重复行,但是这个视图与一个两行的表进行Cross Join,这使得如果要返回结果,则返回一个两行的结果.但这又违背了唯一索引,所以这种情况永远不可能发生。

CREATE UNIQUE CLUSTERED INDEX IX_RegionInvalidOfficeIsActiveView_RegionId ON dbo.InvalidRegionIsInactiveButOfficeIsActiveView(RegionId ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

最后的结果是不会违背业务规则。

测试:关闭Antarctica区域

总部的那帮家伙决定关闭Antarctica区域。下面语句在不顾与之关联的Office的状态的情况下设置Region的IsActive为0。

UPDATE dbo.RegionSET dbo.Region.IsActive  = Convert(bit, 0),dbo.Region.ExpirationDate = GetDate()WHERE dbo.Region.RegionName  = N'Antarctica'

当执行后,发生如下错误:

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.InvalidRegionIsInactiveButOfficeIsActiveView' with unique index 'IX_RegionInvalidOfficeIsActiveView_RegionId'. The duplicate key value is (5).

在关闭Antarctica区域之前,Byrd Station办事处必须设置成不活动的或者是分配给其它区域,因为我并不想解雇这个办事处的任何人,所以我将这个办事处分为了其它区域。

UPDATE dbo.OfficeSET dbo.Office.RegionId = (SELECT dbo.Region.Regionid FROM dbo.Region WHERE dbo.Region.RegionName = N'South')FROM dbo.OfficeWHERE dbo.Office.RegionId =(SELECT dbo.Region.RegionidFROM dbo.RegionWHERE dbo.Region.RegionName = N'Antarctica')

一旦没有任何活动的办事处与Antarctica区域相关联,我就可以通过Update语句来关闭Antarctica区域了。

如何在你的数据库中实现这个技巧

下面几部帮助你在数据库中实现这个技巧:

1.创建dbo.DuplicateRows table表并插入两条数据

2.写一个违反了业务规则并且还能返回结果的查询

3.在这个查询中与dbo.DuplicateRows进行Cross Join

4.创建一个包含SchemaBinding参数和上面查询语句的视图

5.在视图上创建唯一索引

总结

使用索引视图和一个两行的表进行连接或许并不是实现业务规则最有效的手段,但是使用了这种方法可以避免使用复杂的Instead of触发器。假如微软提供了“Before触发器”使得违反业务规则的查询在执行之前就被取消的话,就不需要我这种手段了。上面的技巧可以看作是一个无奈的人实现的山寨版”before 触发器”。

原文链接:http://www.sqlservercentral.com/articles/Business+Rules/91924/

Translated by:CareySon

转载于:https://www.cnblogs.com/CareySon/archive/2012/08/21/2648492.html

【译】如何使用索引视图和一个只有2行的表限制业务规则相关推荐

  1. SQL Server 优化---为什么索引视图(物化视图)需要with(noexpand)强制查询提示

    本文出处:http://www.cnblogs.com/wy123/p/6694933.html 第一次通过索引视图优化SQL语句,以及遇到的一些问题,记录一下. 语句分析 最近开发递交过来一个查询统 ...

  2. 使用 SQL Server 2000 索引视图提高性能1

    什么是索引视图? 许多年来,Microsoft SQL Server" 一直都提供创建虚拟表(称为视图)的功能.在过去,这些视图主要有两种用途: 提供安全机制,将用户限制在一个或多个基表中的 ...

  3. SQL Server索引视图以(物化视图)及索引视图与查询重写

    SQL Server索引视图以(物化视图)及索引视图与查询重写 本文出处:http://www.cnblogs.com/wy123/p/6041122.html 经常听Oracle的同学说起来物化视图 ...

  4. SQL Server索引视图

    SQL Server Views are virtual tables that are used to retrieve a set of data from one or more tables. ...

  5. 索引视图是否物理存储在数据库中以及使用索引视图的一些见解

    索引视图是否物理存储在数据库中以及使用索引视图的一些见解 前言 这个话题我本来是写在文章里没有写在随笔里的,不过赶脚不写在随笔里其他人就看不到了,因为小弟对视图的认识不深 希望写在随笔里让大家也讨论一 ...

  6. 浅谈SQL Server索引视图(物化视图)以及索引视图与查询重写

    目录 (一)前言 (二)正文 1. 物化视图(索引视图)与查询重写的基本概念 2. 创建测试环境 (1)建表 (2)写数据 3. 索引视图创建 (1)创建语法 (2)为索引视图创建索引 4. 查询重写 ...

  7. mysql构架,索引,视图,查询语句

    mysql构架: connection pool:因为单进程多线程,所以需要一个线程池接收请求提供并发,线程重用,还能完成认证 SQL interface:接收并分析SQL语句 Parser:分析器, ...

  8. 四、物理优化(2)索引视图

    一.视图的概念 1. 虚拟表 SQL Server中的视图是一个虚拟表,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在.行和列数 ...

  9. 【C/C++9】天气APP:Oracle的虚表/日期/序列,索引/视图/链路/同义词,数据库高可用性

    文章目录 1.虚表/日期/序列:SEQUENCE 2.索引/视图/链路/同义词:create index/view/link/synonym 3.表空间/数据文件/启动关闭/权限/备份恢复:exp/i ...

最新文章

  1. CSS中的emmet语法(使用缩写的方式提高书写html编写速度)
  2. Nature: 人的肠道古细菌基因组集
  3. oracle form 滚动条,jQuery实现的自定义滚动条实例详解
  4. 西安电子科技大学第16届程序设计竞赛 C题
  5. elementui 加载中_ElementUI cascader级联动态加载回显和搜索看这个就够了
  6. Net Core中数据库事务隔离详解——以Dapper和Mysql为例
  7. 工作93:注意数据对应接口位置
  8. Ant Desgin Pro 修改登录后默认导航到的位置
  9. MongoDB查询用法大全
  10. PHP 使用concat的无限分类
  11. 多参selector
  12. excel中添加图片的代码
  13. 二维数据的分形维数分析(C++实现)
  14. 当下移动互联网的6个泡沫,快要破了!
  15. 优秀开源项目之二:流媒体直播系统Open Broadcaster Software
  16. MySQL单表数据量大优化方案及注意事项
  17. 基于广义线性组合的Capon波束形成原理介绍及MATLAB实现
  18. npm ERR! code EINTEGRITY 错误原因记录
  19. SitePoint播客#70:青年,企业和播客
  20. CSS加载外部字体以及字体格式转换

热门文章

  1. GVRP和VTP比较
  2. 多路隔离输出的车载辅助电源设计
  3. 说说浏览器的沙箱机制
  4. Sub-process /usr/bin/dpkg returned an error code (1) 如何解决
  5. python_day2_数据格式
  6. 使用jquery.qrcode生成二维码(转)
  7. STM32中IO口的8中工作模式
  8. android 自由复制与粘贴功能
  9. profiler 对表跟踪
  10. 最近在学OpenGL和英语