给定一个这样的数据表:
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 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 |
有一些 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
值。
这有一些警告,特别是当您连接非字符串列时。此外,如果您有多个相同的日期,则无法使用平局决胜局。好处是它避免了额外的窗口聚合步骤。