Это грубый пример моего запроса mysql (примечание: это внутри другого цикла, который проходит через всех пользователей):
$query = db.query('SELECT * FROM table WHERE userid = $uid AND reminded = 0');
while ($row = $query->fetch()) {
// send personalized reminder email to the user
db.query('UPDATE table SET reminded = 1 WHERE userid = $uid');
}
В поле reminded установлено значение 1 для всех экземпляров для этого пользователя.
Мой вопрос:
Загружен ли запрос/пока (выборка) в память на основе исходных условий (reminded = 0) или оставшийся цикл while будет вести себя в соответствии с этими обновлениями (reminded = 1)?
Допустим, у пользователя было 50 строк, где reminded равно 0, и запрос выбирает их: они все еще существуют со значением 0 в остальной части цикла while, даже если все они были изменены на 1 во время цикла?
не смешивайте mysql с php. Как только вы запустите первый запрос, вы перенесете данные из mysql в php. Затем вы запускаете цикл обновления через массив php. В результате, если выбрать извлечение 50 записей, вы запустите обновление 50 раз. Вкратце: ответ на ваш вопрос «Да»
@LelioFaieta Ах да, хорошо, это имеет смысл. Теперь я вижу это немного яснее. Итак, я не могу изменить то, что содержит цикл запроса после его загрузки?
вы должны выйти из цикла, снова запустить выбор и зациклиться на новом массиве. Ваш код не имеет для меня особого смысла, но я предполагаю, что это просто пример другой ситуации.
Кроме того, этот метод подвержен условиям гонки, ну, похоже, из-за него вы не можете получить поврежденные данные. Этот комментарий был больше предназначен для того, чтобы вы знали об условиях гонки в целом.
@LelioFaieta Сценарий: у пользователя есть 10 непрочитанных сообщений (напоминается = 0). Я хочу просмотреть их и напомнить пользователю ОДИН раз и установить напоминание = 1 для всех остальных сообщений и игнорировать их, чтобы он/она не получал более одного напоминания.
Ваш запрос UPDATE уже делает это. Просто запустите это (один раз). Вы можете добавить AND reminded = 0 в конце, чтобы более точно ориентироваться только на точные строки (хотя это не будет иметь большого значения, если вы обновите другие строки до значения, которое у них уже есть, но этот пункт делает его строго более правильным). Вам не нужен SELECT, если только он не имеет другой отдельной цели (например, вы хотите заранее отобразить данные на экране или что-то в этом роде).
затем переместите обновление из цикла. Прикрепите его к событию отображения сообщений
Как @ADyson также сказал, что использование UPDATE table SET reminded = 1 WHERE userid = $uid AND reminded = 0 должно делать то же самое. Также остерегайтесь SQL-инъекций в свой код.
@ADyson я предполагаю, что выбор должен отображать сообщения (вот почему цикл). Обновление должно быть привязано к событию, например, по клику для отображения.
Код представляет собой очень грубый пример того, как выглядит мой код для отправителя напоминаний по электронной почте. Он должен проходить без напоминаний и напоминать только ОДИН раз о ЛЮБЫХ непрочитанных сообщениях. Черт, это трудно объяснить ;) но, думаю, это помогает мне лучше понять, чего я хочу.
«Он должен проходить без напоминания»… нет, ему вообще не нужно перебирать их в цикле (если только вам не нужно сначала показать их на экране или выполнить какую-либо другую несвязанную обработку строк). Это наша точка зрения. Для того, чтобы установить для поля «напоминание» значение 1 для всех сообщений без напоминаний, вашего запроса UPDATE уже достаточно — он будет работать с этими строками все в одном операторе. В этом прелесть структуры команд SQL, основанной на наборах. Возможно, вам может понадобиться выбрать первое ненапоминаемое письмо и отправить напоминание о нем, но вам, конечно, не нужно выбирать все из них для этого
@ADyson Мне нужен цикл для выполнения других действий и отправки напоминания каждому пользователю (это для задания cron). Может быть, мне просто нужно перепроверить для каждой итерации, было ли отправлено какое-либо напоминание этому пользователю, и пропустить отправку, если это так
«отправка напоминания каждому пользователю» ... ваш цикл относится к одному пользователю (оператор SQL SELECT выбирает идентификатор пользователя). Возможно, у вас есть цикл разные для проверки каждого пользователя, но вам не нужен показанный здесь цикл, если только вы не можете уточнить, что такое «другие вещи».
@ADyson Ах да, извините. Этот цикл находится внутри другого цикла, который проходит через каждого пользователя. Я ценю вашу помощь, я думаю, что я ближе к тому, как я могу это сделать
SELECT * FROM table WHERE userid = $uid AND reminded = 0 LIMIT 1 вы получите первое ненапоминаемое сообщение для этого пользователя. Затем просто выберите эту единственную строку из результатов и используйте ее для создания электронного письма. После этого запустите UPDATE table SET reminded = 1 WHERE userid = $uid AND reminded = 0 один раз в конце.






Предполагая, что код и SQL, которые у вас есть, являются только примером (потому что вы должны обновлять напрямую без цикла php).
Выборка строк table выполняется в БД построчно.
Итак, если одна или несколько из этих строк обновляются в цикле while, в следующих итерациях вы будете извлекать и обновлять (снова) предыдущие обновленные строки.
Я думаю, что вы должны быть осторожны «только», если вы обновляете поле, которое является частью индекса, или поле, которое используется в SQL для извлечения данных (например, поле, используемое в ORDER BY и т. д.).
UPDATE, вы должны использовать транзакцию и зафиксировать ее.
Не уверен, что вы пытаетесь сделать, но, судя по всему, это может стать 1 запросом.