Database
 sql >> Datenbank >  >> RDS >> Database

So wählen Sie die erste Zeile in jeder GROUP BY-Gruppe aus

Problem:

Sie haben Ihre Daten mit GROUP BY gruppiert und möchte nur die erste Zeile aus jeder Gruppe anzeigen.

Beispiel:

Unsere Datenbank hat eine Tabelle namens exam_results mit Daten in der folgenden Tabelle:

Vorname Nachname Jahr Ergebnis
Johannes Klein 2020 40
Edith Schwarz 2020 43
Markieren Johnson 2019 32
Laura Sommer 2020 35
Kate Smith 2019 41
Jakob Schwarz 2019 44
Tom Bennett 2020 38
Emily Kelly 2020 43

Lassen Sie uns für jedes Jahr den Schüler mit dem besten result finden . Wenn es in einer Gruppe zwei gleichberechtigte Schüler gibt, wählen wir willkürlich einen von ihnen zur Anzeige aus.

Lösung:

WITH added_row_number AS (
  SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
  FROM exam_results
)
SELECT
  *
FROM added_row_number
WHERE row_number = 1;

Das Ergebnis ist:

Vorname Nachname Jahr Ergebnis Zeilennummer
Jakob Schwarz 2019 44 1
Emily Kelly 2020 43 1

Diskussion:

Zuerst müssen Sie einen CTE schreiben, in dem Sie jeder Zeile innerhalb jeder Gruppe eine Nummer zuweisen. Dazu können Sie die ROW_NUMBER() verwenden Funktion. In OVER() , geben Sie die Gruppen an, in die die Zeilen aufgeteilt werden sollen (PARTITION BY ) und die Reihenfolge, in der die Nummern den Zeilen zugeordnet werden sollen (ORDER BY ).

Sehen Sie sich das Ergebnis der inneren Abfrage an:

SELECT
  *,
  ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
FROM exam_results;
Vorname Nachname Jahr Ergebnis Zeilennummer
Jakob Schwarz 2019 44 1
Kate Smith 2019 41 2
Markieren Johnson 2019 32 3
Emily Kelly 2020 43 1
Edith Schwarz 2020 43 2
Johannes Klein 2020 40 3
Tom Bennett 2020 38 4
Laura Sommer 2020 35 5

Sie weisen die Zeilennummern innerhalb jeder Gruppe (d. h. Jahr) zu. Jede Zeile hat eine Zeilennummer basierend auf dem Wert des result Säule. Die Zeilen werden aufgrund des DESC absteigend sortiert Schlüsselwort nach ORDER BY result . Auch wenn es mehrere Zeilen innerhalb einer Gruppe gibt, die den gleichen Wert von result haben , erhalten die Zeilen immer noch unterschiedliche Nummern. Hier haben Edith Black und Emily Kelly das gleiche result aber unterschiedliche Zeilennummern. Um dieses Verhalten zu ändern und dieselbe Zeilennummer für dasselbe Ergebnis innerhalb einer Gruppe zuzuweisen, verwenden Sie RANK() oder DENSE_RANK() statt ROW_NUMBER() .

In der äußeren Abfrage selektieren Sie alle Daten aus dem CTE (added_row_number ) und verwenden Sie ein WHERE Bedingung, um anzugeben, welche Zeile aus jeder Gruppe angezeigt werden soll. Hier wollen wir die erste Zeile anzeigen, also ist die Bedingung row_number = 1 .

Beachten Sie, dass Sie die Lösung leicht ändern können, um beispielsweise die zweite Reihe zu erhalten jeder Gruppe.

WITH added_row_number AS (
  SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
  FROM exam_results
)
SELECT
  *
FROM added_row_number
WHERE row_number = 2;

Hier ist das Ergebnis:

Vorname Nachname Jahr Ergebnis Zeilennummer
Kate Smith 2019 41 2
Edith Schwarz 2020 43 2

Andererseits, wenn Sie die Zeile(n) mit dem zweithöchsten Wert erhalten möchten von result Innerhalb jeder Gruppe sollten Sie den DENSE_RANK() verwenden Funktion. Während die ROW_NUMBER() -Funktion erstellt fortlaufende Nummern für jede Zeile in einer Gruppe, was dazu führt, dass den Zeilen unterschiedliche Werte mit demselben Ergebnis zugewiesen werden, dem DENSE_RANK() Funktion gibt den Zeilen mit dem gleichen Ergebnis die gleiche Nummer.

WITH added_dense_rank AS (
  SELECT
    *,
    DENSE_RANK() OVER(PARTITION BY year ORDER BY result DESC) AS rank
  FROM exam_results
)
SELECT
  *
FROM added_dense_rank
WHERE rank = 2;
Vorname Nachname Jahr Ergebnis Rang
Kate Smith 2019 41 2
Johannes Klein 2020 40 2

Sie können sehen, dass John Klein den zweithöchsten Wert von result (40) hat für das Jahr 2020. John Klein ist eigentlich die dritte Person in der Gruppe, aber die ersten beiden Schüler haben das gleiche result und beide haben rank = 1 .