UPSERT - INSERT ... ON CONFLICT 失败,基于函数的索引作为 'lower()' 唯一约束
UPSERT - INSERT ... ON CONFLICT fails with a function based index as 'lower()' unique constraint
我有一个数据库 table,它有一个 code
列,该列使用小写索引来防止代码值仅大小写不同(例如 'XYZ' = 'xYZ' = 'xyz')。 Postgresql 中的典型方法是创建一个基于函数的索引,如下所示:CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code))
.
现在我遇到一个情况,我需要对该列进行更新插入行为:
-- 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 与表达式的索引一起工作?还是我必须引入物理索引小写列才能完成任务?
尝试按如下方式添加索引:
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';
使用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
where conflict_target
can be one of:
( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
ON CONSTRAINT constraint_name
and index_expression
:
Similar to index_column_name, but used to infer expressions on
table_name columns appearing within index definitions (not simple
columns). Follows CREATE INDEX format.
我有一个数据库 table,它有一个 code
列,该列使用小写索引来防止代码值仅大小写不同(例如 'XYZ' = 'xYZ' = 'xyz')。 Postgresql 中的典型方法是创建一个基于函数的索引,如下所示:CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code))
.
现在我遇到一个情况,我需要对该列进行更新插入行为:
-- 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 与表达式的索引一起工作?还是我必须引入物理索引小写列才能完成任务?
尝试按如下方式添加索引:
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';
使用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
whereconflict_target
can be one of:( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ] ON CONSTRAINT constraint_name
and
index_expression
:Similar to index_column_name, but used to infer expressions on table_name columns appearing within index definitions (not simple columns). Follows CREATE INDEX format.