如何使用单个MySQL查询更新表中的多个记录?

时间:2009-12-14 18:04:50

标签: php sql mysql

我想使用单个查询更新MySQL表中的多个记录。基本上,这是一个任务表,它在不同的日期为不同的人分配。当通过在线表单更改和提交这些作业时,会提交大量POST数据(几乎所有待处理的作业)。我编写了一个算法来对所有这些信息进行排序并获得我想要的信息,但我仍然坚持编写查询来更新MySQL表:

  // Find the modified records and save their information
  $update = 0;
  for ( $n = 0; $n < $total_records; $n++ )
  {
     if ( $_POST['update'.$n] == true )
     {
        $updates_arr[$update] = array( intval($_POST['user_id'.$n]), intval($_POST['task'.$n]), $_POST['date'.$n] );
        $update++;
     }
  }

  if ( $mysql_db = OpenDatabase() )
  {
     $query  = "UPDATE tasks_tbl";
     if ( $updates_arr[0] )
     {
        $query .= "   SET task = ".$updates_arr[0][1]." WHERE user_id = ".$updates_arr[0][0]." AND date = ".$updates_arr[0][2];
     }

     for ( $n = 1; $n < $updates; $n++ )
     {
        $query .= ",   SET task = ".$updates_arr[$n][1]." WHERE user_id = ".$updates_arr[$n][0]." AND date = ".$updates_arr[$n][2];
     }

     $result = mysql_query( $query, $mysql_db );

     if ( $result )
     {
        $page .= "<p>Success!</p>\n\n";
     }
     else
     {
        $page .= "<p>Error: ".mysql_error()."</p>\n\n";
     }
  }

这是生成的查询:

UPDATE tasks_tbl 
   SET task = 1 
 WHERE user_id = 16 
   AND date = 2010-05-05,  
   SET task = 1 
 WHERE user_id = 17 
   AND date = 2222-02-22

任何建议将不胜感激。感谢。

6 个答案:

答案 0 :(得分:5)

您可以生成如下查询:

UPDATE tasks_tbl SET task=1 WHERE 
    (user_id=16 AND date='2010-05-05') OR
    (user_id=17 AND date='2010-02-22')

有些黑客可以避免使用(... and ...) or (... and ...)构造(连接字段和参数:"concat(user_id, date) = '". $user_id. $date. "'",但它们的工作速度稍慢。

PHP代码:

for ($i = 0; !empty($_POST['update'. $i]; $i++)
    if (intval($_POST['task'.$i]) == 1)
        $cond[] = '(user_id='. intval($_POST['user_id'. $i]).
        ' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')';

$query = 'UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')';

编辑:我不太明白为什么你需要在一个查询中执行此操作。 task可以有多少个值? 1,2,3或更多?使用3个值,您可以使用嵌套的IF(...)函数:

UPDATE tasks_tbl SET task=if('. <imploded tasks with value 1>. ', 1, if('.
<tasks with value 2>. ', 2, if('. <tasks with 3>. ', 3,
task))) /* leave as is otherwise */

或者你可以对我给出的代码进行简单的循环:

for ($j = 1; $j <= 3; $j++)
    for ($i = 0; !empty($_POST['update'. $i]; $i++)
        if (intval($_POST['task'.$i]) == 1)
            $cond[] = '(user_id='. intval($_POST['user_id'. $i]).
            ' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')';

    mysql_query('UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')');

答案 1 :(得分:2)

我不赞同你的架构,但以下内容应该有效。使用风险由您自行承担:

UPDATE
     Tasks_Table
SET
     task =
          CASE
               WHEN user_id = 16 AND date = 2010-05-05 THEN 1
               WHEN user_id = 17 AND date = 2222-02-22 THEN 1
               ...
          END
WHERE
     (user_id = 16 AND date = 2010-05-05) OR
     (user_id = 17 AND date = 2222-02-22) OR
     ...

在您的示例中,您在所有情况下都有task = 1,但使用CASE语句,您可以将它们更改为每个案例所需的内容。我会把绳子留给你。

答案 2 :(得分:1)

我更愿意使用准备好的查询并循环数据(如果需要,在事务内部)。这使得理解起来更简单,这对于可维护性更好。

你的代码也有sql injection不安全的气味,准备好的查询会消除。

请参阅:http://www.php.net/manual/en/mysqli.prepare.php或更好地使用PDO prepare

答案 3 :(得分:1)

感谢大家的建议。我最终选择了多个查询,因为它显然不像我希望的那样简单。

    foreach ( $updates_arr as $record => $data ):
       $query  = "UPDATE tasks_tbl";
       $query .= "   SET task = ".$data[1];
       $query .= "   WHERE task_id = ".$data[0];
       $result = mysql_query( $query, $mysql_db );
       if ( !$result )
       {
          break;
       }
       endforeach;

答案 4 :(得分:0)

你在找这个:

UPDATE tasks_tbl 
   SET task = 1 
 WHERE (user_id = 16 AND date = 2010-05-05) 
       OR (user_id = 17 AND date = 2222-02-22)

或者您尝试使用单个语句将“任务”设置为不同行中的不同值? 后者是不可能的

答案 5 :(得分:-4)

我不认为这是可能的。您需要创建单独的UPDATE语句:

UPDATE tasks_tbl SET task = 1 WHERE user_id = 16 AND date = 2010-05-05;
UPDATE tasks_tbl SET task = 1 WHERE user_id = 17 AND date = 2222-02-22

您可以将它们作为一个以';'分隔的字符串传递给mysql_query()如果你将mysql设置为接受multiple queries

  

似乎支持多个查询。   你只需将标志65536传递给   mysql_connect的5个参数   (client_flags)