Ruby PG Gem使用单个查询插入多个记录的示例

时间:2016-08-26 18:41:47

标签: ruby pg

我没有看到任何一次专门执行多个插入的方法。我想你可以迭代地创建语句字符串(带有绑定参数)和params数组,但是必须有更好的方法,对吗?

1 个答案:

答案 0 :(得分:0)

假设您正在从数据库外部插入数据,那么 是一种更好的方法:COPY命令。

pg gem通过PG::Connection#put_copy_data#put_copy_end方法直接支持此功能。以下是来自pg来源的the samples/ directory的一个(精简版)示例:

#!/usr/bin/env ruby

require 'pg'
require 'stringio'

$stderr.puts "Opening database connection ..."
conn = PG.connect( :dbname => 'test' )

conn.exec( <<END_SQL )
DROP TABLE IF EXISTS logs;
CREATE TABLE logs (
    client_ip inet,
    username text,
    ts timestamp,
    request text,
    status smallint,
    bytes int
);
END_SQL

copy_data = StringIO.new( <<"END_DATA" )
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /manual/ HTTP/1.1",404,205
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /favicon.ico HTTP/1.1",404,209
"127.0.0.1","","30/Aug/2010:08:21:24 -0700","GET /favicon.ico HTTP/1.1",404,209
"127.0.0.1","","30/Aug/2010:08:22:29 -0700","GET /manual/ HTTP/1.1",200,11094
"127.0.0.1","","30/Aug/2010:08:22:38 -0700","GET /manual/index.html HTTP/1.1",200,725
"127.0.0.1","","30/Aug/2010:08:27:56 -0700","GET /manual/ HTTP/1.1",200,11094
"127.0.0.1","","30/Aug/2010:08:27:57 -0700","GET /manual/ HTTP/1.1",200,11094
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/index.html HTTP/1.1",200,7709
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/feather.gif HTTP/1.1",200,6471
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/left.gif HTTP/1.1",200,60
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual.css HTTP/1.1",200,18674
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual-print.css HTTP/1.1",200,13200
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/images/favicon.ico HTTP/1.1",200,1078
"127.0.0.1","","30/Aug/2010:08:28:06 -0700","GET /manual/style/css/manual-loose-100pc.css HTTP/1.1",200,3065
"127.0.0.1","","30/Aug/2010:08:28:14 -0700","OPTIONS * HTTP/1.0",200,0
"127.0.0.1","","30/Aug/2010:08:28:15 -0700","OPTIONS * HTTP/1.0",200,0
"127.0.0.1","","30/Aug/2010:08:28:47 -0700","GET /manual/mod/directives.html HTTP/1.1",200,33561
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/mod/mpm_common.html HTTP/1.1",200,67683
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/images/down.gif HTTP/1.1",200,56
"127.0.0.1","","30/Aug/2010:08:28:53 -0700","GET /manual/images/up.gif HTTP/1.1",200,57
"127.0.0.1","","30/Aug/2010:09:19:58 -0700","GET /manual/mod/mod_log_config.html HTTP/1.1",200,28307
"127.0.0.1","","30/Aug/2010:09:20:19 -0700","GET /manual/mod/core.html HTTP/1.1",200,194144
"127.0.0.1","","30/Aug/2010:16:02:56 -0700","GET /manual/ HTTP/1.1",200,11094
"127.0.0.1","","30/Aug/2010:16:03:00 -0700","GET /manual/ HTTP/1.1",200,11094
"127.0.0.1","","30/Aug/2010:16:06:16 -0700","GET /manual/mod/mod_dir.html HTTP/1.1",200,10583
"127.0.0.1","","30/Aug/2010:16:06:44 -0700","GET /manual/ HTTP/1.1",200,7709
END_DATA

buf = ''
conn.transaction do
    conn.exec( "COPY logs FROM STDIN WITH csv" )
    begin
        while copy_data.read( 256, buf )
            until conn.put_copy_data( buf )
                sleep 0.1
            end
        end
    rescue Errno => err
        errmsg = "%s while reading copy data: %s" % [ err.class.name, err.message ]
        conn.put_copy_end( errmsg )
    else
        conn.put_copy_end
        while res = conn.get_result
            $stderr.puts "Result of COPY is: %s" % [ res.res_status(res.result_status) ]
        end
    end
end


conn.finish

这会将多行数据复制到单个语句中的表中。它使用StringIO来模拟从文件中读取,但您(当然)可以从磁盘,套接字或其他数据源上的文件中读取,这些文件以常规文本格式生成行,您可以通过{ {1}}。此示例使用CSV格式,但您也可以使用更多工作从自定义数据格式导入它。例如,如果您有以制表符分隔的列,则可以在开头省略#put_copy_data语句中的WITH csv,或者您也可以定义自定义列分隔符,字符编码,引号字符等。 / p>

如果您更喜欢使用更高级别的库,Sequel通过Postgres-ish COPY logs FROM STDIN对象的#copy_into方法为此机制提供了出色的支持。