PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

पोस्टग्रेस्क्ल में ओवरलैपिंग रिकॉर्ड के साथ दिनांक सीमा खोजें और योग करें

demo:db<>fiddle (ओवरलैपिंग ए-बी-पार्ट के साथ पुराने डेटा सेट का उपयोग करता है)

अस्वीकरण: यह दिन के अंतराल के लिए काम करता है न कि टाइमस्टैम्प के लिए। ts की आवश्यकता बाद में आई।

SELECT
    s.acts,
    s.sum,
    MIN(a.start) as start,
    MAX(a.end) as end
FROM (
    SELECT DISTINCT ON (acts)
        array_agg(name) as acts,
        SUM(count)
    FROM
        activities, generate_series(start, "end", interval '1 day') gs
    GROUP BY gs
    HAVING cardinality(array_agg(name)) > 1
) s
JOIN activities a
ON a.name = ANY(s.acts)
GROUP BY s.acts, s.sum
  1. generate_series प्रारंभ और समाप्ति के बीच सभी तिथियां उत्पन्न करता है। इसलिए किसी गतिविधि के मौजूद होने की हर तारीख को विशिष्ट count . के साथ एक पंक्ति मिलती है
  2. सभी तिथियों को समूहीकृत करना, सभी मौजूदा गतिविधियों को एकत्रित करना और उनकी गणना का योग
  3. HAVING उन तिथियों को फ़िल्टर करता है जहां केवल एक गतिविधि मौजूद होती है
  4. चूंकि समान गतिविधियों के साथ अलग-अलग दिन होते हैं, इसलिए हमें केवल एक प्रतिनिधि की आवश्यकता होती है:सभी डुप्लिकेट को DISTINCT ON के साथ फ़िल्टर करें
  5. प्रारंभ और अंत प्राप्त करने के लिए मूल तालिका के विरुद्ध इस परिणाम में शामिल हों। (ध्यान दें कि पोस्टग्रेज में "एंड" एक आरक्षित शब्द है, आपको बेहतर तरीके से एक और कॉलम नाम खोजना चाहिए!) पहले उन्हें खोना अधिक सुविधाजनक था लेकिन इन डेटा को सबक्वायरी में प्राप्त करना संभव था।
  6. प्रत्येक अंतराल की सबसे प्रारंभिक और नवीनतम तिथि प्राप्त करने के लिए इस समूह में शामिल हों।

यहाँ टाइमस्टैम्प के लिए एक संस्करण है:

demo:db<>fiddle

WITH timeslots AS (
    SELECT * FROM (
        SELECT
            tsrange(timepoint, lead(timepoint) OVER (ORDER BY timepoint)),
            lead(timepoint) OVER (ORDER BY timepoint)     -- 2
        FROM (
            SELECT 
                unnest(ARRAY[start, "end"]) as timepoint  -- 1 
            FROM
                activities
            ORDER BY timepoint
        ) s
    )s  WHERE lead IS NOT NULL                            -- 3
)
SELECT 
    GREATEST(MAX(start), lower(tsrange)),                 -- 6
    LEAST(MIN("end"), upper(tsrange)),
    array_agg(name),                                      -- 5
    sum(count)
FROM 
    timeslots t
JOIN activities a
ON t.tsrange && tsrange(a.start, a.end)                   -- 4
GROUP BY tsrange
HAVING cardinality(array_agg(name)) > 1

मुख्य विचार संभावित समय स्लॉट की पहचान करना है। इसलिए मैं हर ज्ञात समय (शुरुआत और अंत दोनों) लेता हूं और उन्हें एक क्रमबद्ध सूची में डाल देता हूं। तो मैं पहले टो ज्ञात समय (प्रारंभ ए से 17:00 और प्रारंभ बी से 18:00) ले सकता हूं और जांच सकता हूं कि इसमें कौन सा अंतराल है। फिर मैं इसे दूसरे और तीसरे के लिए देखता हूं, फिर तीसरे और चौथे के लिए और इसी तरह।

पहले समय में केवल ए फिट बैठता है। 18-19 से दूसरे में भी बी फिट है। अगले स्लॉट 19-20 में भी सी, 20 से 20:30 तक ए अब फिट नहीं है, केवल बी और सी। अगला वाला 20:30-22 है जहां केवल बी फिट बैठता है, अंत में 22-23 डी जोड़ा जाता है बी और अंतिम लेकिन कम से कम केवल डी 23-23:30 में फिट बैठता है।

इसलिए मैं इस समय सूची को लेता हूं और इसे फिर से गतिविधियों की तालिका में शामिल करता हूं जहां अंतराल प्रतिच्छेद करते हैं। उसके बाद यह केवल समय स्लॉट के आधार पर एक समूहीकरण है और अपनी गिनती का योग करें।

  1. यह एक पंक्ति के दोनों ts को एक सरणी में रखता है जिसके तत्वों को unnest के साथ प्रति तत्व एक पंक्ति में विस्तारित किया जाता है . इसलिए मैं हर समय एक कॉलम में आ जाता हूं जिसे आसानी से ऑर्डर किया जा सकता है
  2. लीड का उपयोग करना विंडो फ़ंक्शन अगली पंक्ति के मान को वर्तमान में ले जाने की अनुमति देता है। इसलिए मैं tsrange . के साथ इन दोनों मानों में से एक टाइमस्टैम्प श्रेणी बना सकता हूं
  3. यह फ़िल्टर आवश्यक है क्योंकि अंतिम पंक्ति का कोई "अगला मान" नहीं है। यह एक NULL बनाता है मान जिसकी व्याख्या tsrange . द्वारा की जाती है अनंत के रूप में। तो यह एक अविश्वसनीय गलत टाइम स्लॉट तैयार करेगा। इसलिए हमें इस पंक्ति को फ़िल्टर करना होगा।
  4. मूल तालिका के सामने समय स्लॉट में शामिल हों। && ऑपरेटर जाँचता है कि क्या दो श्रेणी प्रकार ओवरलैप करते हैं।
  5. एकल समय स्लॉट के आधार पर समूह बनाना, नामों और गिनती को जोड़ना। HAVING . का उपयोग करके केवल एक गतिविधि वाले समय स्लॉट को फ़िल्टर करें खंड
  6. सही शुरुआत और अंत अंक हासिल करना थोड़ा मुश्किल है। तो प्रारंभ बिंदु या तो अधिकतम गतिविधि प्रारंभ या एक समय स्लॉट की शुरुआत है (जिसे lower का उपयोग करके प्राप्त किया जा सकता है ) उदा. 20-20:30 स्लॉट लें:यह 20 घंटे से शुरू होता है लेकिन न तो बी और न ही सी का शुरुआती बिंदु है। समाप्ति समय समान।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL में महीने के हिसाब से ग्रुप कैसे करें

  2. PostgreSQL में क्वेरी को ऑप्टिमाइज़ करें

  3. प्रोटोकॉल उल्लंघन:त्रुटि:बाइंड संदेश 0 मापदंडों की आपूर्ति करता है, लेकिन तैयार किए गए कथन के लिए 1 की आवश्यकता होती है

  4. Apache libphp5.so . से .pgpass का उपयोग करना

  5. मैं postgresql में दशमलव के रूप में कैसे कास्ट करूं?