database - 通过命令行插入 SQL 语句而无需重新打开与远程数据库的连接

标签 database postgresql shell connection psql

我有大量数据文件要处理并存储在远程数据库中。数据文件的每一行代表数据库中的一行,但在插入数据库之前必须格式化。

我的第一个解决方案是通过编写bash脚本处理数据文件并生成SQL数据文件,然后将转储的SQL文件导入数据库。这个解决方案似乎太慢了,正如您所看到的,它涉及创建中间 SQL 文件的额外步骤。

我的第二个解决方案是编写 bash 脚本,在处理数据文件的每一行时,创建 INSERT INTO ... 语句并将 SQL 语句发送到远程数据库:

回显 sql_statement | psql -h remote_server -U 用户名 -d 数据库

即不创建 SQL 文件。但是,此解决方案有一个主要问题,我正在寻找相关建议:
每次我都必须重新连接到远程数据库才能插入一行。

有没有一种方法可以连接到远程数据库,保持连接状态,然后“通过管道”或“发送”insert-SQL 语句,而无需创建巨大的 SQL 文件?

最佳答案

回答您的实际问题

。您可以使用 named pipe而不是创建文件。考虑以下演示。

在我的数据库 event 中创建一个模式 x 用于测试:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.x (id int, a text);

像这样从 shell 创建命名管道 (fifo):

postgres@db:~$ mkfifo --mode=0666 /tmp/myPipe

1) 在服务器上使用命名管道调用 SQL 命令COPY:

postgres@db:~$ psql event -p5433 -c "COPY x.x FROM '/tmp/myPipe'"

这将在数据库中的表 x.x 上获得一个独占锁。连接保持打开状态,直到 fifo 获取数据。小心不要让它打开太久!您可以在填充管道后调用它,以最大限度地减少阻塞时间。您可以选择事件的顺序。一旦两个进程绑定(bind)到管道,该命令就会执行。第一个等待第二个。

或者2)您可以从管道在客户端执行SQL:

postgres@db:~$ psql event -p5433 -f /tmp/myPipe

这更适合您的情况。此外,在执行 SQL 之前,不会锁定任何表。

Bash 将被阻止。它正在等待管道的输入。要从一个 bash 实例完成所有操作,您可以将等待进程发送到后台。像这样:

postgres@db:~$ psql event -p5433 -f /tmp/myPipe 2>&1 &

无论哪种方式,从同一个 bash 或不同的实例,您现在都可以填充管道
变体 1) 的三行演示:

postgres@db:~$ echo '1  foo' >> /tmp/myPipe; echo '2    bar' >> /tmp/myPipe; echo '3    baz' >> /tmp/myPipe;

(小心使用制表符作为分隔符或指示 COPY 使用 WITH DELIMITER 'delimiter_character' 接受不同的分隔符)
这将触发带有 COPY 命令的挂起的 psql 执行并返回:

COPY 3

变体 2) 的演示:

postgres@db:~$ (echo -n "INSERT INTO x.x VALUES (1,'foo')" >> /tmp/myPipe; echo -n ",(2,'bar')" >> /tmp/myPipe; echo ",(3,'baz')" >> /tmp/myPipe;)

INSERT 0 3

完成后删除命名管道:

postgres@db:~$ rm /tmp/myPipe

检查是否成功:

event=# select * from x.x;
 id |         a
----+-------------------
  1 | foo
  2 | bar
  3 | baz

上面代码的有用链接

Reading compressed files with postgres using named pipes
Introduction to Named Pipes
Best practice to run bash script in background


你可能需要也可能不需要的建议

对于批量 INSERT,您有比单独的 INSERT 更好的解决方案每行。使用此语法变体:

INSERT INTO mytable (col1, col2, col3) VALUES
 (1, 'foo', 'bar')
,(2, 'goo', 'gar')
,(3, 'hoo', 'har')
...
;

将您的语句写入文件并执行大量INSERT,如下所示:

psql -h remote_server -U username -d database -p 5432 -f my_insert_file.sql

(5432 或数据库集群正在监听的任何端口)
my_insert_file.sql 可以包含多个 SQL 语句。事实上,像这样恢复/部署整个数据库是很常见的做法。咨询manual about the -f参数,或者在 bash 中:man psql

或者,如果您可以将(压缩的)文件传输到服务器,您可以使用 COPY 更快地插入(解压缩的)数据。

您还可以在 PostgreSQL 中进行部分或全部处理。为此,您可以COPY TO(或INSERT INTO)一个临时表并使用纯SQL 语句准备并最终插入/更新您的表。我经常这样做。请注意,临时表随 session 而生死。

您可以使用类似 pgAdmin 的 GUI舒适的处理。 SQL 编辑器窗口中的 session 保持打开状态,直到您关闭该窗口。 (因此,临时表会一直存在,直到您关闭窗口。)

关于database - 通过命令行插入 SQL 语句而无需重新打开与远程数据库的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7849232/

相关文章:

java - 在 Android 中获取新插入的联系人

sql - 从表中复制 "sliding window"数据的好策略?

bash - 设置 -e 选项后如何避免 bash 脚本失败?

Bash:如何像输入文件一样命名 gs 输出文件,但使用不同的文件扩展名?

database - 当我想使用 db-migration 更新数据库时如何防止数据丢失?

database - sybase系统程序-如何得到结果?

postgresql - 如何为 Postgres DB 配置 Slick 3.0.0(使用或不使用 Hikari)Typesafe Play conf

sql - 跳过 PostgreSQL 中的每第 n 个结果行

php - 在 Codeigniter 中动态加载数据库连接数据

linux - 替换平面文件中的第二行