Oracle-Schlüsselwort "Partition by"


253

Kann jemand bitte erklären, was das partition bySchlüsselwort tut und ein einfaches Beispiel dafür in Aktion geben und warum man es verwenden möchte? Ich habe eine SQL-Abfrage, die von jemand anderem geschrieben wurde, und ich versuche herauszufinden, was sie bewirkt.

Ein Beispiel für eine Partition von:

SELECT empno, deptno, COUNT(*) 
OVER (PARTITION BY deptno) DEPT_COUNT
FROM emp

Die Beispiele, die ich online gesehen habe, scheinen etwas zu ausführlich zu sein.


Antworten:


259

Die PARTITION BYKlausel legt den Datensatzbereich fest, der für jede "GROUP" innerhalb der OVERKlausel verwendet wird.

In Ihrem Beispiel gibt SQL DEPT_COUNTdie Anzahl der Mitarbeiter in dieser Abteilung für jeden Mitarbeiterdatensatz zurück. (Es ist, als würden Sie die empTabelle de-nomalisieren . Sie geben trotzdem jeden Datensatz in der empTabelle zurück.)

emp_no  dept_no  DEPT_COUNT
1       10       3
2       10       3
3       10       3 <- three because there are three "dept_no = 10" records
4       20       2
5       20       2 <- two because there are two "dept_no = 20" records

Wenn es eine andere Spalte gäbe (z. B. state), könnten Sie zählen, wie viele Abteilungen sich in diesem Staat befinden.

Es ist wie immer die Ergebnisse eines GROUP BY( SUM, AVGusw.) , ohne das die Ergebnismenge Aggregation (dh passende Datensätze zu entfernen).

Es ist nützlich, wenn Sie die Funktionen LAST OVERoder MIN OVERverwenden, um beispielsweise das niedrigste und höchste Gehalt in der Abteilung zu erhalten, und dieses dann in einer Berechnung für dieses Datensatzgehalt ohne Unterauswahl verwenden, was viel schneller ist.

Lesen Sie den verlinkten AskTom-Artikel für weitere Details.


6
LAST_VALUE - gibt das letzte Gehalt zurück, MAX gibt das höchste Gehalt zurück
Maciek Kreft

1
Meinen Sie "ohne eine Unterauswahl, die viel langsamer ist"? Ich denke, ich bin verwirrt, wenn die Unterauswahl langsamer oder schneller als last overund ist min over. Ich würde mir vorstellen, dass eine Unterauswahl langsamer ist, aber die englische Grammatik in der Antwort legt dies nicht nahe.
Jason

Dieser Ansatz reduziert die Häufigkeit, mit der die Zeilen verarbeitet werden, und ist damit effizienter als eine Unterauswahl. Am auffälligsten bei sehr großen Datenmengen.
Guy

164

Das Konzept wird durch die akzeptierte Antwort sehr gut erklärt, aber ich finde, je mehr Beispiele man sieht, desto besser sinkt es ein. Hier ist ein inkrementelles Beispiel:

1) Boss sagt "Hol mir die Anzahl der Artikel, die wir auf Lager haben, gruppiert nach Marke"

Sie sagen : "kein Problem"

SELECT 
      BRAND
      ,COUNT(ITEM_ID) 
FROM 
      ITEMS
GROUP BY 
      BRAND;

Ergebnis:

+--------------+---------------+
|  Brand       |   Count       | 
+--------------+---------------+
| H&M          |     50        |
+--------------+---------------+
| Hugo Boss    |     100       |
+--------------+---------------+
| No brand     |     22        |
+--------------+---------------+

2) Der Chef sagt: "Jetzt bekomme ich eine Liste aller Artikel mit ihrer Marke UND der Anzahl der Artikel, die die jeweilige Marke hat."

Sie können versuchen:

 SELECT 
      ITEM_NR
      ,BRAND
      ,COUNT(ITEM_ID) 
 FROM 
      ITEMS
 GROUP BY 
      BRAND;

Aber du bekommst:

ORA-00979: not a GROUP BY expression 

Hier kommt das ins OVER (PARTITION BY BRAND)Spiel:

 SELECT 
      ITEM_NR
      ,BRAND
      ,COUNT(ITEM_ID) OVER (PARTITION BY BRAND) 
 FROM 
      ITEMS;

Was bedeutet:

  • COUNT(ITEM_ID) - Holen Sie sich die Anzahl der Artikel
  • OVER - Über den Satz von Zeilen
  • (PARTITION BY BRAND) - die die gleiche Marke haben

Und das Ergebnis ist:

+--------------+---------------+----------+
|  Items       |  Brand        | Count()  |
+--------------+---------------+----------+
|  Item 1      |  Hugo Boss    |   100    | 
+--------------+---------------+----------+
|  Item 2      |  Hugo Boss    |   100    | 
+--------------+---------------+----------+
|  Item 3      |  No brand     |   22     | 
+--------------+---------------+----------+
|  Item 4      |  No brand     |   22     | 
+--------------+---------------+----------+
|  Item 5      |  H&M          |   50     | 
+--------------+---------------+----------+

etc...


3
Wenn ich ein Ergebnis für jede Gruppe erhalten möchte. Wie bekomme ich es?
Viuu -a

Wissen Sie, ob OVER PARTITION BY in einer WHERE-Klausel verwendet werden kann?
Kevin Burton

Ich schlage vor, Sie stellen eine Frage zu SO, geben Einzelheiten an und erklären, was Sie erreichen möchten
Andrejs

@ Viuu-a: Dann möchten Sie wahrscheinlich eine einfache GROUP BY verwenden.
Jackthehipster

Ich liebe dieses Beispiel ... leicht zu verstehen
Johnny Wu

27

Es ist die SQL-Erweiterung namens Analytics. Das "Over" in der select-Anweisung teilt Oracle mit, dass die Funktion eine analytische Funktion ist, keine Gruppe nach Funktion. Der Vorteil der Verwendung von Analysen besteht darin, dass Sie mit nur einem Durchgang der Daten Summen, Zählungen und vieles mehr erfassen können, anstatt die Daten mit Unterauswahl oder schlechter PL / SQL zu durchlaufen.

Es sieht auf den ersten Blick verwirrend aus, aber dies wird schnell zur zweiten Natur. Niemand erklärt es besser als Tom Kyte. Der obige Link ist also großartig.

Natürlich ist das Lesen der Dokumentation ein Muss.


9
EMPNO     DEPTNO DEPT_COUNT

 7839         10          4
 5555         10          4
 7934         10          4
 7782         10          4 --- 4 records in table for dept 10
 7902         20          4
 7566         20          4
 7876         20          4
 7369         20          4 --- 4 records in table for dept 20
 7900         30          6
 7844         30          6
 7654         30          6
 7521         30          6
 7499         30          6
 7698         30          6 --- 6 records in table for dept 30

Hier werden wir für die jeweilige Abteilung gezählt. Für Abt. 10 haben wir 4 Datensätze in der Tabelle mit ähnlichen Ergebnissen für Abt. 20 und 30.


12
Keine Erklärung zur Frage, wie PARTITION by funktioniert. Nur die Beispielausgabe allein beantwortet die Frage nicht vollständig.
Siraj Samsudeen

2

Das Schlüsselwort over partition ist so, als würden wir die Daten durch client_id partitionieren und eine Teilmenge jeder Client-ID erstellen

select client_id, operation_date,
       row_number() count(*) over (partition by client_id order by client_id ) as operationctrbyclient
from client_operations e
order by e.client_id;

Diese Abfrage gibt die Anzahl der von der client_id ausgeführten Operationen zurück


0

Ich denke, dieses Beispiel schlägt eine kleine Nuance vor, wie die Partitionierung funktioniert und wie Gruppieren nach funktioniert. Mein Beispiel stammt aus Oracle 12, wenn mein Beispiel ein Kompilierungsfehler ist.

Ich habe es versucht :

SELECT t.data_key
,      SUM ( CASE when t.state = 'A' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_a_rows
,      SUM ( CASE when t.state = 'B' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_b_rows
,      SUM ( CASE when t.state = 'C' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_c_rows
,      COUNT (1) total_rows
from mytable t
group by t.data_key  ---- This does not compile as the compiler feels that t.state isn't in the group by and doesn't recognize the aggregation I'm looking for

Dies funktioniert jedoch wie erwartet:

SELECT distinct t.data_key
,      SUM ( CASE when t.state = 'A' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_a_rows
,      SUM ( CASE when t.state = 'B' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_b_rows
,      SUM ( CASE when t.state = 'C' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_c_rows
,      COUNT (1) total_rows
from mytable t;

Erzeugen der Anzahl von Elementen in jedem Zustand basierend auf dem externen Schlüssel "data_key". Wenn also data_key = 'APPLE' 3 Zeilen mit dem Status 'A', 2 Zeilen mit dem Status 'B' und eine Zeile mit dem Status 'C' hätte, wäre die entsprechende Zeile für 'APPLE' 'APPLE', 3, 2 , 1, 6.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.