Gegevens worden om verschillende redenen vastgelegd en opgeslagen. Ontelbare uren (en zelfs meer budget) geïnvesteerd in het verzamelen, opnemen, structureren, valideren en uiteindelijk opslaan van gegevens; zeggen dat het een waardevol bezit is, is een betwistbaar punt naar huis rijden. Tegenwoordig is het misschien wel ons kostbaarste goed.
Sommige gegevens worden uitsluitend als archief gebruikt. Misschien om gebeurtenissen in het verleden vast te leggen of bij te houden. Maar de keerzijde van die medaille is dat historische gegevens waardevol zijn bij het baseren van beslissingen voor de toekomst en toekomstige inspanningen.
- Op welke dag hebben we onze uitverkoop? (Planning voor toekomstige verkopen op basis van hoe we het in het verleden hebben gedaan.)
- Welke verkoper presteerde het beste in het eerste kwartaal? (Terugkijkend, wie kunnen we belonen voor hun inspanningen.)
- Welk restaurant wordt midden juli het meest bezocht? (Het reisseizoen staat voor de deur... Aan wie kunnen we onze levensmiddelen en goederen verkopen?)
Je krijgt het beeld. Het gebruik van beschikbare gegevens is een integraal onderdeel van elke organisatie.
Veel bedrijven bouwen, baseren en leveren diensten met data. Ze zijn ervan afhankelijk.
Enkele maanden geleden, afhankelijk van wanneer je dit leest, begon ik serieus te wandelen om te sporten, om af te vallen, grip te krijgen op mijn gezondheid en om dagelijks een beetje afzondering te zoeken in deze drukke wereld waarin we leven.
Ik heb een mobiele stappenteller-app gebruikt om mijn wandelingen bij te houden, zelfs als ik bedenk welke schoenen ik droeg, omdat ik de neiging heb ultrakieskeurig te zijn als het om schoenen gaat.
Hoewel deze gegevens lang niet zo belangrijk zijn als de gegevens die in de bovenstaande scenario's worden genoemd, is voor mij het gebruik van iets waar ik in geïnteresseerd ben, waarmee ik me kan identificeren en wat ik begrijp, een belangrijk element om iets te leren.
Vensterfuncties staan al een hele tijd op mijn radar om te verkennen. Dus ik dacht dat ik er een paar in dit bericht zou proberen. Nadat ik onlangs werd ondersteund in MySQL 8 (bezoek dit blog van Verscheidene waar ik schreef over MySQL 8-upgrades en nieuwe toevoegingen waar ik ze kort noem), is dat ecosysteem degene die ik hier zal gebruiken. Wees gewaarschuwd, ik ben geen goeroe voor vensteranalysefuncties.
Wat is een MySQL-vensterfunctie?
De MySQL-documentatie definieert ze als volgt: "Een vensterfunctie voert een aggregatie-achtige bewerking uit op een set queryrijen. Terwijl een aggregatiebewerking echter queryrijen groepeert in een enkele resultaatrij, produceert een vensterfunctie een resultaat voor elke queryrij:"
Gegevensset en instellingen voor dit bericht
Ik bewaar de vastgelegde gegevens van mijn wandelingen in deze 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)
Er zijn hier bijna 90 dagen aan gegevens:
mysql> SELECT COUNT(*) FROM hiking_stats;
+----------+
| COUNT(*) |
+----------+
| 84 |
+----------+
1 row in set (0.00 sec)
Ik geef toe, ik ben kieskeurig over mijn schoenen, dus laten we eens kijken welk paar schoenen ik het leukst vond:
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)
Om een betere, beheersbare demonstratie op het scherm te geven, beperk ik het resterende deel van de zoekopdrachtresultaten tot alleen die van de favoriete schoenen die ik 47 keer droeg.
Ik heb ook een kolom trail_hiked en aangezien ik in 'ultra-oefenmodus . was ' tijdens deze periode van bijna 3 maanden telde ik zelfs calorieën terwijl ik de tuin duwde:
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)
Maar om de dataset nog verder te beperken, zal ik die rijen ook uitfilteren:
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)
Omwille van de eenvoud en het gebruiksgemak zal ik een VIEW van kolommen maken om mee te werken:
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)
Mij achterlatend met deze set gegevens:
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)
De eerste vensterfunctie die ik zal bekijken is ROW_NUMBER().
Stel dat ik een resultatenset wil die is geordend op de kolom burn_calories voor de maand 'juli'.
Natuurlijk kan ik die gegevens ophalen met deze vraag:
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)
Maar om welke reden dan ook (misschien persoonlijke voldoening), wil ik een toekenning een rangschikking onder de geretourneerde rijen beginnend met 1 indicatief voor het hoogste aantal verbrande calorieën, helemaal tot aan (n) rijen in de resultatenset.
ROW_NUMBER(), kan dit helemaal geen probleem aan:
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)
U kunt zien dat de rij met verbrande_calorieën een hoeveelheid van 386,4 heeft positie 1, terwijl de rij met waarde 322,9 22 heeft, wat het minste (of laagste) aantal is van de geretourneerde rijenset.
Ik zal ROW_NUMBER() gebruiken voor iets interessanters naarmate we verder komen. Pas toen ik hoorde dat het in die context werd gebruikt, realiseerde ik me echt iets van de echte kracht ervan.
Laten we vervolgens naar de vensterfunctie RANK() gaan om een ander soort 'rangschikking te geven ' tussen de rijen. We richten ons nog steeds op de kolomwaarde burn_calories. En hoewel RANK() vergelijkbaar is met ROW_NUMBER() in die zin dat ze rijen enigszins rangschikken, introduceert het in bepaalde omstandigheden een subtiel verschil.
Ik zal het aantal rijen als geheel nog verder beperken door alle records te filteren die niet in de maand 'juli' zijn, maar zich op een specifiek spoor te richten:
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)
Merk je hier iets vreemds op? Anders dan ROW_NUMBER()?
Bekijk de positiewaarde voor die rijen van '2018-07-22' en '2018-07-27'. Ze staan gelijk op de 3e plaats.
Niet voor niets, aangezien de burn_calorie-waarde van 378,3 in beide rijen aanwezig is.
Hoe zou ROW_NUMBER() ze rangschikken?
Laten we eens kijken:
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...
Geen gelijkspel in de positiekolomnummering deze keer.
Maar wie krijgt voorrang?
Voor zover ik weet, moet je voor een voorspelbare volgorde deze waarschijnlijk op een andere aanvullende manier binnen de zoekopdracht bepalen (bijvoorbeeld de kolom time_walking in dit geval?).
Maar we zijn nog niet klaar met rangschikkingsopties. Hier is 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)
De gelijkspel blijft, maar de nummering is anders waar rijen worden geteld , ga door met de resterende resultaten.
Waar RANK() de telling begon met 5 na de gelijkspelden, gaat DENSE_RANK() verder met het volgende cijfer, dat in dit geval 4 is, aangezien het gelijkspel plaatsvond op rij 3.
Ik zal de eerste zijn om toe te geven dat deze verschillende rijrangschikkingspatronen best interessant zijn, maar hoe kun je ze gebruiken voor een zinvolle resultatenset?
ClusterControlSingle Console voor uw gehele database-infrastructuurOntdek wat er nog meer nieuw is in ClusterControlInstalleer ClusterControl GRATISEen bonusgedachte
Ik moet krediet geven waar krediet verschuldigd is. Ik heb zoveel geleerd over vensterfuncties van een prachtige serie op YouTube en vooral één video inspireerde me voor dit volgende voorbeeld. Houd er rekening mee dat hoewel de voorbeelden in die reeks worden gedemonstreerd met een niet-open-source database systeem (gooi de digitale rotte vruchten en groenten niet naar me), er valt over het algemeen veel te leren van de video's.
Ik zie een patroon in de meeste queryresultaten die ik tot nu toe wil onderzoeken. Ik filter niet op maand of spoor.
Wat ik wil weten, zijn de opeenvolgende dagen dat ik meer dan 350 calorieën verbrandde. Beter nog, groepen van toen.
Dit is de basisquery waarmee ik zal beginnen en van waaruit ik zal voortbouwen:
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)
We hebben ROW_NUMBER() al gezien, maar nu komt het echt in het spel.
Om dit te laten werken (in MySQL tenminste) moest ik de DATE_SUB() functie gebruiken, aangezien we met deze techniek in wezen een getal aftrekken - de waarde geleverd door ROW_NUMBER() van de day_walked datumkolom van dezelfde rij, die in beurt, geeft zelf een datum via de berekening:
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)
Zonder DATE_SUB() krijg je echter dit (of dat deed ik tenminste):
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)
Hé, dat ziet er niet zo slecht uit.
Wat geeft?
Eh, de rij met een positional_bound waarde van '20180698'...
Wacht even, dit zou een datumwaarde moeten berekenen door het getal dat ROW_NUMBER() geeft van de kolom day_of_walk af te trekken.
Juist.
Ik weet niet hoe het met jou zit, maar ik ken geen maand met 98 dagen!
Maar als die er is, kom maar op met de extra loonstrookjes!
Afgezien van het plezier, was dit duidelijk onjuist en bracht het me ertoe om (uiteindelijk) DATE_SUB() te gebruiken, wat een correcte resultatenset oplevert en me vervolgens in staat stelt deze query uit te voeren:
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)
Gerelateerde bronnen ClusterControl voor MySQL MySQL in 2018:What's in 8.0 en andere observaties MySQL Performance Benchmarking:MySQL 5.7 vs MySQL 8.0 Kortom, ik heb ingepakt de resultatenset van die analytische query, in de vorm van een afgeleide tabel, en vroeg om:een start- en einddatum, een telling van wat ik heb gelabeld aantal_of_hikes, vervolgens gegroepeerd op de positional_bound kolom, uiteindelijk het verstrekken van sets van groepen van opeenvolgende dagen waarop ik meer dan 350 calorieën verbrandde.
U kunt zien in het datumbereik van 2018-06-24 tot 2018-06-26, resulteerde in 3 opeenvolgende dagen die voldeden aan de calorieverbrandingscriteria van 350 in de WHERE-clausule.
Niet slecht, al zeg ik het zelf niet, maar zeker een plaat die ik wil proberen en het beste wil maken!
Conclusie
Vensterfuncties zijn een wereld en klasse apart. Ik heb ze niet eens aan de oppervlakte gekrast, ik heb er slechts 3 op een 'hoog niveau behandeld ' inleidende en misschien triviale zin. Hopelijk kom je er door dit bericht achter dat je met een 'absoluut minimaal naar best interessante en potentieel inzichtelijke gegevens kunt zoeken. ' gebruik ervan.
Bedankt voor het lezen.