ちょうどやりたいことができそうだったので、 MySQL8.0 で新しく追加された再帰クエリを使ってみました。なお、単独インストールした Eloquent での使用を想定しているので、リレーションの機能をそのまま使うのは難しそうなケースでした。
経緯
内容としてはありがちな部署マスタのようなもので、親子関係まで見たいと考えたためでした。
| id | parent | name |
|---|---|---|
| 1 | 0 | 営業部 |
| 2 | 1 | 営業1課 |
| 3 | 1 | 営業2課 |
| 4 | 0 | システム部 |
| 5 | 4 | 開発課 |
| 6 | 4 | 運用保守課 |
| 7 | 5 | フロントエンドグループ |
| 8 | 5 | バックエンドグループ |
イメージとしてはこんなイメージのテーブルがあったとして、例えば「システム部」と指定した場合、「開発課」「運用保守課」「フロントエンドグループ」「バックエンドグループ」のIDを子部署として参照したい、というようなケースです。
コード
$hogeObjectsArray = $this->dbConnect->connection('hogera')
->select("
WITH recursive child(
depth,
id,
parent,
name
) AS (
SELECT 0,
id,
parent,
name
FROM hoge
WHERE id = {$foo}
UNION ALL
SELECT child.depth + 1,
hoge.id,
hoge.parent,
hoge.name
FROM hoge, child
WHERE hoge.parent = child.id
)
SELECT depth,
id,
parent,
name
FROM child
ORDER BY
depth
");
最終的には上述の形で取得できました。
->table($this->table) 等でテーブルを指定せず、いきなり ->select() しているのがミソです。
参考
with recursive
単独の Eloquent 内で with recursive を使用したい
- 100行ぐらいのSQLをLaravelのEloquent\/Query Builderで頑張る – Qiita
- Laravel5で生のSQLを実行する方法
- MySQL — サブクエリに AS を付けないとエラーを起こす | Every derived table must have its own alias – Qiita
メソッド確認
- Illuminate\Database\Capsule\Manager | Laravel API
- query(): Illuminate\Database\Connection | Laravel API
- Builder: Illuminate\Database\Query\Builder | Laravel API
- selectRaw(): Illuminate\Database\Query\Builder | Laravel API
- select(): Illuminate\Database\Query\Builder | Laravel API
- raw(): Illuminate\Database\Connection | Laravel API
unionAll
- unionAll(): Illuminate\Database\Query\Builder | Laravel API
- MySQL の UNION \/ UNION ALL – MySQL の基礎 – MySQL 入門