Perl DBD:ODBC 在准备 sql 服务器插入语句时抛出 "does not yet support binding a named parameter more than once"

Perl DBD:ODBC throwing "does not yet support binding a named parameter more than once" when preparing sql-server insert statement

Perl DBD::ODBC 从 sql 服务器插入语句

抛出错误
DBD::ODBC does not yet support binding a named parameter more than once

当不打算在此脚本中绑定参数时。我试过自己回答这个问题,并继续这样做,但没有找到类似问题的答案。

我有一个脚本可以将 csv(包含日期时间、guid 和 comments/message 字符串的组合)加载到数据库中。如果需要,我在下面包含了我的部分脚本以供进一步分析。在 csv 中输入 350,000 多行(大约 20 列)之后,它似乎被这个错误挂断了,但我一直无法弄清楚到底是什么导致了它。

我试过设置 $self->{dbh}->{odbc_ignore_named_placeholders} = 1; 但没有成功克服该错误。 csv 中的所有值都用单引号括起来,但其中一些值是包含 either/both :?.

的字符串

在这种情况下,我不打算使用绑定参数或命名占位符 -- 只是为了将原始数据导入数据库。

由于故障排除,脚本的这一部分打印了很多内容。整个脚本还没有 intentionally/unintentionally 优化——我的目标是让它正常工作。 善良点。

这将实例化“Connection”对象。由于连接是在这里建立的,并分配给 $self->{dbh},我应该可以将 1 分配给 {odbc_ignore_named_placeholders},但它似乎不起作用。

sub New {
my $class = shift;
my $self  = {
    dbh          => DBI->connect( $dsn ),
    dropIfExists => 1, # 1 == drop, 0 == do not drop or create
    debug        => 1, # 1 == enabled, 0 == disabled
};
$self->{dbh}->{odbc_ignore_named_placeholders} = 1;
bless $self, $class;
return $self;
}

这是在插入语句中准备行的重要部分:

while ( my $row = $csv->getline( $fh ) ) {
    my @fields  = @{$row};
    my @newline = ();
    for ( @fields ) {
        my $str = $_;
        $str =~ s/'+/''/;
        my $newString = "'" . $str . "'";
        print $newString.NewLine;
        push( @newline, $newString );
    }
    my $line = join( ",", @newline );
    $values  .= "(" . $line . "),";
    $MasterLineCount++;
    print FancyLine;
    print "MasterLineCount: " . $MasterLineCount . NewLine;
    print FancyLine;
    $count++;
    print FancyLine;
    print "Line count: ".$count.NewLine;
    print FancyLine;

    # sql server allows a maximum of 1000 values (rows) in a
    # single insert statement, so this stops the loop, and 
    # prepares/executes the query. if the loop hits the end of
    # the file with a count < 999, it drops out of the
    # while loop, and checks if count > 0, if it is, it
    # prepares/executes the statement for the remaining
    # rows/lines

    if ( $count == 999 ) {
        $statementCount++;
        print FancyLine;
        print "Statement Count: " . $statementCount . NewLine;
        print FancyLine;
        my $insertStmt        = "insert into " . $db_name . ".dbo." . $tableName . " (" . $colNames . ") values " . $values;
        my $chopTrailingComma = chop( $insertStmt );
        # print "Insert Statement: ".NewLine;
        # print FancyLine;
        # print $insertStmt.NewLine;
        # print FancyLine;
        # load table
        $self->ExecuteStmt( $insertStmt );
        #reset values string
        $values = "";
        #reset count
        $count = 0;
    }

}
if ( $count > 0 ) {
    $statementCount++;
    print FancyLine;
    print "Statement Count: " . $statementCount . NewLine;
    print FancyLine;
    my $insertStmt        = "insert into " . $db_name . ".dbo." . $tableName . " (" . $colNames . ") values " . $values;
    my $chopTrailingComma = chop( $insertStmt );

    # load table
    $self->ExecuteStmt( $insertStmt );
    #reset values string
    $values = "";
    #reset count
    $count = 0;
}

为清楚起见,这是 ExecuteStmt():

sub ExecuteStmt {
    my $self     = shift;
    my $stmt     = shift;
    $self->{sth} = $self->{dbh}->prepare( $stmt );
    $self->{sth}->execute or die "$stmt".NewLine().FancyLine().$self->{sth}->errstr;
}

好吧,我想出了一个解决方法,它与 dbi 模块无关。创建新的Text::CSV对象时,传入如下参数:

    verbatim => 1,

这是我的 Text::CSV 构造函数现在的样子:

my $csv = Text::CSV_XS->new( { binary          => 1,
                               eol             => $/,
                               always_quote    => 1,
                               verbatim        => 1,
                               skip_empty_rows => 1 
                               } );

来自文档 Text::CSV:

> This is a quite controversial attribute to set, but makes some hard
> things possible.
> 
> The rationale behind this attribute is to tell the parser that the
> normally special characters newline (NL) and Carriage Return (CR) will
> not be special when this flag is set, and be dealt with as being
> ordinary binary characters. This will ease working with data with
> embedded newlines.   
> 
> When verbatim is used with "getline", "getline" auto-chomp's every line.

如果我发现与此更改相关的任何意外后果,我会更新此 question/answer。