我有一个简单的表(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"
不太清楚这里出了什么问题。
答案 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
如果为此目的弹出一个虚构的表名称似乎很奇怪,请考虑在编写触发器时发生类似的事情,在此处获得NEW
和type
(取决于您的触发类型) #39;重写)。