4
0

勉強会での小話1

Last updated at Posted at 2023-12-22

はじめに

この記事は2023年度の振り返りです。

こちらの続きとなります。

問題を解いてる時の実話を元に、(実験で)対話形式で書いてみました

問題

こんなテーブルがあったとする
(テーブル構成に突っ込みどころは多数あると思いますが、割愛して見逃してください)

作者テーブル
irb(main):003> Author.all
  Author Load (0.4ms)  SELECT `authors`.* FROM `authors`
+----+-----------+-------------------------+-------------------------+
| id | name      | created_at              | updated_at              |
+----+-----------+-------------------------+-------------------------+
| 1  | 岸本 斉史 | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 2  | 村田 雄介 | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 3  | 冨樫 義博 | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 4  | 鳥山 明   | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
+----+-----------+-------------------------+-------------------------+
作成者テーブル
irb(main):005> Write.all
  Write Load (0.5ms)  SELECT `writes`.* FROM `writes`
+----+---------+---------+-------------------------+-------------------------+
| id | book_id | user_id | created_at              | updated_at              |
+----+---------+---------+-------------------------+-------------------------+
| 1  | 1       | 1       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 2  | 2       | 1       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 3  | 3       | 2       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 4  | 4       | 2       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 5  | 5       | 3       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 6  | 6       | 3       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 7  | 7       | 4       | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 8  | 8       | 4       | 2023-12-22 14:32:30 UTC | 2023-12-22 14:32:30 UTC |
+----+---------+---------+-------------------------+-------------------------+
漫画テーブル
irb(main):004> Comic.all
  Comic Load (0.5ms)  SELECT `comics`.* FROM `comics`
+----+------------------+-------------------------+-------------------------+
| id | name             | created_at              | updated_at              |
+----+------------------+-------------------------+-------------------------+
| 1  | NARUTO -ナルト-  | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 2  | BORUTO -ボルト-  | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 3  | アイシールド21   | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 4  | ワンパンマン     | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 5  | 幽☆遊☆白書     | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 6  | HUNTER×HUNTER   | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 7  | Dr.スランプ      | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
| 8  | ドラゴンボール   | 2023-12-22 14:32:29 UTC | 2023-12-22 14:32:29 UTC |
+----+------------------+-------------------------+-------------------------+
問題
Author(作者テーブル)で、「冨樫 義博」が書いている漫画を取得するSQLをactive recordで作成してください

勉強会内の小話

初学者達:たぶんこんな感じじゃないですか?

author = Author.find_by(name: '冨樫 義博')
write_ids = Write.where(user_id: author.id).pluck(:book_id)
p Comic.where(id: write_ids)

講師:戻ってくる解答としては正しいけど、これ3回クエリ走るんじゃない?

SELECT `authors`.* FROM `authors` WHERE `authors`.`name` = '冨樫 義博' LIMIT 1
SELECT `writes`.`book_id` FROM `writes` WHERE `writes`.`user_id` = 3
SELECT `comics`.* FROM `comics` WHERE `comics`.`id` IN (5, 6)

初学者達:ですね

講師:解き方は色々あるだろうけど、まずはサブクエリを使ってクエリ減らせるよ?

初学者達:サブクエリってなんですか?

講師:
image.png

講師:よ、よし。まずはここで勉強しよう

初学者達:でも、これってSQLの話であって、active recordじゃ作れませんよね

講師:
image.png

講師:普通にできる・・・よ?

講師:さっき解答したやつを少し変えるだけ

author = Author.where(name: '冨樫 義博')
write = Write.where(user_id: author).select(:book_id)
p Comic.where(id: write)
SELECT `comics`.* 
FROM `comics` 
WHERE `comics`.`id` IN (
    SELECT `writes`.`book_id` 
    FROM `writes` 
    WHERE `writes`.`user_id` IN (
        SELECT `authors`.`id` 
        FROM `authors` 
        WHERE `authors`.`name` = '冨樫 義博'
    )
)

初学者達:おーー。クエリが一つになった!

初学者達:でも、なんでこっちにはselect書いてるんですか?

author = Author.where(name: '冨樫 義博')
write = Write.where(user_id: author).select(:book_id) # ←ココ
p Comic.where(id: write)

講師:書かない場合、デフォルトでIDが利用される。試しにやってみよう

author = Author.where(name: '冨樫 義博')
write = Write.where(user_id: author)
p Comic.where(id: write)
SELECT `comics`.* 
FROM `comics` 
WHERE `comics`.`id` IN (
    SELECT `writes`.`id`  -- ← ココが変わってる
    FROM `writes` 
    WHERE `writes`.`user_id` IN (
        SELECT `authors`.`id` 
        FROM `authors` 
        WHERE `authors`.`name` = '冨樫 義博'
    )
)

講師:結果、意味の異なる検索結果になるんで、この場合は必要ですね。まぁ、明示的にきちんとselect(:id)と書いてやってた方が、メンバーに優しいとは思うよ。

初学者達:なるほど!

さいごに

初の対話形式の記事を書いてみました。
少し短いですが、今回はここまでとします。
この勉強会の話は色々あるので、可能な範囲短く区切ってシリーズにしてみようと思います。

4
0
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
4
0