I have a gender table. For genders other than male and female, the default value would be 'other' but due to some errors, the database has some users with gender value = null. So instead of changing the data directly. Is there a query to get the other and null values as the same type.
id | username | gender
1 | mark | male
2 | samantha | female
3 | rupert | other
4 | collins | null
$genders = User::whereNull('deleted_at')
->select([
'gender',
DB::raw('count(*) as total')
])
->groupBy('gender')
->get();
the query above gives 4 labels ['male','female','other','null']. Is there a way to get 3 labels instead ['male','female','other'] and treat the null values the same as the other value ?
You can handle it with a DB::raw query, I think. Please try this one:
$genders = User::whereNull('deleted_at')
->select([
DB::raw('case when gender is null then \'other\' else gender end as gender'),
DB::raw('count(*) as total')
])
->groupBy(DB::raw('case when gender is null then \'other\' else gender end'))
->get();
Related
I currently have a query that sums the number of non-active users in the last year and groups them by country and city and then paginates the result:
UserData::query()
->select(
country,
city,
DB::raw('SUM(CASE WHEN end_date IS NULL THEN 0 ELSE 1 END) AS not_active'),
)
->whereBetween('created_at', [Carbon::now()->subYear(), Carbon::now()])
->groupBy('country', 'city')
->paginate('500');
But I also need to add to each group a column that shows how many active users are of the same group, of all time, not just last year:
UserData::query()
->select(
country,
city,
DB::raw('SUM(CASE WHEN end_date IS NULL THEN 1 ELSE 0 END) AS active'),
)
->groupBy('country', 'city')
->get();
Then in the frontend I want to display the data in a table so I want the data to be "merged" so that I can output the matching active and not_active columns together, so the end result should look like that:
country | city | active(all time) | not active(past year)
------------|-----------|------------------|-----------------------
Sweden | Stockholm | 25 | 1
Switzerland | Bern | 43 | 13
But how can it be done when using pagination?
I tried to do it with subqueries but that didn't work: (Note that I am using slightly different query checking whereNull for active users and whereNotNull for non-active users:
$result = UserData::select('end_date', 'country', 'city')
->where(function ($query) {
$query->select('end_date')
->whereNull('end_date')
->whereBetween('created_at', [Carbon::now()->subYear(), Carbon::now()]);
}, 'active')
->where(function ($query) {
$query->select('end_date')
->whereNotNull('end_date')
}, 'not_active')
->groupBy('country', 'city')
->paginate('500');
This can be solved by using a union()
$first = UserData::query()
->select(
'country',
'city',
DB::raw('SUM(CASE WHEN end_date IS NULL THEN 0 ELSE 1 END) AS not_active'),
)
->whereBetween('created_at', [now()->subYear(), now()]);
$second = UserData::query()
->select(
'country',
'city',
DB::raw('SUM(CASE WHEN end_date IS NULL THEN 1 ELSE 0 END) AS active'),
);
$first->union($second)
->groupBy('country', 'city')
->paginate('500');
Which will execute a SQL union query like select *cols* from *table* where *clause* union (select *cols* from *table* where *someOtherClause*)
This question already has answers here:
GROUP BY - do not group NULL
(6 answers)
Closed 1 year ago.
I want to group by the data based on content_related_group. But there's a condition where content_related_group is null, and I don't want it to group the data with null value.
I've tried like this:
$products = DB::table('product')
->select('*', DB::raw('count(*) as total'))
->orderBy('created_at', 'desc')
->groupBy('content_related_group')
->paginate(9);
It's working, but it grouping the null data into one. I don't want it, what I want is to get all data from database and only group the the data with same content_related_groupinto one.
Example data:
id | content_related_group
1 | content_1
2 | content_1
3 | null
4 | null
Result (the null data keep separated from each other & the same content_related_group is grouped:
id | content_related_group
1 | content_1
2 | null
3 | null
It is possible? Thanks
try this if you want to remove the null rows:
$products = DB::table('product')
->select('*', DB::raw('count(*) as total'))
->whereNotNull('content_related_group')
->orderBy('created_at', 'desc')
->groupBy('content_related_group')
->paginate(9);
try this if you want to keep null value grouped to one row
$x_products = DB::table('product')->whereNull('content_related_group');
$products = DB::table('product')
->whereNotNull('content_related_group')
->union($x_products)
->select('*', DB::raw('count(*) as total'))
->orderBy('created_at', 'desc')
->groupBy('content_related_group')
->paginate(9);
I have following query:
Product::where('shop_id', $shop->id)->with('orderItems')->get()
Product: id | title
OrderItem: id | product_id | sell_price | sold_quantity | sold_date
And i would like to count total income (what is sell_price * sold_quantity) and the same for last 30 days.
How to get all products for shop and calculate that data for every single one.
Thank you.
DB::table('products as p')
->join('orderItems as oi','p.id','oi.product_id')
->where('p.shop_id', $shop->id)
->whereDate('created_at', '>=', Carbon::now()->subDays(30)->toDateTimeString())
->selectRaw('p.id,p.name, sum(oi.sell_price * oi.sold_quantity) as total,
(select sum(sell_price * sold_quantity) from orderItems
where product_id = p.id) as grand_total')
->groupByRaw('p.id,p.name')
->get();
users Tabel
**id|name**
1|xx
users_meta Table
id | user_id | metaKey | metavalue
1 | 1 | city | kolkata
2 |2 |city | london
3 |8 |city |london
My moto is to return users belongs to city London.How can i achive this??
You can query using whereHas:
User::whereHas('users_meta', function ($query) {
$query->where('metavalue', 'london');
})->get();
Lets say u have a relationship with Users and user_meta
Than simply
User::with(['userMeta' => function($query){
$query->where('metaKey', 'city')
$query->where('metavalue', 'london')
}]);
Hope this helps
I'm working with Eloquent on a One-to-Many relationship.
I want to order my Users by using their last post DateTime (created_at) but I can't figure out how to make this work.
Table Users :
id | name
1 | John
2 | Doe
3 | Foo
4 | ...
Table Posts :
id | title | body | user_id | created_at
1 | Title 1| Body1 | 1 | 2014-03-06 14:00:00
2 | Title 2| Body2 | 1 | 2014-03-04 14:00:00
3 | Title 3| Body3 | 2 | 2014-03-03 14:00:00
4 | Title 4| Body4 | 3 | 2014-03-05 14:00:00
Example of final output desired :
name | title | created_at
John | Title 1 | 2014-03-06 14:00:00
Foo | Title 4 | 2014-03-05 14:00:00
Doe | Title 3 | 2014-03-03 14:00:00
The closer I could get was :
$users = User::with(['posts' => function($query){
$query->orderBy('created_at', 'desc');
}])->get();
But this code extracts all the posts for each user and I just want the last one.
Can you help me please? Thanks.
UPDATE : I finally found what I was looking for : Retrieve users' last post and sort the users in ascending order (of this last post's timestamp). Feel free to improve this query!
$users = DB::table('posts')
->join('users', 'posts.user_id', '=', 'users.id')
->select(DB::raw('posts.id, posts.user_id, MAX(created_at) as created_at'))
->groupBy('posts.user_id')
->orderBy('created_at', 'asc')
->get();
You may try this:
$users = User::with(array('posts' => function($query){
$query->orderBy('created_at', 'desc')->groupBy('user_id');
}))->get();
Update: You may try this:
$users = User::join('posts', 'users.id', '=', 'posts.user_id')
->orderBy('posts.created_at', 'desc')
->groupBy('posts.user_id')
->select('users.*', 'posts.created_at as postTime')
->get();
I've only selected created_at from posts table but you may add more fields in select like:
->select('users.*', 'posts.created_at as postTime', 'posts.updated_at as postUpTime', 'posts.id as pid', 'posts.title')
I believe you will either have to use usort() which is a little bit more complicated, or you can use joins, but with that method, you'd also lose the way Eloquent sets up the relations.
Using usort()...
private function cmp($a, $b)
{
if($a->posts->created_at == $b->posts->created_at) {
return 0;
}
return (strtotime($a->posts->created_at) < strtotime($b->posts->created_at)) ? -1 : 1;
}
$users = User::with(array('posts' => function($query){
$query->orderBy('created_at', 'desc')->groupBy('user_id')->first();
}))->get();
$users = usort($users, array($this, 'cmp'));
Or if you would prefer to use joins, I think this should work for you.
$users = DB::table('posts')
->select(DB::raw('MAX(`posts`.`created_at`) AS `created_at`, `user_id`, `users`.*'))
->orderBy('posts.created_at', 'desc')
->groupBy('posts.user_id')
->join('users', 'users.id', '=', 'posts.user_id')
->get();