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

aza*_*a07 12 database postgresql connection shell psql

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

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

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

echo sql_statement | psql -h remote_server -U username -d database

即不创建SQL文件.但是,这个解决方案有一个主要问题,我正在寻求建议:
每次我必须重新连接到远程数据库以插入一行.

有没有办法连接到远程数据库,保持连接,然后"管道"或"发送"插入SQL语句而不创建一个巨大的SQL文件?

Erw*_*ter 19

回答你的实际问题

是的.您可以使用命名管道而不是创建文件.请考虑以下演示.

x在我的数据库中创建架构以event进行测试:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.x (id int, a text);
Run Code Online (Sandbox Code Playgroud)

从shell创建一个命名管道(fifo),如下所示:

postgres@db:~$ mkfifo --mode=0666 /tmp/myPipe
Run Code Online (Sandbox Code Playgroud)

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

postgres@db:~$ psql event -p5433 -c "COPY x.x FROM '/tmp/myPipe'"
Run Code Online (Sandbox Code Playgroud)

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

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

postgres@db:~$ psql event -p5433 -f /tmp/myPipe
Run Code Online (Sandbox Code Playgroud)

这更适合您的情况.此外,在SQL以单件执行之前,没有表锁定.

Bash会出现阻止.它正在等待输入管道.要从一个bash实例执行所有操作,您可以将等待进程发送到后台.像这样:

postgres@db:~$ psql event -p5433 -f /tmp/myPipe 2>&1 &
Run Code Online (Sandbox Code Playgroud)

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

postgres@db:~$ echo '1  foo' >> /tmp/myPipe; echo '2    bar' >> /tmp/myPipe; echo '3    baz' >> /tmp/myPipe;
Run Code Online (Sandbox Code Playgroud)

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

COPY 3
Run Code Online (Sandbox Code Playgroud)

变体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
Run Code Online (Sandbox Code Playgroud)

完成后删除命名管道:

postgres@db:~$ rm /tmp/myPipe
Run Code Online (Sandbox Code Playgroud)

检查成功:

event=# select * from x.x;
 id |         a
----+-------------------
  1 | foo
  2 | bar
  3 | baz
Run Code Online (Sandbox Code Playgroud)

上面代码的有用链接

使用命名管道使用postgres读取压缩文件命名管道
简介
在后台运行bash脚本的最佳实践


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

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

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

将您的语句写入文件并执行INSERT如下操作:

psql -h remote_server -U username -d database -p 5432 -f my_insert_file.sql
Run Code Online (Sandbox Code Playgroud)

(5432或db-cluster正在侦听的任何端口)
my_insert_file.sql可以包含多个SQL语句.事实上,恢复/部署这样的整个数据库是常见的做法.有关参数的信息,请参阅手册-f,或者参考bash : man psql.

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

您也可以在PostgreSQL中进行部分或全部处理.为此,您可以COPY TO(或INSERT INTO)使用临时表并使用纯SQL语句来准备并最终INSERT/UPDATE您的表.我做了很多.请注意临时表会在会话中生存并消亡.

您可以使用像pgAdmin这样的GUI 来实现舒适的处理.在关闭窗口之前,SQL编辑器窗口中的会话将保持打开状态.(因此,临时表会一直存在,直到您关闭窗口.)