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
StartDate
ogSlutdato
værdi) i to rækker, der repræsenterer et tidspunkt, hvor antallet af aktive brugere steg (påStartdato
) og dekrementeret (påSlutdato
). Vi skal konvertereNULL
til en fjern datoværdi, fordiNULL
værdier sorteres før i stedet for efter ikke-NULL
væ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 simpelthen
Skift
væ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 -1
Derefter
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 sidsteActiveCount
række for den måned (dette sker faktisk iWHERE
af 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:http://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å.