有一个表消息,其中包含如下所示的数据:

Id   Name   Other_Columns
-------------------------
1    A       A_data_1
2    A       A_data_2
3    A       A_data_3
4    B       B_data_1
5    B       B_data_2
6    C       C_data_1

如果我按名称从消息组中运行查询select *,我将得到如下结果:

1    A       A_data_1
4    B       B_data_1
6    C       C_data_1

哪个查询将返回以下结果?

3    A       A_data_3
5    B       B_data_2
6    C       C_data_1

也就是说,应该返回每个组中的最后一条记录。

目前,这是我使用的查询:

SELECT
  *
FROM (SELECT
  *
FROM messages
ORDER BY id DESC) AS x
GROUP BY name

但这看起来效率很低。还有其他方法可以达到同样的效果吗?


当前回答

这个怎么样:

SELECT DISTINCT ON (name) *
FROM messages
ORDER BY name, id DESC;

我也有类似的问题(在postgresql tough上),在1M的记录表上。这个解决方案需要1.7秒,而使用LEFT JOIN的解决方案需要44秒。 在我的例子中,我必须根据NULL值过滤您的名称字段的对应项,从而使性能更好0.2秒

其他回答

下面是另一种获取最后一条相关记录的方法,使用GROUP_CONCAT和SUBSTRING_INDEX从列表中选择一条记录

SELECT 
  `Id`,
  `Name`,
  SUBSTRING_INDEX(
    GROUP_CONCAT(
      `Other_Columns` 
      ORDER BY `Id` DESC 
      SEPARATOR '||'
    ),
    '||',
    1
  ) Other_Columns 
FROM
  messages 
GROUP BY `Name` 

上面的查询将组所有Other_Columns在同一名称组和使用ORDER BY id DESC将连接所有Other_Columns在一个特定的组降序与提供的分隔符在我的情况下,我已经使用||,使用SUBSTRING_INDEX在这个列表将选择第一个

小提琴演示

使用子查询返回正确的分组,因为您已经完成了一半。

试试这个:

select
    a.*
from
    messages a
    inner join 
        (select name, max(id) as maxid from messages group by name) as b on
        a.id = b.maxid

如果它不是id,你想要的最大值:

select
    a.*
from
    messages a
    inner join 
        (select name, max(other_col) as other_col 
         from messages group by name) as b on
        a.name = b.name
        and a.other_col = b.other_col

通过这种方式,可以避免在子查询中进行相关子查询和/或排序,这往往非常缓慢/低效。

我得到了一个不同的解决方案,这是获得每个组中最后一个帖子的id,然后从消息表中选择使用第一个查询的结果作为WHERE x IN构造的参数:

SELECT id, name, other_columns
FROM messages
WHERE id IN (
    SELECT MAX(id)
    FROM messages
    GROUP BY name
);

我不知道与其他一些解决方案相比,它的性能如何,但对于我有300多万行的表来说,它的效果非常好。(4秒执行,1200+结果)

这应该工作在MySQL和SQL Server。

如果您真正关心的是性能,则可以在表上引入一个名为IsLastInGroup的类型为BIT的新列。

在最后的列上设置为true,并在每一行插入/更新/删除时保持该值。写的速度会变慢,但读的时候会受益。这取决于您的用例,我只建议在以读取为重点的情况下使用它。

因此,您的查询将如下所示:

SELECT * FROM Messages WHERE IsLastInGroup = 1

另一种方法:

找到每个程序中最大m2_price的属性(一个程序中有n个属性):

select * from properties p
join (
    select max(m2_price) as max_price 
    from properties 
    group by program_id
) p2 on (p.program_id = p2.program_id)
having p.m2_price = max_price