Data fanges og gemmes af en række forskellige årsager. Timer ud over tæller (og endnu mere budget) investeret i indsamling, indtagelse, strukturering, validering og i sidste ende lagring af data; at sige, at det er et værdifuldt aktiv, er at køre et problem hjem. Denne dag i alder kan det faktisk være vores mest dyrebare vare.
Nogle data bruges udelukkende som et arkiv. Måske for at optage eller spore begivenheder, der skete i fortiden. Men den anden side af den mønt er, at historiske data har værdi til at basere beslutninger for fremtiden og fremtidige bestræbelser.
- Hvilken dag skal vi have vores udsalg på? (Planlægning af fremtidigt salg baseret på, hvordan vi gjorde tidligere.)
- Hvilken sælger klarede sig bedst i første kvartal? (Når vi ser tilbage, hvem kan vi belønne for deres indsats.)
- Hvilken restaurant er mest besøgt i midten af juli? (Rejsesæsonen er over os... Hvem kan vi sælge vores madvarer og varer til?)
Du får billedet. Brug af data ved hånden er integreret for enhver organisation.
Mange virksomheder bygger, baserer og leverer tjenester med data. De er afhængige af det.
For flere måneder siden, afhængigt af hvornår du læser dette, begyndte jeg for alvor at gå for at træne, for at tabe mig, få styr på mit helbred og for at søge en daglig smule ensomhed fra denne travle verden, vi lever i.
Jeg brugte en mobil skridttæller-app til at spore mine vandreture, selv i betragtning af hvilke sko jeg havde på, da jeg har en tendens til at være ultra-kræsen, når det kommer til fodtøj.
Selvom disse data ikke er nær så vigtige som dem, der er nævnt i ovenstående scenarier, er et nøgleelement i at lære noget for mig at bruge noget, jeg er interesseret i, kan relatere til og forstå.
Vinduesfunktioner har været på min radar for at udforske i lang tid nu. Så jeg tænkte på at prøve et par af dem i dette indlæg. Efter at have for nylig blevet understøttet i MySQL 8 (besøg denne Severalnines blog skrev jeg om MySQL 8 opgraderinger og nye tilføjelser, hvor jeg nævner dem kort), at økosystemet er det, jeg vil bruge her. Vær opmærksom på, jeg er ikke en vinduesanalytisk funktionsguru.
Hvad er en MySQL-vinduefunktion?
MySQL-dokumentationen definerer dem som sådan: "En vinduesfunktion udfører en aggregatlignende operation på et sæt forespørgselsrækker. Men mens en aggregatoperation grupperer forespørgselsrækker i en enkelt resultatrække, producerer en vinduesfunktion et resultat for hver forespørgselsrække:"
Datasæt og opsætning for dette indlæg
Jeg gemmer de registrerede data fra mine gåture i denne tabel:
mysql> DESC hiking_stats;
+-----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| day_walked | date | YES | | NULL | |
| burned_calories | decimal(4,1) | YES | | NULL | |
| distance_walked | decimal(4,2) | YES | | NULL | |
| time_walking | time | YES | | NULL | |
| pace | decimal(2,1) | YES | | NULL | |
| shoes_worn | text | YES | | NULL | |
| trail_hiked | text | YES | | NULL | |
+-----------------+--------------+------+-----+---------+-------+
7 rows in set (0.01 sec)
Der er tæt på 90 dages data her:
mysql> SELECT COUNT(*) FROM hiking_stats;
+----------+
| COUNT(*) |
+----------+
| 84 |
+----------+
1 row in set (0.00 sec)
Jeg indrømmer, at jeg er kræsen med mit fodtøj, så lad os finde ud af, hvilket par sko jeg foretrak mest:
mysql> SELECT DISTINCT shoes_worn, COUNT(*)
-> FROM hiking_stats
-> GROUP BY shoes_worn;
+---------------------------------------+----------+
| shoes_worn | COUNT(*) |
+---------------------------------------+----------+
| New Balance Trail Runners-All Terrain | 30 |
| Oboz Sawtooth Low | 47 |
| Keen Koven WP(keen-dry) | 6 |
| New Balance 510v2 | 1 |
+---------------------------------------+----------+
4 rows in set (0.00 sec)
For at give en bedre, håndterbar demonstration på skærmen, vil jeg begrænse den resterende del af forespørgselsresultaterne til kun dem af de yndlingssko, jeg havde på 47 gange.
Jeg har også en trail_hiked kolonne og siden jeg var i 'ultra træningstilstand ' i løbet af denne næsten 3 måneders periode talte jeg endda kalorier, mens jeg skubbede græsslåningen:
mysql> SELECT DISTINCT trail_hiked, COUNT(*)
-> FROM hiking_stats
-> GROUP BY trail_hiked;
+------------------------+----------+
| trail_hiked | COUNT(*) |
+------------------------+----------+
| Yard Mowing | 14 |
| Sandy Trail-Drive | 20 |
| West Boundary | 29 |
| House-Power Line Route | 10 |
| Tree Trail-extended | 11 |
+------------------------+----------+
5 rows in set (0.01 sec)
Men for at begrænse datasættet yderligere, vil jeg også filtrere disse rækker fra:
mysql> SELECT COUNT(*)
-> FROM hiking_stats
-> WHERE shoes_worn = 'Oboz Sawtooth Low'
-> AND
-> trail_hiked <> 'Yard Mowing';
+----------+
| COUNT(*) |
+----------+
| 40 |
+----------+
1 row in set (0.01 sec)
For enkelhedens og brugervenlighedens skyld vil jeg oprette en VIEW af kolonner at arbejde med:
mysql> CREATE VIEW vw_fav_shoe_stats AS
-> (SELECT day_walked, burned_calories, distance_walked, time_walking, pace, trail_hiked
-> FROM hiking_stats
-> WHERE shoes_worn = 'Oboz Sawtooth Low'
-> AND trail_hiked <> 'Yard Mowing');
Query OK, 0 rows affected (0.19 sec)
Efterlader mig med dette sæt data:
mysql> SELECT * FROM vw_fav_shoe_stats;
+------------+-----------------+-----------------+--------------+------+------------------------+
| day_walked | burned_calories | distance_walked | time_walking | pace | trail_hiked |
+------------+-----------------+-----------------+--------------+------+------------------------+
| 2018-06-03 | 389.6 | 4.11 | 01:13:19 | 3.4 | Sandy Trail-Drive |
| 2018-06-04 | 394.6 | 4.26 | 01:14:15 | 3.4 | Sandy Trail-Drive |
| 2018-06-06 | 384.6 | 4.10 | 01:13:14 | 3.4 | Sandy Trail-Drive |
| 2018-06-07 | 382.7 | 4.12 | 01:12:52 | 3.4 | Sandy Trail-Drive |
| 2018-06-17 | 296.3 | 2.82 | 00:55:45 | 3.0 | West Boundary |
| 2018-06-18 | 314.7 | 3.08 | 00:59:13 | 3.1 | West Boundary |
| 2018-06-20 | 338.5 | 3.27 | 01:03:42 | 3.1 | West Boundary |
| 2018-06-21 | 339.5 | 3.40 | 01:03:54 | 3.2 | West Boundary |
| 2018-06-24 | 392.4 | 3.76 | 01:13:51 | 3.1 | House-Power Line Route |
| 2018-06-25 | 362.1 | 3.72 | 01:08:09 | 3.3 | West Boundary |
| 2018-06-26 | 380.5 | 3.94 | 01:11:36 | 3.3 | West Boundary |
| 2018-07-03 | 323.7 | 3.29 | 01:00:55 | 3.2 | West Boundary |
| 2018-07-04 | 342.8 | 3.47 | 01:04:31 | 3.2 | West Boundary |
| 2018-07-06 | 375.7 | 3.80 | 01:10:42 | 3.2 | West Boundary |
| 2018-07-07 | 347.6 | 3.40 | 01:05:25 | 3.1 | Sandy Trail-Drive |
| 2018-07-08 | 351.6 | 3.58 | 01:06:09 | 3.2 | West Boundary |
| 2018-07-09 | 336.0 | 3.28 | 01:03:13 | 3.1 | West Boundary |
| 2018-07-11 | 375.2 | 3.81 | 01:10:37 | 3.2 | West Boundary |
| 2018-07-12 | 325.9 | 3.28 | 01:01:20 | 3.2 | West Boundary |
| 2018-07-15 | 382.9 | 3.91 | 01:12:03 | 3.3 | House-Power Line Route |
| 2018-07-16 | 368.6 | 3.72 | 01:09:22 | 3.2 | West Boundary |
| 2018-07-17 | 339.4 | 3.46 | 01:03:52 | 3.3 | West Boundary |
| 2018-07-18 | 368.1 | 3.72 | 01:08:28 | 3.3 | West Boundary |
| 2018-07-19 | 339.2 | 3.44 | 01:03:06 | 3.3 | West Boundary |
| 2018-07-22 | 378.3 | 3.76 | 01:10:22 | 3.2 | West Boundary |
| 2018-07-23 | 322.9 | 3.28 | 01:00:03 | 3.3 | West Boundary |
| 2018-07-24 | 386.4 | 3.81 | 01:11:53 | 3.2 | West Boundary |
| 2018-07-25 | 379.9 | 3.83 | 01:10:39 | 3.3 | West Boundary |
| 2018-07-27 | 378.3 | 3.73 | 01:10:21 | 3.2 | West Boundary |
| 2018-07-28 | 337.4 | 3.39 | 01:02:45 | 3.2 | Sandy Trail-Drive |
| 2018-07-29 | 348.7 | 3.50 | 01:04:52 | 3.2 | West Boundary |
| 2018-07-30 | 361.6 | 3.69 | 01:07:15 | 3.3 | West Boundary |
| 2018-07-31 | 359.9 | 3.66 | 01:06:57 | 3.3 | West Boundary |
| 2018-08-01 | 336.1 | 3.37 | 01:01:48 | 3.3 | West Boundary |
| 2018-08-03 | 259.9 | 2.57 | 00:47:47 | 3.2 | West Boundary |
| 2018-08-05 | 341.2 | 3.37 | 01:02:44 | 3.2 | West Boundary |
| 2018-08-06 | 357.7 | 3.64 | 01:05:46 | 3.3 | West Boundary |
| 2018-08-17 | 184.2 | 1.89 | 00:39:00 | 2.9 | Tree Trail-extended |
| 2018-08-18 | 242.9 | 2.53 | 00:51:25 | 3.0 | Tree Trail-extended |
| 2018-08-30 | 204.4 | 1.95 | 00:37:35 | 3.1 | House-Power Line Route |
+------------+-----------------+-----------------+--------------+------+------------------------+
40 rows in set (0.00 sec)
Den første vinduesfunktion, jeg vil se på, er ROW_NUMBER().
Antag, at jeg vil have et resultatsæt sorteret efter kolonnen forbrændte_kalorier for måneden 'juli'.
Selvfølgelig kan jeg hente disse data med denne forespørgsel:
mysql> SELECT day_walked, burned_calories, trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE MONTHNAME(day_walked) = 'July'
-> ORDER BY burned_calories DESC;
+------------+-----------------+------------------------+
| day_walked | burned_calories | trail_hiked |
+------------+-----------------+------------------------+
| 2018-07-24 | 386.4 | West Boundary |
| 2018-07-15 | 382.9 | House-Power Line Route |
| 2018-07-25 | 379.9 | West Boundary |
| 2018-07-22 | 378.3 | West Boundary |
| 2018-07-27 | 378.3 | West Boundary |
| 2018-07-06 | 375.7 | West Boundary |
| 2018-07-11 | 375.2 | West Boundary |
| 2018-07-16 | 368.6 | West Boundary |
| 2018-07-18 | 368.1 | West Boundary |
| 2018-07-30 | 361.6 | West Boundary |
| 2018-07-31 | 359.9 | West Boundary |
| 2018-07-08 | 351.6 | West Boundary |
| 2018-07-29 | 348.7 | West Boundary |
| 2018-07-07 | 347.6 | Sandy Trail-Drive |
| 2018-07-04 | 342.8 | West Boundary |
| 2018-07-17 | 339.4 | West Boundary |
| 2018-07-19 | 339.2 | West Boundary |
| 2018-07-28 | 337.4 | Sandy Trail-Drive |
| 2018-07-09 | 336.0 | West Boundary |
| 2018-07-12 | 325.9 | West Boundary |
| 2018-07-03 | 323.7 | West Boundary |
| 2018-07-23 | 322.9 | West Boundary |
+------------+-----------------+------------------------+
22 rows in set (0.01 sec)
Alligevel, uanset årsagen (måske personlig tilfredsstillelse), vil jeg gerne tildele en rangering blandt de returnerede rækker, der begynder med 1, der angiver det højeste antal forbrændte_kalorier, hele vejen til (n) rækker i resultatsættet.
ROW_NUMBER(), kan håndtere dette uden problemer:
mysql> SELECT day_walked, burned_calories,
-> ROW_NUMBER() OVER(ORDER BY burned_calories DESC)
-> AS position, trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE MONTHNAME(day_walked) = 'July';
+------------+-----------------+----------+------------------------+
| day_walked | burned_calories | position | trail_hiked |
+------------+-----------------+----------+------------------------+
| 2018-07-24 | 386.4 | 1 | West Boundary |
| 2018-07-15 | 382.9 | 2 | House-Power Line Route |
| 2018-07-25 | 379.9 | 3 | West Boundary |
| 2018-07-22 | 378.3 | 4 | West Boundary |
| 2018-07-27 | 378.3 | 5 | West Boundary |
| 2018-07-06 | 375.7 | 6 | West Boundary |
| 2018-07-11 | 375.2 | 7 | West Boundary |
| 2018-07-16 | 368.6 | 8 | West Boundary |
| 2018-07-18 | 368.1 | 9 | West Boundary |
| 2018-07-30 | 361.6 | 10 | West Boundary |
| 2018-07-31 | 359.9 | 11 | West Boundary |
| 2018-07-08 | 351.6 | 12 | West Boundary |
| 2018-07-29 | 348.7 | 13 | West Boundary |
| 2018-07-07 | 347.6 | 14 | Sandy Trail-Drive |
| 2018-07-04 | 342.8 | 15 | West Boundary |
| 2018-07-17 | 339.4 | 16 | West Boundary |
| 2018-07-19 | 339.2 | 17 | West Boundary |
| 2018-07-28 | 337.4 | 18 | Sandy Trail-Drive |
| 2018-07-09 | 336.0 | 19 | West Boundary |
| 2018-07-12 | 325.9 | 20 | West Boundary |
| 2018-07-03 | 323.7 | 21 | West Boundary |
| 2018-07-23 | 322.9 | 22 | West Boundary |
+------------+-----------------+----------+------------------------+
22 rows in set (0.00 sec)
Du kan se rækken med brændte_kalorier mængde på 386,4 har position 1, mens rækken med værdien 322,9 har 22, hvilket er det mindste (eller laveste) beløb blandt de returnerede rækker.
Jeg vil bruge ROW_NUMBER() til noget lidt mere interessant, efterhånden som vi skrider frem. Først da jeg lærte om det brugt i den sammenhæng, indså jeg virkelig noget af dets virkelige kraft.
Lad os derefter besøge vinduesfunktionen RANK() for at give en anden slags 'rangering ' blandt rækkerne. Vi vil stadig målrette kolonneværdien for brændte_kalorier. Og selvom RANK() ligner ROW_NUMBER() ved, at de i nogen grad rangerer rækker, introducerer det en subtil forskel under visse omstændigheder.
Jeg vil yderligere begrænse antallet af rækker som helhed ved at filtrere alle poster, der ikke er i måneden "juli", men målrette mod et specifikt spor:
mysql> SELECT day_walked, burned_calories,
-> RANK() OVER(ORDER BY burned_calories DESC) AS position,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE MONTHNAME(day_walked) = 'July'
-> AND trail_hiked = 'West Boundary';
+------------+-----------------+----------+---------------+
| day_walked | burned_calories | position | trail_hiked |
+------------+-----------------+----------+---------------+
| 2018-07-24 | 386.4 | 1 | West Boundary |
| 2018-07-25 | 379.9 | 2 | West Boundary |
| 2018-07-22 | 378.3 | 3 | West Boundary |
| 2018-07-27 | 378.3 | 3 | West Boundary |
| 2018-07-06 | 375.7 | 5 | West Boundary |
| 2018-07-11 | 375.2 | 6 | West Boundary |
| 2018-07-16 | 368.6 | 7 | West Boundary |
| 2018-07-18 | 368.1 | 8 | West Boundary |
| 2018-07-30 | 361.6 | 9 | West Boundary |
| 2018-07-31 | 359.9 | 10 | West Boundary |
| 2018-07-08 | 351.6 | 11 | West Boundary |
| 2018-07-29 | 348.7 | 12 | West Boundary |
| 2018-07-04 | 342.8 | 13 | West Boundary |
| 2018-07-17 | 339.4 | 14 | West Boundary |
| 2018-07-19 | 339.2 | 15 | West Boundary |
| 2018-07-09 | 336.0 | 16 | West Boundary |
| 2018-07-12 | 325.9 | 17 | West Boundary |
| 2018-07-03 | 323.7 | 18 | West Boundary |
| 2018-07-23 | 322.9 | 19 | West Boundary |
+------------+-----------------+----------+---------------+
19 rows in set (0.01 sec)
Lægger du mærke til noget mærkeligt her? Forskellig fra ROW_NUMBER()?
Tjek positionsværdien for disse rækker '2018-07-22' og '2018-07-27'. De er uafgjort på 3. pladsen.
Med god grund, da burned_calorie-værdien på 378,3 er til stede i begge rækker.
Hvordan ville ROW_NUMBER() rangere dem?
Lad os finde ud af:
mysql> SELECT day_walked, burned_calories,
-> ROW_NUMBER() OVER(ORDER BY burned_calories DESC) AS position,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE MONTHNAME(day_walked) = 'July'
-> AND trail_hiked = 'West Boundary';
+------------+-----------------+----------+---------------+
| day_walked | burned_calories | position | trail_hiked |
+------------+-----------------+----------+---------------+
| 2018-07-24 | 386.4 | 1 | West Boundary |
| 2018-07-25 | 379.9 | 2 | West Boundary |
| 2018-07-22 | 378.3 | 3 | West Boundary |
| 2018-07-27 | 378.3 | 4 | West Boundary |
| 2018-07-06 | 375.7 | 5 | West Boundary |
| 2018-07-11 | 375.2 | 6 | West Boundary |
| 2018-07-16 | 368.6 | 7 | West Boundary |
| 2018-07-18 | 368.1 | 8 | West Boundary |
| 2018-07-30 | 361.6 | 9 | West Boundary |
| 2018-07-31 | 359.9 | 10 | West Boundary |
| 2018-07-08 | 351.6 | 11 | West Boundary |
| 2018-07-29 | 348.7 | 12 | West Boundary |
| 2018-07-04 | 342.8 | 13 | West Boundary |
| 2018-07-17 | 339.4 | 14 | West Boundary |
| 2018-07-19 | 339.2 | 15 | West Boundary |
| 2018-07-09 | 336.0 | 16 | West Boundary |
| 2018-07-12 | 325.9 | 17 | West Boundary |
| 2018-07-03 | 323.7 | 18 | West Boundary |
| 2018-07-23 | 322.9 | 19 | West Boundary |
+------------+-----------------+----------+---------------+
19 rows in set (0.06 sec)
Hmmm...
Ingen bånd i positionskolonnenummereringen denne gang.
Men hvem får forrang?
Så vidt jeg ved, vil du for en forudsigelig rækkefølge sandsynligvis være nødt til at bestemme den på andre måder i forespørgslen (f.eks. time_walking-kolonnen i dette tilfælde?).
Men vi er endnu ikke færdige med placeringsmuligheder. Her er DENSE_RANK():
mysql> SELECT day_walked, burned_calories,
-> DENSE_RANK() OVER(ORDER BY burned_calories DESC) AS position,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE MONTHNAME(day_walked) = 'July'
-> AND trail_hiked = 'West Boundary';
+------------+-----------------+----------+---------------+
| day_walked | burned_calories | position | trail_hiked |
+------------+-----------------+----------+---------------+
| 2018-07-24 | 386.4 | 1 | West Boundary |
| 2018-07-25 | 379.9 | 2 | West Boundary |
| 2018-07-22 | 378.3 | 3 | West Boundary |
| 2018-07-27 | 378.3 | 3 | West Boundary |
| 2018-07-06 | 375.7 | 4 | West Boundary |
| 2018-07-11 | 375.2 | 5 | West Boundary |
| 2018-07-16 | 368.6 | 6 | West Boundary |
| 2018-07-18 | 368.1 | 7 | West Boundary |
| 2018-07-30 | 361.6 | 8 | West Boundary |
| 2018-07-31 | 359.9 | 9 | West Boundary |
| 2018-07-08 | 351.6 | 10 | West Boundary |
| 2018-07-29 | 348.7 | 11 | West Boundary |
| 2018-07-04 | 342.8 | 12 | West Boundary |
| 2018-07-17 | 339.4 | 13 | West Boundary |
| 2018-07-19 | 339.2 | 14 | West Boundary |
| 2018-07-09 | 336.0 | 15 | West Boundary |
| 2018-07-12 | 325.9 | 16 | West Boundary |
| 2018-07-03 | 323.7 | 17 | West Boundary |
| 2018-07-23 | 322.9 | 18 | West Boundary |
+------------+-----------------+----------+---------------+
19 rows in set (0.00 sec)
Uafgjort forbliver, dog er nummereringen anderledes, hvor rækker tælles , fortsætter gennem de resterende resultater.
Hvor RANK() begyndte optællingen med 5 efter uafgjort, samler DENSE_RANK() op ved det næste tal, som er 4 i dette tilfælde, da uafgjort skete i række 3.
Jeg vil være den første til at indrømme, at disse forskellige rækkerangeringsmønstre er ret interessante, men hvordan kan du bruge dem til et meningsfuldt resultatsæt?
ClusterControlSingle Console for hele din databaseinfrastrukturFind ud af, hvad der ellers er nyt i ClusterControlInstaller ClusterControl GRATISEn bonustanke
Jeg skal give kredit, hvor der skal krediteres. Jeg lærte så meget om vinduesfunktioner fra en vidunderlig serie på YouTube, og især en video inspirerede mig til dette næste eksempel. Husk, selvom eksemplerne i den serie er demonstreret med en ikke-open source-database system (smid ikke de digitale rådne frugter og grøntsager efter mig), der er masser at lære af videoerne generelt.
Jeg ser et mønster i de fleste af de forespørgselsresultater, som jeg hidtil vil udforske. Jeg vil ikke filtrere efter nogen måned eller spor.
Det, jeg gerne vil vide, er de på hinanden følgende dage, hvor jeg forbrændte mere end 350 kalorier. Endnu bedre, grupper af dengang.
Her er den basisforespørgsel, jeg vil starte med og bygge videre på:
mysql> SELECT day_walked, burned_calories,
-> ROW_NUMBER() OVER(ORDER BY day_walked ASC) AS positional_bound,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE burned_calories > 350;
+------------+-----------------+------------------+------------------------+
| day_walked | burned_calories | positional_bound | trail_hiked |
+------------+-----------------+------------------+------------------------+
| 2018-06-03 | 389.6 | 1 | Sandy Trail-Drive |
| 2018-06-04 | 394.6 | 2 | Sandy Trail-Drive |
| 2018-06-06 | 384.6 | 3 | Sandy Trail-Drive |
| 2018-06-07 | 382.7 | 4 | Sandy Trail-Drive |
| 2018-06-24 | 392.4 | 5 | House-Power Line Route |
| 2018-06-25 | 362.1 | 6 | West Boundary |
| 2018-06-26 | 380.5 | 7 | West Boundary |
| 2018-07-06 | 375.7 | 8 | West Boundary |
| 2018-07-08 | 351.6 | 9 | West Boundary |
| 2018-07-11 | 375.2 | 10 | West Boundary |
| 2018-07-15 | 382.9 | 11 | House-Power Line Route |
| 2018-07-16 | 368.6 | 12 | West Boundary |
| 2018-07-18 | 368.1 | 13 | West Boundary |
| 2018-07-22 | 378.3 | 14 | West Boundary |
| 2018-07-24 | 386.4 | 15 | West Boundary |
| 2018-07-25 | 379.9 | 16 | West Boundary |
| 2018-07-27 | 378.3 | 17 | West Boundary |
| 2018-07-30 | 361.6 | 18 | West Boundary |
| 2018-07-31 | 359.9 | 19 | West Boundary |
| 2018-08-06 | 357.7 | 20 | West Boundary |
+------------+-----------------+------------------+------------------------+
20 rows in set (0.00 sec)
Vi har allerede set ROW_NUMBER(), men nu kommer det virkelig i spil.
For at få dette til at fungere (i det mindste i MySQL) var jeg nødt til at bruge DATE_SUB()-funktionen, da vi i det væsentlige med denne teknik trækker et tal - værdien givet af ROW_NUMBER() fra day_walked-datokolonnen i den samme række, som i tur, angiver selv en dato via beregningen:
mysql> SELECT day_walked AS day_of_walk,
-> DATE_SUB(day_walked, INTERVAL ROW_NUMBER() OVER(ORDER BY day_walked ASC) DAY) AS positional_bound,
-> burned_calories,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE burned_calories > 350;
+-------------+------------------+-----------------+------------------------+
| day_of_walk | positional_bound | burned_calories | trail_hiked |
+-------------+------------------+-----------------+------------------------+
| 2018-06-03 | 2018-06-02 | 389.6 | Sandy Trail-Drive |
| 2018-06-04 | 2018-06-02 | 394.6 | Sandy Trail-Drive |
| 2018-06-06 | 2018-06-03 | 384.6 | Sandy Trail-Drive |
| 2018-06-07 | 2018-06-03 | 382.7 | Sandy Trail-Drive |
| 2018-06-24 | 2018-06-19 | 392.4 | House-Power Line Route |
| 2018-06-25 | 2018-06-19 | 362.1 | West Boundary |
| 2018-06-26 | 2018-06-19 | 380.5 | West Boundary |
| 2018-07-06 | 2018-06-28 | 375.7 | West Boundary |
| 2018-07-08 | 2018-06-29 | 351.6 | West Boundary |
| 2018-07-11 | 2018-07-01 | 375.2 | West Boundary |
| 2018-07-15 | 2018-07-04 | 382.9 | House-Power Line Route |
| 2018-07-16 | 2018-07-04 | 368.6 | West Boundary |
| 2018-07-18 | 2018-07-05 | 368.1 | West Boundary |
| 2018-07-22 | 2018-07-08 | 378.3 | West Boundary |
| 2018-07-24 | 2018-07-09 | 386.4 | West Boundary |
| 2018-07-25 | 2018-07-09 | 379.9 | West Boundary |
| 2018-07-27 | 2018-07-10 | 378.3 | West Boundary |
| 2018-07-30 | 2018-07-12 | 361.6 | West Boundary |
| 2018-07-31 | 2018-07-12 | 359.9 | West Boundary |
| 2018-08-06 | 2018-07-17 | 357.7 | West Boundary |
+-------------+------------------+-----------------+------------------------+
20 rows in set (0.00 sec)
Men uden DATE_SUB() ender du op med dette (eller i det mindste gjorde jeg det):
mysql> SELECT day_walked AS day_of_walk,
-> day_walked - ROW_NUMBER() OVER(ORDER BY day_walked ASC) AS positional_bound,
-> burned_calories,
-> trail_hiked
-> FROM vw_fav_shoe_stats
-> WHERE burned_calories > 350;
+-------------+------------------+-----------------+------------------------+
| day_of_walk | positional_bound | burned_calories | trail_hiked |
+-------------+------------------+-----------------+------------------------+
| 2018-06-03 | 20180602 | 389.6 | Sandy Trail-Drive |
| 2018-06-04 | 20180602 | 394.6 | Sandy Trail-Drive |
| 2018-06-06 | 20180603 | 384.6 | Sandy Trail-Drive |
| 2018-06-07 | 20180603 | 382.7 | Sandy Trail-Drive |
| 2018-06-24 | 20180619 | 392.4 | House-Power Line Route |
| 2018-06-25 | 20180619 | 362.1 | West Boundary |
| 2018-06-26 | 20180619 | 380.5 | West Boundary |
| 2018-07-06 | 20180698 | 375.7 | West Boundary |
| 2018-07-08 | 20180699 | 351.6 | West Boundary |
| 2018-07-11 | 20180701 | 375.2 | West Boundary |
| 2018-07-15 | 20180704 | 382.9 | House-Power Line Route |
| 2018-07-16 | 20180704 | 368.6 | West Boundary |
| 2018-07-18 | 20180705 | 368.1 | West Boundary |
| 2018-07-22 | 20180708 | 378.3 | West Boundary |
| 2018-07-24 | 20180709 | 386.4 | West Boundary |
| 2018-07-25 | 20180709 | 379.9 | West Boundary |
| 2018-07-27 | 20180710 | 378.3 | West Boundary |
| 2018-07-30 | 20180712 | 361.6 | West Boundary |
| 2018-07-31 | 20180712 | 359.9 | West Boundary |
| 2018-08-06 | 20180786 | 357.7 | West Boundary |
+-------------+------------------+-----------------+------------------------+
20 rows in set (0.04 sec)
Hej, det ser egentlig ikke så slemt ud.
Hvad giver?
Øh, rækken med en positionsbundet værdi på '20180698'...
Vent et øjeblik, dette skal beregne en datoværdi ved at trække tallet ROW_NUMBER() fra kolonnen day_of_walk.
Korrekt.
Jeg ved ikke med dig, men jeg er ikke klar over en måned med 98 dage!
Men hvis der er en, så tag de ekstra lønsedler på!
Bortset fra det sjove var dette åbenbart forkert og fik mig til (til sidst) at bruge DATE_SUB(), som giver et korrekt resultatsæt, så jeg kan køre denne forespørgsel:
mysql> SELECT MIN(t.day_of_walk),
-> MAX(t.day_of_walk),
-> COUNT(*) AS num_of_hikes
-> FROM (SELECT day_walked AS day_of_walk,
-> DATE_SUB(day_walked, INTERVAL ROW_NUMBER() OVER(ORDER BY day_walked ASC) DAY) AS positional_bound
-> FROM vw_fav_shoe_stats
-> WHERE burned_calories > 350) AS t
-> GROUP BY t.positional_bound
-> ORDER BY 1;
+--------------------+--------------------+--------------+
| MIN(t.day_of_walk) | MAX(t.day_of_walk) | num_of_hikes |
+--------------------+--------------------+--------------+
| 2018-06-03 | 2018-06-04 | 2 |
| 2018-06-06 | 2018-06-07 | 2 |
| 2018-06-24 | 2018-06-26 | 3 |
| 2018-07-06 | 2018-07-06 | 1 |
| 2018-07-08 | 2018-07-08 | 1 |
| 2018-07-11 | 2018-07-11 | 1 |
| 2018-07-15 | 2018-07-16 | 2 |
| 2018-07-18 | 2018-07-18 | 1 |
| 2018-07-22 | 2018-07-22 | 1 |
| 2018-07-24 | 2018-07-25 | 2 |
| 2018-07-27 | 2018-07-27 | 1 |
| 2018-07-30 | 2018-07-31 | 2 |
| 2018-08-06 | 2018-08-06 | 1 |
+--------------------+--------------------+--------------+
13 rows in set (0.12 sec)
Relaterede ressourcer ClusterControl for MySQL MySQL i 2018:Hvad er i 8.0 og andre observationer MySQL Performance Benchmarking:MySQL 5.7 vs MySQL 8.0 Grundlæggende har jeg indpakket resultatsættet, der blev leveret fra den analytiske forespørgsel, i form af en afledt tabel, og forespurgte den efter:en start- og slutdato, en optælling af, hvad jeg har mærket num_of_hikes, derefter grupperet i positionsbundet kolonne, hvilket i sidste ende giver sæt af grupper af dage i træk, hvor jeg forbrændte mere end 350 kalorier.
Du kan se i datointervallet 2018-06-24 til 2018-06-26, hvilket resulterede i 3 på hinanden følgende dage, der opfylder kalorieforbrændingskriterierne på 350 i WHERE-klausulen.
Ikke så dårligt, hvis jeg ikke selv skal sige det, men bestemt en plade, jeg gerne vil prøve og bedst!
Konklusion
Vinduesfunktioner er i en verden og liga for sig. Jeg har ikke engang ridset overfladen af dem, da jeg kun har dækket 3 af dem i et 'højt niveau ' indledende og måske triviel forstand. Men forhåbentlig finder du gennem dette indlæg ud af, at du kan forespørge efter ganske interessante og potentielt indsigtsfulde data med et 'bare minimalt ' brug af dem.
Tak fordi du læste med.