如何在Postgresql查询中使用多个“唯一索引推断”

问题描述 投票:2回答:1

在Postgresql 9.6 DB中,有一个名为X的现有表有四列,abcd,索引设置如下:

"uidx_a_b" UNIQUE, btree (a, b) WHERE c IS NULL AND d IS NULL
"uidx_a_c" UNIQUE, btree (a, b, c) WHERE c IS NOT NULL AND d IS NULL
"uidx_a_d" UNIQUE, btree (a, b, c, d) WHERE c IS NOT NULL AND d IS NOT NULL

我不知道为什么要这样做,因为它是由一个早已离去的人在我不得不修改它之前完成的。

我试图让语法正确,以便在ON CONFLICT语句中指定所有这三个。我尝试了所有错误的变化。 Postgresql Documentation表明这是可能的,特别是在[, ...]中描述的conflict_target

( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) 

此外,来自其中一位提交者的blog也这么说。最后,我再次看着this unit test for the functionality无济于事!因此放弃了,我转向SO寻求帮助。

这是我认为最接近我应该工作的语法:

ON CONFLICT (
((a, b) WHERE c IS NULL AND d IS NULL),
((a, b, c) WHERE c IS NOT NULL AND d IS NULL),
((a, b, c, d) WHERE release_id IS NOT NULL AND d IS NOT NULL)
)

然而,这失败了:

ERROR: syntax error at or near ","

虽然我愿意提出改进这些索引的design的建议,但我真的想知道是否有一个有效的语法来指定ON CONFLICT子句,因为它似乎应该存在!

postgresql insert sql-insert
1个回答
1
投票

在下面我指的是the documentation的语法描述:

ON CONFLICT [ conflict_target ] conflict_action

其中conflict_target可以是以下之一:

( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ] ON CONSTRAINT constraint_name

INSERT ... ON CONFLICT只允许一个conflict_target[, ...]意味着可以指定多个列或表达式(表示单个条件),如下所示:

ON CONFLICT (col1, (col2::text), col3)

此外,如果它是一个部分指数,WHERE条件必须由index_predicate暗示。

所以,你可以做什么?

您可以按照@joop的建议找到cd列中不会出现的值。

然后您可以用以下内容替换三个索引:

CREATE UNIQUE INDEX ON x (a, b, coalesce(c, -1), coalesce(d, -1));

然后conflict_target将成为:

ON CONFLICT (a, b, coalesce(c, -1), coalesce(d, -1))
© www.soinside.com 2019 - 2024. All rights reserved.