PHP / SQL更新 - 仅在值已更改时更新

时间:2011-08-18 10:24:35

标签: php mysql

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

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']未设置' - 将其设置为'0',如果'set'将其设置为1
  • 更新for循环中的数组数据

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

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

3 个答案:

答案 0 :(得分:2)

Bobby tables will destroy your database.你的所有位都属于他(严格来说,这是夸张的,但你需要用mysql_real_escape_string或更好的方式包装所有数据库输入,转移到PDO或MySQLi)

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

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


BTW - 我通常建议人们不要在PHP中使用传统的for循环。 PHP的foreach几乎在所有方面都更好。而不是for ($i=0;$i<count();$i++),请使用foreach( $_POST['id'] as $i => $id )。您已经宣布$id

答案 1 :(得分:2)

猜测您关注的是updated字段,并且只有在某些内容发生变化时此值才会发生变化。 (如果不是这种情况,请忘记这个答案。)
您可以为timestamp字段定义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字段。

答案 2 :(得分:0)

实际上,我认为一种好的做法是:

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

2)通过检查每个要更新的“列”的内容来创建新数组。如果接收到的内容与数据库上存储的值不同,请更新记录数据,否则忽略并继续。最后,使用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,它会调用default列来获取值: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();
];