Как обновить несколько записей в таблице одним запросом MySQL?

0

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

Любые предложения будут оценены. Спасибо.

  • 1
    Для действительно большого количества вставок может быть полезно выполнить массовую вставку во временную таблицу, а затем ОБНОВИТЬ целевую таблицу, используя значения из временной таблицы.
  • 0
    почему вы хотите сделать это таким образом? вы рискуете не обновлять несколько элементов, когда только один из них выходит из строя. не было бы лучше отловить отдельные транзакции для сбоев, чтобы они могли отображаться пользователю?
Показать ещё 5 комментариев
Теги:

6 ответов

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;
  • 0
    Опять же, если бы вы использовали подготовленные операторы, вам не пришлось бы перестраивать строку запроса каждый раз через цикл, вы бы не отправляли весь запрос по сети каждый раз, серверу sql не пришлось бы разбирать каждый раз sql время, и вы будете защищены от внедрения SQL-кода, который не является вашим кодом.
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). ')');
  • 0
    Предполагая, что задача всегда установлена в 1 ..
  • 0
    По электронной почте Ой! Спасибо, исправили это :)
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
     ...

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

  • 0
    Спасибо, Том. Я вижу, как это работает, хотя это было бы ужасно и мучительно отлаживать.
  • 0
    Это выглядит интересно. Обычно используются операторы CASE или это более неясная особенность MySQL?
Показать ещё 1 комментарий
1

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

В вашем коде пахнет sql injection, безопасность, которую подготовленные запросы будут устранены.

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

  • 0
    Спасибо, но это похоже на то, что на моем веб-сайте потребуется переписать весь код PHP -> MySQL. Прямо сейчас я рассматриваю переход от mysql_connect () к mysql_pconnect (), который должен потребовать всего несколько изменений. Я определенно буду помнить API MySQL для моего следующего сайта!
  • 0
    Там гораздо больше кода, чем я показал. Я использую mysql_real_escape_string () и проверяю результаты в ожидаемых пределах, поэтому было бы довольно сложно, если не невозможно, вставить что-либо в запрос.
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)

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

  • 0
    это возможно с помощью функций find_in_set & elt. Всего 2 уровня стека вызовов функций.
-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 для принятия нескольких запросов:

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

  • 1
    Первое полное предложение в документации: mysql_query () отправляет уникальный запрос ( несколько запросов не поддерживаются ) в текущую активную базу данных на сервере, который связан с указанным идентификатором link_identifier.
  • 0
    Я не знал, что единственным обновлением будет изменение задачи на 1. Я думаю, что было бы проще просто выпустить новый оператор для каждого ОБНОВЛЕНИЯ.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню