Я хочу выбрать уведомления пользователей в соответствии с этими правилами:
Вот мой запрос, который получает идентификаторы уведомлений пользователей:
( SELECT id FROM events -- all unread messages
WHERE author_id = ? AND seen = 0
) UNION
( SELECT id FROM events -- 2 read messages
WHERE author_id = ? AND seen <> 0
ORDER BY date_time desc
LIMIT 2
) UNION
( SELECT id FROM events -- at least 15 rows by default
WHERE author_id = ?
ORDER BY seen, date_time desc
LIMIT 15
)
И затем я выбираю сопоставленные идентификаторы в запросе выше плюс другую информацию, подобную этой: (Я не хочу комбинировать эти два запроса из-за некоторых причин в действительности)
SELECT SUM(score) score, post_id, title, content, date_time
FROM events
GROUP BY post_id, title, content, date_time
ORDER BY seen, MAX(date_time) desc
WHERE id IN ($ids)
Он работает и все в порядке.
Проблема заключается в следующем: когда первый запрос выбирает 15 строк, все из которых имеют один и тот же пост_ид, тогда второй запрос будет суммировать их и показать как одну строку уведомлений с суммарными баллами.
Думаю, я должен добавить, что SUM()
также в первом запросе? И что GROUP BY
? Любая идея?
Пример проблемы, если пользователь заработал 15 приоритетов, первый запрос выбирает их как 15 уведомлений, а второй запрос делает это одним из уведомлений. Как я могу получить 15 разделенных уведомлений? (уведомление, которое будет суммировано во втором запросе, должно учитываться как одно уведомление в первом запросе, как?)
Поскольку вы, наконец, хотите 15 строк на группу, у вас должны быть правила по группам, а не по сообщениям, на мой взгляд.
Вы можете агрегировать свои данные для каждой группы, а затем проверить, должна ли группа быть в ваших результатах. Вы сделали бы это в предложении HAVING
с условной агрегацией, то есть функцией агрегации, используемой для условного выражения. Это один из способов подсчета непрочитанных сообщений, например:
SUM(CASE WHEN seen = 0 THEN 1 ELSE 0 END)
Это другое:
COUNT(CASE WHEN seen = 0 THEN 1 END)
(Филиал ELSE
опущен и по умолчанию имеет значение null, которое не считается.)
В MySQL эти выражения еще проще, поскольку false
равно 0, а true
равно 1. Таким образом, в MySQL вы рассчитываете:
SUM(seen = 0)
Вы также можете использовать другие функции агрегации:
HAVING MAX(seen = 0) = 0 -- no unread messages
HAVING MIN(seen = 0) = 1 -- no read messages
Теперь позвольте выбрать все группы с хотя бы одним непрочитанным сообщением:
SELECT SUM(score) AS score, post_id, title, content, date_time
FROM events
GROUP BY post_id, title, content, date_time
HAVING SUM(seen = 0) > 0;
(Мы также можем использовать HAVING MAX(seen = 0) = 1
)
Теперь ваш подход UNION
позволяет получить все группы с хотя бы одним непрочитанным сообщением, а также столько других групп, сколько необходимо, чтобы получить как минимум 15 групп:
(
SELECT SUM(score) AS score, post_id, title, content, date_time, SUM(seen = 0) as unread
FROM events
GROUP BY post_id, title, content, date_time
HAVING SUM(seen = 0) > 0
)
UNION
(
SELECT SUM(score) AS score, post_id, title, content, date_time, SUM(seen = 0) as unread
FROM events
GROUP BY post_id, title, content, date_time
ORDER BY SUM(seen = 0) DESC, date_time DESC
LIMIT 15
)
ORDER BY (unread = 0), date_time DESC;
Если вам нужны одиночные идентификаторы для вышеуказанных групп, используйте IN
:
SELECT id
FROM events
WHERE (post_id, title, content, date_time) IN
(
SELECT post_id, title, content, date_time
FROM (<above query>) q
);
UNION
.
Это не ответ, но слишком длинный для комментария:
Вы думаете, что правила все понятны, но так ли? Скажите, что это не по крайней мере 15, но только по крайней мере 5 строк, которые вы хотите получить в своих окончательных результатах. Из следующей таблицы вам нужны идентификаторы 1, 2, 3 и 4, потому что они непрочитаны. А что насчет остальных?
id | score | post_id | title | content | date_time | seen ---+-------+---------+-------+---------+---------------------+----- 1 | 10 | 11 | hello | it me | 2018-01-11 12:34:56 | 0 2 | 20 | 22 | hello | it me | 2018-01-12 12:34:56 | 0 3 | 30 | 33 | hello | it me | 2018-01-13 12:34:56 | 0 4 | 40 | 44 | hello | it me | 2018-01-14 12:34:56 | 0 5 | 50 | 11 | hello | it me | 2018-01-11 12:34:56 | 1 6 | 60 | 22 | hello | it me | 2018-01-12 12:34:56 | 1 7 | 70 | 44 | hello | it me | 2018-01-14 12:34:56 | 1 8 | 80 | 55 | hello | it me | 2018-01-05 12:34:56 | 1 9 | 90 | 55 | hello | it me | 2018-01-05 12:34:56 | 1
Имеет ли значение, что есть уведомления для чтения для тех же групп? Имеет ли значение, что они новее, чем уведомления 8 и 9? Или вы просто добавите ID 8 (или 9?) В набор и сделаете это?
Независимо от того, выбираете ли вы идентификаторы 1, 2, 3, 4 и говорите 8 или вы выбираете все строки, вы получите пять групп. Поэтому, пожалуйста, сообщите нам, какие идентификаторы вы выберете и почему.