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-........

任何想法如何解决这一问题 ?

4

2 回答 2

4

我在更新表时一直在尝试使用 sql NOW() 函数。但是该日期字段没有任何反应,我认为 DBI 只是忽略了该值。

不,它没有。但是当您实际上尝试添加字符串时,数据库认为您提供的是 datetime 或 timestamp 数据类型NOW()。这当然行不通。不幸的是,DBI 无法为您找到。它所做的只是?变成它得到的字符串的转义(通过$dbh->quote())版本。

你可以做几件事:

  1. 提供适当格式的当前时间戳字符串,而不是字符串NOW()

    如果你有它,你可以DateTime::Format::MySQL像这样使用:

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

    如果没有,只需使用DateTimeor 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. 告诉你的dbUpdate函数去寻找类似的东西NOW()并做出相应的反应。

    你可以做这样的事情。但是有更好的方法来编码。您还应该考虑还有例如CURRENT_TIMESTAMP()

    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. 自己编写查询。

    您可能不会这样做,我也不会添加示例,因为无论如何您都知道该怎么做。


这是另外一件事:这是您在程序运行时对数据库所做的唯一事情吗?每次进行查询时都连接和断开数据库是不明智的。一旦你需要它(或者在程序开始时,如果你总是使用它)连接数据库,并且在任何地方都使用这个 dbh/dbo,性能会更好。它节省了大量时间(和代码)。

于 2012-05-31T14:34:27.437 回答
3

抱歉,您不能NOW()像这样使用内插值。

当 a?在 SQL 语句中使用时,相应的值(通过某种机制或其他)被转义传递给数据库,因此任何值都被解释为字符串,而不是 SQL。因此,您实际上是在尝试将字符串'NOW()'用作日期值,而不是函数NOW()

NOW()用作函数,您必须将其插入 SQL 本身,而不是将其作为绑定值传递。这意味着您将不得不使用您的dbupdate函数的 hack 或编写一个新函数,或者在 perl 中以字符串形式获取时间并将生成的字符串传递给dbupdate.

于 2012-05-31T14:07:41.797 回答