Максимальная сумма в SQL

У меня есть список магазинов, отделов в магазинах и продаж для каждого отдела, например (созданный с использованием max(sales) в подзапросе, но здесь это не очень важно, я не думаю):

toronto    baskets 500
vancouver  baskets 350
halifax    baskets 100
toronto    noodles 275
vancouver  noodles 390
halifax    noodles 120
halifax    fish    200

Я хотел бы попросить самый продаваемый отдел в каждом магазине. Результаты должны выглядеть следующим образом:

toronto    baskets 500
vancouver  noodles 275
halifax    fish    200

Всякий раз, когда я использую GROUP BY, он включает все списки из моего подзапроса. Есть ли хороший чистый способ сделать это без временной таблицы?


person Community    schedule 04.11.2008    source источник
comment
Какая платформа базы данных? sql-сервер? оракул?   -  person TheSoftwareJedi    schedule 04.11.2008
comment
кто бы мог подумать, что лапша будет так популярна в Ванкувере, а?   -  person TheSoftwareJedi    schedule 04.11.2008
comment
Это снова выбрать победителя. stackoverflow.com/questions/246870/simple-sql-query   -  person Amy B    schedule 04.11.2008
comment
Этот вопрос должен быть заблокирован.   -  person sam yi    schedule 01.02.2012


Ответы (7)


Это работает в Sql Server (наверняка 2000 и выше)

SELECT a.Store, a.Department, a.Sales
FROM temp a
INNER JOIN 
(SELECT store, max(sales) as sales
FROM temp
GROUP BY Store) b
ON a.Store = b.Store AND a.Sales = b.Sales;
person Pete    schedule 04.11.2008

Это работает в Oracle, другие реализации могут иметь другой синтаксис для аналитических функций (или полностью отсутствовать):

select store
     , max(department) keep(dense_rank last order by sales)
     , max(sales)
  from (
        ...query that generates your results...
       )
 group by store
person Noah Yetter    schedule 04.11.2008
comment
Да, я собирался предложить это, но я думаю, что он на SQL Server (как указал бы любой, кто использует оракул...) - person TheSoftwareJedi; 04.11.2008

Мои 2 решения для SQL 2005 приведены ниже. Другие, которые я вижу до сих пор, могут не возвращать правильные данные, если два показателя продаж совпадают. Хотя это зависит от ваших потребностей.

Первый использует функцию Row_Number(), все строки ранжируются от самых низких до самых высоких продаж (затем некоторые правила разрешения ничьей). Затем выбирается наивысший ранг для каждого магазина, чтобы получить результат.

Вы можете попробовать добавить предложение Partion By в функцию Row_Number (см. BOL) и/или изучить использование внутреннего соединения вместо предложения «in».

Второй, заимствуя идею Turnkey, снова ранжирует их, но разделяет по магазинам, поэтому мы можем выбрать тот, который ранжируется первым. Dense_Rank, возможно, присвоит двум идентичным строкам одинаковый ранг, поэтому, если магазин и отдел не уникальны, он может вернуть две строки. С Row_number номер уникален в разделе.

Следует помнить, что это может быть медленным, но для большинства наборов данных будет быстрее, чем подзапрос в одном из других решений. В этом решении запрос нужно будет запускать один раз для каждой строки (включая сортировку и т. д.), что может привести к большому количеству запросов.

Другие запросы выбирают максимальные продажи в магазине и возвращают данные таким образом, возвращают повторяющиеся строки для магазина, если два отдела имеют одинаковые продажи. Последний запрос показывает это.

DECLARE @tbl as TABLE (store varchar(20), department varchar(20), sales int)

INSERT INTO @tbl VALUES ('Toronto', 'Baskets', 500)
INSERT INTO @tbl VALUES ('Toronto', 'Noodles', 500)
INSERT INTO @tbl VALUES ('Toronto', 'Fish', 300)
INSERT INTO @tbl VALUES ('Halifax', 'Fish', 300)
INSERT INTO @tbl VALUES ('Halifax', 'Baskets', 200)

-- Expect Toronto/Noodles/500 and Halifax/Fish/300

;WITH ranked AS -- Rank the rows by sales from 1 to x
(
    SELECT 
        ROW_NUMBER() OVER (ORDER BY sales, store, department) as 'rank', 
        store, department, sales
    FROM @tbl
)

SELECT store, department, sales
FROM ranked
WHERE rank in (
    SELECT max(rank) -- chose the highest ranked per store
    FROM ranked
    GROUP BY store
)

-- Another way
SELECT store, department, sales
FROM (
    SELECT 
        DENSE_RANK() OVER (PARTITION BY store ORDER BY sales desc, 
store desc, department desc) as 'rank',
        store, department, sales
    FROM @tbl
) tbl
WHERE rank = 1


-- This will bring back 2 rows for Toronto
select tbl.store, department, sales
from @tbl tbl
    join (
        select store, max(sales) as maxSales from @tbl group by store
    ) tempTable on tempTable.store = tbl.store 
           and tempTable.maxSales = tbl.sales
person Robert Wagner    schedule 04.11.2008

Это будет работать в SQL Server с 2005 года:

with data as
(select store, department, sales
from <your query>),
 maxsales as
(select store,  sales = max(sales)
from data
group by store)
select store, (select top 1 department from data where store = t.store and sales = t.sales order by [your criteria for ties]), sales
from maxsales m

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

person Jeffrey Meyer    schedule 04.11.2008

Это будет работать

Select Store, Department, Sales
From yourTable A
Where Sales = (Select Max(Sales)
               From YourTable
               Where Store = A.Store)
person Charles Bretana    schedule 04.11.2008

Это будет работать в SQL Server без временных таблиц:

SELECT Store, Department, Sales FROM
(SELECT Store, Department, Sales,
DENSE_RANK()  OVER (PARTITION BY Store
ORDER BY Sales DESC) AS Dense_Rank
FROM Sales) A WHERE Dense_Rank = 1

ГДЕ "Продажи" = ваш исходный запрос

person Turnkey    schedule 04.11.2008
comment
Это решение только для SQL 2005 и выше. - person Sean Carpenter; 04.11.2008

Может быть, это может сработать. Хотя не пробовал, может есть решение получше...

select yourTable.store, dept, sales
from yourTable
join (
  select store, max(sales) as maxSales from yourTable group by store
) tempTable on tempTable.store = yourTable.store 
           and tempTable.maxSales = yourTable.sales
person Rockcoder    schedule 04.11.2008
comment
К сожалению, я опубликовал аналогичное решение с опозданием на несколько минут. Этот запрос не будет выполняться так, как опубликовано. ) перед группой должно пройти, max(sales) в tempTable не имеет имени, а столбцы в select должны указывать свой источник. Не хочу быть анальным, но если кто-то придет позже, я хотел, чтобы это было ясно. - person Pete; 04.11.2008