sql - 如何使用 Postgres 中的 CSV 文件中的值更新选定的行?

标签 sql database postgresql file-io csv

我正在使用 Postgres 并想进行一个大的更新查询,该查询将从 CSV 文件中获取,假设我有一个包含 (id, banana, apple) 的表。

我想运行更新来更改 Bananas 而不是 Apples,每个新 Banana 及其 ID 都将在 CSV 文件中。

我试着查看 Postgres 站点,但这些示例让我很受不了。

最佳答案

COPY文件到临时表并从那里更新实际表。喜欢:

CREATE TEMP TABLE tmp_x (id int, apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

如果导入的表与要更新的表完全匹配,这可能很方便:

CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

创建一个与现有表的结构匹配的空临时表,没有约束。

特权

直到 Postgres 10,SQL COPY 需要 super 用户权限。
在 Postgres 11 或更高版本中,也有一些 predefined roles (以前的“默认角色”)允许它。 The manual:

COPY naming a file or command is only allowed to database superusers or users who are granted one of the roles pg_read_server_files, pg_write_server_files, or pg_execute_server_program [...]

psql 元命令 \copy 适用于任何数据库角色。 The manual:

Performs a frontend (client) copy. This is an operation that runs an SQL COPY command, but instead of the server reading or writing the specified file, psql reads or writes the file and routes the data between the server and the local file system. This means that file accessibility and privileges are those of the local user, not the server, and no SQL superuser privileges are required.

临时表的范围仅限于单个角色的单个 session ,因此以上必须在同一个 psql session 中执行:

CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

如果您在 bash 命令中编写脚本,请务必将其全部包装在一个单个 psql 调用中。喜欢:

echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

通常情况下,你需要元命令\\来在psql元命令和psql中的SQL命令之间切换,但是\copy是这个规则的一个异常(exception)。 The manual again:

special parsing rules apply to the \copy meta-command. Unlike most other meta-commands, the entire remainder of the line is always taken to be the arguments of \copy, and neither variable interpolation nor backquote expansion are performed in the arguments.

大表

如果导入表很大,可能需要为 session 临时增加 temp_buffers( session 中的第一件事):

SET temp_buffers = '500MB';  -- example value

为临时表添加索引:

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

然后运行 ​​ANALYZE手动,因为临时表不在 autovacuum/auto-analyze 范围内。

ANALYZE tmp_x;

相关回答:

关于sql - 如何使用 Postgres 中的 CSV 文件中的值更新选定的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8910494/

相关文章:

SQL 所有行之间的最小间隔

sql - 错误 : aggregate function calls cannot be nested

mongodb - mongorestore 可以采用单个 url 参数而不是单独的参数吗?

ruby-on-rails - 如何在 ActiveRecord 中加入 SUM

php - 需要一个高效的 mysql 数据库模式来存储积分/评级

mysql - Clojure QL : running plain SQL queries

Django 1.2 PostgreSQL 使用 ON DELETE NO ACTION 级联删除键

php - 准备语句和SQL结果不同

sql - 在 SQL 中选择最小日期或空值

mysql - 有没有办法在没有第二次查询的情况下执行此条件 JOIN?