İlişkili bir tabloyu, özniteliklerinden birine göre filtreleyen en eski kaydı nasıl bulabilirim?

0

Soru

Model bende. Subscription hangi has_many Versions.

A Version bir status, plan_id ve authorized_at tarih.

Yapılan herhangi bir değişiklik Subscription a'dan geliyor Version ebeveyni güncelleyen değişiklikler Subscription.

Amaç, her Aboneliğin aboneliğini bulmaktır. Version en büyüğü ile authorized_at tarih WHERE bu versions.plan_id denir. subscriptions.plan_id (başka bir deyişle, yetkilendirme tarihine ihtiyacım var Version nerede plan_id geçerli olarak değiştirildi Subscription's plan_id).

Aklıma gelen soru bu. Toplama işlevi sözdiziminde bir hata alıyorum:

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

sorgu:

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'

Ayrıca sürümleri şu şekilde gruplandırmam gerekip gerekmediğinden emin değilim plan_id ve sonra her gruptan birini seçiyorum. Kayboldum sayılır.

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

En iyi cevabı

1

Sql'de en iyi foreach döngüsü olarak tanımlanabilen yanal bir alt sorgu kullanabilirsiniz. Bunlar, ilişkili tek bir kayıttan sütunları veya hatta ilişkili kayıtlar grubundan toplamları seçmenin son derece etkili bir yoludur.

Aboneliklerdeki her satır için DB, authorized_at tarafından sipariş edilen sürümlerden tek bir satır seçecektir:

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

Activerecord'da yanal birleşimler oluşturmak SQL dizeleri veya Arel ile yapılabilir:

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

Sadece seçmek istiyorsanız id ve current_version sütun düzgün hidratlanmamış veritabanı modellerini seçmek yerine pluck kullanmayı düşünmelisiniz.

2021-11-23 16:49:48
1

Kullanabilirsiniz DISTINCT ON satırları filtrelemek ve abonelik başına bir tane tutmak için-grup başına ilkini ORDER BY cümle.

Örneğin:

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

Teşekkür ederim. Sorgu konsolda çalışıyor gibi görünüyor, ancak görünümlerimde bir model kapsamı olarak kullanmaya çalıştığımda alıyorum ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "WHERE" LINE 6: ...s.id, v.authorized_at WHERE "sub...
pinkfloyd90

@pinkfloyd90 ActiveRecord konusunda uzman değilim, ancak belki de işe yaramıyor çünkü görünüm muhtemelen güncellenemiyor.
The Impaler
0

Aşağıdaki kod size versions sürüm nerede plan_id aboneliğe eşittir plan_id.

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

Kayıtları Sürümlere göre filtrelemek için status

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

Kayıtları Sürümlere göre filtrelemek için status ve emriyle authorized_at artan düzende.

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

Kayıtları Sürümlere göre filtrelemek için status ve emriyle authorized_at sipariş decending içinde.

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

Umarım bu sizin için işe yarar!

2021-11-23 14:33:48

Sanırım sana ihtiyacı katıl subscriptions.id = versions.subscription_id veya bu sonuçtaki aboneliğe ait olmayan sürümleri alırsınız. Ayrıca, bir toplama seçen sorunun özüne bile değinmediniz.
max

Diğer dillerde

Bu sayfa diğer dillerde

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