【问题标题】:active record quering in rails 4 and postgresrails 4 和 postgres 中的活动记录查询
【发布时间】:2013-09-23 21:58:06
【问题描述】:

我有 2 个模型

Class Ride
  has_many :trips

  #state (string: active or expired)
end

Class Trip
  #date (Date attribute)
  scope :active, -> (start_at = Date.today) { where("trips.date >= ?", [Date.today, start_at].max) }  
end

每天,我需要更新 Rides 具有活动状态 的状态 all 日期属性 时间> 如何在 1 个查询中执行此操作? 我可以使用以下方法存档这样的结果:

Ride.with_active_state.select{|r| r.trips.active.size ==0}

但它会进行 huje 查询来计算行程,eq:

    [1] pry(main)> Ride.with_active_state.select{|r| r.trips.active.size ==0}
   (7.3ms)  SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='rides'
  Ride Load (1.6ms)  SELECT "rides".* FROM "rides" WHERE (rides.workflow_state = 'active')
   (2.9ms)  SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='trips'
   (1.3ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 9]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 10]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 11]]
   (0.7ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 12]]
   (0.8ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 13]]
   (0.8ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 14]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 15]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 16]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 17]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 18]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 19]]
   (0.5ms)  SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24')  [["ride_id", 20]]

....

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord


    【解决方案1】:

    使用grouphaving 子句在Ride 上添加范围。它将检查骑行的所有未来行程的计数,并以 0 计数返回游乐设施。

    Class Ride
    
      scope :active_state, where(state: "active")
      scope :with_nonactive_trips, -> (start_date = Date.today){ joins(:trips).
                                        group("rides.id").
                                        having( ["sum(trips.date > ?) = 0",start_date] ) }
    
    end
    
    Ride.active_state.with_nonactive_trips
    # returns All the rides with state == active, alteast one trip and having no trips with date > Date.today
    

    使用lambda,因为您在Trip 的活动范围内拥有它。我猜您需要为某些查询使用与Date.today 不同的日期。

    【讨论】:

    • 骑行可以有 2 次行程,一次有过期日期,另一次有未来日期。在这种情况下,不应在此查询中选择它...
    • 解释一下为什么需要对第二个作用域使用 lambda 可能是个好主意。
    • 并且行程总是至少有 1 次行程(是否过期但始终存在)
    • scope :with_nonactive_trips, -> (start_date = Date.today){ includes(:trips). group("rides.id, trips.id").references(:trips). having( ["sum(cast(trips.date >= ? as int)) = 0",start_date] ) } 这对我有用。感谢您的帮助!
    • @Danil 使用includes 时要小心,因为它会创建一个外连接表,如果表很大,查询会很慢。如果joins 为您完成这项工作,我建议您在includes 上使用它。您可以使用分析器查看查询时间的差异。
    猜你喜欢
    • 2016-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多