डेटा का परीक्षण करें :
CREATE TABLE your_table ( usr, start_date, end_date ) AS (
SELECT 'A', DATE '2017-06-01', DATE '2017-06-03' FROM DUAL UNION ALL
SELECT 'B', DATE '2017-06-02', DATE '2017-06-04' FROM DUAL UNION ALL -- Overlaps previous
SELECT 'C', DATE '2017-06-06', DATE '2017-06-06' FROM DUAL UNION ALL
SELECT 'D', DATE '2017-06-07', DATE '2017-06-07' FROM DUAL UNION ALL -- Adjacent to previous
SELECT 'E', DATE '2017-06-11', DATE '2017-06-20' FROM DUAL UNION ALL
SELECT 'F', DATE '2017-06-14', DATE '2017-06-15' FROM DUAL UNION ALL -- Within previous
SELECT 'G', DATE '2017-06-22', DATE '2017-06-25' FROM DUAL UNION ALL
SELECT 'H', DATE '2017-06-24', DATE '2017-06-28' FROM DUAL UNION ALL -- Overlaps previous and next
SELECT 'I', DATE '2017-06-27', DATE '2017-06-30' FROM DUAL UNION ALL
SELECT 'J', DATE '2017-06-27', DATE '2017-06-28' FROM DUAL; -- Within H and I
क्वेरी :
SELECT SUM( days ) AS total_days
FROM (
SELECT dt - LAG( dt ) OVER ( ORDER BY dt ) + 1 AS days,
start_end
FROM (
SELECT dt,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
WHERE start_end IS NOT NULL
)
WHERE start_end = 'end';
आउटपुट :
TOTAL_DAYS
----------
25
स्पष्टीकरण :
SELECT dt, value
FROM your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
यह UNPIVOT
होगा तालिका ताकि प्रारंभ और समाप्ति तिथियां एक ही कॉलम में हों (dt
) और प्रारंभ के लिए +1 और समाप्ति तिथि के लिए -1 का संगत मान दिया जाता है।
SELECT dt,
SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) AS total,
value
FROM your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
प्रारंभ और समाप्ति तिथियां और उन जेनरेट किए गए मानों का संचयी योग देगा। किसी श्रेणी की शुरुआत में हमेशा value=1
होगा और total=1
और किसी श्रेणी के अंत में हमेशा total=0
होगा . यदि कोई तिथि किसी सीमा के बीच में है तो उसके पास total>1
होगा या value=-1
और total=1
. इसका उपयोग करके, यदि आप value
को गुणा करते हैं और total
तब एक श्रेणी की शुरुआत तब होती है जब value*total=1
और एक श्रेणी का अंत तब होता है जब value*total=0
और कोई भी अन्य मान उस तिथि को इंगित करता है जो एक सीमा के बीच में है।
यह क्या देता है:
SELECT dt,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
फिर आप तारीखों को फ़िल्टर कर सकते हैं जब start_end
NULL
है जो आपको वैकल्पिक start
. के साथ एक तालिका के साथ छोड़ देगा और end
पंक्तियाँ जिनका आप उपयोग कर सकते हैं LAG
दिनों के अंतर की गणना करने के लिए:
SELECT dt - LAG( dt ) OVER ( ORDER BY dt ) + 1 AS days,
start_end
FROM (
SELECT dt,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM your_table
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
WHERE start_end IS NOT NULL
इसके बाद आपको केवल SUM
. करना है end - start
. के लिए सभी अंतर; जो ऊपर क्वेरी देता है।