Rails:如何在历史记录中显示列值?

时间:2017-09-29 11:55:19

标签: sql ruby-on-rails postgresql

我有3张桌子,

问题

|id|subject|done_ratio|
-----------------------
|1 |test   | 50       | 
|2 |test1  | 0        | 
|3 |test3  | 10       | 

期刊

|id|issue_id|notes|created_on         |
---------------------------------------
|1 |1       |NULL |2017-09-29 16:35:09|
|2 |3       |test |2017-09-28 16:35:09|

期刊详情

|id|journal_id|prop_key  |old_value|value|
------------------------------------------
|1 |1         |done_ratio|0        |50   |

基本上,有3种型号。

问题

has_many :journals

杂志

belongs_to :issue
has_many :journal_details

JournalDetail

belongs_to :journal

JournalsJournal details表用于维护Issue历史记录。

如果更新某个问题属性,则会为每个更新的属性创建journal条目以及journal details条目。如果只有一个注释添加到issue,则只会使用该注释创建journal条目。

如何在今天之前获取问题列表以及done_ratio值,如果找不到则0

我可以先获取所有问题,然后在今天之前获取done_ratio值,在每个问题的单独查询中

发现问题

issues = Issue.all

在今天之前为每个问题找到done_ratio

journal = issue.journals.joins(:details).where("journal_details.prop_key ='done_ratio' AND DATE(journals.created_on) = ?", Date.today).order('journals.created_on asc').limit(1).first
last_done_ratio = journal.details.where(prop_key: 'done_ratio').first.old_value.to_f unless journal.blank?

但这会增加加载时间。所以,我想在一个查询中做到这一点。

合并可能在这里工作,但不知道如何。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

您可以使用以下查询在今天之前找到问题列表以及done_ratio的值:

Issue
  .joins(journals: :journal_details)
  .where(journal_details: { prop_key: 'done_ratio' })
  .where("DATE(journals.created_on) = ?", Date.today)
  .order('journals.created_on asc')

它不会返回没有与prop_key'done_ratio'相关联的期刊详细信息的问题。如果您还需要解决没有'done_ratio'详细信息的问题,那么您需要使用OUTER JOIN

Issue
  .joins("LEFT OUTER JOIN journals ON issues.id = journals.issue_id")
  .joins("LEFT OUTER JOIN journal_details ON journals.id = journal_details.journal_id")
  .where(journal_details: { prop_key: 'done_ratio' })
  .where("DATE(journals.created_on) = ?", Date.today)
  .order('journals.created_on asc')

答案 1 :(得分:0)

我试过这个:

Issue.select('issues.id, issues.subject, journal_details.old_value as done_ratio')
  .left_outer_joins(journals: [:journal_details])
  .where('journal_details.prop_key = ?', 'done_ratio')
  .where('journals.created_at < ?', Time.now)
  .order('journals.created_at DESC')

但这不符合您的需要 我会把它留在这里,以便人们知道如何不这样做。

答案 2 :(得分:0)

这个简单的SQL查询可以帮助您实现所需的结果。

http://sqlfiddle.com/#!17/54dcb/3

SELECT i.id,  COALESCE(done_ratio,'0')
   FROM    issues i left join ( 
          select j.issue_id, row_number() OVER (ORDER BY j.created_on desc) AS rank_index,
                 jd.new_value done_ratio
            FROM Journals j 
      inner join journal_detail jd 
              on j.id = jd.journal_id 
             AND jd.prop_key = 'done_ratio' -- We are interest only in 'done_ratio' only
             AND j.created_on < CURRENT_DATE -- and which changed before today -- TODO check for time precision
    ) last_day_done
ON i.id = last_day_done.issue_id and rank_index = 1 --Only join with first row (most recent)

这可能需要您在表上创建其他索引。