回答:
@delmadordの回答とコメントに加えて:
現在、FROM
節でサブクエリを作成する方法はないため、rawステートメントを手動で使用する必要があります。その後、必要に応じて、すべてのバインディングをマージします。
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
->count();
バインディングを正しい順序でマージする必要があることに注意してください。他のバウンド句がある場合は、それらをmergeBindings
次のように配置する必要があります。
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
// ->where(..) wrong
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
// ->where(..) correct
->count();
toSql
。PDO php.net/manual/en/book.pdo.phpを読み、結果を確認してください$query->toSql()
$sub
クエリがEloquent Builderの場合でも、->getQuery()
パーツが必要です。そうでない場合は、このメソッドがクラスに対して型指定されるため、エラーが発生しますQuery\Builder
。
Laravel v5.6.12(2018-03-14)が追加されfromSub()
、fromRaw()
クエリビルダーにメソッドが追加されました(#23476)。
受け入れられた答えは正しいですが、次のように簡略化できます。
DB::query()->fromSub(function ($query) {
$query->from('abc')->groupBy('col1');
}, 'a')->count();
上記のスニペットは、次のSQLを生成します。
select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`
@JarekTkaczykの解決策はまさに私が探していたものです。私が見逃している唯一のことは、DB::table()
クエリを使用しているときにそれを行う方法
です。この場合、これは私がそれを行う方法です:
$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
'something',
DB::raw('sum( qty ) as qty'),
'foo',
'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();
方法mergeBindings
を使用せずに作る方法の特別な注意getQuery()
DB::raw()
して仕事ができました
laravel 5.5以降、サブクエリ専用のメソッドがあり、次のように使用できます。
Abc::selectSub(function($q) {
$q->select('*')->groupBy('col1');
}, 'a')->count('a.*');
または
Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');
Call to undefined method subSelect()
subSelect
存在しないようです。
selectSub
。返信を更新しました。
私はこのようなことをするのが好きです:
Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
GROUP BY `from_id` asc) as `sub`"))
->count();
あまりエレガントではありませんが、シンプルです。
目的のクエリを実行するようにコードを作成できませんでした。ASはテーブルのエイリアスabc
であり、派生テーブルのエイリアスではありません。Laravel Query Builderは派生テーブルのエイリアスを暗黙的にサポートしていません。これにはDB :: rawが必要になる可能性が高いです。
私が思いつくことができる最も直線的な解決策はあなたのものとほとんど同じですが、あなたが要求したようにクエリを生成します:
$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();
生成されたクエリは
select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
この回答で説明されている正しい方法:https : //stackoverflow.com/a/52772444/2519714 現時点で最も一般的な回答は完全に正しいわけではありません。
このように、https://stackoverflow.com/a/24838367/2519714は、次のような場合に正しくありません。例のクエリ:
select * from (select * from t1 where col1 = ?) join t2 on col1 = col2 and col3 = ? where t2.col4 = ?
このクエリを作成するには、次のようなコードを記述します。
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->from(DB::raw('('. $subQuery->toSql() . ') AS subquery'))
->mergeBindings($subQuery->getBindings());
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
このクエリの実行中、彼のメソッド$query->getBindings()
は['val3', 'val1', 'val4']
この場合のように不正な順序でバインディングを返し、['val1', 'val3', 'val4']
上記の生のSQLを修正します。
これをもう一度行う正しい方法:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->fromSub($subQuery, 'subquery');
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
また、バインディングは自動的かつ正しく新しいクエリにマージされます。
belongsToMany
副選択として複雑なクエリがある場合は、getQuery()
2回追加する必要があることに注意してください=>$sub->getQuery()->getQuery()