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

ओवरलैप को छोड़कर प्राथमिकता के साथ ओवरलैपिंग अवधियों की कुल अवधि

अपडेट करें मेरा मूल समाधान सही नहीं था। श्रेणियों के समेकन को नियमित विंडो में नियंत्रित नहीं किया जा सकता है। मैंने उसी नाम का उपयोग करके खुद को भ्रमित किया, trange , यह भूलकर कि विंडो परिणाम पंक्तियों के बजाय स्रोत पंक्तियों के ऊपर है। कृपया अपडेट किया गया SQL Fiddle देखें पूरी क्वेरी के साथ-साथ समस्या को स्पष्ट करने के लिए एक अतिरिक्त रिकॉर्ड के साथ।

आप PostgreSQL श्रेणी प्रकारों का उपयोग करके ओवरलैपिंग आवश्यकता को सरल बनाने के साथ-साथ अंतराल और द्वीपों की पहचान कर सकते हैं

प्रक्रिया के प्रत्येक चरण को दिखाने के लिए निम्नलिखित क्वेरी जानबूझकर वर्बोज़ है। कई चरणों को जोड़ा जा सकता है।

SQL Fiddle

सबसे पहले, एक समावेशी [start, end] जोड़ें प्रत्येक रिकॉर्ड की सीमा।

with add_ranges as (
  select id, name, tsrange(start, "end", '[]') as t_range
    from activities
), 

 id | name |                    t_range                    
----+------+-----------------------------------------------
  1 | A    | ["2018-01-09 17:00:00","2018-01-09 20:00:00"]
  2 | A    | ["2018-01-09 18:00:00","2018-01-09 20:30:00"]
  3 | B    | ["2018-01-09 19:00:00","2018-01-09 21:30:00"]
  4 | B    | ["2018-01-09 22:00:00","2018-01-09 23:00:00"]
(4 rows)

&& . द्वारा निर्धारित ओवरलैपिंग श्रेणियों की पहचान करें ऑपरेटर और नए द्वीपों की शुरुआत को 1 . के साथ चिह्नित करें ।

mark_islands as (
  select id, name, t_range,
         case
           when t_range && lag(t_range) over w then 0
           else 1
         end as new_range
    from add_ranges
  window w as (partition by name order by t_range)
),

 id | name |                    t_range                    | new_range 
----+------+-----------------------------------------------+-----------
  1 | A    | ["2018-01-09 17:00:00","2018-01-09 20:00:00"] |         1
  2 | A    | ["2018-01-09 18:00:00","2018-01-09 20:30:00"] |         0
  3 | B    | ["2018-01-09 19:00:00","2018-01-09 21:30:00"] |         1
  4 | B    | ["2018-01-09 22:00:00","2018-01-09 23:00:00"] |         1
(4 rows)

new_range . के योग के आधार पर समूहों को क्रमांकित करें name . के भीतर ।

group_nums as (
  select id, name, t_range, 
         sum(new_range) over (partition by name order by t_range) as group_num
    from mark_islands
),

 id | name |                    t_range                    | group_num 
----+------+-----------------------------------------------+-----------
  1 | A    | ["2018-01-09 17:00:00","2018-01-09 20:00:00"] |         1
  2 | A    | ["2018-01-09 18:00:00","2018-01-09 20:30:00"] |         1
  3 | B    | ["2018-01-09 19:00:00","2018-01-09 21:30:00"] |         1
  4 | B    | ["2018-01-09 22:00:00","2018-01-09 23:00:00"] |         2

name, group_num . द्वारा समूहित करें द्वीप पर बिताए गए कुल समय के साथ-साथ संपूर्ण t_range . प्राप्त करने के लिए ओवरलैप कटौती में इस्तेमाल किया जाना है।

islands as (
  select name,
         tsrange(min(lower(t_range)), max(upper(t_range)), '[]') as t_range,
         max(upper(t_range)) - min(lower(t_range)) as island_time_interval
    from group_nums
   group by name, group_num
),

 name |                    t_range                    | island_time_interval 
------+-----------------------------------------------+----------------------
 A    | ["2018-01-09 17:00:00","2018-01-09 20:30:00"] | 03:30:00
 B    | ["2018-01-09 19:00:00","2018-01-09 21:30:00"] | 02:30:00
 B    | ["2018-01-09 22:00:00","2018-01-09 23:00:00"] | 01:00:00
(3 rows)

A . के बीच ओवरलैप समय गिनने की आवश्यकता के लिए संदेश और B संदेश, जब एक A . की आवृत्तियां ढूंढें संदेश एक B . को ओवरलैप करता है संदेश, और * . का उपयोग करें चौराहा खोजने के लिए प्रतिच्छेदन संचालिका।

priority_overlaps as (
  select b.name, a.t_range * b.t_range as overlap_range
    from islands a
    join islands b
      on a.t_range && b.t_range
     and a.name = 'A' and b.name != 'A'
),

 name |                 overlap_range                 
------+-----------------------------------------------
 B    | ["2018-01-09 19:00:00","2018-01-09 20:30:00"]
(1 row)

प्रत्येक ओवरलैप के कुल समय को name . से जोड़ दें ।

overlap_time as (
  select name, sum(upper(overlap_range) - lower(overlap_range)) as total_overlap_interval
    from priority_overlaps
   group by name
),

 name | total_overlap_interval 
------+------------------------
 B    | 01:30:00
(1 row)

प्रत्येक name . के लिए कुल समय की गणना करें ।

island_times as (
  select name, sum(island_time_interval) as name_time_interval
    from islands
   group by name
)

 name | name_time_interval 
------+--------------------
 B    | 03:30:00
 A    | 03:30:00
(2 rows)

प्रत्येक name . के लिए कुल समय में शामिल हों overlap_time . से समायोजन के लिए सीटीई, और अंतिम duration के लिए समायोजन घटाएं मूल्य।

select i.name,
       i.name_time_interval - coalesce(o.total_overlap_interval, interval '0') as duration
  from island_times i
  left join overlap_time o
    on o.name = i.name
;

 name | duration 
------+----------
 B    | 02:00:00
 A    | 03:30:00
(2 rows)


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

  2. PostgreSQL:ट्रिगर के लिए फ़ंक्शन में नए और पुराने की जाँच करना

  3. क्या PLV8 अन्य सर्वरों पर http कॉल करने का समर्थन करता है?

  4. PostgreSQL डेटाबेस के साथ कैसे काम करें

  5. Postgresql में मूविंग एवरेज