我有以下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();
];