day23(から3日遅れの)今日はfromにサブクエリを使う方法を見ていきます。
Doctrine
<?php declare(strict_types=1); use Doctrine\ORM\EntityManagerInterface; require __DIR__.'/../vendor/autoload.php'; /** @var EntityManagerInterface $entityManager */ $entityManager = require __DIR__.'/bootstrap.php'; $sql = <<<EOQ SELECT t.name, t.books_count FROM (select authors.id, authors.name, count(books.id) as books_count from authors left join books on books.author_id = authors.id group by authors.id, authors.name) as t EOQ; /** @var array<array{name: string, books_count: int}> $rows */ $rows = $entityManager->getConnection()->fetchAllAssociative($sql); foreach ($rows as $row) { echo sprintf('%s(%d)', $row['name'], $row['books_count']).PHP_EOL; }
- fromに限らず、サブクエリを使うときはORMではなくDBALで対応することがほとんどです。無理にEntityにマップせずに一旦連想配列を取得して、必要に応じて後でDTOに詰め替えます。
Eloquent
<?php declare(strict_types=1); use App\Models\Author; use Illuminate\Database\Eloquent\Collection; require __DIR__.'/../vendor/autoload.php'; require __DIR__.'/bootstrap.php'; $subQuery = <<<EOQ select authors.id, authors.name, count(books.id) as books_count from authors left join books on books.author_id = authors.id group by authors.id, authors.name EOQ; /** @var Collection<Author> $result */ $result = Author::query()->fromSub($subQuery, 't')->select('t.name', 't.books_count')->get(); foreach ($result as $author) { // books_countはAuthorのプロパティではないが、Author::query()で始めたのでAuthorにマップされている echo sprintf('%s(%d)', $author->name, $author->books_count).PHP_EOL; }
- Modelは未定義の項目も受け付けるため、サブクエリを使っていてもModelとして取得することができます。
- fromに限らず、DBMSの許す限りselectやwhereにもサブクエリを利用できます。