mysql - Efficient way of counting number of records per day within date range in Rails without requiring one query per day -
rails app using fullcalendar.js
generate reservation calendar shows, on each day, count of check-ins, check-outs , in progress reservations
for each date.
this sample outcome:
using sql i'm able group reservations check-in
, check-out
, generate json count each day (since these 2 dates - check in , check-out - actual columns in database). takes 2 queries (one check-ins, 1 check-outs).
but don't know how handle in progress
counts, since dates not in database, being void
between check_in
, check_out
dates.
my current solution (the 1 think of) requires looping on each day
of calendar , issuing sql count reservations check_in < day , check_out > day
, takes lot of sql queries (one each day in calendar view). current working code:
# start_date , end_date provided fullcallendar.js params start_date, end_date = date.parse(start_date_string), date.parse(end_date_string) # in progress last_in_progress_event = nil array = [] (start_date..end_date).each |day| count = current_user.reservations.where("date(check_in) < :date , date(check_out) > :date", date: day).size if count > 0 # if count > 0, there's active reservation on day. if # count changed when compared previous day, create new event # on fullcalendar (to change `title` of event new count). # if count remained same previous event, can update # it's end date current date being analyzed se nice ui # (continuous event while count doesn't change instead of 1 event # per day) if last_in_progress_event && last_in_progress_event[:count] == count # day + 1 required due fullcalendar.js cutting event short 1 day last_in_progress_event[:end] = (day + 1) else last_in_progress_event = { title: "#{count} in progress", start: day, end: (day + 1), allday: true, classname: 'bgm-lightblue', count: count } array.push(last_in_progress_event) end end # if count > 0 end array
would there way of building hash of {day: in_progress_count}
without 30+ queries per month?
could try one?
create procedure `getinprogresscount`(m_datefrom date, m_dateto date) begin declare m_counter integer; declare m_sqldates longtext; declare m_checkdate date; set m_counter = 0; set m_sqldates = ''; createdates: loop set m_checkdate = date_add(m_datefrom, interval m_counter day); set m_sqldates = concat(m_sqldates, if(trim(m_sqldates) <> "", " union ",""),"(select '", m_checkdate, "' checkdate )"); set m_counter = m_counter + 1; if m_counter < datediff(m_dateto, m_datefrom)+1 iterate createdates; else leave createdates; end if; end loop createdates; set @m_sqlinprogress = concat("select v.checkdate, count(*) inprogresscount (",m_sqldates,") v ", "left join yourtable t on t.check_in < v.checkdate , ", "t.check_out > v.checkdate group v.checkdate"); prepare m_sqldates @m_sqlinprogress; execute m_sqldates; deallocate prepare m_sqldates; end
modify code based on requirements. play until desired output.
Comments
Post a Comment