SQL Upsert 语句不适用于非索引列

标签 sql postgresql

我正在使用 PostgreSQL v9.6.6。我正在运行以下 SQL:

insert into t_vs_config_key (name, description, is_brand_dependent)
  values ('ucp.cluster','UCP Cluster', true)
  ON CONFLICT (name) DO UPDATE SET is_brand_dependent=true;

这会导致以下错误,因为 name 列没有被索引为唯一的。我无法添加索引,因为存在不唯一的现有数据。

ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification

问题 有什么想法如何在没有索引的情况下执行 upsert 语句?

谢谢

最佳答案

正如评论中已经提到的,没有唯一索引就不能使用ON CONFLICT

但是,您可以通过向表中添加一个新列来指示行是否有效并根据该标志创建部分唯一索引来确保 future 的插入是唯一的:

alter t_vs_config_key 
  add column valid boolean not null default false;

这会将所有现有行初始化为 valid = false

现在对于 future 的行,将此列的默认值更改为 true

alter table t_vs_config_key
    alter column valid set default true;

并通过添加检查约束确保不再可以插入“无效”行:

alter table t_vs_config_key  
  add constraint check_valid check (valid);

现在您可以创建唯一索引:

create unique index on t_vs_config_key(name)
where valid;

可用于 on conflict 子句:

insert into t_vs_config_key (name, description, is_brand_dependent)
values ('ucp.cluster','UCP Cluster', true)
ON CONFLICT (name) where valid DO UPDATE 
  SET is_brand_dependent = true;

注意语句中的 where valid 子句。

关于SQL Upsert 语句不适用于非索引列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52185331/

相关文章:

mysql - 选择列值以字符串开头且不以字符串开头的行

mysql - Sequelize 等效范围

sql - 查询以获取每个数据库的日期时间

sql - 如何在 PostgreSQL 中按类别选择具有最大日期组的 ID?

sql - 错误 : syntax error at or near "AS" - What am I doing wrong?

C# Sql 跨页面连接字符串

sql - Access VBA : Run-time error '94' : Invalid use of Null

sql - 查询 Clickhouse 当前安装的版本

ruby-on-rails - 字符编码,如何区分?

ruby-on-rails - ActiveRecord 检查数组中的任何值是否与 postgres 中的数组中的值匹配