Я пишу код, в котором я использую SQL для проверки нескольких различных условий, прежде чем в конечном итоге решить, что делать. Я пытаюсь выбрать между написанием одного составного запроса MySQL или написанием одного запроса для каждого условия, при этом PHP обрабатывает логику их объединения. Мои вопросы:
- Есть ли хорошие практики или подводные камни, которые должны направить меня в любом направлении?
- Если я реализую всю логику в одном запросе SQL, могу ли я получить его, чтобы он возвращал информацию о том, как получилось каждое условие? (см. объяснение ниже.)
Вот упрощенный пример. Я хочу посмотреть, сколько времени прошло с тех пор, как пользователь посетил веб-сайт и находит соответствующее электронное письмо с напоминанием для его отправки. Мы тестируем 3 независимых условия:
- Какие электронные письма следует отправлять в зависимости от времени, прошедшего с последнего посещения пользователя?
- Для каждого из этих писем, пользователь не получил это письмо раньше?
- Получал ли пользователь не письма от нас за последние 3 дня?
Вот SQL-запрос, который проверяет все 3 из них. (этот запрос выполняется для каждого пользователя; он использует PDO, а переменные, начинающиеся с :
, являются связанными параметрами):
SELECT message_id, message_content FROM emailtemplates
WHERE time_before_reminder < :days_since_visit
AND message_id not in
(SELECT message_id FROM sentemails WHERE user = :userid)
AND :userid not in
(SELECT userid FROM sentemails WHERE date_add(timesent, interval 3 day) >= now())
ORDER BY time_before_reminder asc
LIMIT 1;
Возвращает ноль строк, если какое-либо из условий не выполняется, или одну строку, если они все проходят.
С другой стороны, вот код, который выполняет несколько отдельных запросов. Это намного уродливее, но может дать мне объяснения о том, почему мы не пишем по электронной почте данному пользователю. ( Я переключился на псевдокод, чтобы вам не приходилось читать zillion $stmt->bindParam($params)
строк ):
//run the query for condition 1:
query("SELECT message_id, message_content FROM emailtemplates WHERE time_before_reminder < :days_since_visit;")
if 0 rows returned:
echo("no appropriate emails found for this participant")
return false
//then for condition 2:
query("SELECT message_id from sentemails where message_id = :msgid AND user = :userid")
if 1 or more rows returned:
echo("user $userid qualified for message $msgid, but they already received it.");
return false
//then for condition 3:
query("SELECT userid FROM sentemails WHERE user = :userid AND date_add(timesent, interval 3 day) >= now();")
if 1 or more rows returned:
echo("user $userid qualified for message $msgid, but they already received an email from us in the past 3 days. No email sent.")
return false
// if we get here, all tests were passed. Send the message that was found in the first query.
send_reminder($userid, $msgid)
echo("successfully sent message $msgid to user $userid!")
return true
Второй пример кажется действительно громоздким, но мне нравится выяснять, какое именно условие не удалось и почему. Есть ли способ, чтобы один запрос возвращал такую информацию? (Я имею в виду возвращение информации, которая может быть проанализирована в объяснении, конечно же, если бы MySQL не писал для меня английские предложения.) Или есть другой совет по обработке запросов, которые проверяют несколько независимых условий, подобных этому?