2008-11-04 155 views
8

Tengo una lista de tiendas, departamentos dentro de las tiendas y ventas para cada departamento, como tal (creado usando max (ventas) en una subconsulta, pero eso no es terriblemente importante aquí, no lo creo):Máximo de suma en SQL

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

Me gustaría solicitar el departamento de mayor venta en cada tienda. Los resultados deben verse así:

toronto baskets 500 
vancouver noodles 275 
halifax fish 200 

Siempre que utilizo GROUP BY, incluye todos los listados de mi subconsulta. ¿Hay una buena manera de hacerlo sin una tabla temporal?

+0

¿Qué plataforma de la base de datos? ¿servidor SQL? ¿oráculo? – TheSoftwareJedi

+0

que hubiera pensado que los fideos serían tan populares en Vancouver, ¿eh? – TheSoftwareJedi

+0

Es "elegir un ganador" de nuevo. http://stackoverflow.com/questions/246870/simple-sql-query –

Respuesta

2

Esto funciona en Oracle, otras implementaciones pueden tener diferentes sintaxis para funciones analíticas (o carecer por completo):

select store 
    , max(department) keep(dense_rank last order by sales) 
    , max(sales) 
    from (
     ...query that generates your results... 
     ) 
group by store 
+0

Sí, iba a proponer eso, pero creo que está en SQL Server (como cualquiera que haya utilizado Oracle hubiera especificado ...) – TheSoftwareJedi

1

Esto funciona en SQL Server, a partir de 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 

Supongo que solo desea mostrar 1 departamento en caso de empates, de ahí los primeros 1 y [su criterio de empate] para distinguir entre ellos.

0

Quizás esto podría funcionar. no lo han intentado, sin embargo, no puede haber una solución mejor ...

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 
+0

Vaya, publiqué una solución similar unos minutos tarde. Esta consulta no se ejecutará como al corriente. El) antes del grupo tiene que irse, el máximo (ventas) en la tabla de temptables no tiene nombre y las columnas en la selección necesitan especificar su fuente. No quiero ser anal, pero si alguien viene después, quería que fuera claro. – Pete

+0

ok, lo arreglé, gracias por notar – Rockcoder

4

Esto funciona en SQL Server (2000 y superior a ciencia cierta)

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; 
0

Esto funcionará en SQL Server sin temp tablas:

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 

donde "Ventas" = su búsqueda original

+0

Esta solución es SQL 2005 y superior solamente. –

0

Esto funcionará

Select Store, Department, Sales 
From yourTable A 
Where Sales = (Select Max(Sales) 
       From YourTable 
       Where Store = A.Store) 
2

Mis 2 soluciones para SQL 2005 están a continuación. Los otros que puedo ver hasta ahora pueden no devolver los datos correctos si dos de las cifras de ventas son las mismas. Eso depende de tus necesidades sin embargo.

El primero usa la función Row_Number(), todas las filas se clasifican desde las ventas más bajas hasta las más altas (luego algunas reglas de desempate). Luego, se elige el rango más alto por tienda para obtener el resultado.

Puede intentar agregar una cláusula Partion By a la función Row_Number (ver BOL) y/o investigar utilizando una unión interna en lugar de una cláusula "in".

El segundo, tomando prestado de la idea de Turnkey, los clasifica de nuevo, pero las particiones por tienda, para que podamos elegir el primero clasificado. Dense_Rank posiblemente dará dos filas idénticas del mismo rango, por lo que si la tienda y el departamento no fueran únicos, podría devolver dos filas. Con Row_number, el número es único en la partición.

Algunas cosas a tener en cuenta es que esto puede ser lento, pero sería más rápido para la mayoría de los conjuntos de datos que la sub consulta en una de las otras soluciones. En esa solución, la consulta debería ejecutarse una vez por fila (incluida la clasificación, etc.), lo que podría generar muchas consultas.

Otras consultas Seleccione las ventas máximas por tienda y devuelva los datos de esa manera, devuelva las filas duplicadas para una tienda si dos departamentos tienen las mismas ventas. La última consulta muestra esto.

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 
Cuestiones relacionadas