Laravel query using with() method with unproper sub-query - mysql

I perform the following query with no problem. But it doesn't get the results I want.
I want 3 comments for each post, but I think it gets 3 comments totally. How can I resolve this?
$posts = Post::with([
'comments' => function($c) {
$c->orderBy('commentTimestamp', 'desc')->take(3)->get();
}
])
->take(10)
->get();

Your query is totally valid, I just ran it myself and got the right results, please check your database, if you do SELECT * FROM comments do you get records?

Related

laravel eloquent join where clause with sub query to use column name comparision not working

I am having issues with laravel eloquent join to compare date in where clause using sub query. below query gives me error unknown column policy_periods.statecode i am using this column in where clause of the join subquery for example App\Elrd::where("state_code",'=',DB::raw(policy_periods.statecode))->where('date',"<=",$mod_rating_eff_date)->max('date')
can you please give me an idea if any solution possible ?
i have already tried whereRaw, whereColumn but none of them is working.
DB::table('policy_periods')
->join('payrolls','payrolls.policy_period_id', '=', 'policy_periods.id')
->leftjoin('elrds', function($join) use($mod_rating_eff_date)
{
$join->on('elrds.state_code', '=', 'policy_periods.statecode');
$join->on('elrds.class_code', '=', 'payrolls.code');
$join->where('elrds.date',App\Elrd::where("state_code",'=',DB::raw(`policy_periods`.`statecode`))->where('date',"<=",$mod_rating_eff_date)->max('date'));
})
->select('payrolls.*','payrolls.elr as payrollelr','policy_periods.id as pid','policy_periods.policy_no',DB::raw('CONCAT(eff_date, "-", exp_date) as dateGroup'),'policy_periods.eff_date','policy_periods.exp_date','policy_periods.statecode as ratingeffPolicyYear','policy_periods.statecode','elrds.class_code','elrds.year','elrds.date','elrds.elr','elrds.dratio')
->where('policy_periods.mod_id',$id)
->get();
When I encounter such issue, the first thing I usually do is to determine if the generated query is what I wanted.
You should log your queries so that you can ensure it.
To do that, a possible solution is to add a log in your AppServiceProvider (in function boot):
DB::listen(function ($query) {
Log::debug('query',[
$query->sql,
$query->bindings,
$query->time
]);
});
That being said, where do these backticks come from?
DB::raw(`policy_periods`.`statecode`)
You could replace it with DB::raw('policy_periods.statecode')
Please tell me if it fixes your issue, or provide the generated SQL query if the problem is not fixed.

MySQL to Eloquent query

I've been having some issues with a query. I'm trying to get the most recent record for each 'category' from a table, but I can't figure out how to write the query in Laravel.
I got the query working in MySQL, but no real luck in translating it.
The MySQL query looks like this:
SELECT *
FROM messages
WHERE id IN (
SELECT MAX(id)
FROM messages
GROUP BY conversation_id
);
I was trying something like this in Laravel, but it doesn't seem to work:
return self::where(function($query){
$query->select(max(['id']))
->from('messages')
->groupBy('conversation_id');
})
->get();
(Posted on behalf of the OP).
Thanks to AlexM's comments I figured it out.
return self::whereIn('id', function($query){
$query->select(max(['id']))
->from('messages')
->orderBy('created_at', 'desc')
->groupBy('conversation_id');
})
->get();
Was my first solution but that didn't work quite well. It was selecting two records as intended, but not the last ones.
I've then come up with the idea to use selectRaw instead select, which solved my issue perfectly. The final query looks like this, for any interested:
return self::whereIn('id', function($query){
$query->selectRaw('max(id)')
->from('messages')
->orderBy('created_at', 'desc')
->groupBy('conversation_id');
})
->get();

Laravel 5.3 Query - Left join some table

I'm trying to get the most recent record for each candidate_id from a ìnterviews` table.
This is what I want to achive:
I'm using Eloquent on laravel and have already tried this methods (with and without eloquent):
$candidates = DB::table('interviews')->select('interviews.*', 'i2.*')
->leftJoin('interviews as i2',
function ($join) {
$join->on('interviews.candidate_id', '=', 'i2.candidate_id');
$join->on('interviews.created_at', '<', 'i2.created_at');
}
)
->whereNull('i2.candidate_id')
->get();
and with eloquent I've tried this:
$candidates = Interview::leftJoin('interviews as i2',
function ($join) {
$join->on('interviews.candidate_id', '=', 'i2.candidate_id');
$join->on('interviews.created_at', '<', 'i2.created_at');
}
)->whereNull('i2.candidate_id')
->get();
If I change get() to toSql() I have exactly the same query that's shown on the above image, but running on laravel I'm getting always these results (this using the first method, with query builder):
Anyone know why I get this results? Is hard to understand that laravel is doing the same query that I do in HeidiSql but I get diferent results :(
Any tip?
Thanks in advance!
Because you are using ->select('interviews.*', 'i2.*') combined with ->whereNull('i2.candidate_id') I am assuming the second select parameter is overriding all fields on the interviews table with nulls, try reversing the order to ->select('i2.*','interviews.*') or not use the i2.* at all.
This is because the output ignores the alias and only uses the fieldname as element key in the returned collection.
Hope it works.
Perfect case scenario you pick the exact columns you want from each of the joined tables for e.g. it may go like this: table1.id,table1.column1,table1.column2,table2.column2 as smth_so_it_doesnt_override

Eloquent count distinct returns wrong totals

i'm having an issue with how eloquent is formulation a query that i have no access to. When doing something like
$model->where('something')
->distinct()
->paginate();
eloquent runs a query to get the total count, and the query looks something like
select count(*) as aggregate from .....
The problem is that if you use distinct in the query, you want something like
select count(distinct id) as aggregate from .....
to get the correct total. Eloquent is not doing that though, thus returning wrong totals. The only way to get the distinct in count is to pass an argument through the query builder like so ->count('id') in which case it will add it. Problem is that this query is auto-generated and i have no control over it.
Is there a way to trick it into adding the distinct on the count query?
P.S Digging deep into the builders code we find an IF statement asking for a field on the count() method in order to add the distinct property to the count. Illuminate\Database\Query\Grammars\BaseGrammar#compileAggregate
if ($query->distinct && $column !== '*')
{
$column = 'distinct '.$column;
}
return 'select '.$aggregate['function'].'('.$column.') as aggregate';
P.S.1 I know that in SQL you could do a group by, but since i'm eager loading stuff it is not a good idea cause it will add a IN (number of id's found) to each of the other queries which slows things down significantly.
I faced the exact same problem and found two solutions:
The bad one:
$results = $model->groupBy('foo.id')->paginate();
It works but it will costs too much memory (and time) if you have a high number of rows (it was my case).
The better one:
$ids = $model->distinct()->pluck('foo.id');
$results = $query = $model->whereIn('foo.id', $ids)->paginate();
I tried this with 100k results, and had no problem at all.
This seems to be a wider problem, discussed here:
https://github.com/laravel/framework/issues/3191
https://github.com/laravel/framework/pull/4088
Untill the fixes are shipped with one of the next Laravel releases, you can always try using the raw expressions, like below (I didnt test it, but should work)
$stuff = $model->select(DB::raw('distinct id as did'))
->where('whatever','=','whateverelse')
->paginate();
Reference: http://laravel.com/docs/queries#raw-expressions
$model->where('something')->distinct()->count('id')->paginate();

Yii activerecord and pagination count() slow query

So basicly the problem is in query SELECT COUNT(*) which executed in calculateTotalItemCount function in activedataprovider. As i understood it needed for pagination for $itemcount variable. The problem is this query slow for big tables. For my ~30m table it executes 5 seconds.
So there are 2 ways to solve this problem:
1. Disable pagination ('pagination'=>'false') and write own pagination.
2. Rewrite AR count function.
I dont have enough experience/knowledge to acomplish this.
Maybe some one had same issues before and can share his solution.
Atleast for totalItemCount we can use EXPLAIN SELECT *. Its way more faster.
I appreciate any help. Thank you.
If you have a "cheaper" query in raw SQL than the one that active records create automatically, you can also query manually (e.g. through DAO) and set the totalItemCount on your data provider:
$count = Yii::app()->db->createCommand('SELECT COUNT(*)...')->queryScalar();
$provider = new CActiveDataProvider('SomeModel', array(
'totalItemCount' => $count,
'criteria' => $criteria,
...