【问题标题】:Selecting maximum value with offset > 0 returns nil选择偏移量 > 0 的最大值返回 nil
【发布时间】:2013-01-09 06:37:17
【问题描述】:

我想将fresh_when last_modified: @conversations.maximum(:updated_at) 与分页一起使用。但是,当 @conversations 在第 2 页上时,updated_at 将返回为 nil,即使该集合中有一条记录。

irb(mail):001:0> conversations = conversations.paginate(page: 1)
=> [10 conversations]

irb(main):002:0> conversations.maximum(:updated_at)
   (3.0ms)  SELECT MAX(`inbox_conversations`.`updated_at`) AS max_id FROM `inbox_conversations` LIMIT 10 OFFSET 0
=> 2013-01-09 05:12:10 UTC # Correct

irb(main):003:0> conversations = conversations.paginate(page: 2)
=> [10 conversations]

irb(main):004:0> conversations.maximum(:updated_at)
   (2.7ms)  SELECT MAX(`inbox_conversations`.`updated_at`) AS max_id FROM `inbox_conversations` LIMIT 10 OFFSET 10
=> nil # Not correct

【问题讨论】:

  • 我需要左连接
  • 这里的左连接和内连接没有区别。
  • 您正在从 11-20 提取结果,该位置是否有任何数据

标签: mysql sql ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

Rails 误解了你想要的内容

SELECT MAX(`inbox_conversations`.`updated_at`) AS max_id FROM `inbox_conversations` LIMIT 10 OFFSET 10

意味着运行查询,然后从偏移量 10 获取前 10 个结果。这将返回 nil,因为结果集只有一行 - 最大 updated_at。相反,您想要的是影响计算最大值的行的偏移​​限制。

您可以使用子查询来执行此操作,但我只会在 ruby​​ 中执行此计算,因为无论如何您都在使用常规的 Enunerable 方法加载行。类似的东西

conversations.map(&:updated_at).max

【讨论】:

  • 在这种情况下,无论如何我都不必加载行。 fresh_when 是唯一的查询,我永远不必加载其余的行。将ORDER BY updated descOFFSETLIMIT 1 一起使用怎么样?这将获得相同的结果并且比获得所有十个更快,不是吗?
  • 好吧,如果 etag 实际上是新鲜的,您就不需要加载行。但是是的,在那种情况下可能会更快
【解决方案2】:

SQL MAX 查询不适用于 OFFSET (plain SQL workaround)

如果n > 0,任何 ActiveRecord .offset(n).maximum(:field) 都会给出 nil

尝试使用纯 Ruby 作为解决方法(它可以提前为您节省查询)。

conversations.max_by(&:updated_at)

【讨论】:

    猜你喜欢
    • 2016-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2021-10-20
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多