Sql server 基于另一个表中的信息检查约束

Sql server 基于另一个表中的信息检查约束,sql-server,check-constraints,Sql Server,Check Constraints,给出两个表格: 表 id:主键, 类型:tinyint, ... 表B id:主键, tableAId:TableA.id的外键, ... TableA.type上存在允许值为0、1、2、3的检查约束。所有其他值都是禁止的 由于已知的限制,只有TableB.TableAId使用TableA.type=0、1或2而不是3引用TableA中的记录时,TableB中的记录才能存在。后一种情况是禁止的,并导致系统进入无效状态 在这种情况下,如何保证插入到TableB失败?使用空索引视图的跨表约束: 桌子

给出两个表格:

id:主键, 类型:tinyint, ... 表B

id:主键, tableAId:TableA.id的外键, ... TableA.type上存在允许值为0、1、2、3的检查约束。所有其他值都是禁止的

由于已知的限制,只有TableB.TableAId使用TableA.type=0、1或2而不是3引用TableA中的记录时,TableB中的记录才能存在。后一种情况是禁止的,并导致系统进入无效状态


在这种情况下,如何保证插入到TableB失败?

使用空索引视图的跨表约束:

桌子 创建表dbo.TableA id整数不是空主键, [类型]tinyint不为空 在0、1、2、3中选中[type] ; 创建表dbo.TableB id整数不是空主键, tableAId整数不为空 外键 参考文献dbo.TableA ; “约束视图” -此视图始终为空,仅限于错误行 创建视图dbo.TableATableBConstraint 以诡计多端为目的 选择 错误= 案例 -错误条件:类型=3,行连接 当TA.[type]=3且TB.id=TA.id时 -获取更多信息的错误 然后CONVERTbit,“TableB不能引用TableA中的类型3行。” 否则无效 终止 从dbo.TableA作为TA 将dbo.TableB作为TB加入 ON TB.id=TA.id 哪里 TA.[type]=3; 去 创建唯一聚集索引cuq 关于dbo.TableATableBConstraint错误; -都成功了 插入dbo.tableaid,[type]值1,1; 插入dbo.tableaid,[type]值2,2; 插入dbo.tableaid,[type]值3,3; 插入dbo.TableB 身份证 价值观 1, 1, 2, 2; -失败 插入dbo.TableB id,tableAId值3,3; -失败 更新dbo.TableA SET[type]=3,其中id=1; 这在概念上类似于to,但此解决方案是自包含的,不需要始终使用一个包含多行的单独表。它还会生成更多信息性错误消息,例如:

信息245,16级,状态1 将varchar值“TableB无法引用TableA中的类型3行”转换为数据类型位时,转换失败

重要注意事项 错误条件必须在CASE表达式中完全指定,以确保在所有情况下都能正确操作。不要试图忽略语句其余部分隐含的条件。在本例中,省略联接隐含的TB.id=TA.id将是一个错误

SQL Server查询优化器可以自由地对谓词进行重新排序,并且对标量表达式的计算时间或数量没有一般性的保证。特别是

在一个CASE表达式中完全指定错误条件可以确保完整的测试集被一起评估,并且不会早于正确性要求。从执行计划的角度来看,这意味着与案例测试关联的计算标量将出现在索引视图增量维护分支上:


浅色区域高亮显示索引视图维护区域;包含大小写表达式的计算标量是深色的。

One-way@MartinSmith看起来可以接受,但设计过度。与其在具有唯一约束的TableA和TableB上添加其他视图,不如编写一个before触发器或类似于check约束的内容,以防mssql Server支持此类功能。您可以使用触发器来执行此操作。您需要在表A和表B上写入触发器,并负责确保它们在所有条件下都能正确运行。索引视图将其留给引擎来执行。嗯,你说得对。索引或检查约束视图是更好的解决方案。也许你可以给我写一个答案,让我检查一下是否正确?哦,聪明。。。给你一个奇怪的转换错误,但至少你得到了错误信息。考虑到优化的风险,看起来有点危险,你不能总是确定计算标量的顺序,是吗?我曾经因为这个原因在索引视图上有一个被零除的结果