一意なデータを取ってくる方法を探していた時、ActiveRecordのdistinctメソッドを発見したため、実際どのようなSQLを発行しているのかし調べてみました。
下記のようなテーブルがあったとします。Userテーブルが親でTaskテーブルは子の状況です。
Userテーブル
id | name | color |
---|---|---|
1 | Bob | blue |
2 | Tom | red |
3 | Emi | black |
4 | Rick | red |
5 | Goto | red |
6 | Alice | black |
Taskテーブル
id | user_id | task |
---|---|---|
1 | 1 | 掃除 |
2 | 4 | 宿題 |
3 | 1 | 風呂掃除 |
4 | 6 | 買い物 |
5 | 3 | 昼寝 |
6 | 4 | 野球 |
User.all.distinct
Userテーブルの全てのデータを取得し、そこにdistinctメソッドを実行しました。以下のようなSQLになります。
SELECT DISTINCT `users`.* FROM `users`
テーブルから取得した列に対して重複を省いています。今回の場合、全ての列を取得しているため、重複が発生することはありません。(そもそもidは一意だから。)
User.select("color").distinct
取得する列をcolorで絞ってみましょう。
SELECT DISTINCT `users`.`color` FROM `users`
すると、取得できるデータはblue、red、blackの3つのみになるはずです。distinctメソッドを使用することで6つ全てのデータを取得するのではなく、値が重複している分のredとblackのデータは除かれます。これはUsersテーブルにあるcolorの列に対してDISTINCTを実行しているからです。
では結合(inner join)させた場合はどうなるでしょうか?タスクを作成しているユーザーのみを取得したい時、下記のようなものができます。
User.joins(:tasks).distinct
SELECT DISTINCT `users`.* FROM `users` INNER JOIN `tasks` ON `tasks`.`users._id` = `users`.`id`
取得するデータは4つになるはずです。取得したデータの中でUsersテーブルのレコードが同じものがあった場合、その重複分は排除されます。