Începând de aici? Această lecție face parte dintr-un tutorial complet privind utilizarea SQL pentru analiza datelor. Verificați începutul.
În această lecție vom acoperi:
- Introducere în funcțiile ferestrei
- Sintaxa de bază a ferestrelor
- Suspecții obișnuiți: SUM, COUNT și AVG
- ROW_NUMBER ()
- RANK () și DENSE_RANK ()
- NTILE
- LAG și LEAD
- Definirea unui alias de fereastră
- Tehnici avansate de fereastrare
Această lecție folosește date din Programul Capital Bikeshare din Washington DC, care publică date istorice detaliate la nivel de excursie pe site-ul lor web. Datele au fost descărcate în februarie 2014, dar sunt limitate la datele colectate în primul trimestru al anului 2012. Fiecare rând reprezintă o călătorie. Majoritatea câmpurilor se explică de la sine, cu excepția rider_type
: „Înregistrat” indică un abonament lunar la programul de rideshare, „Casual” înseamnă că riderul a cumpărat un abonament de 3 zile. Câmpurile start_time
și end_time
au fost curățate din formularele lor originale pentru a se potrivi formatării datei SQL – sunt stocate în acest tabel ca timestamp-uri.
Introducere în funcțiile de fereastră
Documentația PostgreSQL face o treabă excelentă de a introduce conceptul de funcții de fereastră:
O funcție de fereastră efectuează un calcul pe un set de rânduri de tabele care sunt cumva legate de rândul curent. Acest lucru este comparabil cu tipul de calcul care se poate face cu o funcție agregată. Dar, spre deosebire de funcțiile agregate obișnuite, utilizarea unei ferestre funcția nu determină gruparea rândurilor într-un singur rând de ieșire – rândurile își păstrează identitățile separate. În culise, funcția fereastră poate accesa mai mult decât rândul curent al rezultatului interogării.
Cel mai practic exemplu în acest sens este un total care rulează:
Puteți vedea că interogarea de mai sus creează o agregare (running_total
) fără a utiliza GROUP BY
. Să „descompunem sintaxa și să vedem cum funcționează.
Sintaxa de fereastră de bază
Prima parte a agregării de mai sus, SUM(duration_seconds)
, seamănă foarte mult cu orice altă agregare. Adăugarea OVER
îl desemnează ca o funcție de fereastră. Puteți citi agregarea de mai sus ca „luați suma duration_seconds
pentru întregul set de rezultate, în ordine de start_time
. „
Dacă doriți să restrângeți fereastra din întregul set de date la grupuri individuale din cadrul setul de date, puteți utiliza PARTITION BY
pentru a face acest lucru:
Grupurile de interogări de mai sus și comandă interogarea prin start_terminal
. În cadrul fiecărei valori start_terminal
, este ordonată de start_time
și sumele totale care rulează pe rândul curent și pe toate rândurile anterioare din duration_seconds
. Derulați în jos până când valoarea start_terminal
se schimbă și veți observa că running_total
începe din nou. Asta se întâmplă atunci când grupați utilizând PARTITION BY
. În cazul în care sunteți încă stumped de ORDER BY
, pur și simplu ordonează după coloana desemnată (s) în același mod în care ar face clauza ORDER BY
, cu excepția faptului că tratează fiecare partiție ca separată. De asemenea, creează totalul care rulează – fără ORDER BY
, fiecare valoare va fi pur și simplu o sumă a tuturor valorilor duration_seconds
din start_terminal
. Încercați să rulați interogarea de mai sus fără ORDER BY
pentru a vă face o idee:
ORDER
și definiți ceea ce se numește„ fereastră ”- subsetul ordonat de date pe care se fac calculele.
Notă: Nu puteți utiliza funcțiile ferestrei și agregările standard în același interogare. Mai exact, nu puteți „include funcțiile ferestrei într-o clauză GROUP BY
.
Problemă practică
Scrieți o modificare a interogării exemplului de interogare de mai sus, care arată durata fiecărei curse ca procent din timpul total acumulat de rideri de la fiecare start_terminal
Încercați-l Vedeți răspunsul
Suspecții obișnuiți: SUM, COUNT și AVG
Când utilizați funcțiile de fereastră, puteți aplica aceleași agregate pe care le-ați face în circumstanțe normale – SUM
, COUNT
și AVG
. Cel mai simplu mod de a le înțelege este să rulați exemplul anterior cu câteva funcții suplimentare. Asigurați
Alternativ, aceleași funcții cu ORDER BY
:
Asigurați-vă că conectați cele două interogări anterioare în Mode și le executați. Această următoare problemă de practică este foarte asemănătoare cu exemplele, așa că încercați să modificați codul de mai sus decât să începeți de la zero.
Problemă de practică
Scrieți o interogare care să arate o durată totală a duratei plimbărilor cu bicicleta (similar cu ultimul exemplu), dar grupat după end_terminal
și cu durata călătoriei sortate în ordine descrescătoare.
Încercați-l Vedeți răspunsul
ROW_NUMBER ()
ROW_NUMBER()
face exact cum sună – afișează numărul unui rând dat. Începe este 1 și numerotează rândurile în conformitate cu partea ORDER BY
din instrucțiunea ferestrei. ROW_NUMBER()
nu necesită specificarea unei variabile între paranteze:
Utilizarea clauzei PARTITION BY
vă va permite să începeți să numărați din nou 1 în fiecare partiție. Următoarea interogare începe din nou contorizarea pentru fiecare terminal:
RANK () și DENSE_RANK ()
RANK()
este ușor diferit de ROW_NUMBER()
. Dacă comandați de start_time
, de exemplu, ar putea fi cazul ca unele terminale să aibă plimbări cu două ore de pornire identice. În acest caz, li se acordă același rang, în timp ce ROW_NUMBER()
le oferă numere diferite. În următoarea interogare, observați observațiile a 4-a și a 5-a pentru start_terminal
31000 – ambele au un rang 4 și următorul rezultat primește un rang 6:
De asemenea, puteți utiliza DENSE_RANK()
în loc de RANK()
în funcție de aplicația dvs. Imaginați-vă o situație în care trei intrări au aceeași valoare. Folosind oricare comandă, toți vor obține același rang. De dragul acestui exemplu, să spunem „s” 2. „ Iată cum cele două comenzi ar evalua următoarele rezultate în mod diferit:
-
RANK()
ar da rândurilor identice un rang de 2, apoi sări peste rândurile 3 și 4, deci următorul rezultat ar fi 5 -
DENSE_RANK()
ar da în continuare tuturor rândurilor identice un rang de 2, dar următorul rând ar fi 3 – nu rândurile ar fi omise.
Problemă practică
Scrieți o interogare care să afișeze cele mai lungi 5 plimbări de la fiecare terminal de pornire, ordonat de terminal și de la cele mai lungi la cele mai scurte plimbări din fiecare terminal. Limitați la plimbările care au avut loc înainte de 8 ianuarie 2012.
Încercați Vedeți răspunsul
NTILE
Puteți utiliza funcțiile ferestrei pentru a identifica în ce percentilă (sau quartile sau orice altă subdiviziune) intră un rând dat. Sintaxa este NTILE(*# of buckets*)
. În acest caz, ORDER BY
determină ce coloană să utilizați pentru a determina quartile (sau orice număr de „dale vă specifica). De exemplu:
Privind rezultatele din interogarea de mai sus, puteți vedea că coloana percentile
nu calculează exact așa cum v-ați putea aștepta. Dacă numai avea două înregistrări și măsurați percentile, vă așteptați ca o înregistrare să definească prima percentilă, iar cealaltă înregistrare să definească percentila 100. Folosind funcția NTILE
, ceea ce ați vedea de fapt este o înregistrare în prima percentilă și una în a doua percentilă. Puteți vedea acest lucru în rezultatele pentru start_terminal
31000 — coloana percentile
arată doar ca o clasare numerică. Dacă derulați în jos la start_terminal
31007, poate vedea că calculează în mod corespunzător percentilele, deoarece există mai mult de 100 de înregistrări pentru acel start_terminal
. Dacă lucrați cu ferestre foarte mici, țineți cont de acest lucru și luați în considerare utilizarea quartilelor sau la fel de mici benzi.
Problemă de practică
Scrieți o interogare care arată doar durata călătoriei și percentila în care durata respectivă scade (pe întregul set de date – nu este partiționat de terminal).
Încercați-l Vedeți răspunsul
LAG și LEAD
Deseori poate fi util să comparați rândurile cu rândurile precedente sau următoare, în special dacă „aveți datele într-o ordine care are sens. Puteți utiliza LAG
sau LEAD
pentru a crea coloane care extrag valori din alte rânduri – tot ce trebuie să faceți este să introduceți din ce coloană să trageți și câte rânduri distanță doriți să faceți. LAG
extrage din rândurile anterioare și LEAD
extrage din rândurile următoare:
Acest lucru este util mai ales dacă doriți să calculați diferențe între rânduri:
Primul rând al coloanei difference
este nul deoarece nu există niciun rând anterior din care să trageți. În mod similar, utilizarea LEAD
va crea valori nule la sfârșitul setului de date. Dacă doriți să faceți rezultatele puțin mai curate, le puteți înfășura într-o interogare externă pentru a elimina nulele:
Definirea unui alias de fereastră
Dacă intenționați să scrie mai multe funcții de fereastră în aceeași interogare, folosind aceeași fereastră, puteți crea un alias.Luați exemplul NTILE
de mai sus:
Acesta poate fi rescris ca:
WINDOW
clauza, dacă este inclusă, ar trebui să apară întotdeauna după clauza WHERE
.
Tehnici avansate de fereastrare
Puteți consulta o listă completă funcții în Postgres (se folosește modul de sintaxă) în documentația Postgres. Dacă utilizați funcțiile de fereastră într-o bază de date conectată, ar trebui să consultați ghidul de sintaxă adecvat pentru sistemul dvs.