SQL-запрос для потоковых сообщений
Мой сайт имеет функцию обмена сообщениями, где один пользователь может отправлять сообщения другому. Сообщения поддерживают многопоточность - родительское сообщение может иметь любое количество дочерних элементов, но только один уровень.
Таблица сообщений выглядит так:
Messages
- Id (PK, Auto-increment int)
- UserId (FK, Users.Id)
- FromUserId (FK, Users.Id)
- ParentMessageId (FK to Messages.Id)
- MessageText (varchar 200)
Я хотел бы показывать сообщения на странице с каждым "родительским" сообщением, за которым следует свернутый просмотр дочерних сообщений.
Могу ли я использовать предложение GROUP BY или аналогичную конструкцию для извлечения родительских и дочерних сообщений в одном запросе? Сейчас я получаю только родительские сообщения, затем перебираю их и выполняю еще один запрос для каждого, чтобы получить все связанные дочерние сообщения.
Я хотел бы получить такие сообщения:
Parent1
Child1
Child2
Child3
Parent2
Child1
Parent3
Child1
Child2
2 ответа
Вы можете использовать временный идентификатор для заказа сообщений. Если сообщение является родительским, то временный идентификатор будет равен идентификатору, иначе временный идентификатор будет равен ParentMessageID. Тогда вам просто нужно заказать по временному идентификатору
SELECT Messages.*,
CASE WHEN ParentMessageId IS NULL THEN Id ELSE ParentMessageId END AS tempId
FROM Messages
ORDER BY tempId
редактировать
Если вы хотите первые 10 записей, вы можете сначала получить идентификаторы, а затем выполнить запрос
SELECT Messages.*,
CASE WHEN ParentMessageId IS NULL THEN Id ELSE ParentMessageId END AS tempId
FROM Messages
WHERE Messages.tempId IN (SELECT Messages.Id
FROM Messages
WHERE ParentMessageId IS NULL
LIMIT 10
ORDER BY Messages.Id )
ORDER BY tempId
Таким образом, вы получаете сообщения и соответствующие дочерние элементы только из первых 10 сообщений.
Попробуй это. Вы можете заменить range_, используя некоторую переменную, хранящуюся на вашем интерфейсе для нумерации страниц.
select child.MessageText from
(select @i:=@i+1 as range_, id, MessageText from messages, (select @i:=0) k where ParentMessageId is null order by id asc) parent
left outer join messages child on (parent.id = child.ParentMessageId or parent.id = child.id)
where parent.range_ between 1 and 3;