MySQL — ВЫБЕРИТЕ, затем ОБНОВИТЕ

#mysql #select #sql-update

#mysql #выберите #sql-обновить

Вопрос:

У меня есть скрипт, написанный на PHP, в котором есть эта строка, которая работает правильно для выбора нужных мне данных;

 $result = mysql_query("SELECT product_name, sku, qty FROM supplier_dropship_items WHERE supplier_id = '3' AND status = '2'", $db_beb);
  

С чем я борюсь, так это со способом обновления выбранных мной записей, после выбора мне нужно изменить status = '1' , чтобы при следующем запуске моего скрипта он не извлекал те же данные из выбора, а извлекал только новые элементы в таблице, которые имеют статус 2.

Это мой рабочий результат благодаря комментариям к принятому ответу ниже;

 $result = mysql_query("SELECT id, product_name, sku, qty FROM supplier_dropship_items WHERE supplier_id = '3' AND status = '2' FOR UPDATE", $db_beb); 

while($row = mysql_fetch_assoc($result)) 
{ 
    $sql_table_data[] = $row;
    mysql_query("UPDATE supplier_dropship_items SET status=1 WHERE id='".$row['id']."'", $db_beb); 
} 
  

Комментарии:

1. запустите запрос обновления после запроса выбора

2. Хорошо, извините, я изучаю MySQL. Если бы я выполнил отдельное обновление после выбора, я мог бы технически изменить продукт, который, возможно, был добавлен после выбора, который не был бы доступен для выбора при следующем запуске скрипта? Если это имеет смысл.

3. Нет, если вы обновляете только те SKU, которые вы выбрали в первую очередь. (Или укажите на то, что еще является вашим первичным ключом)

4. есть ли у вас какой-либо первичный ключ, определенный в таблице, если да, то вы можете запустить update table set status = '1' where primarykey_column in(primaykey ids of selected records)

Ответ №1:

Просто сделайте это одновременно, UPDATE когда вы SELECT это сделаете.

Измените это:

 SELECT product_name, sku, qty 
FROM supplier_dropship_items 
WHERE supplier_id = '3' AND status = '2';
  

к этому:

 UPDATE supplier_dropship_items as t, 
(
    SELECT id, product_name, sku, qty 
    FROM supplier_dropship_items 
    WHERE supplier_id = '3' AND status = '2'
) as temp
SET status = '1' WHERE temp.ID = t.ID;
  

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


Редактировать

Вот ссылка на документацию по этому синтаксису

По сути, что это делает, так это то, что при попытке обновить таблицу, которую мы здесь обозначаем как t , вы одновременно запускаете инструкцию select .
Этот оператор select возвращает результирующую таблицу, для которой мы используем псевдоним с именем temp .
Итак, теперь представьте, что результат вашего оператора select находится внутри temp , в то время как вся таблица, которую вы обновляете, находится внутри t .
Наконец, вы обновляете status поле до 1 того, где ID ‘s (в этих двух наборах результатов псевдонимов) совпадают

Комментарии:

1. Привет @John Ruddell, я только что протестировал это, и, хотя он обновил выбранные элементы, они не были переданы $result для меня, чтобы затем использовать в моем php-скрипте?

2. хорошо, тогда просто запустите запрос перед запуском обновления. по сути, просто запустите свой запрос, чтобы он был у вас в $ result, а затем обновите таблицу впоследствии, если это имеет смысл.

3. Этот синтаксис приводит к ошибкам на моем сервере MySQL: 1. Ожидалось выражение. (рядом с «(» в позиции 39) 2. Неожиданный токен. (рядом с «(» в позиции 39) 3. Был найден новый оператор, но между ним и предыдущим не было разделителя. (рядом с «ВЫБРАТЬ» в позиции 46)

4. @samtuke это допустимый синтаксис, вы не скопировали, как это сделать правильно?

5. @JohnRuddell Как упоминалось выше, ваше решение выше не возвращает значения product_name, sku, qty в $result. И запуск select перед обновлением, я думаю, нарушает назначение блока кода, который «блокирует» запись путем обновления и выбора в 1 команде, поэтому вторая транзакция не может захватить / обновить запись. Итак, мой вопрос заключается в следующем.. Возможно ли передать данные, которые вы храните в temp, в $result в рамках этой одной команды?

Ответ №2:

Если supplier_dropship_items имеется первичный ключ (он должен), то включите эти поля в SELECT , затем, при циклическом просмотре результатов, выполните UPDATE с использованием первичного ключа для установки status , как в:

 UPDATE supplier_dropship_items SET status=1 WHERE <id_field>=<id_value>;
  

Это предполагает, что вы не выполняетесь в параллельной среде. Если это так, то вам следует заблокировать записи для обновления, используя SELECT... FOR UPDATE . Вы можете прочитать об этом здесь. Насколько я знаю, это работает в MySQL для таблиц InnoDB.

Комментарии:

1. вы также можете просто заблокировать таблицы, чтобы порядок не приводил к взаимоблокировке (в InnoDB). LOCK TABLES supplier_dropship_items WRITE

2. Спасибо @Marion C’Ascanio, это работает отлично, и, что более важно, я это понимаю 🙂 Я добавлю результат к вопросу для справки.