Techioz Blog

この 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 バージョンでは使用できないことに注意してください。