Perl DBI和sql now()

3

我一直在尝试使用SQL NOW()函数来更新一个表中的日期字段,但是什么也没有发生,我认为DBI会忽略那个值。代码如下:

dbUpdate($id, (notes => 'This was an update', filesize => '100.505', dateEnd => 'NOW()'));

而该函数的作用是:
sub dbUpdate {
    my $id = shift;
    my %val_hash = @_;
    my $table = 'backupjobs';

    my @fields = keys %val_hash;
    my @values = values %val_hash;

    my $update_stmt = "UPDATE $table SET ";
    my $count = 1;
    foreach ( @fields ) {
        $update_stmt .=  "$_ = ? ";
        $update_stmt .=  ', ' if ($count != scalar @fields);
        $count++;
    }
    $update_stmt .= " WHERE ID = ?";
    print "update_stmt is : $update_stmt\n";
    my $dbo = dbConnect();
    my $sth = $dbo->prepare( $update_stmt );
    $sth->execute( @values, $id ) or die "DB Update failed : $!\n";
    $dbo->disconnect || die "Failed to disconnect\n";
    return 1;
}#dbUpdate

如您所见,这是一个“动态”生成的SQL查询,因此我不知道SQL日期函数(例如now())在哪里使用。

在给定的示例中,SQL查询将会是:

UPDATE backupjobs SET filesize = ? , notes = ? , dateEnd = ?  WHERE ID = ?

使用参数值

100.55, This was an update, NOW(), 7

但是日期列仍显示0000-00-......。有什么解决办法吗?
2个回答

4
我一直在尝试在更新表时使用SQL NOW()函数。但是日期字段没有任何变化,我认为DBI会忽略该值。
实际上不是这样的。但是当您尝试添加字符串NOW()时,DB认为您正在提供日期时间或时间戳数据类型。这显然行不通。不幸的是,DBI无法为您找出这一点。它所做的只是将?更改为通过$dbh->quote()转义的字符串版本。
有几件事情你可以做:
  1. Supply a current timestamp string in the appropriate format instead of the string NOW().

    If you have it available, you can use DateTime::Format::MySQL like this:

    use DateTime::Format::MySQL;
    dbUpdate(
      $id,
      (
        notes => 'This was an update',
        filesize => '100.505',
        dateEnd => DateTime::Format::MySQL->format_datetime(DateTime->now),
      )
    );
    

    If not, just use DateTime or Time::Piece.

        use DateTime;
        my $now = DateTime->now->datetime;
        $now =~ y/T/ /;
        dbUpdate(
          $id,
          (notes => 'This was an update', filesize => '100.505', dateEnd => $now));
    
  2. Tell your dbUpdate function to look for things like NOW() and react accordingly.

    You can do something like this. But there are better ways to code this. You should also consider that there is e.g. CURRENT_TIMESTAMP() as well.

    sub dbUpdate {
        my $id = shift;
        my %val_hash = @_;
        my $table = 'backupjobs';
    
        my $update_stmt = "UPDATE $table SET ";
    
        # Check for the NOW() value
        # This could be done with others too
        foreach ( keys %val_hash ) {
          if ($val_hash{$_} =~ m/^NOW\(\)$/i) {
            $update_stmt .= "$_ = NOW()";
            $update_stmt .= ', ' if scalar keys %val_hash > 1;
            delete $val_hash{$_};
          }
        }
    
        # Put everything together, join keeps track of the trailing comma
        $update_stmt .= join(', ', map { "$_=?" } keys %val_hash );
        $update_stmt .= " WHERE ID = ?";
        say "update_stmt is : $update_stmt";
        say "values are: ", join(', ', values %val_hash);
    
        my $dbo = dbConnect();
        my $sth = $dbo->prepare( $update_stmt );
        $sth->execute( values %val_hash, $id ) or die "DB Update failed : $!\n";
        $dbo->disconnect || die "Failed to disconnect\n";
        return 1;
    }
    
  3. Write your queries yourself.

    You're probably not going to do it and I'll not add an example since you know how to do it anyway.


这里有另一个建议:在程序运行期间,您只使用数据库做这些事情吗?每次查询时连接和断开数据库并不明智。最好的做法是在需要时连接数据库(或者如果您总是使用它,则在程序开始时),并且在所有地方都使用此dbh/dbo。这样可以节省大量时间(和代码)并提高性能。


如果有人知道如何将粗体内容格式化为列表并保留代码,请继续。我做不到。 - simbabque

3
抱歉,您不能像那样使用NOW()作为插值的值。
当在SQL语句中使用?时,相应的值(通过某种机制)会被转义传递到数据库,因此任何值都会被解释为字符串而不是SQL。因此,您实际上正在尝试将字符串'NOW()'用作日期值,而不是函数NOW()
要使用NOW()作为函数,您将必须将其插入到SQL本身中,而不是作为绑定值传递。这意味着您将需要使用dbupdate函数的hack或编写新的函数,或者在perl中将时间作为字符串获取并将结果字符串传递给dbupdate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接