Как обновить несколько записей в таблице одним запросом MySQL? - PullRequest
0 голосов
/ 14 декабря 2009

Я хотел бы обновить несколько записей в таблице 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 ]

5 голосов
/ 14 декабря 2009

Вы можете сгенерировать запрос следующим образом:

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). ')');
2 голосов
/ 14 декабря 2009

Я не согласен с вашей архитектурой, но следующее должно работать. Используйте на свой страх и риск:

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
     ...

В вашем примере у вас есть задача = 1 во всех случаях, но с помощью оператора CASE вы можете изменить их на то, что вам нужно для каждого случая. Я оставлю тебе струнное здание.

1 голос
/ 14 декабря 2009

Спасибо за предложения, всем. Я закончил с несколькими запросами, потому что, очевидно, это было не так просто, как я надеялся.

    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;
1 голос
/ 14 декабря 2009

Я бы предпочел использовать подготовленный запрос и зацикливать данные (при необходимости, внутри транзакции). Это упрощает понимание, что лучше для удобства обслуживания.

Ваш код пахнет sql инъекция небезопасность, что подготовленные запросы устранят.

См .: http://www.php.net/manual/en/mysqli.prepare.php или даже лучше с Подготовка PDO :

0 голосов
/ 14 декабря 2009

Вы ищете это:

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

Или вы пытаетесь задать «задачу» разным значениям в разных строках одним оператором? Последнее просто невозможно

0 голосов
/ 14 декабря 2009

Я не думаю, что это возможно с одним утверждением. Вам нужно будет создать отдельные операторы 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 для приема нескольких запросов :

Похоже, что поддерживается несколько запросов. Вы просто должны передать флаг 65536 как Параметр mysql_connect 5 (client_flags)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...