In my products table, I have 2 columns: price and discounted_price in which discounted_price is null most of the time unless there is a promotion for that product:
+----+--------------------+-------+------------------+
| id | name | price | discounted_price |
+----+--------------------+-------+------------------+
| 1 | test 1 | 79.00 | null |
| 2 | test 2 | 50.00 | 45.00 |
+----+--------------------+-------+------------------+
The product with id of 2 is now on promotion and has discounted_price.
Now I want to query products to get products cheaper than 50 but in my query I need to check if discounted_price is null then look into price, otherwise look into discounted_price. What Google said is using:
$products = Product::where('coalesce(price, discounted_price) <= 50);
But it's not working :(
Alternative, you can use sub query, like this :
$q = 50;
$product = Product::where(function($query) use($q) {
$query->where('discounted_price', '<=', $q)
->orWhere('price', '<=', $q)
})
->get();
you can use whereRaw
instead of where or where(DB::raw('coalesce(price, discounted_price') <= 50))
also be carful to close your where by ' character
i recommend using where with clouser like this:
$products = Product::where(function ($query)
{
$query->where('discounted_price',null)->where('price','<=',50);
})->orWhere('discounted_price','<=',50)->get();
Related
I am trying to building ecoommerce system using laravel 9. Everything goes fine but Suddenly I got one issue. I want to show product based on category id but my product table category id store multiple. Bellow I am showing my table structure:
Product Table:
|---ID---|---Name---|---Cat_id---|---Status--|
| 1 | T-shirts | 1,2, | active |
| 2 | Pants | 4,3, | active |
| 3 | Sweaters | 5,2, | active |
Category Table
|---ID---|---Name---|
| 1 | General |
| 2 | News |
| 3 | Festival |
| 4 | Category |
Controller
public function category($slug)
{
//
$cat = Category::where('slug', $slug)->first();
$products = Product::whereIn('cat_id', [$cat->id])->where('status', 'active')->orderby('id', 'asc')->paginate('12');
return view('frontend/Catproducts', compact('products', 'cat'));
}
Now I want when I am click on "NEWS" category I want to see two product. How can I fix it
As #aynber said in the comments, best solution is to normalize the database, so you have a setup like this:
Categories table:
id
name
Products table:
id
name
status
Product_categories table:
id
product_id
category_id
With a belongsToMany relationship from Product to Category(and back), your query should look something like:
$categoryIdArray = [2];
Product
::whereHas('category', function($query) use($categoryIdArray) {
$query->whereIn('id', $categoryIdArray);
})
->get();
It is still possible with your current setup though, while a little hacky:
$cat = Category
::where('slug', $slug)
->first();
$catId = $cat->id;
$products = Product
::where(function($where) {
$where->where('cat_id', 'like', "$catId,%")//Look for first cat in col, don't forget trailing comma
->orWhere('cat_id', 'like', "%,$catId,%")//Look for appended cat between commas
})
->where('status', 'active')
->orderby('id', 'asc')
->paginate('12');
This will work on small scale, but because we are using like, mysql needs to check ALL records, and cannot optimize the query. That's the reason why normalization is important :)
I have two three tables:
// invoices
+----+----------------+
| id | invoice_code |
+----+----------------+
| 1 | d09823r230r4 |
| 2 | 34tf354f45tf |
+----+----------------+
// commodities
+----+-------------+------------+--------+
| id | invoice_id | product_id | number |
+----+-------------+------------+--------+
| 1 | 1 | 1 | 2 |
| 2 | 1 | 3 | 4 |
+----+-------------+------------+--------+
-- number columns is the number of each ordered product in the invoice
// products
// invoices
+----+-----------+---------+
| id | name | price |
+----+-----------+---------+
| 1 | SFX-300 | 15000 |
| 2 | GB32-b10 | 2000 |
| 3 | SVX-m30 | 1200 |
+----+-----------+---------+
All I need to do is calculating the total price of an invoice. Here is the formula to calculate the total price for invoice x:
$total_invoice_price = 0;
foreach( $invoice_x->commodities as $commodity){
$total_invoice_price += ( $commodity.number * <products.price> )
}
echo $total_invoice_price;
The problem is about getting <products.price>. It needs one more join to products table. Any idea how can I do that using Laravel relationships ?
If you just need the total price, this could be done in pure sql with aggregate statements and joins over the three tables.
SELECT invoice.invoice_code, SUM(product.price * commodities.number)
FROM invoice
JOIN commodities ON invoice.id = commodities.invoice_id
JOIN product ON product.id = commodities.product_id
GROUP BY invoice.id
To save the query, you should do eager loading using "with()" the model you wish to join.
I'm not sure how you named your model and how well it linked to each other.
Let's assume that it've been done in the conventional way.
Here is the script.
$total_invoice_price = $invoice_x->commodities
->with('products')
->get()
->map(function ($commodity) {
return $commodity->number * $commodity->product->price;
})
->sum();
What I've done is after getting the products joined with each commodity. I do the get() to have the commodities collection. The from the collection, we do map on each commodity and return the number and price of product. Then we multiply and return as the sum of each commodity record. After that we sum all the totals to the grand total and get your result.
I wrote the code without testing, so try to adjust it to your code.
Please check below Query
$invoices_total = DB::table('invoices')
->join('products', 'invoices.id', '=', 'commodities.invoice_id')
->join('commodities', 'products.id', '=', 'commodities.product_id')
->sum('products.price * commodities.number')
->groupBy('invoices.id')
->get();
How to update data with calculating by it's column
I have table item
+---------+-------+-------+-----------+
| item_id | stock | price | name |
+---------+-------+-------+-----------+
| 1 | 10 | 9.4 | Paper |
+---------+-------+-------+-----------+
| 2 | 10 | 12.8 | Pencil |
+---------+-------+-------+-----------+
| 3 | 10 | 99.9 | Note Book |
+---------+-------+-------+-----------+
and then I wanna update the sock by calculating stock column
stock - $request->qty
If I do manualy base query
update items set stock = stock - 3 where item_id = 1
it's working, but when I use laravel eloquent the stock become 0 (zero), I dunno why,
here is my controller
public function saveOrder(Request $request) {
$item = new Item;
$item->where('item_id', '=', $request->item_id)->update(['stock' => 'stock - '. $request->qty]);
return redirect('order');
}
any solution? Thanks for answer, sorry for bad english :)
Try this one:
$item = new Item;
$item->where('item_id', '=', $request->item_id)->decrement('stock', $request->qty);
You could try something like this:
$item = Item::where('item_id', '=', $request->item_id)->first();
$item->stock = (int)$item->stock - (int)$request->qty;
$item->save();
Alternatively you could try to use DB::raw expression.
This should do the trick for you
public function saveOrder(Request $request) {
Item::where('item_id', $request->item_id)
->decrement('stock', $request->qty);
return redirect('order');
}
public function saveOrder(Request $request){
$stockdetails = \DB::table('tablename')->where('itemid',$request->itemid)->first(['stock as stock']);
//update query
$update= \DB::table('tablename')->update(['stock'=>($stockdetails->stock)-($request->quantity)])->where(itemid',$request->itemid);
if($update){
//sucecss
}else{
//Fail
}
I want to get all the purchases and their sums and also I don't want to add the amount if payments.deleted_at is not null.
Here are the tables
purchases
id | name
1 | Gamerzone Book
2 | Recipe Book
3 | EngineX Book
payments
id | purchase_id | amount | deleted_at
1 1 100 2015-06-12 11:00:00
2 2 50 NULL
2 2 10 NULL
Code
$query = DB::table('purchases')
->select(['purchases.*',
DB::raw("IFNULL(sum(payments.amount),0) as total")
])
->leftJoin('payments','payments.purchase_id','=','purchases.id')
->whereNull('payments.deleted_at')
->groupBy('purchases.id')->get();
When I run the code below the 1st result is not included.
Result
id | name | total
2 | Recipe Book 60
3 | EngineX Book 0
I know why It is not included but the problem is if I remove whereNull('payments.deleted_at') that particular row in payments
will also add to the sum.How should I solve this ??
Expected Result
id | name | total
1 | Gamerzone Book 0
2 | Recipe Book 60
3 | EngineX Book 0
In this case your join condition should looks like this:
ON (payments.booking_id = purchases.id AND payments.deleted_at IS NOT NULL)
And it is not about WHERE (according to your SELECT).
You should use join-closure like this:
$query = DB::table('purchases')
->select(['purchases.*', DB::raw("IFNULL(sum(payments.amount),0) as total")])
->leftJoin('payments', function($join) {
$join->on('payments.booking_id', '=', 'purchases.id');
$join->on('payments.deleted_at', 'IS', DB::raw('NOT NULL'));
})
->groupBy('purchases.id')->get();
Just replace
->leftJoin('payments','payments.booking_id','=','purchases.id')
with
->leftJoin('payments', function($join) {
$join->on('payments.booking_id', '=', 'purchases.id');
$join->on('payments.deleted_at', 'IS', DB::raw('NOT NULL'));
})
and remove this:
->whereNull('payments.deleted_at')
it should help.
I have a table entries similar as follows:
+---------+---------+----------+
| Test_id | User_id | Attempts |
+---------+---------+----------+
| 12 | 5 | 1 |
| 13 | 5 | 1 |
| 12 | 5 | 2 |
+---------+---------+----------+
Now I want to select the elements group by test_id and should get the latest entry.
I tried this query:
$tests_took = Testresult::where('course_id', $courseId)
->where('user_id', Auth::id())
->groupby('test_id')
->orderBy('attempts', 'desc')
->get();
When I display the result, I'm getting the first two rows only (only one row for one test_id - which I what I want.) But instead of the last row for the test_id=12, it shows the first row. I always want the biggest attempt to be displayed.
My current output is like:
| 12 | 5 | 1 |
| 13 | 5 | 1 |
But I want this:
| 12 | 5 | 2 |
| 13 | 5 | 1 |
How can I achieve this? to get the latest row as the first array element when I use groupby or is there any other way to do this?
ORDER BY and GROUP BY don't work very well together...
If you simply want the highest attempt per test_id i suggest using the MAX() function:
$tests_took = Testresult::select('test_id', 'user_id', DB::raw('MAX(attempts) AS max_attempts'))
->where('course_id', $courseId)
->where('user_id', Auth::id())
->groupby('test_id')
->get();
You may use the following lines:
Testresult::select('*')
->join(DB::raw('(Select max(id) as last_id from Testresult group by test_id) LatestId'), function($join) {
$join->on('Testresult.id', '=', 'LatestId.last_id');
})
->orderBy('attempts', 'desc');
}