Denne forespørgsel viser antallet af aktive brugere, der er gældende fra slutningen af måneden.
Sådan fungerer det:
-
Konverter hver inputrække (med
StartDateogSlutdatoværdi) i to rækker, der repræsenterer et tidspunkt, hvor antallet af aktive brugere steg (påStartdato) og dekrementeret (påSlutdato). Vi skal konvertereNULLtil en fjern datoværdi, fordiNULLværdier sorteres før i stedet for efter ikke-NULLværdier:Dette får dine data til at se sådan ud:
OnThisDate Change2018-01-01 12019-01-01 -12018-01-01 19999-12-31 -12019-01-01 12019-06-01 -12017-01-091 03-01 -1 -
Så
SUMMER vi simpelthenSkiftværdier (efter sortering) for at få antallet af aktive brugere fra den specifikke dato:Så først sorter efter
OnThisDate:OnThisDate Change2017-01-01 12018-01-01 12018-01-01 12019-01-01 12019-01-01 -12019-03-01 -12019-06-091 -19-19-19-19 -1Derefter
SUM OVER:OnThisDate ActiveCount2017-01-01 12018-01-01 22018-01-01 32019-01-01 42019-01-01 32019-03-01 22019-06-01 029 029 kode> -
Så
PARTITION(ikke grupper!) rækkerne efter måned og sorter dem efter deres dato, så vi kan identificere den sidsteActiveCountrække for den måned (dette sker faktisk iWHEREaf den yderste forespørgsel ved hjælp afROW_NUMBER()ogCOUNT()for hver månedPARTITION):OnThisDate ActiveCount IsLastInMonth2017-01-01 1 12018-01-01 2 02018-01-01 3 12019-01-01 4 02019-01-01 3 12019-2030-12019-203 1999-12-31 0 1 -
Filtrer derefter på det, hvor
IsLastInMonth =1(faktisk hvorROW_COUNT() =COUNT(*)inde i hverPARTITION) for at give os de endelige outputdata:Aktivt antal ved månedens slutning2017-01 12018-01 32019-01 32019-03 22019-06 19999-12 0
Dette resulterer i "huller" i resultatsættet, fordi Ved-af-måned kolonne viser kun rækker, hvor Active-count værdi faktisk ændret i stedet for at inkludere alle mulige kalendermåneder - men det er ideelt (så vidt jeg er bekymret for), fordi det udelukker overflødige data. Du kan udfylde hullerne i din applikationskode ved blot at gentage outputrækker for hver ekstra måned, indtil den når den næste Ved udgangen af måneden værdi.
Her er forespørgslen, der bruger T-SQL på SQL Server (jeg har ikke adgang til Oracle lige nu). Og her er den SQLFiddle, jeg brugte til at finde en løsning:https://sqlfiddle.com/# !18/ad68b7/24
SELECT OtdYear, OtdMonth, ActiveCountFROM ( -- Denne forespørgsel tilføjer kolonner for at angive, hvilken række der er den sidste række-i-måned (hvor RowInMonth ==RowsInMonth ) SELECT OnThisDate, OtdYear, OtdMonth, ROW_NUMBER() ( PARTITION BY OtdYear, OtdMonth ORDER BY OnThisDate ) AS RowInMonth, COUNT(*) OVER ( PARTITION BY OtdYear, OtdMonth ) AS RowsInMonth, ActiveCounte FROM (SELECT OnThisDate, YEAR) AS ThisMonth(OtdMonth) [Skift] ) OVER ( BESTIL AF OnThisDate ASC ) AS ActiveCount FROM ( SELECT StartDate AS [OnThisDate], 1 AS [Change] FROM tbl UNION ALL SELECT ISNULL( EndDate, DATEFROMPARTS( 9999, 12, 31 ) ), AS [OnThisDate] -1 AS [Skift] FRA tbl ) AS sq1 ) AS sq2 ) AS sq3WHERE RowInMonth =RowsIn MonthORDER BY OtdYear, OtdMonth
Denne forespørgsel kan udjævnes til færre indlejrede forespørgsler ved at bruge aggregat- og vinduesfunktioner direkte i stedet for at bruge aliaser (som OtdYear , ActiveCount osv.), men det ville gøre forespørgslen meget sværere at forstå.