ON CONFLICT DO UPDATE 缺少 FROM 子句
Posted
技术标签:
【中文标题】ON CONFLICT DO UPDATE 缺少 FROM 子句【英文标题】:ON CONFLICT DO UPDATE has missing FROM-clause 【发布时间】:2016-05-11 14:38:26 【问题描述】:我有一个简单的表(id 和 name 列,都是唯一的),我正在导入一个制表符分隔的 CSV 文件。
我正在运行 psql 9.5,并且想尝试新的ON CONFLICT
功能来更新名称列(如果 ID 已存在)。
CREATE TEMP TABLE tmp_x AS SELECT * FROM repos LIMIT 0;
COPY tmp_x FROM '/Users/George/git-parser/repo_file' (format csv, delimiter E'\t');
INSERT INTO repos SELECT * FROM tmp_x
ON CONFLICT(name) DO UPDATE SET name = tmp_x.name;
DROP TABLE tmp_x;
我收到此错误:
SELECT 0
COPY 1
ERROR: missing FROM-clause entry for table "tmp_x"
LINE 4: ON CONFLICT(name) DO UPDATE SET name = tmp_x.name;
^
Query failed
PostgreSQL said: missing FROM-clause entry for table "tmp_x"
不太清楚这里出了什么问题。
【问题讨论】:
【参考方案1】:如果您查看the documentation of the ON CONFLICT
clause,它会说“冲突行动”:
ON CONFLICT DO UPDATE 中的 SET 和 WHERE 子句可以使用表名(或别名)访问现有行
在您的查询中,目标表是repos
。
另一方面,tmp_x
是您尝试插入的数据的来源,但 ON CONFLICT
子句无法“看到”这一点 - 它正在查看已计算且失败的特定行。考虑一下你是否写过这样的东西:
INSERT INTO repos SELECT max(foo_id) FROM tmp_x
显然,未能插入repos
的行访问tmp_x
中的任何一行是没有意义的。
如果无法查看被拒绝的数据,那么整个功能将毫无用处,但如果我们继续阅读:
... 以及建议使用特殊排除表插入的行。
因此,您需要访问魔术表别名excluded
,其中包含您尝试插入但发生冲突的值,为您提供以下信息:
INSERT INTO repos SELECT * FROM tmp_x
ON CONFLICT(name) DO UPDATE SET name = excluded.name;
如果为此目的弹出一个假想的表名看起来很奇怪,请考虑在编写触发器时发生类似的事情,您会得到OLD
和NEW
(取决于您正在编写的触发器的类型) .
【讨论】:
请注意,在第二个示例中,最好使用ON CONFLICT DO NOTHING
代替(尽管我知道 OP 可能不想这样做)。
我刚才遇到了这个问题,并在谷歌中输入了一个查询,没有抱太大希望。我很高兴得到你的回答。谢谢!以上是关于ON CONFLICT DO UPDATE 缺少 FROM 子句的主要内容,如果未能解决你的问题,请参考以下文章
Postgresql on conflict do update 设置当前值,原始值,当前值与原始值相加值
在 clickhouse 上类似 ON CONFLICT DO NOTHING
POSTGRES - 使用 ON CONFLICT DO NOTHING 防止串行增量 [重复]
PostgreSQL INSERT ON CONFLICT UPDATE (upsert) 使用所有排除值