Perl - DBI字符串错误地被双引号

时间:2014-07-25 02:10:46

标签: sql-server perl csv dbi

我使用Text :: CSV读取csv文件,解析字段,然后通过DBI将记录写入SQL Server。除了我必须操作的日期字段外,所有字段都是黄金。

CSV中日期字段的格式是,例如,' Fri Dec 20 14:56:54 2013'。当然,SQLServer并不喜欢这种格式。因此,我在脚本中使用了这个块:

    if ( $i == 12 || $i == 13 || $i == 22 || $i == 23 || $i == 24 || $i == 25)
    {
        if ( defined $fields[$i] )
        {
            $dummy = UnixDate($fields[$i],'%m/%d/%Y %H:%M:%S');
            $fields[$i] = $dummy;
        }
    }

(定义的检查是因为如果CSV中的字段包含单词' None',那么我在该元素上执行undef,以便在插入到该字段时该字段为NULL DB。在此示例行中,除元素24和25之外的所有列/字段都是'无'。

打开DBI跟踪显示我:

<- bind_param(19, '1')= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(20, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(21, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(22, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(23, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(24, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(25, "12/20/2013 14:56:54")= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(26, "12/20/2013 14:55:37")= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(27, 'Unknown')= ( 1 ) [1 items] at upload_merged_host.pl line 71

因此,您可以看到CSV中的其他字段/列已正确绑定(&#39; 1&#39;和&#39;未知&#39;上面),但我现在操作的日期字段/列有双引号,SQL对此并不满意。

为了进一步清楚,如果我不操作日期字段,它正确地具有单引号,但不再是SQLServer可接受的格式:

<- bind_param(19, '1')= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(20, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(21, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(22, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(23, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(24, undef)= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(25, 'Fri Dec 20 14:56:54 2013')= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(26, 'Fri Dec 20 14:55:37 2013')= ( 1 ) [1 items] at upload_merged_host.pl line 71
<- bind_param(27, 'Unknown')= ( 1 ) [1 items] at upload_merged_host.pl line 71

会喜欢任何指针/建议!

更新:@ Vinbot的评论让我尝试了一些东西。而不是使用UnixDate操作日期字符串,为什么不只是在开始时切换星期几。所以它现在看起来像这样:

  

$ fields [$ i] = substr($ fields [$ i],4);

我在跟踪中看到的内容现在应该好了:

...
<- bind_param(25, 'Dec 20 15:33:42 2013')= ( 1 ) [1 items] at upload_merged_host.pl line 93
...

但是我仍然像以前一样得到了投射错误。直接对sql使用相同的格式没有问题(例如通过sql server management studio):

INSERT INTO <schema>.dbo.host(hostname,interface_ipaddress,interface_name,host_modified_date) VALUES ('some_host','10.1.1.1','Local Area Connection','Dec 20 15:33:42 2013')

工作得很好。

UPDATE2
我能够使用不同的日期操作例程,问题现在得到解决(虽然我仍然需要优化更改,但它至少是功能性的。)

决议是使用DateTime和DateTime :: Format :: DBI。截至目前,我必须手动操作日期字符串,因为它从CSV进入DateTime-&gt; new()然后将该值传递给DateTime :: Format :: DBI-&gt; format_datetime ()。

希望在经过一段时间的睡眠后,我可以减少一些我刚刚做过的蛮力! :)

1 个答案:

答案 0 :(得分:1)

我认为您可能错误地诊断出了您的问题而且您没有向我们提供完整的信息。很高兴知道a)你用什么DBD连接到MS SQL Server,b)日期的列类型和c)你得到的确切错误信息。

我将假设您正在使用DBD :: ODBC与MS SQL Server通信,但其中大部分无关紧要,且该列是日期时间。

第一件事是我相信bind_param的跟踪输出会在所有参数周围放置引号,所以我不认为你的日期时间被神秘地引用了。第二件事是我不认为这是一个有效的日期时间,尤其是在使用ODBC时。如果您的错误类似于“数字值超出范围:日期/时间字符串中的无效字符”或“无效的转换值”,我认为它会证明日期时间只是错误的格式。

在ODBC中,输入日期时间/时间戳的正确方法是{ts'yyyy-mm-dd hh:mm:ss'},驱动程序应确保将正确的内容发送到数据库。

use 5.016;
use strict;
use warnings;
use DBI;

my $h=DBI->connect("dbi:ODBC:abc","xx","yy", {RaiseError => 1, PrintError => 0});
eval {
    $h->do(q/drop table mje/);
};
$h->do(q/create table mje (a varchar(50), b datetime)/);

my $s = $h->prepare(q/insert into mje values(?,?)/);
$s->bind_param(1, 'fred');
$s->bind_param(2, "{ts '2013-12-20 14:55:37'}");
$s->execute;
# or $s->execute("fred", "{ts '2013-12-20 14:55:37'}");

请记住,成功地将日期时间输入到sql server management studio并不能保证它正好位于不是数据库引擎的驱动程序后面,因为驱动程序没有通过字符串datetime,它会将其解析为其他内容(除非是当然你的日期时间在你的sql本身)。会话也可以有不同的日期时间输入格式。