1

我正在运行 Postgres DB 并使用COPYruby​​ 中的命令将数据加载到临时表中。

它看起来像这样:

@conn = PG.connect(dbname: 'load_test')
res = @conn.async_exec <<-QUERY
  COPY tmp_inventory FROM '#{infile_location}' CSV HEADER DELIMITER '|'
QUERY

有一条 INFO 日志消息,其中包含添加的总行数。我怎样才能从 ruby​​ 中以编程方式获得这个数字?

4

2 回答 2

1

您可以在 Postgres 中执行此操作,也可以直接从 Ruby 中的 Postgres 接口获取它:

使用红宝石

更具体地说是类PGresult

我不是 Ruby 专家,但在此处此处研究文档,似乎该方法cmd_tuples仅适用于INSERT|DELETE|UPDATE|MOVE|FETCH.

还有常数PGRES_COPY_OUTPGRES_COPY_IN(对于手头的情况)。似乎该方法result_status返回了相应的值

返回查询的状态。状态值是以下之一:

PGRES_EMPTY_QUERY
PGRES_COMMAND_OK
PGRES_TUPLES_OK
PGRES_COPY_OUT
PGRES_COPY_IN
PGRES_BAD_RESPONSE
PGRES_NONFATAL_ERROR
PGRES_FATAL_ERROR
PGRES_COPY_BOTH

因此,在您的示例中,您应该通过以下方式获得所需的值:

res.result_status

使用 Postgres

您将使用 PL/pgSQL 函数来访问以COPY编程方式处理的行数(需要 9.2+ 版本):

于 2014-11-05T21:34:36.013 回答
1

Erwin Brandstetter 走在了正确的轨道上。尽管 Ruby API 文档目前说了什么(它需要更新),但它PG::Result#cmd_tuples确实可以使用COPY命令,至少从 PostgreSQL 9.6.3 开始。问问题时可能没有,但PQcmdTupleslibpq文档现在包括COPY,因此我将更新 Ruby API 的文档以反映这一点。

这是源目录中示例之一的sample/修改版本,它使用围绕API的PG::Connection#copy_data包装器方法说明了这一点:libpqCOPY

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

csv_io = 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

### You can test the error case from the database side easily by
### changing one of the numbers at the end of one of the above rows to
### something non-numeric like "-".

$stderr.puts "Running COPY command with data ..."
buf = ''
conn.transaction do
    res = conn.copy_data( "COPY logs FROM STDIN WITH csv" ) do
        $stderr.print "Sending lines... "
        csv_io.each_line.with_index do |buf, i|
            $stderr.print "#{i + 1} "
            conn.put_copy_data( buf )
        end
        $stderr.puts "done."
    end
    $stderr.puts "Result of COPY is: %s" % [ res.res_status(res.result_status) ]
    $stderr.puts "  tuples copied: %p" % [ res.cmd_tuples ]
end

conn.finish

运行时输出:

$ ruby sample/copyfrom.rb
Opening database connection ...
Running COPY command with data ...
Sending lines... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 done.
Result of COPY is: PGRES_COMMAND_OK
  tuples copied: 26

PG::Result#result_status方法只返回一个整数结果状态代码,并且PGRES_COPY_OUT/PGRES_COPY_IN由低级COPYAPI 使用,因此它们在正常情况下不是很有用。

于 2017-06-02T00:29:27.290 回答