代码之家  ›  专栏  ›  技术社区  ›  Chris

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

  •  1
  • Chris  · 技术社区  · 10 年前

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

    CSV中日期字段的格式为,例如,“2013年12月20日星期五14:56:54”。当然,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,以便该字段在插入到DB中时为NULL。在此示例行中,除元素24和25之外的所有列/字段均为“None(无)”。)

    打开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中的其他字段/列已正确绑定(上面的“1”和“未知”),但我操作的日期字段/列现在有双引号,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]=子字符串($fields$$i],4);

    我在痕迹中看到的 应该 现在开始吧:

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

    但我仍然得到了铸造错误,和以前一样。直接对sql使用相同的格式没有问题(例如,通过sqlservermanagementstudio):

    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')
    

    工作正常。

    更新2
    我能够使用不同的日期操作例程,现在问题已经解决了(尽管我仍然需要优化更改,但至少是功能性的)。

    解决方案是使用DateTime和DateTime::Format::DBI。到目前为止,我必须手动操作从CSV传入的日期字符串,以将其传递给DateTime->new(),然后将该值传递到DateTime::Format::DBI->format_datetime()。

    希望在一段时间的睡眠后,我可以消除我刚才所做的一些暴力!:)

    1 回复  |  直到 10 年前
        1
  •  1
  •   bohica    10 年前

    我想你可能诊断出了错误的问题,而且你没有向我们提供完整的信息。如果知道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并不能保证它就在不是数据库引擎的驱动程序后面,因为驱动程序不会传递字符串日期时间,而是将其解析为其他内容(当然,除非日期时间在sql本身中)。会话也可以具有不同的日期时间输入格式。