I'm trying to retrieve a subset of data based on the sum of a column. The goal is a script to release backordered items. Say we have 100 BO products and get 50 in stock. I'd like to update the oldest orders where the sum of order qty < 50. So something like:
Sample Schema:
Orders Table:
order_id, order_date
order_products Table:
order_product_id, order_id, product_id, product_status, ordered_quantity
select * from products
where products_id=1234
and status=1
and sum(products_qty) < 50;
Where sum(products_qty) is the total returned qty, not just for the individual row. Not sure if this is possible with a single query or even a subquery, but thought I would ask the experts here first. I'm trying to avoid returning all the rows and then manually count up till I reach the limit.
You need use GROUP by and Having
select * from products
where products_id=1234
and status=1
group by YourGroupingFields
Having sum(products_qty) < 50;
based on your info:
select product_id from products
where status=1
group by product_id
Having sum(products_qty) < 50;
will be return product_id for which total quantity less 50
When you're using aggregate functions like SUM() and COUNT(), you can't use them in WHERE clauses. WHERE clauses are applied row-by-row as the database scans the table/indexes, which means that the results of the aggregate functions aren't available yet.
Filtering by aggregate results has to be done using HAVING, which is essentially done as the last step before returning data to the client.
From the sounds of your requirement, you need a running count to be kept, until you've retrieved enough rows/orders to use up the new product being entered. This can't be done with a single query. You'd need to use a server-side variable to keep track of how much product's been "used up" by the individual backorders.
Going off the top of my head, something like this might do the trick:
SET #Available = 50;
SELECT order_id, SUM(ordered_quantity), #Available := #Available - SUM(ordered_quantity) AS available
FROM order_products
WHERE product_id = XXX
GROUP BY order_id, product_id
HAVING available >= 0;
with whatever extra WHERE clauses so you get the oldest backorders first
Related
I'm working on a panel to show all orders from our e-commerce site and the way I have the orders set up is to have a row for each order referring to the customer id.
I'm working on showing all open orders on our back-end however the rows are showing multiple rows for the same order if (so if the orderID is 18, and the order has 2 items ordered there a 2 rows all the with the orderID of 18).
I'll include some screenshots below so you have an idea of what's happening.
This is my sql statement to show all open orders:
function GetAllOpenOrders (){
global $conn;
$sql = "SELECT * FROM customer_orders LEFT JOIN ordered_products ON ordered_products.custOrderID=customer_orders.custOrderID WHERE customer_orders.orderOpen=1";
return $result = $conn->query($sql);
}
So again, I want to combine the orders with multiple products and display the total price in the open orders screen.
You need an aggregate query to display the total. Something like:
SELECT sum(prod.totalPrice) as TotalPrice
FROM customer_orders
LEFT JOIN ordered_products ON ordered_products.custOrderID=customer_orders.custOrderID
WHERE customer_orders.orderOpen=1
group by customer_orders.custOrderID
I don't have your database to test that query but that should point you in the right direction.
You need a sub-query where you SUM the order totals and then aggregate. You also can't add the "product ID" to your query otherwise it will by definition break it down into rows for each product ordered.
For example
select
customer_order_id,
sum(product_total_price) as order_total
from
(select
customer_order_id,
product_id,
product_total_price
from table
group by 1,2,3)
group by 1
If you're looking to show the names of the products ordered in your 1 row, I suggest using a CONCAT function for the product names (so it's all in one field) and then you'll have the total in 1 row.
I have two tables one for incoming goods and inventory and another for the exit of products.
How do I do a select in mysql to return the amount available in stock without using PHP.
In the case would STOCK - OUTPUTS.
Thanks!
I think you want something like this:
SELECT
(SELECT SUM(quantity) FROM stock) -
(SELECT SUM(quantity) FROM outputs) AS 'slo'
I have a series of items displayed on my homepage, which I want to order by popularity. I have a column called sales, which is a counter for how many sales the product has.
How can I use this and/or other columns to determine what items to display on the homepage? I obviously can't just use sales to search for popular items, because the items with the most sales will dominate the homepage - I want a balanced query.
If possible the query should also only occur within a certain timeframe, for example the past week etc.
Here's my query:
$popular_items = DB::fetch("SELECT * FROM `products` ORDER BY `sales` DESC LIMIT 10");
You have to define "popularity" first: by views, by sales, or by number of counts in shopping carts?
Assuming you have 2 factors: pageview and sales. You can order by these factors with a ratio, with respect to certain "fresh period":
SELECT * FROM `products`
WHERE DATEDIFF(last_update_date, CURDATE()) < 30
ORDER BY (pageview * 0.7 + sales * 0.3) DESC
Something like that (as I don't know the column names in your table)
If you want to have balanced results, you can use:
SELECT * FROM `products` ORDER BY RAND() DESC
which will return random results. You probably need LIMIT too (pointless to list out all products).
Side note:
it is suggested to select useful columns only (avoid using SELECT *)
If you have your sales have same value in some case then you can use
SELECT * FROM `products` ORDER BY sales DESC,rand() LIMIT 3
which will return random results with sales Descending order. I was not sure what is your data you have I just tested at my end its word.
i have 2 tables:
1st table is called maxlift with 1 column called, exercise
2nd table is called workout with 5 columns called, exercise, sets, reps, weight, date
i want display the highest weight for each exercise where exercise in both tables is the same.
i am using:
`SELECT *
FROM workout, maxlift
WHERE workout.exercise = maxlift.exercise
GROUP BY maxlift.exercise
ORDER BY workout.weight desc`
the problem i have is the weight displayed is not the highest weight from table workout.
thanks for any help.
You can use the aggregate function max() for this.
SELECT workout.exercise, max(weight) as weight
FROM workout, maxlift
WHERE workout.exercise=maxlift.exercise
GROUP BY workout.exercise;
Now, you basically group by exercise and find the maximum weight for each such group using the max() function. You can alias your selected column using column_name as alias.
`SELECT *
FROM workout, maxlift
WHERE workout.exercise = maxlift.exercise
ORDER BY workout.weight desc`
use this by removing group by and let me know about it
I have a SQL database of products from different suppliers, so the same product could appear multiple times with different prices.
Is it possible to select all of the products that have more than 4 prices, so bascially all of the rows which have more than 4 rows with the same ID?
You could add COUNT(*) AS number_of_products to SELECT, GROUP BY product_id, then use HAVING number_of_products > 4.
Note that HAVING is applied on the results (it basically goes through all the results, one by one, and applies the conditions), so it will be slower than WHERE. If you have hundreds of thousands of rows and you need performance, consider pre-counting the products, storing the indexed count value somewhere, then using a simple WHERE instead.
Yes, GROUP on the identificator for your item, and specify the number of prices to count in a HAVING clause, something like this :
SELECT ItemID, COUNT(Price) FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4
You can then use this to later filter and get more information:
SELECT Item.*, Category.Name, Filter.NumPrices from itemTBL AS Item
INNER JOIN categoryTBL as Category ON Item.CategoryID = Category.CategoryID
INNER JOIN (SELECT ItemID, COUNT(Price) AS NumPrices FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4) AS Filter on Item.ItemID = Filter.ItemID
This is the perfect thing for a group by:
SELECT ProductID, COUNT(*) AS PriceCount
FROM Product GROUP BY
Product,Price HAVING COUNT(Product) > 4