How can I avoid Eloquent query to be chained? - php

I'm new to Laravel.
I wonder how I can avoid query to be chained.
$visitRecords = VisitRecord::whereDate('visited_at', '=', Carbon::today()->toDateString());
$knockBounce = $visitRecords->where("bounce_zone", "1")->get()->count();
$approachBounce = $visitRecords->where("bounce_zone", "2")->get()->count();
This is the code I wrote but this gives me the result I don't expect...
Result
select * from `visit_records` where date(`visited_at`) = '2017-05-12'
select * from `visit_records` where date(`visited_at`) = '2017-05-12' and `bounce_zone` = '1'
select * from `visit_records` where date(`visited_at`) = '2017-05-12' and `bounce_zone` = '1' and `bounce_zone` = '2'
I checked the query conducted and this is what I got.
What I expect...
select * from `visit_records` where date(`visited_at`) = '2017-05-12'
select * from `visit_records` where date(`visited_at`) = '2017-05-12' and `bounce_zone` = '1'
select * from `visit_records` where date(`visited_at`) = '2017-05-12' and `bounce_zone` = '2'
I want to conduct this query instead via Eloquent methods.

You've only instantiated a single QueryBuilder object.
You should create a second QueryBuilder object for the second query.
//Only create one carbon object
$date = Carbon::today()->toDateString()
$knockBounce = VisitRecord::whereDate('visited_at', '=', $date)->where("bounce_zone", "1")->count();
$approachBounce = VisitRecord::whereDate('visited_at', '=', $date)->where("bounce_zone", "2")->count();
Updated as per Matthew's comment, Laravel will execute a ->get() anyway for aggregate functions (count, min, max, avg) under the hood so it's not needed.

You need to have two different objects
you might try below code
$visitRecords = VisitRecord::whereDate('visited_at', '=', Carbon::today()->toDateString());
$visitRecords1 = clone $visitRecords;
$knockBounce = $visitRecords->where("bounce_zone", "1")->get()->count();
$approachBounce = $visitRecords1->where("bounce_zone", "2")->get()->count();
Here I have used clone to copy the $visitRecords object
Further reading about php clone

Edit to take only the needed bounce_zone
Alternatively, you can use collections :
$visitRecords = VisitRecord::whereDate('visited_at', '=', Carbon::today()->toDateString())->where("bounce_zone", "1")->orWhere("bounce_zone", "2")->get();
$knockBounce = $visitRecords->where("bounce_zone", "1")->count();
$approachBounce = $visitRecords->where("bounce_zone", "2")->count();
You run only one query and use all the power of Laravel :)

Related

Use number in where condition in Laravel Query

The below query works well in mysql but how to represent the same thing using Laravel.
select * from user_subscription where vendor_id = 'user_100'
and 0 = (select count(*) from user_restricted_dates where vendor_id = 'user_100')
I tried with code but gives error as unknown column '0' in where clause
$list = UserSubscription::where('vendor_id', '=', $vendor_obj->vendor_id)
->where(0, '=', "(select count(*) from user_restricted_dates where vendor_id = 'user_100'")
->get();
Well the error indicates what it is but how to represent it
The where method of the Query Builder maps the first value you pass to a field in the model. You'd have to use the whereRaw method instead.
$list = UserSubscription::where('vendor_id', '=', $vendor_obj->vendor_id)
->whereRaw("0 = (select count(*) from user_restricted_dates where vendor_id = 'user_100')")
->get();

Clone eloquent models for different queries

Sorry for modifying this question (to all those who have answered here). The question was in fact wrong.
$query = User::find(1)->books(); //books() is "return $this->hasMany('Book');"
$query_for_counting_history_books = clone $query;
$query_for_counting_geography_books = clone $query;
$number_of_history_books = $query_for_counting_history_books->where('type', '=', 'history')->count();
$number_of_geography_books = $query_for_counting_geography_books->where('type', '=', 'geography')->count();
$books = $query->paginate(10);
I want $books to be queried as:
SELECT * FROM books WHERE user_id=1 limit 10;
But its output is:
SELECT * FROM books WHERE user_id=1 and type="history" and type="geography"
limit 10;
Am I missing something about Clone here?
What should be done for this solution?
Not sure why your clone() is not working - but try this:
$query = User::where('confirmed', '=', '1');
$query_for_counting_male = $query->replicate();
$query_for_counting_female = $query->replicate();
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Model.html#method_replicate
Since $query is instance of HasMany, So the cloning should be done as:
$query_for_counting_history_books = clone $query->getQuery();
$query_for_counting_geography_books = clone $query->getQuery();
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Relations/HasOneOrMany.html#method_getQuery

how to find month by date to fetch records for the given month

I have stored date like this format in db "2014-10-13" from this I need to show records only for the given month in Laravel.
Use mysql Month function
SELECT * FROM tbl_name WHERE MONTH( col_name ) = 3
In laravel:
$name = DB::table('tbl_name')->whereRaw('MONTH(col_name) = 3')->get();
Try this it will work :
SELECT * FROM table_name WHERE MONTH('2014-10-13') = '10';
larval :
$results = DB::select('select * from users where MONTH('2014-10-13') = ?', array(10));
Let me just assume the table names as users and assuming you are using eloquent since you have tagged it under laravel.
This is how you get the users who were created in a particular month.
Eloquent:
$month = 12;// for december
$users = User::whereRaw('MONTH(created_at) = ?',[$month])->get();
return $users;
Query Builder:
$users = DB::table('users')->whereRaw('MONTH(created_at) = ?',[$month])->get();
if you also want to get the month in the results then
Eloquent:
$users = User::select(['*',DB::raw('MONTH(created_at) as month')])
->whereRaw('MONTH(created_at) = ?',[$month])->get();
Query Builder:
$users = DB::table('users')->select(['*',DB::raw('MONTH(created_at) as month')])
->whereRaw('MONTH(created_at) = ?',[$month])->get();

How to count and group by in yii2

I would like to generate following query using yii2:
SELECT COUNT(*) AS cnt FROM lead WHERE approved = 1 GROUP BY promoter_location_id, lead_type_id
I have tried:
$leadsCount = Lead::find()
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Which generates this query:
SELECT COUNT(*) FROM (SELECT * FROM `lead` WHERE approved = 1 GROUP BY `promoter_location_id`, `lead_type_id`) `c`
In yii 1.x I would've done the following:
$criteria = new CDbCriteria();
$criteria->select = 'COUNT(*) AS cnt';
$criteria->group = array('promoter_location_id', 'lead_type_id');
Thanks!
Solution:
$leadsCount = Lead::find()
->select(['COUNT(*) AS cnt'])
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->all();
and add public $cnt to the model, in my case Lead.
As Kshitiz also stated, you could also just use yii\db\Query::createCommand().
You can get the count by using count() in the select Query
$leadCount = Lead::find()
->where(['approved'=>'1'])
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Reference Link for various functions of select query
If you are just interested in the count, use yii\db\Query as mentioned by others. Won't require any changes to your model:
$leadsCount = (new yii\db\Query())
->from('lead')
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Here's a link to the Yii2 API documentation
Without adding the $cnt property to model
$leadsCount = Lead::find()
->select(['promoter_location_id', 'lead_type_id','COUNT(*) AS cnt'])
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->createCommand()->queryAll();
Just a note, in case it helps anyone, that a getter used as a property is countable (whereas if called as a function it will return 1). In this example, I have a Category class with Listings joined by listing_to_category. To get Active, Approved Listings for the Category, I return an ActiveQuery, thus:
/**
* #return \yii\db\ActiveQuery
*/
public function getListingsApprovedActive() {
return $this->hasMany(Listing::className(), ['listing_id' => 'listing_id'])
->viaTable('listing_to_category', ['category_id' => 'category_id'])
->andWhere(['active' => 1])->andWhere(['approved' => 1]);
}
Calling count on the property of the Category will return the record count:
count($oCat->listingsApprovedActive)
Calling count on the function will return 1:
count($oCat->getListingsApprovedActive())

How to write this query in laravel 4 using query builder

update `access_tokens` as at3 set at3.`expires` = 1393995576
where
`access_token_expires` > 1393995576
and at3.`id` in (select * from (
select `at2`.`id` from `refresh_tokens` as `rt`
left join `access_tokens` as `at` on `at`.`id` = `rt`.`access_token_id`
inner join `access_tokens` as `at2` on `at2`.`session_id` = `at`.`session_id`
where `rt`.`refresh_token` = 's2kF5Ev6NXncnTPwVz99ksgsCGXfwPIDzXJMZJqz') as t)
I am trying above query in laravel 4 using query builder. But not able to find how to write this. I have written upto this:
DB::table("access_tokens as at3")
->whereIn('id', function($query) use ($authParams)
{
$query->select('at2.id')
->from('refresh_tokens as rt')
->leftJoin("access_tokens as at", "at.id", "=", "rt.session_access_token_id")
->join("access_tokens as at2", "at2.session_id", "=", "at.session_id")
->where('rt.refresh_token', '=', $authParams['refresh_token']);
})
//->delete();
->where('at3.access_token_expires', '>', time())
->update(array('at3.access_token_expires' => time()));
If you just need the query to work, you can use this syntax:
$affected_rows = DB::update( DB::raw("UPDATE users set username = 'wadus' WHERE username = :somevariable"), array('somevariable' => $someVariable));
It works and it's safe.

Categories