Laravel - Eloquent select with count some related data - laravel

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();

Related

How to get the product name with the highest value by month?

I'm trying to display a data by month and displays the product with the highest value or bought quantity. But I don't know how I should do it.
This is the code I have and tried so far
public function viewSales(){
$data = sales::select(
[sales::raw("SUM(product_fee) as product_fee, MONTHNAME(created_at) as month_name, MAX(bought) as bought"),'product']
)->whereYear('created_at', date("Y"))
->orderBy('created_at', 'asc')
->groupBy('month_name')
->get();
return view('admin.viewSales', compact('data'));
}
This is what's inside my database
id
product
bought
product_fee
created_at
1
Dictionary
1
200
2023-01-14 18:55:34
2
Horror
3
100
2023-01-15 17:55:34
3
How to cook
5
300
2023-01-16 11:55:34
and this is what I'm trying to display
Most bought product
sold
overall earning
How to cook
5
600
i think you can try this :
public function viewSales(){
$data = sales::select(
[sales::raw("(bought*product_fee) as overall_earning, MONTHNAME(created_at) as month_name, MAX(bought) as bought"),'product']
)->whereYear('created_at', date("Y"))
->orderBy('created_at', 'asc')
->groupBy('month_name')
->get();
return view('admin.viewSales', compact('data'));
}
I hope this works for you
Below SQL will give you the desired output for current year and month.
Fetch for current year
SELECT
product as most_bought_product_for_the_year,
bought as sold,
(SELECT SUM(product_fee) from products WHERE YEAR(created_at) = year(curdate())) as overall_earning
FROM `products`
WHERE
bought = (SELECT MAX(bought) from products WHERE YEAR(created_at) = year(curdate()));
Fetch for months of the current year
SELECT
product as most_bought_for_the_month,
bought as sold,
MONTHNAME(created_at) as month_name,
SUM(product_fee) as overall_earning
FROM `products`
WHERE
YEAR(created_at) = YEAR(curdate())
AND
bought IN (SELECT MAX(bought) from products WHERE YEAR(created_at) = YEAR(curdate()) GROUP by MONTH(created_at))
GROUP BY MONTH(created_at)
ORDER BY MONTH(created_at);
SQL Fiddle

Laravel leftJoin only last record of right table and order by it

I have two tables. 1) products 2) prices
-------------------------
- products -
-------------------------
- id | int -
- name | varchar -
- created_at | datetime -
- updated_at | datetime -
-------------------------
----------------------------
- prices -
----------------------------
- id | int -
- product_id | int -
- sale_price | int -
- regular_price | int -
- created_at | datetime -
- updated_at | datetime -
-----------------------------
I want to search through products and get the last price of each product from prices table. I use this :
class Product extends Model
{
public function lastPrice()
{
return $this->hasOne(Price::class)->orderBy('id', 'DESC');
}
}
And I get products list with the last price using :
$products=Product::with('lastPrice')->paginate(9);
My question is: I want to order the result by highest/lower price. How I will do that?
You can select latest row from prices table along with product data there are 2 ways which I can think of right now as
// Approach 1
Product::join('prices as a', 'products.id', '=', 'a.product_id')
->leftJoin('prices as a1', function ($join) {
$join->on('a.product_id', '=', 'a1.product_id')
->whereRaw(DB::raw('a.id < a1.id'));
})
->whereNull('a1.product_id')
->select('products.*', 'a.*')
->orderBy('sale_price','desc')
->orderBy('regular_price','desc')
->get();
// Approach 2 with whereExists
Product::join('prices as a', 'products.id', '=', 'a.product_id')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('prices as b')
->whereRaw(DB::raw('a.product_id = b.product_id'))
->havingRaw('max(b.id) = a.id');
})
->select('products.*', 'a.*')
->orderBy('sale_price','desc')
->orderBy('regular_price','desc')
->get();
I believe using laravel 6 or above you can use correlated sub queries in addSelect() clause as
Product::addSelect(['latest_price' =>
Price::select('price')
->whereColumn('product_id', 'products.id')
->orderBy('id', 'desc')
->limit(1)
])->orderBy('latest_price','desc')
->paginate(9);
So from above we will get products data along with latest price column from database so you can apply sorting on latest_price
Edit If you have limited columns to select like sale_price you can add another sub query but if you want to select whole row from price table then see another approach using join/exists
Product::addSelect(['sale_price' =>
Price::select('sale_price')
->whereColumn('product_id', 'products.id')
->orderBy('id', 'desc')
->limit(1),
'regular_price' =>
Price::select('regular_price')
->whereColumn('product_id', 'products.id')
->orderBy('id', 'desc')
->limit(1),
])->orderBy('sale_price','desc')
->orderBy('regular_price','desc')
->get();

Laravel Sum transactions amount grouped by category

I'm trying to sum all transactions and group these records by category with the summed value of transactions for a particular month.
Example (Current month):
Groceries => 500
Subscriptions => 100
Coffee => 0
But the current code I have only groups categories when a transaction has occurred for that month and will return the following:
Groceries => 500
Subscriptions => 100
Here are my the following database tables:
Transactions table:
id
date
category_id
amount
1
2021-01-01
1
200
2
2021-01-01
1
300
3
2021-01-01
2
100
3
2020-06-06
3
100
Categories table:
id
display_name
description
1
Groceries
Food
2
Subscriptions
Subscriptions
3
Coffee
Coffee
And my code that selects transactions for the current month but doesn't return a full list of categories even if there are no transactions.
$currentMonth = date('m');
$grouped = DB::table('categories')
->join('transactions', function ($join) use ($currentMonth) {
$join->on('transactions.category_id', '=', 'categories.id')
->whereRaw('MONTH(date) = ?',[$currentMonth]);
})
->groupBy('categories.display_name')
->selectRaw('sum(transactions.amount) as sum, display_name as name')
->pluck('sum', 'name');
Move the criteria in the WHERE clause to the ON clause of the join, and use a left join:
$grouped = DB::table('categories c')
->leftJoin('transactions t', function ($join) {
$join->on('t.category_id', '=', 'c.id')
$join->on(DB::raw('MONTH(t.date) = ?'))
})
->groupBy('c.display_name')
->selectRaw('SUM(t.amount) AS sum, c.display_name AS name')
->setBindings([$currentMonth])
->pluck('sum', 'name');
The raw MySQL query I am suggesting here is:
SELECT
c.display_name,
SUM(t.amount) AS sum
FROM categories c
LEFT JOIN transactions t
ON c.id = t.category_id AND
MONTH(t.date) = ?
GROUP BY
c.display_name;
The structure used above in the left join is critical here, because it ensures that every category on the left side of the join would appear in the result set, even if it have no matching transactions for a given month.

Laravel ordering and limit results of a left join

One to many relationships, each product has many prices
table products
id | name | slug | created_at | update_at
table prices
id | product_id | title | price | link
I want to get the data limit of product limit 20 table and order created_at and each product get the lowest price, order column price. I want to use the query builder.
i tried
$products = DB::table('products')
->leftJoin('prices', 'products.id', '=', 'prices.product_id')
->select('products.id', 'products.name')->distinct()
->selectRaw('max(prices.price) as price')
->groupby('products.id')
->orderby('products.updated_at')
->get();
but it get all products and table prices order column id
You can use Eloquent Like This
public function price() {
return $this->hasMany('App\model\Prices' , 'product_id' ,'id');
}
and get like this , It will give you the mapped price only for your specific product
$product = Product::with('price')
->where(do the stuffs)
->orderBy(do the stuffs)
->get();
Or you can use the callback as well in with()

Laravel: Sorting a column in the Left Join

Lets say I have a simple table of users
id | userName
3 Michael
4 Mike
5 George
And another table of their cars and prices
id | belongsToUser | carPrice
1 4 5000
2 4 6000
3 4 8000
I would like to do a left join that would return the highest or lowest carPrice
At the moment, the query would return the last/first instance of that users carPrice.
I've tried entering the orderBy in various join queries but to no avail.
I have a helper function that would return the highest/lowest price on demand but I'm not sure how that would fit within this query as I would like to use laravels inbuilt paginate
This is the aggregate problem so here is the solvation:
DB::table('users')
->leftJoin('carPrices', 'belongsToUser', '=', 'users.id')
->select('users.*', DB::raw('MAX(carPrice) as highestCarPrice'), DB::raw('MIN(carPrice) as lowestCarPrice'))
->groupBy('users.id')
->get();

Resources