复杂的sql顺序

时间:2009-08-08 22:44:44

标签: sql mysql

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 个答案:

答案 0 :(得分:7)

我猜对于文章,“回复ID”为0,是评论的文章编号。如果这是你的设计,这应该有效:

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

已添加:感谢您在评论中提供的其他信息。将结果按所需顺序放置并不容易,因为第一个排序键是thread-starter帖子的created_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. 线程中的所有消息(thread =消息及其注释)应该组合在一起。

  2. 在一个帖子中,将消息置于顶部,然后按反向时间顺序将其注释。具有最新创建的/ _date的线程应该是第一个,然后是具有第二个最近的created_date的线程,依此类推。 (您的示例数据具有相同created_date的许多注释,因此我使用“id”作为线程中注释的二级订单键。)

  3. 注意: 您的转储表明如果修改了帖子,created_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
    

    顺便说一句,我怀疑我的两个解决方案都会合并最后一次修改的线程......

答案 1 :(得分:2)

.... 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。)

答案 2 :(得分:0)

我不确定你的要求,所以我的回答是抽象的...... 最大值 - 可能需要一分钟(再次,我不清楚你的确切要求)

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,你可以使用一个名为over row_number的函数。

答案 3 :(得分:0)

这是关于在关系数据库中表示分层数据的链接。 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。*列中。