我有一张桌子,看起来像这样:

CREATE TABLE IF NOT EXISTS list (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tok TEXT,
  sid TEXT NOT NULL,
  aid TEXT,
  hash TEXT,
  qtt SMALLINT,
  p DECIMAL,

  UNIQUE (tok, sid, aid),
  UNIQUE (sid, qtt, hash)
);

我想用node-pg创建一个动态插入函数,其查询大致如下所示:

INSERT (tok, sid, aid, qtt, hash, p)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (tok, sid, aid, qtt, hash)
DO UPDATE SET p = $6;

当我try 插入值(NULL, string, NULL, int, string, decimal)(与某个组合键匹配的值)时,会抛出以下错误:

错误:没有与ON冲突规范匹配的唯一或排除约束.

这与node-pg关系不大,但看起来我是如何创建INSERT查询本身的.我的意图是使用单个upsert查询来处理这两种"UNIQUE类型"的列表项.在冲突的情况下,没有其他关于组合唯一的问题给出了关于如何使用具有重叠列的组合键的确切答案.

假设只有与其中一个唯一键匹配的行,我应该如何处理INSERT或约束才能使其正常工作?有没有办法也让它保持一个动态的单一查询解决方案?

推荐答案

INSERT ... ON CONFLICT ...DO UPDATE版本适用于single个"冲突目标".The manual:

对于ON CONFLICT DO NOTHING,可以 Select 指定 101;如果省略,则处理与所有可用约束(和唯一索引)的冲突.对于ON CONFLICT DO UPDATE,必须提供101.

您不能将来自多个UNIQUE个约束的列合并为一个"冲突目标".这使得postgres在所有五列上查找single多列约束,但该约束并不存在,并导致您报告的错误消息.

ON CONFLICT (tok, sid, aid, qtt, hash)

你可以用ON CONFLICT ... DO NOTHING来"判断",它会处理所有的约束,包括你提到的两个约束.但这只会 suppress 异常,并不能避免稍后的UPDATE可能出现的竞争条件.没有干净的"一次查询解决方案".

设计问题

你想要的工作流程本身就有缺陷.

如果只违反了这两个唯一约束中的一个,然后更新了Value列,而不更新其他列,则会使结果状态变得可疑.该行以其余列的不同(预先存在的)值结束,这反过来将触发对下一个INSERT列的不同值的唯一违规.批量UPSERT的结果突然取决于输入行的顺序.

此外,two行可能一次引发唯一的违规.哪些将被更新?(UPSERT是围绕更新one的前提构建的.真是一团糟

干净的解决方案是two separate tables个,每个one个PK.

或者一张桌子大概two mutually exclusive partial unique indexes张.所有列都是nullable,除了sid是两个唯一索引的交集.这将指向那个方向.是否每行只有(tok, aid)(qtt, hash)中的一个?

幸运的是,您运行Postgres 15 or later,并且可以使用NULLS NOT DISTINCT子句将两个唯一约束合并为一个:

ALTER TABLE list
  DROP CONSTRAINT list_sid_qtt_hash_key
, DROP CONSTRAINT list_tok_sid_aid_key
, ADD CONSTRAINT list_uni_key UNIQUE NULLS NOT DISTINCT (sid, qtt, hash, tok, aid);

然后你所有的问题都会消失. 请参见:

相关:

Node.js相关问答推荐

即使DDB键不存在, node Lambda也不会失败,并返回NULL作为结果

使用xml-crypto时出现NodeJS XPath解析错误

根据我的测试,为什么在编写Varint代码方面,NodeJS要比Rust快这么多?

设置默认 node 版本

如何修复PostgreSQL和NodeJS/NestJS应用程序之间的日期时间和时区问题?

如何使用 Node.js 连接到 Cloud SQL?

PEAN auth 应用程序:为什么 Angular 拦截器总是使用BehaviorSubject 返回 null(即初始值),而不是更新后的值?

Redis Typescript 删除方法类型转换

如何修复node.js中的错误代码无法加载资源:服务器响应状态为403(禁止)

express app.post的多个参数在Node.js中的定义是什么

如何在 node /快速服务器上配置 mongoDB

为什么它无法发送发布请求并更改为 chrome 中的获取方法?

每个数组值在 mongodb 中查找一个文档

多字段传递获取查询失败

Nodejs mongoose 在一个查询中从多个集合中获取结果

JSHint 是否支持异步/等待?

使用 Webpack 和 font-face 加载字体

如何在离线时安装 npm 包?

nodejs:Ajax 与 Socket.IO,优缺点

Mongoose - 验证邮箱语法