这里有很多类似的问题,但我认为没有一个能充分回答这个问题。

如果可以的话,我将从当前最流行的问题继续,用他们的例子。

这个实例中的任务是获取数据库中每个作者的最新文章。

示例查询产生了不可用的结果,因为它并不总是返回的最新帖子。

SELECT wp_posts.* FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author           
    ORDER BY wp_posts.post_date DESC

目前公认的答案是

SELECT
    wp_posts.*
FROM wp_posts
WHERE
    wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author
HAVING wp_posts.post_date = MAX(wp_posts.post_date) <- ONLY THE LAST POST FOR EACH AUTHOR
ORDER BY wp_posts.post_date DESC

不幸的是,这个答案显然是错误的,在许多情况下产生的结果不如原始查询稳定。

我的最佳解决方案是使用表单的子查询

SELECT wp_posts.* FROM 
(
    SELECT * 
    FROM wp_posts
    ORDER BY wp_posts.post_date DESC
) AS wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author 

我的问题很简单: 有没有办法在分组之前对行进行排序而不诉诸子查询?

编辑:这个问题是另一个问题的延续,我的具体情况略有不同。您可以(也应该)假设还有一个wp_posts。Id,是该特定帖子的唯一标识符。


当前回答

不。在分组之前对记录排序是没有意义的,因为分组将会改变结果集。子查询方式是首选方式。如果速度太慢,你就必须改变你的表设计,例如将每个作者的最后一篇文章的id存储在一个单独的表中,或者引入一个布尔列,为每个作者指出他的最后一篇文章。

其他回答

以下是我使用用户定义变量获得一致结果的解决方案,甚至没有GROUP BY。我们的目标是获取整个行,而不仅仅是一行中一个单元格的最大值。请看下面的例子:

SET @product_id := 0;

SELECT
    products.order_code,
    purchases.`date`,
    purchases.price
FROM products
LEFT JOIN (       
    SELECT
        purchases.`date`,
        purchases.price,
        IF(@product_id = purchases.product_id, 0, 1) AS is_last,
        @product_id := purchases.product_id AS product_id
    FROM purchases
    ORDER BY purchases.product_id ASC, purchases.id DESC
) purchases ON products.id = purchases.product_id
WHERE purchases.is_last = 1
ORDER BY products.order_code ASC;

我不确定性能如何,但在50000行购买表上它是0.1秒。如果我能做些什么改进,请告诉我。

试试这个。只需要从每个作者那里获得最新发布日期的列表。这是它

SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post' AND wp_posts.post_date IN(SELECT MAX(wp_posts.post_date) FROM wp_posts GROUP BY wp_posts.post_author) 

简单回顾一下,标准的解决方案使用了一个不相关的子查询,看起来像这样:

SELECT x.*
  FROM my_table x
  JOIN (SELECT grouping_criteria,MAX(ranking_criterion) max_n FROM my_table GROUP BY grouping_criteria) y
    ON y.grouping_criteria = x.grouping_criteria
   AND y.max_n = x.ranking_criterion;

如果你正在使用一个古老版本的MySQL,或者一个相当小的数据集,那么你可以使用以下方法:

SELECT x.*
  FROM my_table x
  LEFT
  JOIN my_table y
    ON y.joining_criteria = x.joining_criteria
   AND y.ranking_criteria < x.ranking_criteria
 WHERE y.some_non_null_column IS NULL;  

首先,不要在select中使用*,这会影响它们的性能并阻碍group by和order by的使用。 试试这个问题:

SELECT wp_posts.post_author, wp_posts.post_date as pdate FROM wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author           
ORDER BY pdate DESC

当你在ORDER BY中不指定表,只指定别名时,他们将对选择的结果进行排序。

不。在分组之前对记录排序是没有意义的,因为分组将会改变结果集。子查询方式是首选方式。如果速度太慢,你就必须改变你的表设计,例如将每个作者的最后一篇文章的id存储在一个单独的表中,或者引入一个布尔列,为每个作者指出他的最后一篇文章。