【问题标题】:PostgreSQL 9.4 - Use custom operator in EXCLUDE constraintPostgreSQL 9.4 - 在 EXCLUDE 约束中使用自定义运算符
【发布时间】:2015-12-22 02:09:49
【问题描述】:

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

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 = =!=
);

我有一个允许两个NULL 值的表,我想防止重复记录,将NULL 视为一个值。

CREATE TABLE "Foo" (
    "FooID" SERIAL PRIMARY KEY,
    "Foo" TEXT NOT NULL,
    "Bar" TIMESTAMPTZ
    "Baz" TIMESTAMPTZ
    EXCLUDE ("Foo" WITH =, "Bar" WITH =!=, "Baz" WITH =!=)
);

我收到以下错误:

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

我已经查看了文档(herehere),但我很难理解这些材料。

另外,this question 可以被认为是这个的副本;但是,该问题中的问题在于与其他 RDBMS 的兼容性...此问题专门针对如何处理上述错误。

【问题讨论】:

  • 如果没有thisthis,opclass 文档将毫无用处。 btree_gist 扩展对 timestamp 的 GiST 实现是 herehere,只是为了让您了解您要进入的内容。
  • FWIW,排除约束似乎没有必要;我认为像这样的约束应该(理论上)可以通过唯一索引和自定义 B 树操作类来实现。但是我tried it,它似乎不起作用。我怀疑空值的处理是硬连线到索引方法中的。不确定 GiST opclass 是否会有所不同。

标签: postgresql postgresql-9.4


【解决方案1】:

你选择了真正的考验。使用唯一索引,这样更简单、更安全、更快捷。

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 创建一个唯一索引。那么,如果使用一个语句可以实现类似的结果,为什么还要定义自己的运算符、运算符类别和索引类型呢?我认为没有理由避免coalesce (),因为IS DISTINCT 实际上归结为同一件事。为什么更安全?代码越少,麻烦就越少。
  • @loshorse 此外,现有功能的测试比自定义代码要严格得多。
  • 我同意你的推理(更少的代码,更少的麻烦),@jpmc26 也提出了一个令人信服的观点......我同意你俩,coalesce() 可能是更好的选择(在这种情况下);但是,您的回答未能回答所提出的问题......如果您可以扩展您的答案以包括如何将自定义运算符与索引联系起来(也许有一个示例),那么我会排除它。
  • 对于给定的数据和索引类型,您应该 create operator class。您必须非常小心,但不要覆盖现有的默认运算符类,除非您定义了索引实现中预期的所有运算符和函数。这不是一项微不足道的任务,您应该有非常重要的理由来尝试处理它。
猜你喜欢
  • 2014-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 2019-10-24
  • 2015-07-13
相关资源
最近更新 更多