如何在 SQL 查询中选择每个组的第一行?
Posted
技术标签:
【中文标题】如何在 SQL 查询中选择每个组的第一行?【英文标题】:How do I select the first row per group in an SQL Query? 【发布时间】:2010-12-25 07:13:41 【问题描述】:我有这个 SQL 查询:
SELECT Foo, Bar, SUM(Values) AS Sum
FROM SomeTable
GROUP BY Foo, Bar
ORDER BY Foo DESC, Sum DESC
这会产生类似这样的输出:
47 1 100
47 0 10
47 2 10
46 0 100
46 1 10
46 2 10
44 0 2
我希望每个 Foo 仅具有第一行(它及其最高 Bar),而忽略其余部分。
47 1 100
46 0 100
44 0 2
我该怎么做?
【问题讨论】:
那么,您使用的是什么数据库以及该数据库的哪个版本?这是一个很好的标签候选者! 选择保留哪些记录和丢弃哪些记录的标准是什么? @ILMV:有时我希望你能给好的编辑点数...... 重写了问题,简化了查询。除非更新以反映更改,否则某些答案可能不再有意义。 这能回答你的问题吗? Select first row in each GROUP BY group? 【参考方案1】:仅对 Players.Nick 进行分组,然后选择描述的第一个(最少)
SELECT Players.Nick, MIN(Reasons.Description), SUM(Marks.Value) AS Sum
FROM Marks INNER JOIN
Players ON Marks.PlayerID = Players.ID INNER JOIN
Reasons ON Marks.ReasonId = Reasons.ID
GROUP BY Players.Nick
ORDER BY Players.Nick, Sum DESC
如果你总是想要第一个而不知道它
【讨论】:
我想要第三列中值最高的行。【参考方案2】:(已编辑基于已编辑的问题) 然后,由于您希望根据聚合列的值进行过滤,因此您需要一个拥有子句。
SELECT p.Nick, r.Description, SUM(m.Value) Sum
FROM Marks m
JOIN Players p
ON m.PlayerID = p.ID
JOIN Reasons r
ON m.ReasonId = r.ID
GROUP BY p.Nick, r.Description
Having SUM(m.Value) =
(Select Max(Sum) From
(SELECT SUM(m.Value) Sum
FROM Marks mi
JOIN Players pi
ON mi.PlayerID = pi.ID
JOIN Reasons r i
ON mi.ReasonId = ri.ID
Where pi.Nick = p.Nick
GROUP BY pi.Nick, ri.Description))
Order By p.Nick, Sum Desc
【讨论】:
我不想选择'X'的输出。相反,通过第三行中的值(见编辑)。【参考方案3】:一般来说,尝试使用子查询而不是加入和分组 - 这通常会使 SQL 更容易理解。
SELECT Nick,
(SELECT Description from Reasons WHERE Reasons.ID = (
SELECT FIRST(Marks.ReasonId) from Marks WHERE Marks.PlayerID = Players.ID)
),
(SELECT SUM(Value) from Marks WHERE Marks.PlayerID = Players.ID)
【讨论】:
【参考方案4】:我可能不同意 rjmunru,因为使用 Ansii 样式的连接通常比子查询更容易阅读,但对于每个人来说,我只是按照我们的 DBA 所说的去做。
如果您只想要查询的第一个结果,您可以使用 rownum(如果使用 oracle,其他数据库可能有类似的东西)。
从 foo_t f 中选择 * 其中 f.bar = 'bleh' 和 rownum = 1
当然,HAVING 子句也可能是合适的,具体取决于您要执行的操作。
“HAVING 用于对由 GROUP BY 创建的组执行操作,类似于对基本 SQL 语句中行的 WHERE 子句的操作。WHERE 子句限制评估的行。HAVING 子句限制返回的分组行。”
第
【讨论】:
如果我理解正确,那么这就是我想要的,其实。【参考方案5】:好奇。我能让这个工作的唯一方法是在内存中使用一个临时保存表。 (TSQL 语法)
-- original test data
declare @sometable table ( foo int, bar int, value int )
insert into @sometable values (1, 5, 10)
insert into @sometable values (1, 4, 20)
insert into @sometable values (2, 1, 1)
insert into @sometable values (2, 1, 10)
insert into @sometable values (2, 1, 1)
insert into @sometable values (2, 2, 13)
insert into @sometable values (3, 4, 25)
insert into @sometable values (3, 5, 1)
insert into @sometable values (3, 1, 1)
insert into @sometable values (3, 1, 1)
insert into @sometable values (3, 1, 1)
insert into @sometable values (3, 1, 1)
insert into @sometable values (3, 1, 1)
-- temp table for initial aggregation
declare @t2 table (foo int, bar int, sums int)
insert into @t2
select foo, bar, sum(value)
from @sometable
group by foo, bar
-- final result
select foo, bar, sums
from @t2 a
where sums =
(select max(sums) from @t2 b
where b.foo = a.foo)
【讨论】:
【参考方案6】:SQL Server 2005 你可以使用这个:
声明@sometable table ( foo int, bar int, value int )
插入@sometable 值(1、5、10) 插入@sometable 值(1、4、20) 插入@sometable 值 (2, 1, 1) 插入@sometable 值 (2, 1, 10) 插入@sometable 值 (2, 1, 1) 插入@sometable 值 (2, 2, 13) 插入@sometable 值(3、4、25) 插入@sometable 值 (3, 5, 1) 插入@sometable 值 (3, 1, 1) 插入@sometable 值 (3, 1, 1) 插入@sometable 值 (3, 1, 1) 插入@sometable 值 (3, 1, 1) 插入@sometable 值(3、1、1)
-- 初始聚合的临时表 声明@t2 表(foo int,bar int,sums int) 插入@t2 选择 foo, bar, sum(value) 来自@sometable 按 foo、bar 分组
从 ( SELECT foo, bar, sums, ROW_NUMBER() OVER (PARTITION BY Foo ORDER BY Sums DESC) ROWNO FROM @t2) x 其中 x.ROWNO = 1
【讨论】:
【参考方案7】:declare @sometable table ( foo int, bar int, value int )
insert into @sometable values (47, 1, 100)
insert into @sometable values (47, 0, 10)
insert into @sometable values (47, 2, 10)
insert into @sometable values (46, 0, 100)
insert into @sometable values (46, 1, 10)
insert into @sometable values (46, 2, 10)
insert into @sometable values (44, 0, 2)
WITH cte AS
(
SELECT Foo, Bar, SUM(value) AS SumValue, ROW_NUMBER() OVER(PARTITION BY Foo ORDER BY FOO DESC, SUM(value) DESC) AS RowNumber
FROM @SomeTable
GROUP BY Foo, Bar
)
SELECT *
FROM cte
WHERE RowNumber = 1
【讨论】:
【参考方案8】:这是一个旧帖子,但我今天遇到了同样的问题。我已经通过尝试许多查询来解决它,直到它起作用。我在 Visual Basic 2010 中使用 SQL Compact 3.5。
此示例适用于名为“TESTMAX”的表,其中包含“Id”(主键)、“nom”(名称)和“value”列,您可以使用它来获取每个“nom”的最大“值”行" :
SELECT TESTMAX.Id, TESTMAX.NOM, TESTMAX.Value
FROM TESTMAX INNER JOIN
TESTMAX AS TESTMAX_1 ON TESTMAX.NOM = TESTMAX_1.NOM
WHERE (TESTMAX.Value IN
(SELECT MAX(Value) AS Expr1
FROM TESTMAX AS TESTMAX_2
WHERE (NOM = TESTMAX_1.NOM)))
GROUP BY TESTMAX.Id, TESTMAX.NOM, TESTMAX.Value
如果要删除其他行,也可以使用:
DELETE FROM TESTMAX
WHERE (Id NOT IN
(SELECT TESTMAX_3.Id
FROM TESTMAX AS TESTMAX_3 INNER JOIN
TESTMAX AS TESTMAX_1 ON TESTMAX_3.NOM = TESTMAX_1.NOM
WHERE (TESTMAX_3.Value IN
(SELECT MAX(Value) AS Expr1
FROM TESTMAX AS TESTMAX_2
WHERE (NOM = TESTMAX_1.NOM)))
GROUP BY TESTMAX_3.Id, TESTMAX_3.NOM, TESTMAX_3.Value))
【讨论】:
以上是关于如何在 SQL 查询中选择每个组的第一行?的主要内容,如果未能解决你的问题,请参考以下文章
如何编写查询以获取 SQL Server 中每个组的第一个条目? [复制]
如何在 hive sql 中获取每个组的最大 row_number()