यह क्वेरी महीने के अंत तक सक्रिय-उपयोगकर्ता-गणना को प्रभावी दिखाती है।
यह कैसे काम करता है:
-
प्रत्येक इनपुट पंक्ति को रूपांतरित करें (
StartDate
. के साथ) औरEndDate
मान) दो . में पंक्तियाँ जो उस बिंदु-समय का प्रतिनिधित्व करती हैं जब सक्रिय-उपयोगकर्ता-गणना में वृद्धि हुई (StartDate
पर) ) और घटा हुआ (EndDate
. पर) ) हमेंNULL
को कन्वर्ट करने की जरूरत है दूर दिनांक मान के लिए क्योंकिNULL
मानों को गैर-NULL
. के बाद के बजाय पहले क्रमबद्ध किया जाता है मान:इससे आपका डेटा इस तरह दिखता है:
OnThisDate Change 2018-01-01 1 2019-01-01 -1 2018-01-01 1 9999-12-31 -1 2019-01-01 1 2019-06-01 -1 2017-01-01 1 2019-03-01 -1
-
फिर हम बस
SUM OVER
Change
मान (सॉर्ट करने के बाद) उस विशिष्ट तिथि के अनुसार सक्रिय-उपयोगकर्ता-गणना प्राप्त करने के लिए:तो सबसे पहले,
OnThisDate
. के आधार पर छाँटें :OnThisDate Change 2017-01-01 1 2018-01-01 1 2018-01-01 1 2019-01-01 1 2019-01-01 -1 2019-03-01 -1 2019-06-01 -1 9999-12-31 -1
फिर
SUM OVER
:OnThisDate ActiveCount 2017-01-01 1 2018-01-01 2 2018-01-01 3 2019-01-01 4 2019-01-01 3 2019-03-01 2 2019-06-01 1 9999-12-31 0
-
फिर हम
PARTITION
(समूह नहीं!) पंक्तियों को महीने के अनुसार और उन्हें उनकी तिथि के अनुसार क्रमबद्ध करें ताकि हम अंतिमActiveCount
की पहचान कर सकें उस महीने के लिए पंक्ति (यह वास्तव मेंWHERE
. में होता हैROW_NUMBER()
. का उपयोग करके सबसे बाहरी क्वेरी का औरCOUNT()
प्रत्येक माह के लिएPARTITION
):OnThisDate ActiveCount IsLastInMonth 2017-01-01 1 1 2018-01-01 2 0 2018-01-01 3 1 2019-01-01 4 0 2019-01-01 3 1 2019-03-01 2 1 2019-06-01 1 1 9999-12-31 0 1
-
फिर उस पर फ़िल्टर करें जहां
IsLastInMonth = 1
(वास्तव में, जहांROW_COUNT() = COUNT(*)
प्रत्येकPARTITION
. के अंदर ) हमें अंतिम आउटपुट डेटा देने के लिए:At-end-of-month Active-count 2017-01 1 2018-01 3 2019-01 3 2019-03 2 2019-06 1 9999-12 0
इसका परिणाम परिणाम-सेट में "अंतराल" के रूप में होता है क्योंकि At-end-of-month
कॉलम केवल उन पंक्तियों को दिखाता है जहां Active-count
मूल्य वास्तव में सभी संभावित कैलेंडर महीनों को शामिल करने के बजाय बदल गया है - लेकिन यह आदर्श है (जहां तक मेरा संबंध है) क्योंकि इसमें अनावश्यक डेटा शामिल नहीं है। प्रत्येक अतिरिक्त महीने के लिए आउटपुट पंक्तियों को तब तक दोहराते हुए जब तक कि यह अगले At-end-of-month
तक न पहुंच जाए, आपके एप्लिकेशन कोड के भीतर अंतरालों को भरना किया जा सकता है। मूल्य।
एसक्यूएल सर्वर पर टी-एसक्यूएल का उपयोग कर क्वेरी यहां दी गई है (मेरे पास अभी ओरेकल तक पहुंच नहीं है)। और यहाँ SQLFiddle मैं एक समाधान के लिए आया करता था:http://sqlfiddle.com/# !18/ad68b7/24
SELECT
OtdYear,
OtdMonth,
ActiveCount
FROM
(
-- This query adds columns to indicate which row is the last-row-in-month ( where RowInMonth == RowsInMonth )
SELECT
OnThisDate,
OtdYear,
OtdMonth,
ROW_NUMBER() OVER ( PARTITION BY OtdYear, OtdMonth ORDER BY OnThisDate ) AS RowInMonth,
COUNT(*) OVER ( PARTITION BY OtdYear, OtdMonth ) AS RowsInMonth,
ActiveCount
FROM
(
SELECT
OnThisDate,
YEAR( OnThisDate ) AS OtdYear,
MONTH( OnThisDate ) AS OtdMonth,
SUM( [Change] ) OVER ( ORDER BY 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 [Change]
FROM
tbl
) AS sq1
) AS sq2
) AS sq3
WHERE
RowInMonth = RowsInMonth
ORDER BY
OtdYear,
OtdMonth
यह क्वेरी कर सकते हैं एलियासेस (जैसे OtdYear
) का उपयोग करने के बजाय सीधे एग्रीगेट और विंडो फ़ंक्शंस का उपयोग करके कम नेस्टेड प्रश्नों में फ़्लैट किया जाए , ActiveCount
, आदि) लेकिन इससे क्वेरी को समझना बहुत कठिन हो जाएगा।