#mysql #sql #join #hql #between
#mysql #sql #Присоединиться #hql #между
Вопрос:
Я хочу добавить мессенджер в свой любимый проект, но у меня возникают трудности с написанием запросов к базе данных. Я использую MySQL для этой службы с гибернацией в качестве ORM. Почти все запросы были написаны на HQL, но в принципе я могу использовать собственные запросы.
Messenger может содержать групповые беседы. Помимо написания сообщений, пользователь может войти в переписку, выйти из нее, очистить историю личных сообщений. Пользователь видит все сообщения, когда он был в разговоре, но он также может очистить историю и видеть только сообщения после последней очистки.
Ниже я описал упрощенную структуру двух таблиц, важных для этой задачи.
Таблица сообщений:
ID | текст | временная метка |
---|---|---|
1 | first_msg | 1609459200 |
2 | second_msg второй | 1609545600 |
Таблица Member_event:
ID | идентификатор пользователя | Тип | временная метка |
---|---|---|---|
1 | 1 | 1 | 1609459100 |
2 | 1 | 3 | 1609459300 |
3 | 1 | 2 | 1609459400 |
4 | 1 | 1 | 1609545500 |
where type:
1 - user entered the chat,
2 - user leaved the chat,
3 - user cleared his own history of messages in the chat
Возможно ли прочитать все сообщения чата, доступные пользователю, одним запросом?
Я понятия не имею, как динамически проверять условия: ГДЕ временные метки сообщения находятся между всеми циклами «введено-оставлено» и после последнего «введено», если не оставлено, НО только после последней очистки истории. Если существует.
Комментарии:
1. Какая у вас версия MySQL?
2. версия MySQL @trincot — 8.0.20
3. Когда именно вводится -считывается оставленный? Если последнее событие равно 2? Как если бы 4-я строка не существовала в member_event? Тогда история ясности не имеет значения?
4. Чем то, что вы хотите, отличается от чтения всех сообщений в amp; позже последнего события, если только тип события не равен 2?
Ответ №1:
Я думаю, вы могли бы выполнить следующие шаги:
- возьмите объединение обеих таблиц и рассмотрите записи в порядке временной метки
- Используйте оконные функции, чтобы определить, был ли самый последний тип 1 или 2 равен 1. Мы можем использовать текущую сумму, где тип 1 добавляет единицу, а тип 2 вычитает единицу (а 3 ничего с этим не делает). С помощью другой оконной функции вы можете определить, существует ли еще следующий тип 3. Комбинация этих двух сведений может быть преобразована в 1, когда строка принадлежит интервалу, который должен быть собран, и в 0, когда нет.
- Отфильтруйте предыдущий результат, чтобы получить только записи сообщений, и только те, где вычисление составило 1.
Вот запрос:
with unified as (
select id, text, timestamp, null as type
from message
union
select id, null, timestamp, type
from member_event
where user_id = 1),
validated as (
select unified.*,
sum(case type when 1 then 1 when 2 then -1 else 0 end)
over (order by timestamp
rows unbounded preceding) *
min(case type when 3 then 0 else 1 end)
over (order by timestamp
rows between current row and unbounded following) valid
from unified
order by timestamp)
select id, text, timestamp
from validated
where type is null and valid = 1
order by timestamp
Комментарии:
1. Это ответило на ваш вопрос? Не могли бы вы дать обратную связь?
2. Привет, @trincot! Я опоздал, но да, благодаря вашему ответу и этим оконным функциям я переработал службу чата своего приложения.
Ответ №2:
Я не понимаю, как вы могли бы сопоставить таблицу Member_event с таблицей Message_table без дополнительного FOREIGN_KEY
. Вы пытаетесь назначить сообщения, доступные пользователю, с помощью метки времени? Если это так, попробуйте следующее:
SELECT * FROM MESSAGE_TABLE m
WHERE m.TIMESTAMP BETWEEN
(SELECT TOP 1 TIMESTAMP FROM MEMBER_EVENT_TABLE WHERE type = 1 ORDER BY TIMESTAMP DESC)
AND (SELECT TOP 1 TIMESTAMP FROM MEMBER_EVENT_TABLE WHERE type != 1 ORDER BY TIMESTAMP DESC)
Это, по крайней мере, должно показывать последние сообщения между join и clean / leave
Комментарии:
1. Есть много других полей, таких как chat_id и т.д. Я упростил таблицы для вопроса.
2. Я допустил незначительную ошибку при выборе. Просто исправил это: D
3. Проблема в том, что теоретически пользователь может покинуть чат, пропустить определенное количество сообщений, а затем вернуться в чат.
4. Сложно проверить ранее назначенные сообщения через SQL. Может работать с циклом WHILE, но я не знаю, как правильно это сделать 🙂
5. В миллионный раз я убеждаюсь, что не имеет значения, сколько языков программирования и насколько хорошо знает разработчик, если он не знает, как нормально работать с базами данных. Это, конечно, обо мне. 🙂