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

दिनांक समय सीमा के बीच कक्षा उपलब्ध घंटे प्राप्त करें

मैं कम से कम वर्नफ्राइड की अवधारणा में समान समाधान देख रहा था, लेकिन मुझे लगता है कि यह पोस्ट करने के लिए काफी अलग है। शुरुआत एक ही विचार है, पहले संभावित समय स्लॉट उत्पन्न करना, और यह मानते हुए कि आप 15-मिनट की विंडो देख रहे हैं:मैं CTE का उपयोग कर रहा हूं क्योंकि मुझे लगता है कि वे नेस्टेड चयनों की तुलना में अधिक स्पष्ट हैं, विशेष रूप से इतने स्तरों के साथ।

with date_time_range as (
  select to_date('10/10/2013 07:00', 'DD/MM/YYYY HH24:MI') as date_start,
    to_date('10/10/2013 21:15', 'DD/MM/YYYY HH24:MI') as date_end
  from dual
),
time_slots as (
  select level as slot_num,
    dtr.date_start + (level - 1) * interval '15' minute as slot_start,
    dtr.date_start + level * interval '15' minute as slot_end
  from date_time_range dtr
  connect by level <= (dtr.date_end - dtr.date_start) * (24 * 4) -- 15-minutes
)
select * from time_slots;

यह आपको आपके द्वारा निर्दिष्ट प्रारंभ और समाप्ति तिथि के बीच 57 15-मिनट का स्लॉट देता है। date_time_range . के लिए सीटीई कड़ाई से जरूरी नहीं है, आप अपनी तिथियां सीधे time_slots . में डाल सकते हैं शर्तें, लेकिन आपको उन्हें दोहराना होगा और फिर एक संभावित विफलता बिंदु का परिचय देना होगा (और इसका मतलब है कि एक ही मान को कई बार JDBC या कहीं से भी बांधना)।

फिर उन स्लॉट्स को कक्षाओं की सूची में क्रॉस-जॉइन किया जा सकता है, जो मुझे लगता है कि पहले से ही किसी अन्य तालिका में हैं, जो आपको 171 (3x57) संयोजन देता है; और उनकी तुलना मौजूदा बुकिंग से की जा सकती है - एक बार उन्हें हटा दिए जाने के बाद आपके पास 153 15-मिनट के स्लॉट रह जाएंगे जिनकी कोई बुकिंग नहीं है।

with date_time_range as (...),
time_slots as (...),
free_slots as (
  select c.classroom, ts.slot_num, ts.slot_start, ts.slot_end,
    lag(ts.slot_end) over (partition by c.classroom order by ts.slot_num)
      as lag_end,
    lead(ts.slot_start) over (partition by c.classroom order by ts.slot_num)
      as lead_start
  from time_slots ts
  cross join classrooms c
  left join occupied_classrooms oc on oc.classroom = c.classroom
    and not (oc.occupied_end <= ts.slot_start 
      or oc.occupied_start >= ts.slot_end)
  where oc.classroom is null
)
select * from free_slots;

लेकिन फिर आपको उन्हें सन्निहित श्रेणियों में समेटना होगा। ऐसा करने के कई तरीके हैं; यहाँ मैं यह तय करने के लिए पिछली और अगली पंक्तियों को देख रहा हूँ कि क्या कोई विशेष मान किसी श्रेणी का किनारा है:

with date_time_range as (...),
time_slots as (...),
free_slots as (...),
free_slots_extended as (
  select fs.classroom, fs.slot_num,
    case when fs.lag_end is null or fs.lag_end != fs.slot_start
      then fs.slot_start end as slot_start,
    case when fs.lead_start is null or fs.lead_start != fs.slot_end
      then fs.slot_end end as slot_end
  from free_slots fs
)
select * from free_slots_extended
where (fse.slot_start is not null or fse.slot_end is not null);

अब हम 12 पंक्तियों तक नीचे हैं। (बाहरी where क्लॉज पिछले चरण से 153 स्लॉट्स में से सभी 141 को हटा देता है जो कि मिड-रेंज हैं, क्योंकि हम केवल किनारों की परवाह करते हैं):

CLASSROOM   SLOT_NUM SLOT_START       SLOT_END       
--------- ---------- ---------------- ----------------
A                  1 2013-10-10 07:00                  
A                 12                  2013-10-10 10:00 
A                 19 2013-10-10 11:30                  
A                 57                  2013-10-10 21:15 
B                  1 2013-10-10 07:00                  
B                  9                  2013-10-10 09:15 
B                 16 2013-10-10 10:45                  
B                 30                  2013-10-10 14:30 
B                 37 2013-10-10 16:00                  
B                 57                  2013-10-10 21:15 
C                  1 2013-10-10 07:00                  
C                 57                  2013-10-10 21:15 

तो वे किनारों का प्रतिनिधित्व करते हैं, लेकिन अलग-अलग पंक्तियों पर, और एक अंतिम चरण उन्हें जोड़ता है:

...
select distinct fse.classroom,
  nvl(fse.slot_start, lag(fse.slot_start)
    over (partition by fse.classroom order by fse.slot_num)) as slot_start,
  nvl(fse.slot_end, lead(fse.slot_end)
    over (partition by fse.classroom order by fse.slot_num)) as slot_end
from free_slots_extended fse
where (fse.slot_start is not null or fse.slot_end is not null)

या वह सब एक साथ रखकर:

with date_time_range as (
  select to_date('10/10/2013 07:00', 'DD/MM/YYYY HH24:MI') as date_start,
    to_date('10/10/2013 21:15', 'DD/MM/YYYY HH24:MI') as date_end
  from dual
),
time_slots as (
  select level as slot_num,
    dtr.date_start + (level - 1) * interval '15' minute as slot_start,
    dtr.date_start + level * interval '15' minute as slot_end
  from date_time_range dtr
  connect by level <= (dtr.date_end - dtr.date_start) * (24 * 4) -- 15-minutes
),
free_slots as (
  select c.classroom, ts.slot_num, ts.slot_start, ts.slot_end,
    lag(ts.slot_end) over (partition by c.classroom order by ts.slot_num)
      as lag_end,
    lead(ts.slot_start) over (partition by c.classroom order by ts.slot_num)
      as lead_start
  from time_slots ts
  cross join classrooms c
  left join occupied_classrooms oc on oc.classroom = c.classroom
    and not (oc.occupied_end <= ts.slot_start
      or oc.occupied_start >= ts.slot_end)
  where oc.classroom is null
),
free_slots_extended as (
  select fs.classroom, fs.slot_num,
    case when fs.lag_end is null or fs.lag_end != fs.slot_start
      then fs.slot_start end as slot_start,
    case when fs.lead_start is null or fs.lead_start != fs.slot_end
      then fs.slot_end end as slot_end
  from free_slots fs
)
select distinct fse.classroom,
  nvl(fse.slot_start, lag(fse.slot_start)
    over (partition by fse.classroom order by fse.slot_num)) as slot_start,
  nvl(fse.slot_end, lead(fse.slot_end)
    over (partition by fse.classroom order by fse.slot_num)) as slot_end
from free_slots_extended fse
where (fse.slot_start is not null or fse.slot_end is not null)
order by 1, 2;

जो देता है:

CLASSROOM SLOT_START       SLOT_END       
--------- ---------------- ----------------
A         2013-10-10 07:00 2013-10-10 10:00 
A         2013-10-10 11:30 2013-10-10 21:15 
B         2013-10-10 07:00 2013-10-10 09:15 
B         2013-10-10 10:45 2013-10-10 14:30 
B         2013-10-10 16:00 2013-10-10 21:15 
C         2013-10-10 07:00 2013-10-10 21:15 

SQL Fiddle



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ओरेकल मदद लापता अल्पविराम

  2. Visual Studio 2012 RC में .NET के लिए Oracle डेटा प्रदाता नहीं देख सकता

  3. प्राथमिक कुंजी अद्यतन बनाम प्राथमिक कुंजी हटाना + सम्मिलन

  4. इस मामले में मैं जो चाहता हूं उसे पाने के लिए मुझे अपना एसक्यूएल बदलने की ज़रूरत कैसे है?

  5. Ubuntu 9.x पर ORACLE_HOME वैरिएबल को सही तरीके से कैसे सेट करें?