PHP/SQL Update -仅当值被更改时更新


PHP/SQL Update - update only if value has been change

我有以下PHP循环+ SQL Update查询。

for ($i=0;$i<count($_POST['id']);$i++) {
    if(!isset($_POST['live'][$i])){
        $_POST['live'][$i] = "0";
    } else { $_POST['live'][$i] = "1"; }
    $id = ($_POST['id'][$i]);
    $live = ($_POST['live'][$i]);
    $usr2 = $_SESSION['usr'];
    $updated = date("F j, Y, g:i a",time()+60*60);
    $sql = "UPDATE news SET live = '$live', usr2 = '$usr2', updated = '$updated' WHERE id = $id";
    $result = mysql_query($sql);
    //echo $sql."<br />";

}
if($result) {
    header("location: notes.php");
    exit();
}else {
    die("Query failed");
}

如何工作:

  • 我正在提交大表格将所有的表行。
  • 在不同的文件中以数组的形式接收这个
  • 如果$_POST['live']是'not set' -设为'0',如果'set'设为1
  • 在for循环中更新数组数据

如何仅更新已实际更改的行?

$_POST['live']的值实际上与保存在DB中的值不同,因为条件将改变我们的$live row

你关心的是updated字段,这个值只有在某些东西被改变时才会改变。(如果不是这样的话,就忘了这个答案吧。)
您可以为时间戳字段定义ON UPDATE CURRENT_TIMESTAMP子句。每次更新记录时,如果没有显式设置该字段的值,mysql将使用当前时间作为其新值…
...但前提是记录被篡改;如果你"更新"的字段与已经在记录中的值相同,什么也不会发生。

演示脚本:

<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setup($pdo);
$stmt = $pdo->prepare('UPDATE soNews SET somevalue=:v WHERE id=:id');
show('original', $pdo);
$stmt->execute( array(':id'=>1, ':v'=>'z') );
show('update with new=old & id=1', $pdo);
$stmt->execute( array(':id'=>2, ':v'=>'y') ); // new value=old value
show('update with new!=old & id=2', $pdo);

function setup($pdo) {
    $pdo->exec('
        CREATE TEMPORARY TABLE soNews ( 
            id int auto_increment,
            somevalue varchar(32),
            updated TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP,
            primary key(id)
        )
    ');
    $pdo->exec("INSERT INTO soNews (id,somevalue,updated) VALUES (1,'x', Now()-interval 47 hour),(2,'y', Now()-interval 47 hour)");
}
function show($label, $pdo) {
    echo "------ $label --------'n";
    foreach( $pdo->query('SELECT * FROM soNews', PDO::FETCH_ASSOC) as $row ) {
        echo join(', ', $row), "'n";
    }
}

打印

------ original --------
1, x, 2011-08-16 14:09:53
2, y, 2011-08-16 14:09:53
------ update with new=old & id=1 --------
1, z, 2011-08-18 13:09:53
2, y, 2011-08-16 14:09:53
------ update with new!=old & id=2 --------
1, z, 2011-08-18 13:09:53
2, y, 2011-08-16 14:09:53

您可以看到,作为第一个更新查询的结果,时间戳字段已经更新,而第二个查询设置new=old并没有影响updated字段。

Bobby表将破坏您的数据库。你所有的比特都属于他(严格来说,这是一种夸张,但你需要用mysql_real_escape_string包装你所有的db输入,或者更好的是,移动到PDO或MySQLi)。

长和短?不,没有可靠的方法来确定用户输入是否与数据库中的内容相同,而不首先实际查询数据库或以某种方式将DB的原始输出存储在本地($_SESSION或诸如此类)。

有合法的用例,但看起来你最好只是调用更新。您可以通过添加AND LIVE != '$live' AND UR2 != '$ur2'来稍微防止它们,但是您仍然需要运行那么多查询。


顺便说一句——我通常建议人们不要在PHP中使用传统的for循环。PHP的foreach几乎在各个方面都更好。用foreach( $_POST['id'] as $i => $id )代替for ($i=0;$i<count();$i++)。您已经声明了$id

实际上,我认为一个好的方法是:

1)执行一个查询,从数据库中获取旧记录,然后将行内容存储在一个关联数组中,以列名作为键。

2)通过检查每个要更新的"列"的内容来创建一个新的数组。如果接收到的内容与存储在db上的值不同,则更新记录数据,否则忽略并继续。最后用UPDATE

将更新后的数据发送回数据库
function updateRecord(array $input_data) {
   // Get the data associated to the record id we want to update.
   $record_data = $yourDBWrapperClass
                     ->where("id",$_GET['record_id'])
                     ->get(TABLE_NAME);  
   // Process column by column and append data to the final array.
   $final_data = [];
   $ignored_columns = ['id', 'last_update'];
   foreach ($record_data as $col_name => $value) {
       // Update the record data, only when input data shows a difference
       if(array_key_exists($col_name, $input_data) 
           && 
          $record_data[$col_name] != $input_data[$col_name]) 
       {
          $final_data[$col_name] = $inputData[$col_name];
       }
       else if (array_key_exist($ignored_columns, $col_name) == FALSE && $record_data[$col_name] == $input_data[$col_name] 
       {
          $final_data[$col_name] == $value;
       }
   }

  // Finally, perform the db update.
  $update_result = $yourDBWrapperClass
                       ->where("id", $_GET['record_id'])
                       ->update(TABLE_NAME, $final_data);

  return $update_result ? "Record update success" : "Record update failed";
}

注释:您不需要发回id或last_update列:它们的值由服务器自动计算。发送错误的值,将导致错误,或提供错误的信息。考虑last_update列:最好留给MySQL,它将调用使用列默认值来获取值:NOW();

或CURDATE ();

变量/数组的期望方面

$_GET['record_id'] = 123;
$record_data = [
   "id" => 123,
   "name" => "John",
   "surname" => "Dahlback",
   "age" => 31,
   "last_update" => "2019-01-01 10:00:00"
];
$input_data = [
   "age" => 32
];
$final_data = [
  // "id" => 123,
  "name" => "John",
  "surname" => "Dahlback",
  "age" => 32,
  // "last_update" => CURDATE();
];