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はその値を無視しているだけだと思います。

いいえ、そうではありません。ただし、DBは、実際に文字列を追加しようとしているときに、日時またはタイムスタンプのデータ型を指定していると見なします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),
      )
    );
    

    そうでない場合は、DateTimeまたはを使用して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()そのような補間値として使用することはできません。

SQLステートメントでa?が使用されている場合、対応する値は(何らかのメカニズムまたはその他の方法で)データベースに渡されてエスケープされるため、値はSQLではなく文字列として解釈されます。'NOW()'したがって、実際には、関数ではなく、日付値として文字列を使用しようとしていますNOW()

関数として使用するNOW()には、バインドされた値として渡すのではなく、SQL自体に挿入する必要があります。これは、関数のハックを使用するかdbupdate、新しい関数を作成するか、perlで文字列として時間を取得し、結果の文字列を渡す必要があることを意味しますdbupdate

于 2012-05-31T14:07:41.797 に答える