13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

指定した全ての要素をhas_many関連先に持つ条件の書き方

Posted at

商品Aと商品Bの両方を注文した顧客の一覧を取得したい。顧客には複数の注文が紐付いていて、注文はひとつの商品を持つ。

上のような場合のSQLとArelの書き方を試行錯誤していて、なんとかできたのでメモしておきます。

SQL

select *
from customers
where id in (
  select customer_id
  from orders
  where item_id in (1,2) /* 指定する商品ID */
  group by customer_id
  having count(distinct item_id) = 2 /* 指定する商品IDの数 */
)

複数の商品ID(1,2)で注文テーブルを絞り込んで、指定した商品だけの注文にします。
と同時に顧客IDで集計して、商品IDが指定された数だけあるものを抽出しています。

Arel

app/models/Customer.rb
# 引数の商品全てを注文したことがある
  scope :has_item_id_all, -> item_ids {
    customer = arel_table
    order = Order.arel_table
    subquery = order.project(order[:customer_id])
      .where(order[:item_id].in(item_ids))
      .group(order[:customer_id])
      .having(order[:item_id].count('distinct').eq(item_ids.size))
    where(customer[:id].in(subquery))
  }

SQL文ををArelの文法に変えただけですが、サブクエリの書き方がわからずにひどく苦労しました。
Arelを使ったことで他スコープとのマージもできるようになりました。

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?