Geo*_*e L 7 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;
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
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"
Run Code Online (Sandbox Code Playgroud)
不太清楚这里出了什么问题.
IMS*_*SoP 14
如果你查看该ON CONFLICT条款的文档,它会说"冲突行动":
ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行
在您的查询中,目标表是repos.
tmp_x另一方面,是您尝试插入的数据的来源,但该ON CONFLICT条款无法"看到" - 它正在查看已计算并失败的特定行.考虑一下你是否写过这样的东西:
INSERT INTO repos SELECT max(foo_id) FROM tmp_x
Run Code Online (Sandbox Code Playgroud)
显然,对于未能插入的行来说,repos访问任何一行都没有意义tmp_x.
如果没有办法看到被拒绝的数据,整个功能将毫无用处,但如果我们继续阅读:
...以及使用特殊排除表建议插入的行.
因此,您需要访问魔术表别名excluded,该别名包含您尝试插入的值但发生冲突,为您提供:
INSERT INTO repos SELECT * FROM tmp_x
ON CONFLICT(name) DO UPDATE SET name = excluded.name;
Run Code Online (Sandbox Code Playgroud)
如果它似乎不可思议的是一个虚构的表名用于此目的弹出,考虑编写触发器,当你当了类似的事情发生OLD,并NEW(根据其种类你写触发).