如何按一个列分组并检索T/SQL中另一列的最小值的行?

ljs*_*ljs 13 sql t-sql sql-server

所以我知道这是一个非常愚蠢的问题,但是(正如相当冗长的标题所示)我想知道如何做到以下几点:

我有这样一张桌子:

ID Foo Bar Blagh
----------------
1  10  20  30
2  10  5   1
3  20  50  40
4  20  75  12
Run Code Online (Sandbox Code Playgroud)

我想按Foo分组,然后用最小的Bar拉出行,即我想要以下内容:

ID Foo Bar Blagh
----------------
2  10  5   1
3  20  50  40
Run Code Online (Sandbox Code Playgroud)

我不能为我的生活找出正确的SQL来检索这个.我想要的东西:

SELECT ID, Foo, Bar, Blagh
FROM Table
GROUP BY Foo
HAVING(MIN(Bar))
Run Code Online (Sandbox Code Playgroud)

然而,这显然不起作用,因为完全无效HAVING语法和ID,Foo,Bar和Blagh没有聚合.

我究竟做错了什么?

but*_*ken 11

几乎是完全相同的问题,但它有一些答案!

这是我嘲笑你的桌子:

declare @Borg table (
    ID int,
    Foo int,
    Bar int,
    Blagh int
)
insert into @Borg values (1,10,20,30)
insert into @Borg values (2,10,5,1)
insert into @Borg values (3,20,50,70)
insert into @Borg values (4,20,75,12)
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行匿名内部联接以获取所需的数据.

select B.* from @Borg B inner join 
(
    select Foo,
        MIN(Bar) MinBar 
    from @Borg 
    group by Foo
) FO
on FO.Foo = B.Foo and FO.MinBar = B.Bar
Run Code Online (Sandbox Code Playgroud)

编辑 Adam Robinson帮助指出"当Bar的最小值重复时,此解决方案有可能返回多行,并且消除了bar所在的任何foo值null"

根据您的用例,其中酒吧是重复的重复值可能是有效的 - 如果你想找到博格的所有值,其中酒吧是最小的,然后有两个结果似乎要走的路.

如果你需要NULLs在你聚合的字段中捕获(在这种情况下是MIN),那么你可以coalesce使用可接受的高(或低)值的NULL(这是一个hack):

...
MIN(coalesce(Bar,1000000)) MinBar -- A suitably high value if you want to exclude this row, make it suitably low to include
...
Run Code Online (Sandbox Code Playgroud)

或者你可以去一个UNION并将所有这些值附加到结果集的底部.

on FO.Foo = B.Foo and FO.MinBar = B.Bar
union select * from @Borg where Bar is NULL
Run Code Online (Sandbox Code Playgroud)

后者不会将@Borg中的值分组为相同的Foo值,因为它不知道如何在它们之间进行选择.

  • 请记住,当Bar的最小值重复时,此解决方案可能会返回多行,并消除bar为null时的任何foo值 (4认同)
  • 厚脸皮.我评论时编辑. (2认同)