我有一个带有code
列的数据库表,它使用小写索引来防止代码值只有大小写不同(例如'XYZ'='xYZ'='xyz')。 Postgresql中的典型方法是创建一个基于函数的索引,如下所示:CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code))
。
现在我有一个案例,我需要在该列上进行upsert行为:
-- first insert
INSERT INTO mytable (code) VALUES ('abcd');
-- second insert, with upsert behaviour
INSERT INTO mytable (code) VALUES ('Abcd')
ON CONFLICT (code) DO UPDATE
SET code='Abcd';
对于第二个插入,我得到一个唯一的密钥违规:ERROR: duplicate key value violates unique constraint "mytable_lower_code_idx"
(我也尝试使用ON CONFLICT ON CONSTRAINT mytable_lower_code_idx
,但Postgresql告诉我这个约束不存在所以也许它不会将索引视为约束。)
我的最后一个问题:有没有办法让INSERT ... ON CONFLICT与表达式的索引一起工作?或者我必须引入物理索引的小写列来完成任务吗?
使用ON CONFLICT (lower(code)) DO UPDATE
:
CREATE TABLE mytable (
code text
);
CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code));
INSERT INTO mytable VALUES ('abcd');
INSERT INTO mytable (code) VALUES ('Abcd')
ON CONFLICT (lower(code)) DO UPDATE
SET code='Abcd';
SELECT * FROM mytable;
产量
| code |
|------|
| Abcd |
请注意,ON CONFLICT
syntax允许冲突目标是index_expression
(我的重点):
ON CONFLICT conflict_target
其中conflict_target
可以是以下之一:( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ] ON CONSTRAINT constraint_name
和
index_expression
:与index_column_name类似,但用于推断出现在索引定义(非简单列)中的table_name列上的表达式。遵循CREATE INDEX格式。
尝试添加索引如下:
CREATE UNIQUE INDEX CONCURRENTLY mytable_lower_code_idx
ON mytable (lower(code));
ALTER TABLE mytable
ADD CONSTRAINT unique_mytab_code
UNIQUE USING INDEX mytable_lower_code_idx ;
接着:
INSERT INTO mytable (code) VALUES ('abcd');
-- second insert, with upsert behaviour
INSERT INTO mytable (code) VALUES ('Abcd')
ON CONFLICT ON CONSTRAINT unique_mytab_code DO UPDATE
SET code='Abcd';