我的 MSSQL 数据库表中有以下(以及更多不相关的)列:Id
、ImageUrl
和ImageId
。ImageUrl
和的组合ImageId
可以出现多次。ImageUrl
属于ImageId
,反之亦然。
为了清楚起见,以下示例使用虚拟值,对于真实数据库表 ImageId: int 和 ImageUrl: nvarchar 用作数据类型。
ImageId
a
属于ImageUrl
=的=a.com
可以出现多次,但ImageId
=a
不能用于其他的ImageUrl
。
ImageUrl
=a.com
可以与相同的词一起出现多次ImageId
,但ImageUrl
=a.com
不能与多个 ' 一起出现,ImageId
例如a
and b
。
以下数据必须是可能的:
ID | 图片ID | 图片网址 |
---|---|---|
1 | A | a.com |
2 | A | a.com |
3 | 乙 | b.com |
以下两个示例是不允许的:
ID | 图片ID | 图片网址 |
---|---|---|
1 | A | a.com |
2 | 乙 | a.com |
ID | 图片ID | 图片网址 |
---|---|---|
1 | A | a.com |
2 | A | b.com |
我不知道,也没有找到 MSSQL 解决方案。
问题:有没有解决方案可以在 MSSQL 中强制执行此操作?有没有一个词/术语来表示这种约束/执行?
编辑:这是我现有的包含大量数据的数据库,其中该表是“主”表。我宁愿不通过更改或删除列来更改此表的结构。添加列就好了。这就是为什么 @LeppyR64 的答案不会成为我的用例的解决方案。
正如其他人所建议的,最好的办法是修复模型。通常可以使用视图+代替触发器来实现向后兼容性。
如果不可能并且您的目的是防止添加格式错误的数据,您可以使用触发器:
您可能还应该为更新添加一个
小提琴
使用关系数据库模型可以避免这个问题。转换数据和调整应用程序的痛苦是错误的初始设计所付出的代价。
也就是说,您可以使用物化视图对现有安排强制执行所需的约束:
测试:
输出:
聚集索引键长度的限制为 900 字节,因此仅当ImageId和ImageUrl的组合符合该长度时才有效。
此解决方案为影响视图的每次数据修改增加了少量成本。物化行也有存储要求。另一方面,您可能会发现视图中的信息对其他查询很有帮助。数据库引擎也可以利用它。
db<>小提琴演示
注意事项
数据库引擎负责保持物化视图与基表同步所需的所有细节。
如果您编写自己的解决方案(例如使用触发器),您将负责覆盖高并发下可能发生的所有边缘情况。这并不总是微不足道的。两个会话可能会同时检查冲突行,得出其不存在的结论,然后都在此基础上插入,从而导致未检测到的重复。
另一方面,视图维护中内置的额外安全性是以潜在并发性为代价的。如果基表中的许多行汇总在单个视图行中,则由于这种“锁集中”,可能会发生额外的阻塞。死锁也是一种可能,尽管正确的索引可以缓解这种情况。
维护索引视图通常比触发器稍快,因为维护视图所需的计划运算符被插入到数据更改语句的计划中。触发器需要行版本控制,并且其逻辑在单独的 SQL 上下文中执行。成本与执行额外的 SQL 命令类似。
物化视图在创建时会验证基表中的所有数据。触发器仅适用于在创建触发器之后且保持启用状态时添加或修改的行。默认情况下,对表的批量插入将跳过触发触发器。
这些都是概括,并不是考虑因素的完整列表。您需要在您的环境中测试各种方法。或者过渡到一个好的设计,不需要这些混乱。
创建一个
Images
表。ImageId
是主键。在列上创建额外的唯一索引ImageUrl
。然后,数据表可以将
Id
, 和ImageId
作为图像表的外键。