2008-11-04 12 views
8

Ich habe eine Liste von Geschäften, Abteilungen innerhalb der Geschäfte und Verkäufe für jede Abteilung, so (erstellt mit Max (Umsatz) in einer Unterabfrage, aber das ist nicht sehr wichtig hier denke ich nicht):Max der Summe in SQL

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

Ich möchte um die meistverkaufte Abteilung in jedem Geschäft bitten. Die Ergebnisse sollten wie folgt aussehen:

toronto baskets 500 
vancouver noodles 275 
halifax fish 200 

Wenn ich GROUP BY verwende, enthält es alle Einträge aus meiner Unterabfrage. Gibt es einen schönen sauberen Weg, dies ohne einen temporären Tisch zu tun?

+0

Welche Datenbankplattform? SQL Server? Orakel? – TheSoftwareJedi

+0

Wer hätte gedacht, dass Nudeln in Vancouver so beliebt sind, oder? – TheSoftwareJedi

+0

Es ist wieder "Gewinner". http://stackoverflow.com/questions/246870/simple-sql-query –

Antwort

2

Dies funktioniert in Oracle, können andere Implementierungen haben unterschiedliche Syntax für analytische Funktionen (oder ganz fehlen):

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

Ja, ich wollte das vorschlagen, aber ich denke, er ist auf SQL Server (wie jeder, der Orakel benutzt, spezifiziert hätte) – TheSoftwareJedi

1

Dies wird in SQL Server arbeiten, ab 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 

Ich nehme an, dass Sie nur eine Abteilung im Falle von Bindungen anzeigen möchten, daher die Top 1 und [Ihre Kriterien für Verbindungen], zwischen ihnen zu unterscheiden.

0

Vielleicht könnte das funktionieren. Habe es allerdings nicht versucht, könnte es eine bessere Lösung sein ...

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

Hoppla, ich habe eine ähnliche Lösung einige Minuten später gepostet. Diese Abfrage wird nicht ausgeführt Gesendet. Bevor die Gruppierung vorbei ist, hat die Max (Umsatz) in der TempTabelle keinen Namen und die Spalten in der Auswahl müssen ihre Quelle angeben. Ich will nicht anal sein, aber wenn jemand später kommt, wollte ich, dass es klar ist. – Pete

+0

ok, ich habe es behoben, danke, dass Sie es bemerkt haben – Rockcoder

4

Diese in SQL Server arbeitet (2000 und höher sicher)

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

Diese in SQL Server ohne Temperatur arbeiten Tabellen:

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 

WHERE "Sales"

Ihre ursprüngliche Abfrage =
+0

Diese Lösung ist nur SQL 2005 und höher. –

0

Dies funktioniert

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

Meine 2 Lösungen für SQL 2005 ist unten. Die anderen, die ich bisher gesehen habe, geben möglicherweise nicht die korrekten Daten zurück, wenn zwei der Verkaufszahlen gleich sind. Das hängt aber von Ihren Bedürfnissen ab.

Die erste verwendet die Row_Number() - Funktion, alle Zeilen werden von den niedrigsten bis zu den höchsten Verkäufen (dann einige Regeln zum Brechen von Zeilen) gereiht. Dann wird der höchste Rang pro Geschäft gewählt, um das Ergebnis zu erhalten.

Sie können versuchen, eine Partion By-Klausel zur Funktion Row_Number (siehe BOL) hinzuzufügen und/oder einen inneren Join statt einer In-Klausel zu untersuchen.

Die zweite, Leihgabe auf Turnkey-Idee, rangiert sie wieder, aber Partitionen nach Laden, so dass wir die erste Rangliste wählen können. Der Dense_Rank gibt möglicherweise zwei identische Zeilen mit dem gleichen Rang an. Wenn also Filiale und Abteilung nicht eindeutig sind, könnten zwei Zeilen zurückgegeben werden. Mit Zeilennummer ist die Nummer in der Partition eindeutig.

Einige Dinge zu beachten ist, dass dies langsam sein kann, aber für die meisten Datensätze schneller als die Unterabfrage in einer der anderen Lösungen wäre. In dieser Lösung müsste die Abfrage einmal pro Zeile ausgeführt werden (einschließlich Sortierung usw.), was zu vielen Abfragen führen könnte.

Andere Abfragen die maximale Verkäufe pro Geschäft auswählen und die Daten auf diese Weise zurückgeben, doppelte Zeilen für ein Geschäft zurückgeben, wenn zwei Abteilungen die gleichen Verkäufe haben. Die letzte Abfrage zeigt dies.

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