简体   繁体   English

在Rails中计算日期范围内每天记录数量的有效方法,而无需每天进行一次查询

[英]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 to generate a reservation calendar that shows, on each day, the count of check-ins , check-outs and in progress reservations for each date . Rails应用程序使用fullcalendar.js生成一个预订日历,该日历显示每天每一天的入住退房进行中 reservations 的次数

This is a sample outcome: 这是一个示例结果:

在此处输入图片说明

Using SQL I'm able to group reservations by check-in and check-out and easily generate the JSON with the count for each day (since these two dates - check in and check-out - are actual columns in the database). 使用SQL,我能够通过check-incheck-out对预订进行分组check-out并轻松生成每天计数的JSON(因为这两个日期-签入和签出-是数据库中的实际列)。 All it takes are 2 queries (one for check-ins, another one for check-outs). 它只需要2个查询(一个用于签入,另一个用于签出)。

But I don't know how to handle the in progress counts, since the dates are not in the database, being the void between the check_in and check_out dates. 但我不知道如何处理in progress次数,因为日期是不是在数据库中,作为void之间check_incheck_out日期。

My current solution (the only one I could think of) requires looping over each day of the calendar and issuing a SQL count for the reservations whose check_in < day AND check_out > day , but that takes a LOT of SQL queries (one for each day in the calendar view). 我当前的解决方案(我唯一能想到的解决方案)要求循环日历的每day ,并为其check_in < day AND check_out > day的预订发出一个SQL计数,但这需要很多SQL查询(每天一个)在日历视图中)。 This is the current working code: 这是当前的工作代码:

# Start_date and end_date are provided by 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 do |day|

  count = current_user.reservations.where("DATE(check_in) < :date AND DATE(check_out) > :date", date: day).size

  if count > 0
    # If the count > 0, there's an active reservation on this day. If the
    # count changed when compared to the previous day, we create a new event
    # on fullcalendar (to change the `title` of the event with the new count).
    # If the count remained the same as the previous event, we can just update
    # it's end date to the current date being analyzed so se get a nice UI
    # (continuous event while the count doesn't change instead of one event
    # per day)

    if last_in_progress_event && last_in_progress_event[:count] == count
      # Day + 1 is required due to fullcalendar.js cutting the event short one 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 be a way of building this hash of {day: in_progress_count} without 30+ queries per month? 是否有一种方法可以构建每月{day: in_progress_count}哈希,而每月没有30多个查询?

Could you try something like this 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 ALL ",""),"(SELECT '", m_CheckDate,
                              "' AS CheckDate )");
      SET m_Counter = m_Counter + 1;
      IF m_Counter < DATEDIFF(m_DateTo, m_DateFrom)+1 THEN
          ITERATE CreateDates;
      ELSE
          LEAVE CreateDates;
      END IF;

    END LOOP CreateDates;
    SET @m_SQLInProgress = CONCAT("SELECT v.CheckDate, Count(*) InProgressCount FROM (",m_SQLDates,") v ",
                                  "LEFT JOIN yourtable t ON t.check_in < v.CheckDate AND ",
                                  "t.check_out > v.CheckDate GROUP BY v.CheckDate"); 

    PREPARE m_SQLDates FROM @m_SQLInProgress;
    EXECUTE m_SQLDates;
    DEALLOCATE PREPARE m_SQLDates;
END

Modify the code based on your requirements. 根据您的要求修改代码。 Play with it until you get your desired output. 播放直到获得所需的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM