комплексный заказ sql - PullRequest
       3

комплексный заказ sql

5 голосов
/ 09 августа 2009
id    |    message    |    reply id    |    date  

1     |  my new app.. |     0          | 10 / 10 / 2009 (latest message on top, follow by replies)
5     | love ur app.. |     1          | 11 / 10 / 2009 (this should show under the main message)
6     | another comm  |     1          | 12 / 10 / 2009
2     | application 2 |     0          | 09 / 10 / 2009
3     | reply of 2    |     2          | 11 / 10 / 2009

Я хочу показать последние комментарии и их ответы после основных комментариев. Очевидно, что ответы будут иметь самую последнюю дату, поэтому я не могу отсортировать их по дате, потому что ответы будут в верхней части главной. Я не уверен, как сделать это правильно с одним запросом. Любая идея, пожалуйста.

дамп базы данных: http://pastie.org/576963

Ответы [ 4 ]

7 голосов
/ 09 августа 2009

Полагаю, что "идентификатор ответа" равен 0 для статей и является номером статьи для комментариев. Если это ваш дизайн, это должно работать:

select * from yourTable
order by
  case when "reply id" = 0 then id else "reply id" end, id

ДОБАВЛЕНО: Спасибо за дополнительную информацию в вашем комментарии. Расставить результаты в нужном вам порядке не так-то просто, потому что первый ключ упорядочения - это create_date сообщения начального потока. Это не в строке данных, поэтому вам нужно объединение. Вот мое лучшее предположение, основанное на дополнительной информации (которая все еще не является полной, чтобы не дать мне угадать):

select
  f.id, f.user_id, f.type, f.reply_id, f.text, f.url, f.created_date,
  coalesce(parentfeed.created_date,f.created_date) as thread_date
from feed as f left outer join feed as parentfeed
on f.reply_id = parentfeed.id
order by
  thread_date desc,
  case when f.reply_id = 0 then 0 else 1 end,
  created_date desc, id;

Возможно, вам придется настроить синтаксис для postgre. Я проверил это в SQL Server.

Если это все еще не дает того, что вы хотите, пожалуйста, уточните, как вы хотите вернуть данные. Предпочтительно, сообщите мне порядок «id», который я должен увидеть для данных в вашем файле дампа, и также объяснит основание для этого порядка. Вот что я сделал:

  1. Все сообщения в цепочке (ветка = сообщения и их комментарии) должны быть сгруппированы вместе.

  2. В цепочке поместите сообщение сверху, а затем комментарии в обратном хронологическом порядке. Сначала следует поток с самым последним созданным / _date, затем поток со вторым самым последним созданным_date и т. Д. (В ваших образцах данных было много комментариев с одной и той же созданной датой, поэтому я использовал «id» в качестве вторичного ключа заказа для комментариев в потоке.)

Примечание: Ваш дамп указывает, что create_date обновляется до CURRENT_TIMESTAMP, если сообщение изменено. Если это живая доска объявлений, помните, что это может привести к тому, что комментарии будут датированы до родительского сообщения, и это означает, что поток будет оставаться на вершине, если он часто изменяется (даже без фактического изменения его текст). (Это не относится к моему решению, но я подумал, что это стоит отметить.)

Поскольку требуется соединение, этот запрос теперь будет выполняться намного медленнее. Мое предложение: сохранить два столбца даты, "thread_last_modified" и "item_last_modified". Вам нужно будет каскадно обновлять обновления от потоков до комментариев, но я думаю, что это стоит того, чтобы обновлений было немного, потому что запрос может быть намного проще. Я не проверял это, потому что это требует нескольких изменений в вашем дизайне:

select
  id, user_id, type, reply_id, text, url, thread_last_modified, item_last_modified
from feed
order by
  thread_last_modified desc,
  case when f.reply_id = 0 then 0 else 1 end,
  item_last_modified desc, id;

ADDED # 2 : Если вы хотите только поток, содержащий комментарий с id :: thisOne, я думаю, вы можете добавить эту строку между предложениями ON и ORDER BY (для моего первого добавленного решения, присоединиться):

where parentfeed.id = (
  select coalesce(reply_id,id)
  from feed
  where id = ::thisOne
)

Теоретически, этот поиск должен оцениваться только один раз для запроса, но если это не практикуется, вы можете предварительно вычислить его как :: thisOneThreadID и добавить

where parentfeed.id = ::thisOneThreadID

Для второго решения, при условии, что вы выполняете предварительные вычисления снова, попробуйте

where coalesce(id,reply_id) = ::thisOneThreadID

Кстати, я подозреваю, что оба моих решения объединят потоки, которые были изменены в последний раз в одно и то же время ...

2 голосов
/ 09 августа 2009

.... order by (некоторые предикаты, которые верны для «основных комментариев», но не последующих) desc, date desc

Поскольку вы не ясно даете понять, что отличает «главный комментарий», это все, что я могу для вас сделать. Если, как в вашем примере, все основные комментарии имеют reply_id нуля, это может быть:

order by case reply_id = 0 then 1 else 0 end desc, date desc

Обратите внимание, что использование оператора case вместо простого упорядочивания по reply_id необходимо, поскольку вы хотите, чтобы первое выражение имело одинаковое значение (а именно, ноль) для всех неосновных сообщений, чтобы они сортировались исключительно по второе выражение, date.

(О, если я понимаю вашу схему, reply_id должно действительно называться in_repky_to_id.)

0 голосов
/ 10 августа 2009

Вот ссылка на представление иерархических данных в реляционной базе данных. http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

Суть в том, что вам нужно присоединиться к столу на столько уровней, сколько вы хотите пройти. Предоставленные данные примера были всего двумя уровнями глубины.

SELECT
f1.id AS `parent_id`, 
f1.text AS `parent_text`, 
f1.created_date AS `parent_created_date`, 
f2.*
FROM 
feed AS `f1`
LEFT JOIN feed `f2` ON (f1.id = f2.reply_id)
WHERE f1.reply_id = 0
ORDER BY f1.created_date DESC, f2.created_date DESC
;

Информация о родительской статье будет в столбцах f1. *, А дочерняя информация (ответы) будет в столбцах f2. *.

0 голосов
/ 09 августа 2009

Я не уверен в ваших требованиях, поэтому мой ответ - абстракция ... максимум - может потребоваться минута (опять же, я не совсем точно понимаю ваши требования)

select
    y.column1
    , y.column2
    , y.column3
    , y.datecolumn
from
(select 
    column1
    , max(datecolumn) as rank_date
 from tableA
 group by column1) as x
inner join tableA y on x.id = y.id
order by x.rank_date, y...., y.... desc, y... asc, etc...

если вы используете sql server, есть функция с именем row_number, которую вы также можете использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...