在使用分组依据的选择中,获取不在分组依据中的列的最后一个值

问题描述 投票:0回答:2

给定一个这样的数据表:

a b c d e
1 测试 9 h 2024-10-22 08:00:00.000
1 测试 9 l 2024-10-23 08:00:00.000
1 测试 9 q 2024-10-22 08:00:00.000

我想按 a、b、c 列对数据进行分组,并显示 d 列中的值,该值在 e 列中具有最新日期。

所以我希望像这样返回一行数据:

a b c d
1 测试 9 l

我希望像下面这样简单的“last()”,但据我所知,没有这么简单的东西?

SELECT 
    a, b, c,
    last(d)
FROM
    dbo.items 
GROUP BY 
    a, b, c

我能找到的唯一一个与我想要的远程接近的例子是

LAST_VALUE OVER PARTITION
它不能在组中工作

LAST_VALUE(d) OVER (PARTITION BY d ORDER BY e) AS d

而且我知道类似的事情可以访问不在分组中的东西,就像如果 b 想要在分组中一样,我仍然可以

STRING_AGG
所有像这样的值

STRING_AGG(b, ',') AS b 

并获取“测试,测试,测试”作为值

sql sql-server greatest-n-per-group
2个回答
3
投票

如果您使用的是 SQL Server,则使用 Row_Number 可能会起作用

SELECT a, b, c, d FROM
(SELECT *,
      ROW_NUMBER() OVER (PARTITION BY a,b,c ORDER BY e desc) as rn
FROM dbo.items 
)t
WHERE rn=1

小提琴

a b c d
1 测试 9 l

0
投票

有一些 hacky 和一些更标准的解决方案。

标准是获取子查询中的最后一个值并稍后聚合它,例如:

select a, STRING_AGG(b, ',') WITHIN GROUP(ORDER BY a,c) as b, c, max(lastD) as d
from (
    select a, b,c,d, e, last_value(d) over(partition by a,b,c order by e desc) as lastD
    from (
        VALUES  (1, N'test', 9, N'h', N'2024-10-22 08:00:00.000')
        ,   (1, N'test', 9, N'l', N'2024-10-23 08:00:00.000')
        ,   (1, N'test', 9, N'q', N'2024-10-22 08:00:00.000')
    ) t (a,b,c,d,e)
    ) x
GROUP BY a,b,c

我称之为“重建”的黑客方法,它需要组合聚合值,然后在检索最大值后将其解构回来,例如:

SELECT  a, STRING_AGG(b, ',') WITHIN GROUP(ORDER BY a,c) AS b, c
,   STUFF(MAX(CONCAT(CONVERT(VARCHAR(30), cast(e AS datetime), 121), d)), 1,23, '') AS d
FROM
(
    VALUES  (1, N'test', 9, N'h', N'2024-10-22 08:00:00.000')
    ,   (1, N'test', 9, N'l', N'2024-10-23 08:00:00.000')
    ,   (1, N'test', 9, N'q', N'2024-10-22 08:00:00.000')
    ) t (a,b,c,d,e)
GROUP BY a,b,c

在这里,通过将日期的 varchar 表示形式与您的

d
值相结合,可以得到按日期自然升序的值,因此可以使用 MAX。得到最高值后,可以使用STUFF函数去掉日期部分,得到
d
值。

这有一些警告,特别是当您连接非字符串列时。此外,如果您有多个相同的日期,则无法使用平局决胜局。好处是它避免了额外的窗口聚合步骤。

© www.soinside.com 2019 - 2024. All rights reserved.