为什么 Perl DBI 接口无法插入到 Postgres table?

Why does Perl DBI interface fail to INSERT to Postgres table?

我开发了一个可以将数据格式化为 CSV 格式的 Perl 脚本,想将数据保存到 Postgres 数据库中 table。

following this tutorial 作为如何与 Postgres 交互的指南。我在 PPM 中验证我安装了与教程相同的版本:DBI 的 1.634 版本和 DBD::Pg 的 3.5.3 版本安装在 Windows 10 x64 的 Perl 5.22.1 中。数据库是 Windows Server 2008r2 上的 Postgres 12。

Perl 脚本的第一部分读取、解析一条数据记录并将其格式化为 CSV。 这是一个 CSV 数据记录的示例:

"2020-05-10 20:39:16+0","0.528239011764526","15:39 05/10/2020","0x1c","LOW STATUS","0x85","Normal","73.8","32","29.11","29.31","61.2","29","80","0.7","2.5","22.6","378.64","3009","7","0.00","0.00","0.97","0.97","11.96"

在进入下面的数据库界面片段之前,它存储在 $SQLstring 中: 这是我根据教程修改的代码,编译运行没有错误。

# ------------- Postgres Database Connection --------------

        # Connection config
my $dbname = 'MyDatabase';  
my $host = '192.168.1.1';  
my $port = 5432;  
my $username = 'myuser';  
my $password = 'mypassword';  
        # Create DB handle object by connecting
my $dbh = DBI -> connect("dbi:Pg:dbname=$dbname;host=$host;port=$port",  
                            $username,
                            $password,
                            {AutoCommit => 0, RaiseError => 1}
                         ) or die $DBI::errstr;

# Trace to a file
$dbh -> trace(1, 'tracelog.txt');


# Copy from STDIN into the table
my $SQL = "COPY AmbientWeather (  
                        datetimestamp ,     
                        CurrTime      ,
                        IndoorID      ,
                        inBattSta     ,
                        Outdoor1ID    ,
                        outBattSta1   ,
                        inTemp        ,  
                        inHumi        ,        
                        AbsPress      ,
                        RelPress      ,      
                        outTemp       ,       
                        outHumi       ,       
                        windir        ,        
                        avgwind       ,      
                        gustspeed     ,    
                        dailygust     ,    
                        solarrad      ,     
                        uv            ,          
                        uvi           ,         
                        rainofhourly  , 
                        rainofdaily   , 
                        rainofweekly  , 
                        rainofmonthly ,
                        rainofyearly  
                    )
               FROM STDIN WITH DELIMITER ',' CSV HEADER";

my $sth = $dbh->do($SQL);  


# putcopy data from saved line in CSV format

$dbh->pg_putcopydata($SQLstring);
$dbh->pg_putcopyend();      # finished with one line
$dbh->commit or die $DBI::errstr;
exit;

这运行没有错误,但数据库没有改变。没有创建记录。

这是跟踪日志,没有显示任何table错误,但我不太熟悉语法:

    DBI::db=HASH(0x3c62268) trace level set to 0x0/1 (DBI @ 0x0/0) in DBI 1.634-ithread (pid 19436)
    <- DESTROY(DBI::db=HASH(0x3c62268))= ( undef ) [1 items] at Ambient_Parser.pl line 158
    DBI::db=HASH(0x3c76ca8) trace level set to 0x0/1 (DBI @ 0x0/0) in DBI 1.634-ithread (pid 2108)
    <- do('COPY AmbientWeather (  
                        datetimestamp ,     
                        CurrTime      ,
                        IndoorID      ,
                        inBattSta     ,
                        Outdoor1ID    ,
                        outBattSta1   ,
                        inTemp        ,  
                        inHumi        ,        
                        AbsPress      ,
                        RelPress      ,      
                        outTemp       ,       
                        outHumi       ,       
                        windir        ,        
                        avgwind       ,      
                        gustspeed     ,    
                        dailygust     ,    
                        solarrad      ,     
                        uv            ,          
                        uvi           ,         
                        rainofhourly  , 
                        rainofdaily   , 
                        rainofweekly  , 
                        rainofmonthly ,
                        rainofyearly  
      ...')= ( -1 ) [1 items] at Ambient_Parser.pl line 177
    <- pg_putcopydata('"2020-05-10 20:35:59+0","0.547099113464355","15:35 05/10/2020","0x1c","LOW STATUS","0x85","Normal","73.6","32","29.11","29.31","61.3","24","193","3.8","4.9","22.6","380.54","3082","7","0.00","0.00","0.97","0.97","11.96"
')= ( 1 ) [1 items] at Ambient_Parser.pl line 182
    <- pg_putcopyend= ( 1 ) [1 items] at Ambient_Parser.pl line 183
    <- commit= ( 1 ) [1 items] at Ambient_Parser.pl line 184
    <- DESTROY(DBI::db=HASH(0x3c76ca8))= ( undef ) [1 items] at Ambient_Parser.pl line 193

参考线193是最后的出口;在文件中。

我一定是遗漏了什么,但我看不出是什么。你能指出我的错误吗?

编辑:我将我的 $SQL = "COPY.... 中的教程命令选项与 Postgres COPY command documentation 进行了比较。教程添加了选项 CSV HEADER,这在 Postres 中是看不到的文档。我不确定为什么在教程中使用这些选项,或者为什么它们会导致静默失败。我删除了它们,现在我收到错误。

上面的代码现在看起来像这样:

                rainofyearly  
            )
       FROM STDIN WITH DELIMITER ','";

现在正在输出这些错误:

DBD::Pg::db pg_putcopyend failed: ERROR:  invalid input syntax for type real: ""0.520319223403931""
CONTEXT:  COPY ambientweather, line 1, column fetchelapsed: ""0.520319223403931"" at Ambient_Parser.pl line 186.
DBD::Pg::db pg_putcopyend failed: ERROR:  invalid input syntax for type real: ""0.520319223403931""
CONTEXT:  COPY ambientweather, line 1, column fetchelapsed: ""0.520319223403931"" at Ambient_Parser.pl line 186.
Issuing rollback() due to DESTROY without explicit disconnect() of DBD::Pg::db handle dbname=MyDatabase;host=192.168.1.1;port=5432 at Ambient_Parser.pl line 186.

我正在调查为什么实际值被视为双引号。这与我在 PSQL 命令行中使用 COPY FROM 时使用的 CSV 格式相同,并且如上所示接受了实数。

你告诉它第一行将被忽略 header。但是你只发送了一行。所以没有发送数据线。

CSV 和 HEADER 是单独的选项。这些都(单独)存在于您 link 的文档中。需要保留CSV,否则引号看不懂