我怎么能找到一个相关的表的最古老的记录过滤通过它的一个属性?

0

的问题

我有的模型 Subscriptionhas_many Versions.

一个 Version 有一个 status, plan_idauthorized_at 日期。

任何改变一个 Subscription 来自一个 Version 修改更新它的父母 Subscription.

我们的目标是找到每个订阅的 Version 最古老的 authorized_at 日期 WHEREversions.plan_id 是一样的 subscriptions.plan_id (换句话说我需要授权的日期 Version 这里的 plan_id 改变目前的 Subscription's plan_id).

这是查询我来了。 我得到一个错误总体功能的语法:

syntax error at or near "MIN" LINE 3: MIN (authorized_at) from versions ^

查询:

select subscriptions.id,
MIN (authorized_at) from versions
where versions.plan_id = subscriptions.plan_id
) as current_version
from subscriptions
join versions on subscriptions.id = versions.subscription_id
where versions.status = 'processed'

我也不知道我是否应该被分组的版本 plan_id 然后挑选从各个小组。 我失去了。

database postgresql ruby ruby-on-rails
2021-11-23 14:26:06
3

最好的答案

1

你可以使用一种 横向子查询 其可以被描述为一个foreach循环在SQL。 他们是一个极高效的方式来选择列从一个单一的相关记录或甚至聚集体,从一群有关的记录。

为每个行订阅的数据库将会选择一个单一的排版本的命令authorized_at:

SELECT "subscriptions".*,
       "latest_version"."authorized_at" AS current_version,
       "latest_version"."id" AS current_version_id -- could be very useful
FROM   "subscriptions" 
LATERAL
  (
     SELECT   "versions"."authorized_at", "versions"."id"
     FROM     "versions"
     WHERE    "versions"."subscription_id" = "subscriptions"."id" -- lateral reference
     AND      "versions"."plan_id" = "subscriptions"."plan_id"
     AND      "versions"."status" = 'processed'
     ORDER BY "versions"."authorized_at" ASC
     LIMIT 1
  ) latest_version ON TRUE

建立横向联接在Email可以与SQL串或阿雷尔:

class Subscription < ApplicationRecord
  # Performs a lateral join and selects the 
  # authorized_at of the latest version 
  def self.with_current_version
    lateral = Version.arel_table.then do |v|
      v.project(
        v[:authorized_at],
        v[:id] # optional
      ).where(
        v[:subscription_id].eq(arel_table[:id])
          .and(v[:plan_id].eq(arel_table[:plan_id]) )
          .and(v[:status].eq('processed'))
      )
      .order(v[:authorized_at].asc)
      .take(1) # limit 1
      .lateral('latest_version ON TRUE')
    end
    lv = Arel::Table.new(:latest_version) # just a table alias
    select(
      *where(nil).arel.projections, # selects everything previously selected
      lv[:authorized_at].as("current_version"),
      lv[:id].as("current_version_id") # optional
    ).joins(lateral.to_sql)
  end
end

如果你只是想要选择的 idcurrent_version 你应该考虑采用替代选择的数据库模式,不适当地水合。

2021-11-23 16:49:48
1

你可以使用 DISTINCT ON 过滤出行,并保持一个单一的每个订阅--第一个,每组根据的 ORDER BY 条款。

例如:

select distinct on (s.id) s.id, v.authorized_at
from subscription s
join versions v on v.subscription_id = s.id and v.plan_id = s.plan_id
where v.status = 'processed'
order by s.id, v.authorized_at
2021-11-23 16:40:51

谢谢你。 查询似乎工作在控制台,但是当我试着用它在我的看法作为一种模式的范围,我得到 ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "WHERE" LINE 6: ...s.id, v.authorized_at WHERE "sub...
pinkfloyd90

@pinkfloyd90我不是专家在Email,但也许它不工作,因为查看可能是不可更新。
The Impaler
0

以下代码会给你的 versions 哪儿的版本是 plan_id 等于订阅的 plan_id.

@versions = Version.joins("LEFT JOIN subscriptions ON subscriptions.plan_id = versions.plan_id")

过滤记录的版本是 status

@versions = Version.joins("LEFT JOIN subscriptions ON subscriptions.plan_id = versions.plan_id").where(status: "processed")

过滤记录的版本是 status 和秩序, authorized_at 升序排列。

@versions = Version.joins("LEFT JOIN subscriptions ON subscriptions.plan_id = versions.plan_id").where(status: "processed").order(:authorized_at)

过滤记录的版本是 status 和秩序, authorized_at 在递减的顺序。

@versions = Version.joins("LEFT JOIN subscriptions ON subscriptions.plan_id = versions.plan_id").where(status: "processed").order(authorized_at: :desc)

希望这对你的作品!

2021-11-23 14:33:48

我认为你需要参加 subscriptions.id = versions.subscription_id 或者您将会得到的版本,结果不属于该订阅。 你还没有触及的核心问题是选择一个集合体。
max

其他语言

此页面有其他语言版本

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................