首页 > 解决方案 > MSSQL 命名空间约束

问题描述

在 SQL Server 上,我有一个表命名空间

Namespace
---------
Prefix
com.foo
com.bar
com.foobar

如果已经存在冲突的命名空间,我想防止插入。命名空间包括所有子命名空间。例如 com.foo 包括所有“低于” com.foo 例如 com.foo.bar 和 com.foo.bar.baz 但不包括 com.foobar 或 com.foobar.baz(com.foobar 是与 com.foo 不同的命名空间)

检查应该是原子的,以防止并发问题。

我有这个插入有条件的插入。但我不确定它是否是原子的。

INSERT INTO namespace
(PREFIX)
SELECT t1.PREFIX
FROM namespace t1
WHERE NOT EXISTS(SELECT t2.PREFIX
                 FROM namespace t2
                 WHERE t2.PREFIX in ('com.foo.bar','com.foo','com'))

这里的评论https://stackoverflow.com/a/16636779/1844551表明 Postgres 不能保证是原子的。MSSQL 怎么样?

理想情况下,这将是一个检查约束,但我不知道如何where t2.PREFIX in ('com.foo.bar','com.foo','com')从像com.foo.bar.

注意:一个简单的 startwith 并不能解决问题,因为com.foo它们com.foobar是不同的命名空间,它们不会相互冲突。所以如果存在com.foobar就可以插入。com.foo

所以我目前的想法是在客户端代码中实现这个查询并检查结果是否插入了一些东西。

有没有更好的方法在数据库中实现这一点作为约束?

标签: sqlsql-server

解决方案


如果您想检查与 this 的冲突insert

INSERT INTO namespace (PREFIX)
    SELECT v.PREFIX
    FROM (VALUES ('com.foo.bar')) v(prefix);

您可以使用:

INSERT INTO namespace (PREFIX)
    SELECT v.PREFIX
    FROM (VALUES ('com.foo.bar')) v(prefix)
    WHERE NOT EXISTS (SELECT 1
                      FROM namespace n
                      WHERE v.prefix LIKE n.prefix + '.%'
                     );

我想不出一种简单的方法来实现这个逻辑作为一个约束。这基本上留下了三个选择:

  • 使用上面的手动编码,可能嵌入到存储过程中。
  • 使用触发器。
  • 使用带有check约束的用户定义函数。

推荐阅读