I have 3 models that are as follows
Orders
|id, customer_id, created_at, updated_at|
Customers
|id, name, zip_code, gender, created_at, updated_at|
Genders
|id, name, created_at, updated_at|
I am working on some sort of statistical dashboard. What I would like to do is to basically group the customers based on their gender so that I can have an output as below
Male = 60,
Female = 65 etc.
The Gender table basically contains records for each gender whilst the gender column on the customers table contains the gender id from which the gender name can be determined.
I have set up all the necessary relationships in the Model and I am able to run the code below which produces me a list with the genders however, I am struggling to group and then count how many customers are which.
$orders = Order::with('customer.gender')
->get()
->groupBy(['gender.name']);
You could do it with a couple of joins.
Gender::query()
->selectRaw('count(*) as count', 'genders.name')
->join('customers as c', 'genders.id', 'c.gender')
->join('orders as o', 'o.customer', 'c.id')
->groupBy('genders.name')
->get();
The model you start from (in this case Gender) doesn't really matter. Just that you join the other two tables.
Alternatively, with your approach maybe this would work:
Gender::query()
->with(['customers' => fn($customer) => $customer->withCount('orders')])
->get()
->mapWithKeys(fn($gender) => [
$gender->name => $gender->customers->sum('orders_count')
]);
Try this:
$orders = Order::with('customer.gender')
->select(DB::raw('count(*) as total'))
->get()
->groupBy(['gender.name']);
Related
i has raw query in laravel like this
public function getPopularBook(){
$book = DB::select("
with totalReview as(
SELECT r.book_id , count(r.id)
FROM review r
GROUP BY r.book_id
)
SELECT *
from totalReview x
left JOIN (
SELECT b.*,
case when ((now() >= d.discount_start_date and now() <= d.discount_end_date) or (now() >= d.discount_start_date and d.discount_end_date is null)) then (b.book_price-d.discount_price)
ELSE b.book_price
end as final_price
FROM discount d
right JOIN book b
on d.book_id = b.id
) as y
on x.book_id = y.id
ORDER BY x.count DESC, y.final_price ASC
LIMIT 8"
);
return $book;
}
so when i want to return a paginate, it doesn't work so can i convert this to query build to use paginate
This is a very un-optimized raw query in itself. You are performing too many Join in Subquery just to sort by price
i'm assuming the database table:
books[ id, name, price ]
reviews[ id, book_id ]
discounts[ id, book_id, start_date, end_date, discount_price]
Look how easy it is if you just use Eloquent:
Book::withCount('reviews')->orderBy('reviews_count')->get();
this will give you all the Books order by number of reviews
now with the final price, this can be a bit tricky, let's take a look at a query when we don't consider discount time
Book::withCount('reviews')
->withSum('discounts', 'discount_price') //i'm assuming a book can have many discount at the same time, so i just sum them all
->addSelect(
DB::raw('final_price AS (books.price - discounts_sum_discount_price)')
)
->orderBy('reviews_count', 'asc') // =you can specify ascending or descending
->orderBy('final_price', 'desc') //in laravel chaining multiple orderBy to order multiple column
->get();
I dont even need to use Subquery!! But how do we actually only add the "active" discount?, just need to modify the withSum a bit:
Book::withCount('reviews')
->withSum(
[
'discounts' => function($query) {
$query->where('start_date', '<=', Carbon::now())
->where('end_date', '>=', Carbon::now())
}
],
'discount_price'
)
->addSelect(
DB::raw('final_price AS (books.price - discounts_sum_discount_price)')
)
->orderBy('reviews_count', 'asc') // =you can specify ascending or descending
->orderBy('final_price', 'desc') //in laravel chaining multiple orderBy to order multiple column
->get();
and it is done
What about pagination? just replace the get() method with paginate():
Book::withCount('reviews')
->withSum(['discounts' => function($query) {
$query->where('start_date', '<=', Carbon::now())->where('end_date', '>=', Carbon::now())
}],'discount_price')
->addSelect(DB::raw('final_price AS (books.price - discounts_sum_discount_price)')) //just format to be a bit cleaner, nothing had changed
->orderBy('reviews_count', 'asc')
->orderBy('final_price', 'desc')
->paginate(10); //10 books per page
WARNING: this is written with ELoquent ORM, not QueryBuilder, so you must define your relationship first
I have these models
I want to make a query that shows me all the products whose stock quantity> 0 and that does not repeat the products.
My query:
$stock_products_limit = Stock::distinct('product_id')->where('quantity', '!=', 0)->get();
This would be much easier using a size chart relating it to stocks ... but for now I don't have it
I need the model to return me, and then do a foreach:
#foreach($stock_products_limit as $stock_product)
#foreach($stock_product->product->product_images as $i=>$product_image)
...
#endforeach
...
#enforeach
In my models I have the hasMany and belongsTo relations made
How could I make the query? I've been trying the distinct, group by ... but nothing works for me. It only removes the ones with quantity 0 and repeats the product ID ...
Example of the query I want:
SELECT DISTINCT(stocks.product_id)
FROM stocks
INNER JOIN products ON stocks.product_id = products.id
WHERE quantity != 0
ORDER BY product_id
LIMIT 10;
Another example query (but LIMIT doesn't work with IN)
SELECT * from products where id in (SELECT DISTINCT(product_id)
FROM stocks
INNER JOIN products ON stocks.product_id = products.id
WHERE quantity != 0
ORDER BY product_id)
Instead of making the Stock model as the starting point, you might want to use the Product model. Then you don't even have to think about using DISTINCT. Let's use whereHas
return Product::whereHas('stocks', function ($query) {
$query->where('quantity', '>', 0);
})
->limit(10)
->get();
My working SQL query is as follows:
SELECT post_id
FROM news_tags
ORDER BY (link_clicks+views) DESC
What I've tried so far in eloquent is like this:
$newsTagSaved = NewsTag::
orderBy(DB::raw("`views` + `link_clicks`"), 'desc')
->paginate(12)
->pluck('post_id');
Newstag table has many columns and views and link_clicks are two of them. Now, I'm trying to retrieve the post_id order by desc of sum of views and link_click.
How can I do it in Laravel eloquent?
Thank you!
Do something like this:
$newsTagSaved = NewsTag::select(DB::raw('views + link_clicks as score'))
->orderBy('score', 'desc')
->get();
dd($newsTagSaved);
This will return just score value. If you want to return other fields, simply add them to select. As an example:
$newsTagSaved = NewsTag::select(
DB::raw('views + link_clicks as score'),
'title',
'created_at'
)
->orderBy('score', 'desc')
->get();
dd($newsTagSaved);
I have two tables contact_us and upload_new_car.
contact_us table contains columns:
id
name
email
phone
message
created_at
updated_at
upload_new_car contains columns:
id
name
phone_number
car_name
car_price
location
car_model_year
car_model
variant
driven
fuel
transmission
city
no_of_owners
upload_1
upload_2
upload_3
upload_4
upload_5
created_at
updated_at
How can I get the UNION of these tables in Laravel? Please help
Not allowing to different size of columns is not laravel's businuess. It is a matter of SQL .You can follow [this link] for more info about UNION statements .
On the other hand for laravel you can use those syntax using union (We can benefit from selecting the same count of columns from each tables).
$first = DB::table('contact_us')
->select('name','phone');
$users = DB::table('users')
->select('name','phone_number as phone')
->union($first)
->get();
dd($users)
I have a user with countries relationship. (hasMany)
user_id 1
country_id 1
user_id 1
country_id 2
...
What I want is to get those users who have both countries (country 1 and country 2) How can I do this? I'm reading http://laravel.com/docs/eloquent#querying-relations but I'm not very sure what to do.
edit: almost the solution
$users = \User::whereHas('countries', function($query) {
$countries_ids = [1, 2, 4];
$query->whereIn('users_countries.country_id', $countries);
})->get();
This will work as long as there are no duplicates in the pivot table (unique index for pair of fk keys for example):
$countries = [1,5,9];
User::whereHas('countries', function ($q) use ($countries) {
$q->whereIn('users_countries.country_id', $countries);
}, '=', count($countries) )->get();
In case there are duplicates, like:
user_id | country_id
1 | 1
1 | 2
1 | 1
Then you would need raw count(distinct ...) so you couldn't use whereHas, so I suggest this, which will be much faster:
$countries = [1,5,9];
User::join('users_countries as uc','uc.user_id', '=', 'users.id')
->whereIn('uc.country_id', $countries)
->having(DB::raw('count(distinct uc.country_id)'), '=', count($countries))
->groupBy('users.id')
->get(['users.*']);
You can do it the other way. Make the query on the country model. Add a function in the country model
public function user(){
return $this->belongsTo('user');//or if there is no user_id column in the countries table, use the ('model','local_key','foreign_key') pattern.
}
Then create an array with the country_ids, and que the country model.
$country_ids=array(4,67);
$countries=Country::where('id',$country_ids[0])->where('id',$country_ids[1])->get();
In order to get the users you should loop through like this
foreach($countries->user as $user)