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

在T/SQL中,如何按一列分组并检索具有另一列最小值的行?,sql,sql-server,tsql,Sql,Sql Server,Tsql,因此,我知道这是一个相当愚蠢的问题,但是(正如标题所说的)我想知道如何做到以下几点: ID Foo Bar Blagh ---------------- 2 10 5 1 3 20 50 40 DECLARE @TEST TABLE( ID int, Foo int, Bar int, Blagh int) INSERT INTO @TEST VALUES (1,10,20,30) INSERT INTO @TEST VALUES (2,10,5,1) I

因此,我知道这是一个相当愚蠢的问题,但是(正如标题所说的)我想知道如何做到以下几点:

ID Foo Bar Blagh
----------------
2  10  5   1
3  20  50  40
DECLARE @TEST TABLE(    ID int,    Foo int,    Bar int,    Blagh int)
INSERT INTO @TEST VALUES (1,10,20,30)
INSERT INTO @TEST VALUES (2,10,5,1)
INSERT INTO @TEST VALUES (3,20,50,70)
INSERT INTO @TEST VALUES (4,20,75,12)

SELECT Id, Foo, Bar, Blagh 
FROM (
      SELECT id, Foo, Bar, Blagh, CASE WHEN (Min(Bar) OVER(PARTITION BY FOO) = Bar) THEN 1 ELSE 0 END as MyRow
      FROM @TEST) t
WHERE MyRow = 1
我有一张这样的桌子:

ID Foo Bar Blagh
----------------
1  10  20  30
2  10  5   1
3  20  50  40
4  20  75  12
select * from Table t
join (
   select Foo, min(Bar) as minbar
   from Table group by Foo
) tt on t.Foo=tt.Foo and t.Bar=tt.minbar
我想按Foo分组,然后拉出具有最小条的行,即,我想要以下内容:

ID Foo Bar Blagh
----------------
2  10  5   1
3  20  50  40
DECLARE @TEST TABLE(    ID int,    Foo int,    Bar int,    Blagh int)
INSERT INTO @TEST VALUES (1,10,20,30)
INSERT INTO @TEST VALUES (2,10,5,1)
INSERT INTO @TEST VALUES (3,20,50,70)
INSERT INTO @TEST VALUES (4,20,75,12)

SELECT Id, Foo, Bar, Blagh 
FROM (
      SELECT id, Foo, Bar, Blagh, CASE WHEN (Min(Bar) OVER(PARTITION BY FOO) = Bar) THEN 1 ELSE 0 END as MyRow
      FROM @TEST) t
WHERE MyRow = 1
我一辈子都无法计算出正确的SQL来检索这个。我想要像这样的东西:

SELECT ID, Foo, Bar, Blagh
FROM Table
GROUP BY Foo
HAVING(MIN(Bar))
然而,这显然不起作用,因为如果语法和ID、Foo、Bar和Blagh没有聚合,这是完全无效的

我做错了什么?

几乎是同一个问题,但它有一些答案

我来模拟一下你的桌子:

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)
然后,您可以进行匿名内部联接以获取所需的数据

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
EDIT亚当·罗宾逊(Adam Robinson)很有帮助地指出,“当Bar的最小值被复制时,此解决方案有可能返回多行,并消除Bar为
null的任何foo值。”

根据您的用例,在Bar被复制的地方复制值可能是有效的-如果您想在Borg中找到Bar最小的所有值,那么两个结果都是可行的

如果需要在要聚合的字段中捕获
空值
(在本例中为MIN),则可以
将空值与可接受的高(或低)值合并(这是一种攻击):

或者,您可以使用联合并将所有这些值附加到结果集的底部

on FO.Foo = B.Foo and FO.MinBar = B.Bar
union select * from @Borg where Bar is NULL

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

我的理解是,您不能一次完成这项工作

select Foo, min(Bar) from table group by Foo
,获取每个不同Foo的最小栏。但不能将最小值与特定ID绑定,因为可能有多行具有该条值

您可以这样做:

ID Foo Bar Blagh
----------------
1  10  20  30
2  10  5   1
3  20  50  40
4  20  75  12
select * from Table t
join (
   select Foo, min(Bar) as minbar
   from Table group by Foo
) tt on t.Foo=tt.Foo and t.Bar=tt.minbar
请注意,如果有多行具有最小条值,则您将通过上述查询获得所有行

现在,我并不是在宣称自己是SQL大师,现在已经很晚了,我可能错过了一些东西,但我的$0.02:)

这可能会有所帮助:

DECLARE @Table TABLE(
        ID INT,
        Foo FLOAT,
        Bar FLOAT,
        Blah FLOAT
)

INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 1, 10 ,20 ,30
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 2, 10 ,5 ,1
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 3, 20 ,50 ,40
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 4, 20 ,75 ,12

SELECT  t.*
FROM    @Table t INNER JOIN
        (
            SELECT  Foo,
                    MIN(Bar) MINBar
            FROM    @Table
            GROUP BY Foo
        ) Mins ON t.Foo = Mins.Foo
                AND t.Bar = Mins.MINBar

这将再次在表上联接,但这一次为
bar
的值添加了一个相对行号,就好像它在
foo
的每个值内按升序排序一样。通过对
rowNumber=0
进行过滤,它仅为
bar
的每个
foo
值选择最低值。这也有效地消除了
group by
子句,因为现在每个
foo
只检索一行。另一个选项是以下内容:

ID Foo Bar Blagh
----------------
2  10  5   1
3  20  50  40
DECLARE @TEST TABLE(    ID int,    Foo int,    Bar int,    Blagh int)
INSERT INTO @TEST VALUES (1,10,20,30)
INSERT INTO @TEST VALUES (2,10,5,1)
INSERT INTO @TEST VALUES (3,20,50,70)
INSERT INTO @TEST VALUES (4,20,75,12)

SELECT Id, Foo, Bar, Blagh 
FROM (
      SELECT id, Foo, Bar, Blagh, CASE WHEN (Min(Bar) OVER(PARTITION BY FOO) = Bar) THEN 1 ELSE 0 END as MyRow
      FROM @TEST) t
WHERE MyRow = 1
尽管这仍然需要一个子查询,但它确实消除了连接的需要


只是另一种选择。

厚颜无耻。在我评论时编辑。@gbn我在给我的答案“添加值!”:)嘿,我很欣赏它的附加值!!:)请记住,当Bar的最小值被复制时,此解决方案有可能返回多行,并且在Bar为nullHm的情况下消除任何foo值,我不知道这些警告@butterchicken-也许值得将它们添加到解决方案中,以便其他用户知道?值得一提的是,在MSSQLS2005引入行号()之前,这是不起作用的。不要从其他人那里复制答案。
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)

select * from @Borg

select Foo,Bar,Blagh from @Borg b 
where Bar = (select MIN(Bar) from @Borg c where c.Foo = b.Foo)