Efficient way to query database with multiple conditions in laravel - laravel

Is it possible to make this a single query?
$yl_min = DB::connection($this->db2)->table('historical')
->where([['slug','=',$crypto_id],['low_usd','!=', null]])
->whereBetween('created_time',[$this->range_1y,$this->hislatest])
->min('low_usd');
$yl = DB::connection($this->db2)->table('historical')
->select('id','coin','low_usd','created_time','created_at')
->where([['slug','=',$crypto_id],['low_usd',$yl_min]])
->whereBetween('created_time',[$this->range_1y,$this->hislatest])
->first();
I've tried this but no luck:
$yl = DB::connection($this->db2)->table('historical')
->select('id','coin','created_time','created_at',DB::raw('SELECT MIN(low_usd) as low_usd'))
->where([['slug','=',$crypto_id],['low_usd','!=', null]])
->whereBetween('created_time',[$this->range_1y,$this->hislatest])
->first();

After looking at your query code, I found the two query condition is same, and you just want to get min low_usd record,
I think you can just use the multiple condition and ORDER BY low_usd ASC, then take the first one:
$yl = DB::connection($this->db2)->table('historical')
->where([['slug','=',$crypto_id],['low_usd','!=', null]])
->whereBetween('created_time',[$this->range_1y,$this->hislatest])
->orderBy('low_usd','asc')
->select('id','coin','low_usd','created_time','created_at')
->first();
After this, if you want to make this query more efficient,
you need to add index on slug, low_usd, created_time

Related

Laravel query use parent column inside whereRelation

I have problem with my eloquent query, i need to use data of my base model into whereRelation.
I tried this query bottom, but results was not what i except. The query return me all users who have one city relation, not only user who have city updated between my last user sync.
$users = People::whereRaw('TIMESTAMPDIFF(SECOND, people.latest_sync, people.updated_at) > 20')
->orWhereRelation('city', 'updated_at', '>', 'people.updated_at')
->get();
I'v tried people.updated_at and latest_sync in value of my Where Relation
Do i need to make pure SQL Raw query with classic join ?
PS: the first whereRaw is ok, and work (i really need)

Unique query for one record

I need to turn off the "where" for one entry that I know of. I don’t understand how to do this. To understand the general problem: I need a collection with all the records + a unique one for which the "where" has not been applied. They should be displayed in the usual manner. Perhaps there is a solution to add this entry to the collection after querying sort the new collection?
$reviews = Review::query()
->orderBy("id", 'desc')
->whereNotNull('published_at')
//But don't apply whereNotNull ('published_at') to a record with id = ...
->get()
$reviews = Review::query()
->orderBy("id", 'desc')
->whereNotNull('published_at')
->orWhere('id', $your_id_here)
->get()
Is it what you are looking for? It will get all records where published_at is not null or where the id is $your_id_here.

How to get sum along with this Laravel Eloquent query

Database Structure:
Table: sales_payments
columns: id, payer_id, payment_status, amount , ...
Please see this eloquent query. it's working fine but now i need the sum of amount key along with this given eloquent query and where conditions.
$query = SalesPayment::with(['abc.xyz'])
->whereHas('abc.xyz', function ($query) use ($options) {
$query->where('xyz_id',$options['xyz_id']);
});
$query->where(['key3' => key3(), 'payment_status' => PAYMENT_STATUS_SUCCESS]);
$query->orderBy('created_at', 'desc');
return $query->paginate(config('constants.PAGE_LIMIT'));
Possible Solution
Just put a select as mentioned below
$query = SalesPayment::select('*', \DB::raw('SUM(amount) AS total_sale_amount')->with ....
I have tested this solution it's working fine.
Please let me know if there is a better solution than this. And I'm looking for some other solutions Also.
Edit: But there is one problem with this solution that it returning me only one record when i put aggregate function (sum) in select otherwise it was returning more than one records.
You could use the sum method on the query.
$amount = $query->sum('amount');
A new query with the same conditions will be executed to calculate the sum of a column.
https://laravel.com/docs/6.x/queries#aggregates

Laravel Eloquent - distinct() and count() not working properly together

So I'm trying to get the number of distinct pids on a query, but the returned value is wrong.
This is what I try to do:
$ad->getcodes()->groupby('pid')->distinct()->count()
what returns the value "2", while the value it should return, should be "1".
As a workaround, I'm doing this:
count($ad->getcodes()->groupby('pid')->distinct()->get())
what works fine and returns "1"
Is there any rule where count and distinct cannot be on the same query? I find the workaround kind of "heavy", I would like to make the original query work :(
The following should work
$ad->getcodes()->distinct()->count('pid');
A more generic answer that would have saved me time, and hopefully others:
Does not work (returns count of all rows):
DB::table('users')
->select('first_name')
->distinct()
->count();
The fix:
DB::table('users')
->distinct()
->count('first_name');
Anyone else come across this post, and not finding the other suggestions to work?
Depending on the specific query, a different approach may be needed. In my case, I needed either count the results of a GROUP BY, e.g.
SELECT COUNT(*) FROM (SELECT * FROM a GROUP BY b)
or use COUNT(DISTINCT b):
SELECT COUNT(DISTINCT b) FROM a
After some puzzling around, I realised there was no built-in Laravel function for either of these. So the simplest solution was to use use DB::raw with the count method.
$count = $builder->count(DB::raw('DISTINCT b'));
Remember, don't use groupBy before calling count. You can apply groupBy later, if you need it for getting rows.
You can use the following way to get the unique data as per your need as follows,
$data = $ad->getcodes()->get()->unique('email');
$count = $data->count();
Hope this will work.
I had a similar problem, and found a way to work around it.
The problem is the way Laravel's query builder handles aggregates. It takes the first result returned and then returns the 'aggregate' value. This is usually fine, but when you combine count with groupBy you're returning a count per grouped item. So the first row's aggregate is just a count of the first group (so something low like 1 or 2 is likely).
So Laravel's count is out, but I combined the Laravel query builder with some raw SQL to get an accurate count of my grouped results.
For your example, I expect the following should work (and let you avoid the get):
$query = $ad->getcodes()->groupby('pid')->distinct();
$count = count(\DB::select($query->toSql(), $query->getBindings()));
If you want to make sure you're not wasting time selecting all the columns, you can avoid that when building your query:
$query = $ad->select(DB::raw(1))->getcodes()->groupby('pid')->distinct();
I came across the same problem.
If you install laravel debug bar you can see the queries and often see the problem
$ad->getcodes()->groupby('pid')->distinct()->count()
change to
$ad->getcodes()->distinct()->select('pid')->count()
You need to set the values to return as distinct. If you don't set the select fields it will return all the columns in the database and all will be unique. So set the query to distinct and only select the columns that make up your 'distinct' value you might want to add more. ->select('pid','date') to get all the unique values for a user in a day
Based on Laravel docs for raw queries I was able to get count for a select field to work with this code in the product model.
public function scopeShowProductCount($query)
{
$query->select(DB::raw('DISTINCT pid, COUNT(*) AS count_pid'))
->groupBy('pid')
->orderBy('count_pid', 'desc');
}
This facade worked to get the same result in the controller:
$products = DB::table('products')->select(DB::raw('DISTINCT pid, COUNT(*) AS count_pid'))->groupBy('pid')->orderBy('count_pid', 'desc')->get();
The resulting dump for both queries was as follows:
#attributes: array:2 [
"pid" => "1271"
"count_pid" => 19
],
#attributes: array:2 [
"pid" => "1273"
"count_pid" => 12
],
#attributes: array:2 [
"pid" => "1275"
"count_pid" => 7
]
$solution = $query->distinct()
->groupBy
(
[
'array',
'of',
'columns',
]
)
->addSelect(
[
'columns',
'from',
'the',
'groupby',
]
)
->get();
Remember the group by is optional,this should work in most cases when you want a count group by to exclude duplicated select values, the addSelect is a querybuilder instance method.
Wouldn't this work?
$ad->getcodes()->distinct()->get(['pid'])->count();
See here for discussion..
Distinct do not take arguments as it adds DISTINCT in your sql query, however, you MAY need to define the column name that you'd want to select distinct with. Thus, if you have
Flight->select('project_id')->distinct()->get() is equialent to SELECT DISTINCT 'project_id' FROM flights and you may now add other modifiers like count() or even raw eloquent queries.
Use something like this
DB::table('user_products')->select('user_id')->distinct()->pluck('user_id')->toArray();
This was working for me so
Try This:
$ad->getcodes()->distinct('pid')->count()
try this
$ad->getcodes()->groupby('pid')->distinct()->count('pid')

Doctrine: how to return the row count of a records in a groupby statement

Seems like such a simple thing, but I can't get my query to return the number of records in a group. Here's my statement:
public function getGroupCount($user_id)
{
$q = Doctrine_Query::create()
->select('ss.*')
->from('SalarySurvey ss')
->where('ss.user_id=?', $user_id)
->groupBy('created_at')
->execute();
return $q->rowCount();
}
rowCount() does not work in the above query.
It might also be helpful to know that this is being used in a foreach statement.
As CappY suggested, this is not possible in Doctrine 1.2, as far as I know. As a work-around, I was able to finally get a count for each grouping by adding another field to the table and setting that field the same for each group at save time. Then I changed my query to pull that field and just did a simple:
$q->count();
Never work with Doctrine 1.2, but can't U use php's count function or SELECT COUNT() AS 'cnt' ?
return count($q);

Resources