在rails中改进调度/预订sql查询

时间:2015-03-09 17:39:37

标签: sql ruby-on-rails ruby postgresql

我正在尝试改进以下计划的SQL:

enter image description here

它看起来像这样:

- @users.each do |user|
  - @dates.each do |date|
    %td
      - Booking.where(user: user, date: date).each do |booking|
        = booking.shift_time

@users由表格中的用户组成。

@dates由日期组成:周初 - >一周结束

显然这段代码很糟糕,因为每个日期,预订和用户都会触发查询。 拥有多个用户需要很长时间才能加载页面。

如何改进此查询?是否可以通过使用一个(大)查询从数据库中获取所有这些数据?如果这有任何区别,我会使用PostgreSQL。

一个建议是我按日期在@dates和组之间进行所有预订。但这意味着我必须用NULL值替换特定日期和用户的不存在的预订,但我不知道我将如何做到这一点。

这是sql输出:

SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-09'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-10'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-11'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-12'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-13'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-14'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 1 AND "bookings"."date" = '2015-03-15'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-09'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-10'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-11'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-12'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-13'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-14'
SELECT "bookings".* FROM "bookings" WHERE "bookings"."user_id" = 2 AND "bookings"."date" = '2015-03-15'

2 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

# controller
def your_action
  @users = User.some_scope
  @dates = some_logic_to_return_array_of_dates
  bookings = Booking.where(user_id: @users.map(&:id), date: @dates)
  # the above will select all Booking record having user_id in the selected users' ids AND date IN the selected range/array of dates
  @bookings_by_date = bookings.group_by(&:date)
  # group results like
  # {
  # <Date> => [<Booking>, <Booking>],
  # <Date2> => [<Booking>]
  # }
end

然后在你看来:

# view
- @users.each do |user|
  - @dates.each do |date|
    %td
      - todays_bookings = @bookings_by_date[date].presence || []
      - todays_bookings.select{ |booking| booking.user == user }.each do |booking|
        = booking.shift_time

答案 1 :(得分:0)

# action
@dates = start_date..end_date
@users = User.some_scope.includes(:bookings)

# view
- @users.each do |user|
  %tr
    - @dates.each do |date|
      %td
        = user.bookings.select{|booking| booking.date == date}.each do |user_booking|
          = user_booking

这应该只打两次数据库(2个用户查询,1个用于预订)