2016-06-02 7 views
0

Ich habe eine Datenbank für einen Fahrradladen, mit einer Tabelle, die ich 10 nannte, die unter anderem diese 2 Spalten hat: CustomerID, TotalDue.Wie extrahiere ich das Maximum der Summe von ~ 120k Zeilen in Postgresql?

Es enthält Informationen über alle Verkäufe des Fahrradladens. Also, wenn z. ein Kunde kaufte insgesamt 2 mal aus dem Laden, es werden 2 Registries seiner CustomerID mit dem Geldbetrag (TotalDue) sein, den er jedes Mal zahlte.

Wie schreibe ich eine Select-Abfrage, die den 1 (oder mehr, im Falle eines Gleichstandes) Kunden zeigt, der am meisten insgesamt bezahlt hat. Das Ergebnis muss 2 Spalten eins mit dem CustomerID und eins mit dem TotalMoneyHePaid bringen.

+1

http://meta.stackoverflow.com/questions/285551/why-may-i-not-upload-images-of-code-on-so -when-ask-a-question/285557 # 285557 –

+0

Sie haben eine Mischung aus in Anführungszeichen gesetzten und nicht in Anführungszeichen gesetzten Bezeichnern in der Frage. Beachten Sie, dass [Bezeichner in Postgres die Groß-/Kleinschreibung beachten] (http://stackoverflow.com/a/20880247/939860). Angenommen, alle nicht aufgezählten Bezeichner für meine Antwort. –

Antwort

1

Sie eine Unterabfrage in Ihrem HAVING-Klausel verwenden können, um dieses zu erhalten:

SELECT customerid, 
    sum(totaldue) 
FROM SalesOrderHeader 
GROUP BY customerid 
HAVING sum(totaldue) = (
     SELECT sum(totaldue) 
     FROM SalesOrderHeader 
     GROUP BY customerID 
     ORDER BY sum(totalDue) DESC LIMIT 1 
     ) 

Die Unterabfrage:

SELECT sum(totaldue) 
    FROM SalesOrderHeader 
    GROUP BY customerID 
    ORDER BY sum(totalDue) DESC LIMIT 1 

ist immer die sum(totalDue) der größte Kunde durch die Aufzeichnungen der Bestellung von dieser sum(totaldue) und dann halten nur die erste Aufzeichnung LIMIT 1. Wir verwenden das in der HAVING Klausel, um das mit dem Sum(totaldue) für jeden Kunden zu vergleichen. Wenn der Kunde in der Hauptabfrage eine sum(totaldue) Entsprechung zum Ergebnis der Unterabfrage hat, behalten wir den Datensatz.

postgres=> CREATE TABLE salesorderheader 
postgres-> (
postgres(> customerid integer, 
postgres(> totaldue integer 
postgres(>); 
CREATE TABLE 

postgres=> INSERT INTO salesorderheader VALUES 
postgres-> (1, 10), 
postgres-> (1, 12), 
postgres-> (2, 22), 
postgres-> (3, 5), 
postgres-> (4, 4); 
INSERT 0 5 

postgres=> SELECT customerid, sum(totaldue) FROM SalesOrderHeader GROUP BY customerid HAVING sum(totaldue) = (SELECT sum(totaldue) FROM SalesOrderHeader GROUP BY customerID ORDER BY sum(totalDue) desc LIMIT 1); 
customerid | sum 
------------+----- 
      1 | 22 
      2 | 22 
(2 rows) 
+2

Dieser Rand Fall ist von OP: "Die Frage ist, eine Select-Abfrage schreiben, die die 1 (oder mehr, im Falle eines Gleichstandes) Kunden, die insgesamt bezahlt hat, am meisten zeigt." Diese Abfrage wird besser zu MySQL portieren, aber die Window Function Version von Erwin wird in den meisten anderen RDBMS funktionieren (Oracle, Sql Server, Teradata, etc ..) – JNevill

+0

Vielen Dank für die Hilfe! Ich habe deine Lösung benutzt, weil sie mir näher ist (neu in PostgreSQL) –

1

Ich schlage vor, die window function rank() über die Summe von totaldue in einer Unterabfrage:

SELECT customerid, total_money_paid 
FROM (
    SELECT customerid, sum(totaldue) AS total_money_paid 
     , rank() OVER (ORDER BY sum(totaldue) DESC NULLS LAST) AS rnk 
    FROM salesorderheader 
    GROUP BY 1 
    ) sub 
WHERE rnk = 1; 

Auf diese Weise wird die Tabelle einmal nur gescannt. Sollte schneller sein. Fensterfunktionen werden nach einfache Aggregatfunktionen ausgewertet, daher ist dies möglich. Verwandte:

NULLS LAST nur kann, wenn die Summe NULL sein benötigt wird (.. I e totaldue kann NULL sein).Details:

wählte ich diese Technik aufgrund Ihrer Anforderung:

zeigen das 1 (oder mehr, bei einem Unentschieden) Kunde

Wenn Sie wollen genau 1 (Break Krawatten irgendwie, wenn es mehr sind), dann DISTINCT ON wäre vorzuziehen: