带有谓词的 Postgresql EXCLUDE 约束:意外结果

Postgresql EXCLUDE constraint with a predicate : unexpected result

我试图通过添加 PREDICATE.

进一步 Postgresql's EXCLUDE example

在一种情况下,它的工作方式与我预期的一样。 另一种情况……不是这样

第一个示例,谓词为“cage”。工作正常:

=> CREATE TABLE zoo(
    cage     INTEGER,
    animal   TEXT,
    EXCLUDE USING GIST (cage WITH =, animal WITH <>) WHERE (cage = 1)
);
CREATE TABLE

=> INSERT INTO zoo VALUES (1, 'zebra');
INSERT 0 1

=> INSERT INTO zoo VALUES (2, 'lion');
INSERT 0 1

=> INSERT INTO zoo VALUES (1, 'lion');
ERROR:  conflicting key value violates exclusion constraint "zoo_cage_animal_excl"
DETAIL:  Key (cage, animal)=(1, lion) conflicts with existing key (cage, animal)=(1, zebra).

到目前为止,还不错。 (1, lion) 确实与 (1, zebra).

冲突

第二个例子,谓词是“动物”。意外结果:

=> CREATE TABLE zoo(
        cage     INTEGER,
        animal   TEXT,
        EXCLUDE USING GIST (cage WITH =, animal WITH <>) WHERE (animal = 'lion')
    );
    CREATE TABLE

    => INSERT INTO zoo VALUES (1, 'zebra');
    INSERT 0 1

    => INSERT INTO zoo VALUES (2, 'lion');
    INSERT 0 1

    => INSERT INTO zoo VALUES (2, 'zebra');
    INSERT 0 1

为什么最后一条语句没有引发冲突错误?

WHERE (animal = 'lion') 构建部分 GIST 索引。 最后一行 ((2, zebra)) 应与现有行 (2, lion) 冲突(同一个笼子,不同的动物:2 = 2zebra <> lion)。

那么 PostgreSQL 为什么允许插入这一行 (2, zebra)

'zebra' <> 'lion' 起,zebra 记录未包含在部分索引中。

实际上只有 lion 条记录包含在部分索引中。

'lion' <> 'lion' 永远不会为真,因此永远不会满足 exclude 条件。