PostgreSQL 9.4-在排除约束中使用自定义运算符

PostgreSQL 9.4-在排除约束中使用自定义运算符,postgresql,postgresql-9.4,Postgresql,Postgresql 9.4,查看后,我创建了以下自定义运算符: CREATE OR REPLACE FUNCTION is_not_distinct_from( ANYELEMENT, ANYELEMENT ) RETURNS BOOLEAN AS $$ SELECT $1 IS NOT DISTINCT FROM $2; $$ LANGUAGE sql IMMUTABLE; CREATE OPERATOR =!= ( PROCEDURE = is_not_distinct_from(anye

查看后,我创建了以下自定义运算符:

CREATE OR REPLACE FUNCTION is_not_distinct_from(
    ANYELEMENT, 
    ANYELEMENT
)
RETURNS BOOLEAN AS
$$
SELECT $1 IS NOT DISTINCT FROM $2;
$$
LANGUAGE sql 
IMMUTABLE;

CREATE OPERATOR =!= (
    PROCEDURE = is_not_distinct_from(anyelement,anyelement),
    LEFTARG  = anyelement,
    RIGHTARG = anyelement,
    COMMUTATOR = =!=,
    NEGATOR = <!>
);

CREATE OR REPLACE FUNCTION is_distinct_from(
    ANYELEMENT, 
    ANYELEMENT
)
RETURNS BOOLEAN AS
$$
SELECT $1 IS DISTINCT FROM $2;
$$
LANGUAGE sql 
IMMUTABLE;

CREATE OPERATOR <!> (
    PROCEDURE = is_distinct_from(anyelement,anyelement),
    LEFTARG  = anyelement,
    RIGHTARG = anyelement,
    COMMUTATOR = <!>,
    NEGATOR = =!=
);
我得到以下错误:

错误:运算符==(anyelement,anyelement)不是 运算符系列“datetime_ops”详细信息:排除运算符必须为 与约束的索引运算符类相关

我已经审阅了文档(和),但我很难理解这些材料


此外,可将其视为本文件的副本;然而,这个问题的一个问题是与其他RDBMS的兼容性这个问题专门针对如何处理上述错误。

您选择了一个真正的考验。使用一个唯一的索引,它更简单、更安全、更快

CREATE TABLE foo (
    foo_id serial PRIMARY KEY,
    foo text NOT NULL,
    bar timestamptz,
    baz timestamptz
);
CREATE TABLE

CREATE UNIQUE INDEX foo_foo_bar_baz_idx ON foo 
(foo, coalesce(bar, 'infinity'), coalesce(baz, 'infinity'));
CREATE INDEX

INSERT INTO foo VALUES
(default, '', null, null),
(default, '', now(), null),
(default, '', null, now());
INSERT 0 3

INSERT INTO foo VALUES
(default, '', null, null);
ERROR:  duplicate key value violates unique constraint "foo_foo_bar_baz_idx"
DETAIL:  Key (foo, (COALESCE(bar, 'infinity'::timestamp with time zone)), (COALESCE(baz, 'infinity'::timestamp with time zone)))=(, infinity, infinity) already exists.

我试图避免在函数索引中使用
coalesce()
,而是坚持
EXCLUDE
约束;然而,你说你的答案更简单、更安全、更快,但其他的就不多了。。。请您解释一下所请求方法的问题好吗?
Exclude
创建一个唯一索引。那么,如果使用一条语句可以获得类似的结果,为什么还要定义自己的运算符、运算符类和索引类型呢?我认为没有理由避免
合并()
,因为
是不同的
实际上可以归结为同一件事。为什么更安全?代码越少,麻烦就越少。@losshorse另外,现有的功能比自定义代码要经过大量测试。我同意你的推理(代码越少,麻烦就越少)@jpmc26也提出了一个令人信服的观点。。。我同意你们两位的观点,
coalesce()
可能是更好的选择(在这种情况下);但是,您的回答未能回答所提出的问题。。。如果您可以扩展您的答案,以包括如何将自定义运算符绑定到索引(可能有一个示例),那么我将排除它。对于给定的数据和索引类型,您应该这样做。但是,必须非常小心,除非定义了索引实现中预期的所有运算符和函数,否则不要覆盖现有的默认运算符类。这不是一项琐碎的任务,您应该有非常重要的理由来尝试处理它。没有和,opclass文档是非常无用的。
btree_gist
扩展的
timestamp
的gist实现是,并且,为了让您了解您要进入的内容。FWIW,排除约束似乎不是必需的;我认为这样的约束(理论上)应该可以通过一个唯一的索引和一个定制的B树类来实现。但是我,它似乎不起作用。我怀疑空值的处理是硬连接到索引方法中的。不确定一个类是否会有任何不同。
CREATE TABLE foo (
    foo_id serial PRIMARY KEY,
    foo text NOT NULL,
    bar timestamptz,
    baz timestamptz
);
CREATE TABLE

CREATE UNIQUE INDEX foo_foo_bar_baz_idx ON foo 
(foo, coalesce(bar, 'infinity'), coalesce(baz, 'infinity'));
CREATE INDEX

INSERT INTO foo VALUES
(default, '', null, null),
(default, '', now(), null),
(default, '', null, now());
INSERT 0 3

INSERT INTO foo VALUES
(default, '', null, null);
ERROR:  duplicate key value violates unique constraint "foo_foo_bar_baz_idx"
DETAIL:  Key (foo, (COALESCE(bar, 'infinity'::timestamp with time zone)), (COALESCE(baz, 'infinity'::timestamp with time zone)))=(, infinity, infinity) already exists.