2011-08-29 49 views
7

在我的系统中,我有客户。客户有程序。我想显示一个客户列表,显示他们最近的活动(如果存在)程序。组内排序?

因此,我们有这样的事情:

SELECT * 
FROM clients AS client 
    JOIN programs AS program ON client.id=program.client_id 
GROUP BY client.id 
ORDER BY program.close_date=0 DESC, program.close_date DESC 

close_date=0意味着这个程序没有关闭。因此,它会首先将非关闭程序,然后是最近关闭的程序。

问题是,顺序不在组内。它只是随机挑选其中一个程序。我该如何解决这个问题?


就想出了这个:

SELECT * 
FROM clients AS client 
    JOIN (SELECT * FROM programs AS program ORDER BY program.close_date=0 DESC, program.close_date DESC) AS program ON client.id=program.client_id 
GROUP BY client.id 

这似乎给出正确的结果。这是正确的,还是我幸运?即在加入之前,我基本上已经整理了桌子;这些结果将保持排序,因为它加入,对吧?


解决方案:我现在认为这是一个经典的group-wise maximum问题。如果您遇到类似问题,请搜索该文件。解决方案涉及两次连接同一个表。

+3

子选择中的ORDER BY应该对结果没有确定性影响。它可能碰巧与MySQL一起工作,但SQL标准甚至不允许它。关键是要在主(外部查询)中对client.id进行ORDER BY,然后再对其他任何列进行排序。你可能不得不在GROUP BY和ORDER BY子句中说同样的东西;这样做并不需要花费任何费用。 –

+2

@Mark:我不认为你的备用解决方案(上面发布)可以保证给出正确的结果。在'client.id'完成'GROUP BY'之后,[“服务器可以自由选择来自每个组的任何记录”](http://dev.mysql.com/doc/refman/5.0/en/group逐隐藏columns.html)。 – unutbu

+0

@ubutbu:谢谢!这正是我想知道的。我担心情况可能如此。 – mpen

回答

7
SELECT c.*, p.* 
FROM clients AS c 
JOIN programs AS p 
ON  p.id = 
     (
     SELECT pi.id 
     FROM programs AS pi 
     WHERE pi.client_id = c.id 
     ORDER BY 
       pi.close_date=0 DESC, pi.close_date DESC 
     LIMIT 1 
     ) 

感谢名单应该去@Quassnoi。见他的回答类似的(但更复杂的)问题:mysql-group-by-to-display-latest-result


如果更新programs表,并设置close_date的所有记录,它是零close_date='9999-12-31',那么你的ORDER BY会简单(整个查询速度更快,并具有适当的索引):

 ORDER BY 
       pi.close_date DESC 
+0

啊...是的,这个连接更有意义。非常感谢! – mpen

+0

这是我到处寻找的答案。 – atomkirk

1

尝试通过这条命令...

ORDER BY client.id, CASE WHEN program.close_date = 0 THEN 0 ELSE 1 END, program.close_date DESC 
+0

我不明白这是怎么实现的。 'program.close_date = 0'已经评估为“0”或“1”。问题是我需要在组内排序,整体排序(分组后)没有问题。 – mpen

+2

列出的第一列是client.id ...,它将使您的组保持在一起。 – JSR

+0

哦.....你应该在你的答案中指出这一点。尽管我仍然不能100%确定你的意思。首先放置'client.id'将使订购工作成为可能?为什么会有所作为? – mpen