Как выбрать первую строку для каждой группы в SQL Query?

У меня есть этот 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 и игнорировать остальные.

47  1   100
46  0   100
44  0   2

Как это сделать?

Ответ 1

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

Ответ 2

Я мог бы не согласиться с rjmunru тем, что использование сочетаний стиля Ansii часто может быть легче читать, чем подзапросы, но для каждого из них - я просто следую тому, что говорят наши администраторы баз данных.

Если вам нужен только первый результат запроса, вы можете использовать rownum (если использовать oracle, другие базы данных, вероятно, имеют что-то похожее).

выберите * из foo_t f где f.bar = 'bleh' и rownum = 1

Конечно, предложение HAVING также может быть соответствующим, в зависимости от того, что вы пытаетесь сделать.

"HAVING используется для выполнения действия над группами, созданными GROUP BY, аналогичными действиям WHERE в строках в базовом выражении SQL. Предложение WHERE ограничивает оцениваемые строки. Предложение HAVING ограничивает возвращаемые сгруппированные строки".

HTH

Ответ 3

Просто установите группу на 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

если вы всегда хотите первого, не зная об этом

Ответ 4

Это старая должность, но сегодня у меня была такая же проблема. Я решил это, попробовав много запросов, пока это не сработает. Я использую SQL Compact 3.5 с визуальным базовым 2010.

Этот пример предназначен для таблицы с именем "TESTMAX" с столбцами "Id" (первичный ключ), "nom" (имя) и "значение", вы можете использовать это для получения строк с максимальным значением для каждого "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))

Ответ 5

(EDITED На основании отредактированного вопроса) Затем, поскольку вы хотите отфильтровать, основываясь на значении агрегированного столбца, вам понадобится параметр "Бытие".

  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

Ответ 6

В общем, попробуйте использовать подзапросы, а не присоединяться и группировать - это часто делает 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)

Ответ 7

Возможно ли использовать предложение "HAVING"? (Вы хотите различить по агрегатной функции - "Сумма" )?

Ответ 8

Любопытный. Единственный способ, которым я мог заставить это работать, - использовать временную таблицу хранения в памяти. (Синтаксис 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)

Ответ 9

SQL Server 2005 вы можете использовать это:

объявить @sometable table (foo int, bar int, значение 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)

- временная таблица для начальной агрегации declare @t2 table (foo int, bar int, sums int) вставить в @t2 выберите foo, bar, sum (value) из @sometable group by foo, bar

выберите * from (  SELECT foo, bar, sums, ROW_NUMBER() OVER (PARTITION by Foo ORDER BY Sums DESC) ROWNO  FROM @t2) x где x.ROWNO = 1