初めに
laravelでEloquentでデータベースから取得する際にA and B or C の条件で
データを持ってくる方法とwhereInという便利なものを学んだのでまとめてみました。
実行環境
・Windows10
・php8.2.0
・xamppを使用
前提条件
・laravelのプロジェクトの作成をすることはできる
・migrationファイルを使ったテーブルの作成方法を知っている
・データベースからデータを取得する方法はある程度知っている
と仮定して進めていきます。
使用するテーブル
id | name | gender | age | prefecture |
---|---|---|---|---|
1 | 田中仁 | 男 | 18 | 宮城 |
2 | 鈴木太郎 | 男 | 12 | 石川 |
3 | 青山光 | 女 | 14 | 東京 |
4 | 山田花子 | 女 | 25 | 島根 |
5 | 山岸杏 | 女 | 22 | 宮城 |
6 | 斎藤一 | 男 | 38 | 北海道 |
A and (B or C)の条件でデータを取得するコード
// 15歳より上で宮城か東京の人の名前を取得
$persons = Test::where('age', '>', 15)->where(function($query) {
$query->where('prefecture', '宮城')
->orWhere('prefecture', '東京');
})->get('name');
// $personsをddで出力
dd($persons);
// 出力結果
"name" => "田中仁"
"name" => "山岸杏"
条件が15歳以上が必須で宮城または東京のどちらかなら取得するという条件になっているためその条件に当てはまる山田仁と山岸杏という名前を取得することができました。
今回は省略していますがddを使って出力している際に実際は下記のようなものが出力されます。
実際の出力(押すと表示されます)
Illuminate\Database\Eloquent\Collection {#1243 ▼ // app\Http\Controllers\TestController.php:16
#items: array:2 [▶
0 => App\Models\Test {#1245 ▶
#connection: "mysql"
#table: "tests"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
+preventsLazyLoading: false
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#escapeWhenCastingToString: false
#attributes: array:1 [▶
"name" => "田中仁"
]
#original: array:1 [▶
"name" => "田中仁"
]
#changes: []
#casts: []
#classCastCache: []
#attributeCastCache: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
+usesUniqueIds: false
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [▶
0 => "*"
]
}
1 => App\Models\Test {#1246 ▶
#connection: "mysql"
#table: "tests"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
+preventsLazyLoading: false
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#escapeWhenCastingToString: false
#attributes: array:1 [▶
"name" => "山岸杏"
]
#original: array:1 [▶
"name" => "山岸杏"
]
#changes: []
#casts: []
#classCastCache: []
#attributeCastCache: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
+usesUniqueIds: false
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [▶
0 => "*"
]
}
]
#escapeWhenCastingToString: false
}
ちなみに
先ほどのコードですが書き方を変えて下記のように書くと
$persons = Test::where('age', '>', 15)
->where('prefecture', '宮城')->orWhere('prefecture', '東京')
->get('name');
// $personsをddで出力
dd($persons);
//出力結果
"name" => "田中仁"
"name" => "青山光"// 年齢が14歳なので求めていた条件に合っていない
"name" => "山岸杏"
15歳より下の人のデータまで取ってきてしまいます。自分も引っかかったのですがこの書き方だと
年齢が15歳以上で宮城の人かもしくは年齢は関係なく東京の人を取得するというものになってしまい結果的に東京の部分だけにしか当てはまっていないデータが取得されてしまいます。
つまり(A and B) or C という条件式になってしまいます。
whereInについて
データを取得する際 A or B のA、B両方のカラム名が同じ場合whereInというものを使うことができます。
whereInを使って書き換えた例
$persons = Test::where('age', '>', 15)->whereIn('prefecture', ['宮城', '東京'])->get('name');
// $personsをddで出力
dd($persons);
// 出力結果
"name" => "田中仁"
"name" => "山岸杏"
ORにしたい条件が同名カラムのデータの場合こちらの方がすっきりまとまった書き方になると思います。
補足
今まで書いてきたコードの中に
Test::where('age', '>', 15)
の15の部分のように数字や文字などをそのまま入れているところがありましたがハードコーディングというものになってしまい保守性などの関係でよろしくない可能性があるため実際に書くときは
$acquisition_age = 15;
Test::where('age', '>', $acquisition_age)...
のようにするようにしましょう。
参考記事
ハードコーディング(Hard Coding)は初心者の証?回避方法を3分で解説する
まとめ
今回はwhere、orWhereを使ったA and (B or C) の書き方と便利なwhereInについてまとめていきました。まだまだ勉強中の身なのでこれからも学んだことや役に立ちそうなことを投稿していけたらなと思います。
参考文献
・【Laravel】whereとorWhereの併用で気をつけること
・Laravelのクエリビルダ用メソッド(where・orWhere)を用いて、論理演算の優先度を調整する