【问题标题】:Why does Perl DBI interface fail to INSERT to Postgres table?为什么 Perl DBI 接口无法插入到 Postgres 表?
【发布时间】:2020-08-26 08:47:24
【问题描述】:

我开发了一个 Perl 脚本,可以将数据格式化为 CSV 格式,并希望将数据保存到 Postgres 数据库表中。

我是following this tutorial,作为如何与 Postgres 交互的指南。我在 PPM 中验证了我安装了与教程相同的版本:1.634 版本的 DBI 和 3.5.3 版本的 DBD::Pg 安装在 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"

这是在进入下面的数据库界面sn -p之前存储在$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;

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

这是跟踪日志,没有显示任何明显的错误,但我对语法不是很熟悉:

    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 格式相同,并且如上所示接受了实数。

【问题讨论】:

  • 我的猜测是,invalid input syntax for type real: "0.520319223403931" 你需要一个数字,但你将它作为参数传递给双引号。
  • @GeorgMavridis 如果他在第二次尝试中没有放弃 CSV 选项,那么引号就不会成为问题。指定 DELIMITER ',' 但不指定 CSV 意味着引号只是文字字符,与数字类型不兼容。

标签: postgresql perl dbi


【解决方案1】:

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

CSV 和 HEADER 是单独的选项。这些都(单独)存在于您链接到的文档中。您需要保留CSV,否则无法理解引用。

【讨论】:

  • 感谢(也感谢@GeorgMavridis) - 添加 CSV 作为选项是解决方案。 COPY 的联机帮助页令人困惑。 “其中选项可以是以下之一:”下面的列表不包含 CSV 作为选项。有一个选项“FORMAT format_name”。 CSV 在下面关于格式的讨论中被间接引用。再往下,有一个关于兼容性的部分说“以下语法在 PostgreSQL 版本 9.0 之前使用并且仍然受支持:”那里的语法显示 CSV 作为一个选项。我猜 v9 后的语法是“FORMAT CSV”,但向后兼容性允许单独使用“CSV”。
  • 是的,为向后兼容而保留的记录(和实现)功能通常是一团糟。如果您遵循的教程使用现代格式,则更容易弄清楚。您应该更改您的代码以使用新格式,以便寻找下一个出现的人。
猜你喜欢
  • 1970-01-01
  • 2017-10-26
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 2016-02-08
  • 2023-01-22
  • 2018-04-05
  • 1970-01-01
相关资源
最近更新 更多