この SQL クエリの Rails スコープの記述方法
概要
複数の条件でデータベースから行を取得する際に問題があります。 テーブル Slot と SlotAlteration があります。
スロットには time_off_id フィールドがあります。
SlotAlteration には、slot_id と action の 2 つの列があります。アクションは 0 または 1 です。各スロットは、アクション 0 と 1 (0 と 0、および 1 と 1 ではありません) を持つ SlotAlteration テーブルに最大 2 つのエントリを持つことができます。あるいは、SlotAlteration への接続をまったく持たないこともできます。
Rails スコープに変換する必要があるクエリは
select *
from Slot s
where time_off_id is null
and not exists (
select 1 from Slot
left outer join SlotAlteration a
on s.id = a.slot_id
where a.action = 1
)
order by s.id;
Alterr は SlotAlteration テーブルです
これは視覚的に表現するための SQL 構造とクエリです。
https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://dbfiddle.uk/yejKnaAi
私のスロットモデルには関連付けがあります has_many :変更
scope :free, -> {
left_joins(:alterations)
.where(time_off_id: nil)
.where.not(alterations: { action: 1 })
}
試してみましたが、これは変更されていない選択されたスロットではありません
解決策
action = 1 の代替用に専用の has_many 関連付けを追加します。つまり、関連付けは次のようになります。
# in app/models/slot.rb
has_many :alternations, class_name: 'SlotAlternation'
has_many :action_1_alternations, -> { where(action: 1) }, class_name: 'SlotAlternation'
そうすれば、そのような関連付けられたレコードがなくてもレコードをクエリできるはずです。
Slot
.where(time_off_id: nil)
.where.missing(:action_1_alternations)
欠落しているクエリ メソッドは Ruby on Rails 6.1 で導入されたものであり、6.1 より前の Rails バージョンでは使用できないことに注意してください。