ON CONFLICT DO UPDATE缺少FROM子句

时间:2016-02-02 17:00:12

标签: sql postgresql postgresql-9.5

我有一个简单的表(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 个答案:

答案 0 :(得分:12)

如果你看一下the documentation of the ON CONFLICT clause,它会说明"冲突行动":

  

ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行

在您的查询中,目标表为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

如果为此目的弹出一个虚构的表名称似乎很奇怪,请考虑在编写触发器时发生类似的事情,在此处获得NEWtype(取决于您的触发类型) #39;重写)。