ยังไงฉันหาข้อที่เกี่ยวข้องโต๊ะที่แก่ที่สุดบันทึกการกรองโดยหนึ่งในลักษณะแบบนั้น?

0

คำถาม

ฉันมีนางแบบ Subscription ซึ่งนั่น has_many Versions.

เป็ Version มี status, plan_id แล้ว authorized_at ออกเดท

ความเปลี่ยนแปลงทำให้เป็น Subscription มาจาก Version การแก้ไขปรับปรุงมันเป็นพ่อแม่ Subscription.

เป้าหมายคือค้นหากันและการสมัครสมาชิกเป็น Version กับที่เก่าแก่ที่สุด authorized_at เดท WHERE คน versions.plan_id มันก็เหมือนกันที่ subscriptions.plan_id (พูดอีกอย่างฉันต้องการการตรวจสอบสิทธิ์ของวัน Version อยู่ที่ไหน plan_id เปลี่ยนแปลงปัจจุบัน Subscription's plan_id).

นี่คือกับการค้นหาฉันได้มาอยู่ด้วย ฉันกำลังจะเกิดข้อผิดพลาดใน aggregate ฟังก์ชันรูปแบบการสั่งงาน:

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

คุณสามารถใช้ ด้านข้าง subquery ซึ่งสามารถที่ดีที่สุดที่ถูกระบุว่าเป็นคน foreach วงในภาษา sql. พวกเขาเป็น extremly performant ทางเลือกสดมภ์จากเดียว correlated บันทึกหรือแม้กระทั่ง aggregates จากกลุ่มของที่เกี่ยวข้องรายการบันทึก

สำหรับแต่ละแถวด้วใน subscriptions ที่ DB จะเลือกเดียวแถวออกจากรุ่นออกคำสั่งโดย 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

กำลังสร้างด้านข้างจะมาร่วมกันใน ActiveRecord สามารถทำได้เหมือนกันกับภาษา sql ใช้เส้นสายหรือ Arel:

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

ถ้าคุณแค่ต้องการเลือก id แล้ว current_version คอลัมน์นายควรพิจารณาเรื่องการใช้ pluck แทนที่จะเป็นการเลือกฐานข้อมูลแบบนั้นไม่เหมาะสมยาเพิ่ม

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 ฉันอาจจะไม่ได้เชี่ยวชาญทางด้านบน ActiveRecord แต่บางทีมันอาจจะไม่ได้ผลเพราะการแสดงผลเป็นอาจไม่ใช่ updatable.
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 ใน decending คำสั่ง

@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 หรือคุณจะเข้าใจเวอร์ชั่นอยู่ในนั้นผลลัพธ์ที่ไม่เหมาะกับการสมัครสมาชิก. คุณก็ยังไม่ได้แตะต้องบแกนกลางของคำถามซึ่งเป็นการเลือกเป็น aggregate.
max

ในภาษาอื่นๆ

หน้านี้อยู่ในภาษาอื่นๆ

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

ดังอยู่ในนี้หมวดหมู่

ดังคำถามอยู่ในนี้หมวดหมู่