How do I select the first row per group in an SQL Query?

后端 未结 9 840
别跟我提以往
别跟我提以往 2020-12-29 09:26

I\'ve got this SQL query:

SELECT   Foo, Bar, SUM(Values) AS Sum
FROM     SomeTable
GROUP BY Foo, Bar
ORDER BY Foo DESC, Sum DESC

This resul

相关标签:
9条回答
  • 2020-12-29 09:55

    I might disagree with rjmunru in that using Ansii style joins can often be easier to read than subqueries but to each his own -- I just follow what our DBAs say to do.

    If you just want the first result from a query, you might be able to use a rownum (if using oracle, other databases probably have something similiar).

    select * from foo_t f where f.bar = 'bleh' and rownum = 1

    Of course a HAVING clause might also be appropriate, depending on what you are trying to do.

    "HAVING is used to perform an action on groups created by GROUP BY similar to that of the WHERE clause on rows in a basic SQL statement. The WHERE clause limits the rows evaluated. The HAVING clause limits the grouped rows returned."

    hth

    0 讨论(0)
  • 2020-12-29 09:55

    It's an old post but I had the same problem today. I've solved it by trying many queries until it works. I'm using SQL Compact 3.5 with visual basic 2010.

    This example is for a table named "TESTMAX" with columns "Id" (primary key), "nom" (name) and "value", you can use this to obtain rows with max "value" for each "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
    

    If you want to delete the other rows, you can also use :

    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))
    
    0 讨论(0)
  • 2020-12-29 09:58

    (EDITED Based on edited question) Then, since you wish to filter based on the value of an aggregated column, what you need is a Having Clause.

      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
    
    0 讨论(0)
  • 2020-12-29 10:00
    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
    
    0 讨论(0)
  • 2020-12-29 10:02

    Curious. Only way I could get this to work was by using a temporary holding table in memory. (TSQL syntax)

    -- 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)
    
    0 讨论(0)
  • 2020-12-29 10:12

    Just group on Players.Nick alone, and select the first (min) of the description

    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
    

    that is if you always want the first without knowing it

    0 讨论(0)
提交回复
热议问题