Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Nhận giờ có sẵn trong lớp học trong khoảng thời gian ngày

Tôi đã xem xét một giải pháp tương tự về khái niệm, ít nhất là với Wernfried, nhưng tôi nghĩ nó cũng đủ khác để đăng. Khởi đầu là cùng một ý tưởng, trước tiên tạo ra các khoảng thời gian có thể và giả sử bạn đang xem các cửa sổ 15 phút:Tôi đang sử dụng CTE vì tôi nghĩ chúng rõ ràng hơn các lựa chọn lồng nhau, đặc biệt là với nhiều cấp độ này.

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;

Điều này cung cấp cho bạn 57 khoảng thời gian 15 phút giữa ngày bắt đầu và ngày kết thúc mà bạn đã chỉ định. CTE cho date_time_range không hoàn toàn cần thiết, bạn có thể đặt ngày của mình thẳng vào time_slots nhưng bạn sẽ phải lặp lại chúng và điều đó sau đó dẫn đến điểm lỗi có thể xảy ra (và có nghĩa là liên kết cùng một giá trị nhiều lần, từ JDBC hoặc bất cứ nơi nào).

Các vị trí đó sau đó có thể được kết hợp chéo với danh sách các lớp học, mà tôi cho rằng đã có trong một bảng khác, cung cấp cho bạn 171 (3x57) kết hợp; và những thứ đó có thể được so sánh với những lượt đặt chỗ hiện tại - khi những lượt đặt chỗ đó bị loại bỏ, bạn sẽ còn lại 153 khoảng thời gian 15 phút không có lượt đặt chỗ nào.

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;

Nhưng sau đó bạn phải thu gọn chúng thành các phạm vi liền nhau. Có nhiều cách khác nhau để làm điều đó; ở đây, tôi đang xem xét các hàng trước đó và tiếp theo để quyết định xem một giá trị cụ thể có phải là cạnh của một phạm vi hay không:

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);

Bây giờ chúng ta xuống 12 hàng. (where mệnh đề loại bỏ tất cả 141 trong số 153 vị trí từ bước trước đó là tầm trung, vì chúng tôi chỉ quan tâm đến các cạnh):

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 

Vì vậy, chúng đại diện cho các cạnh, nhưng trên các hàng riêng biệt và bước cuối cùng kết hợp chúng:

...
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)

Hoặc kết hợp tất cả những thứ đó lại với nhau:

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;

Điều này mang lại:

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. Oracle 12.2 - Thay thế tính năng NOPARTITION

  2. Nhận oracle.jdbc.driver.LogicalConnection, cần oracle.jdbc.OracleConnection

  3. Sự khác biệt giữa CLOB và NCLOB là gì?

  4. Phần khởi tạo của gói

  5. Viết một hàm trong plsql