可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'd like to get value by the following SQL using Eloquent ORM.
- SQL
SELECT COUNT(*) FROM (SELECT * FROM abc GROUP BY col1) AS a;
Then I considered the following.
- Code
$sql = Abc::from('abc AS a')->groupBy('col1')->toSql(); $num = Abc::from(\DB::raw($sql))->count(); print $num;
I'm looking for a better solution.
Please tell me simplest solution.
回答1:
In addition to @delmadord's answer and your comments:
Currently there is no method to create subquery in FROM
clause, so you need to manually use raw statement, then, if necessary, you will merge all the bindings:
$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();
Mind that you need to merge bindings in correct order. If you have other bound clauses, you must put them after 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();
回答2:
The solution of @JarekTkaczyk it is exactly what I was looking for. The only thing I miss is how to do it when you are using DB::table()
queries. In this case, this is how I do it:
$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();
Special atention how to make the mergeBindings
without using the getQuery()
method
回答3:
I could not made your code to do the desired query, the AS is an alias only for the table abc
, not for the derived table. Laravel Query Builder does not implicitly support derived table aliases, DB::raw is most likely needed for this.
The most straight solution I could came up with is almost identical to yours, however produces the query as you asked for:
$sql = Abc::groupBy('col1')->toSql(); $count = DB::table(DB::raw("($sql) AS a"))->count();
The produced query is
select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
回答4:
I like doing something like this:
Message::select('*') ->from(DB::raw("( SELECT * FROM `messages` WHERE `to_id` = ".Auth::id()." AND `isseen` = 0 GROUP BY `from_id` asc) as `sub`")) ->count();
It's not very elegant, but it's simple.
回答5:
From laravel 5.5 there is a dedicated method for subqueries and you can use it like this:
Abc::subSelect(function($q) { $q->select('*')->groupBy('col1'); }, 'a')->count('a.*');
or
Abc::subSelect(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');
回答6:
Do you need the sub-query? You could try something like
$num = Abc::groupBy('col1')->get()->count();
Not ideal if you've got millions of rows, though.