Ruby on rails 如何在活动记录查询中选择上一行?

Ruby on rails 如何在活动记录查询中选择上一行?,ruby-on-rails,postgresql,rails-activerecord,redmine,Ruby On Rails,Postgresql,Rails Activerecord,Redmine,我是Rails新手,我的第一个项目是为Redmine制作插件。我需要找出问题中状态更改之间经过了多少时间 我通过对每个状态更改执行以下操作来计算: 从创建日期减去上一个状态更改的创建日期 如果是问题的第一次状态更改,请减去问题的创建日期。 我在PostgreSQL中编写了以下代码,使用lag函数访问前一行,这将为我提供所需的输出 SELECT issues.subject, journals.id, COALESCE( (journals.created_on - lag(journals.cr

我是Rails新手,我的第一个项目是为Redmine制作插件。我需要找出问题中状态更改之间经过了多少时间

我通过对每个状态更改执行以下操作来计算:

从创建日期减去上一个状态更改的创建日期 如果是问题的第一次状态更改,请减去问题的创建日期。 我在PostgreSQL中编写了以下代码,使用lag函数访问前一行,这将为我提供所需的输出

SELECT issues.subject, journals.id,
COALESCE(
(journals.created_on - lag(journals.created_on) 
 OVER (PARTITION BY journals.journalized_id ORDER BY journals.created_on)),
journals.created_on - issues.created_on
) AS time_elapsed
FROM journals 
INNER JOIN journal_details ON journal_details.journal_id = journals.id
INNER JOIN issues ON issues.id = journals.journalized_id 
WHERE journal_details.prop_key = 'status_id';
…在Rails中我做到了

Journal.joins(:details, :issue)
.where(:journal_details => {prop_key: :status_id})
.select("issues.subject, journals.id")

但是,为了选择前一行,我不能使用Postgres函数,因为我需要此代码与数据库无关

花了几个小时,我只能想出一个选择前一行的子查询:

subquery = "SELECT j.created_on FROM journals AS j 
INNER JOIN journal_details ON journal_details.journal_id = j.id 
WHERE journal_details.prop_key = 'status_id' 
AND j.journalized_id = journals.journalized_id 
AND j.id < journals.id ORDER BY j.id DESC LIMIT 1"

Journal.joins(:details, :issue)
.where(:journal_details => {prop_key: :status_id})
.select("issues.subject, journals.id, 
COALESCE(journals.created_on - (#{subquery}), 
(journals.created_on - issues.created_on)) AS time_elapsed")
这不是一个可行的选项,因为它对每一行执行一个以上的select查询,我需要一个性能有效的解决方案。也不干


所以我的问题是,如果我可以选择上一行,我如何使用活动记录查询界面?或者至少,什么是解决这个问题的最佳实践/rails方法?

如果我忽略了这里的一些复杂性,我深表歉意,但似乎最简单的解决方案就是跟踪rails中以前的记录

previous_detail = nil

journal.journal_details.each do |detail|
  if previous_detail
    # do processing with current and prevous details
  else
    # do progessing with current detail and journal
  end
  previous_detail = detail
end

为了选择前一行,我不能使用Postgres函数,因为我需要此代码与数据库无关。函数滞后也适用于最流行的DBMS,如MySQL 8.0。Oracle 10g Release 2 10.2+我相信可能会更早,PostgreSQL 8.4+,SQL Server MSSQL version 2012+,SQLite在我看来使用LAG是相当不可知数据库的。此外,如果您担心数据库不可知性。。LIMIT仅适用于MySQL、MySQL的MariaDB fork和PostgreSQL。因此,您不必担心使用LAG而不是数据库无关性。如果您知道要在SQL中执行的查询,您也可以只执行一个查询,或者发布一个无法完全转换为ActiveRecord语法的工作查询,因为这可能会得到更具针对性的帮助。您可能也会考虑询问SQL特定于ORM问题。我在第一次尝试中尝试过,但是如果我在Rails中进行时间计算,那么我将无法使用该结果数据进行排序或分组。我的意思是我也可以在应用层做这些,但速度会慢得多。这就是为什么我试图在DB端计算它,并将它作为查询结果的一列。是的,我理解。一个想法是,你的插件可以迁移新字段,并且可以通过before_create callaback填充列,并且有一个初始种子来填充现有记录中的新字段,最后它将使查询更高效。