带有比较谓词的PostgreSQL排除约束

时间:2018-01-15 04:05:41

标签: postgresql

很容易模仿像

这样的唯一约束
create table foo(x int, exclude (x with =));

但是如何使用IS NOT DISTINCT FROM代替=(因此表中只有一个NULL值?)

创建f(anyelement, anyelement)之类的函数并且运算符失败,因为null具有未知类型。还有一个问题:是否可以将IS NOT DISTINCT FROM谓词包装到PostgreSQL中的运算符中?

要有耐心,我不是在寻找替代解决方案,我知道很多:)

另外阅读:enter image description here

1 个答案:

答案 0 :(得分:3)

很容易创建一个与NOT DISTINCT TO对应的函数和运算符:

CREATE FUNCTION ndist(anyelement, anyelement) RETURNS boolean
   IMMUTABLE CALLED ON NULL INPUT LANGUAGE sql
   AS 'SELECT $1 IS NOT DISTINCT FROM $2';

CREATE OPERATOR === (
   PROCEDURE = ndist,
   LEFTARG = anyelement,
   RIGHTARG = anyelement,
   COMMUTATOR = "==="
);

如果两个参数都是无类型的NULL,则会失败:

test=> SELECT NULL === NULL;
ERROR:  could not determine polymorphic type because input has type unknown

一种解决方案是使用重载并为您需要的每种类型定义相同的函数和运算符:

CREATE FUNCTION ndist(integer, integer) RETURNS boolean
   IMMUTABLE CALLED ON NULL INPUT LANGUAGE sql
   AS 'SELECT $1 IS NOT DISTINCT FROM $2';

CREATE FUNCTION ndist(text, text) RETURNS boolean
   IMMUTABLE CALLED ON NULL INPUT LANGUAGE sql
   AS 'SELECT $1 IS NOT DISTINCT FROM $2';

CREATE OPERATOR === (
   PROCEDURE = ndist,
   LEFTARG = integer,
   RIGHTARG = integer,
   COMMUTATOR = "==="
);

CREATE OPERATOR === (
   PROCEDURE = ndist,
   LEFTARG = text,
   RIGHTARG = text,
   COMMUTATOR = "==="
);

然后该示例将起作用:

test=> SELECT NULL === NULL;
 ?column? 
----------
 t
(1 row)

这是因为在这种情况下,类型解析规则更倾向于text上的运算符。

但所有这些都不允许您创建排除约束,因为您的运算符与运算符类没有关联,这对于确定要使用哪种索引是必要的。

您必须为每个btree index method strategies创建匹配函数,并使用这些函数为btree定义运算符类。