У меня есть система, где могут быть "сообщения", "комментарии" к сообщениям и "комментарии" к другим комментариям. Подумайте об этом как о очень упрощенной системе комментариев в facebook.
Чтобы вернуть данные, я решил использовать одну таблицу для сообщений и комментариев, так как их структура почти такая же:
ID (комментария или сообщения) | TopParentID (если сообщение, то же, что и ID, если комментарий, идентификатор сообщения) | DirectParentID (0, если сообщение, либо идентификатор сообщения, либо идентификатор родительского комментария, если комментарий) | Еще несколько полей, которые одинаковы для сообщений и комментариев
Что я хотел бы достичь: выберите, например, первые 20 сообщений. Тем не менее, с сообщениями, также выберите комментарии этого сообщения.
Я знаю, что это похоже на то, что JOIN с другой таблицей будет более оптимальным, чем наличие только одной таблицы, но я подумал, что было бы полезно, чтобы оба сообщения и комментарии использовали один и тот же счетчик ID, чтобы было легче найти как прямые комментарии к сообщению и комментарии к комментарию сообщения.
Тем не менее, я не знаю, как спроектировать мой запрос с приведенным выше дизайном таблицы; Мне нужно было бы выбрать первые x строк, где DirectParentID = 0, но также и строки, где TopParentID = идентификатор сообщения для каждой выбранной строки.
Должен ли я просто изменить свой дизайн стола в конце концов?
Я рекомендую вам иметь одну таблицу для "Тема" плюс одну таблицу для "Комментарии". Вероятно, "Посты" можно просто выбросить с помощью комментариев, но не пытайтесь также вставлять Thread.
Если вам нужна иерархия (Комментарии к комментариям), Post следует отличать от комментариев просто с помощью directParentId = 0
.
Если вам не нужна иерархия, тогда все, что вам нужно, это thread_id
на всех сообщениях/комментариях, а также простой флаг, чтобы сказать, что является исходным сообщением.
Вы могли бы сделать что-то вроде этого:
SELECT *
FROM t
WHERE topParentId IN (SELECT id
FROM t
WHERE directParentId = 0
AND id <= 20);
LIMIT
не может использоваться в подзапросах, поэтому вам понадобится предложение where, чтобы отфильтровать ваши родительские сообщения (возможно, по дате или пользователю или что-то еще).
Если вы хотите использовать лимит, вы можете использовать "self-join", например:
SELECT t.*
FROM (SELECT *
FROM t
WHERE t.did = 0
LIMIT 20) AS t1
INNER JOIN t
ON t.tid = t1.id;
В вашем дизайне нет ничего плохого. Обычные таблицы ссылок являются общими. Вы можете рассмотреть, что ваша таблица содержит "объекты с комментариями", и оба комментария и сообщения могут быть разделены на них. Но запросы, которые обрабатывают сообщения и комментарии как два отдельных объекта, могут быть сложнее/сложнее создать для таблицы, рассматривающей их как единую сущность (по крайней мере, это для меня :))