My database looks like this after I do my query:
What I would like to get is the orderID with the most amount of quantities.
This is why I did to get the result from the picture:
SELECT orderid, quantity
From "Order"
JOIN orderitem
ON "Order".id = orderitem.orderid
JOIN product
ON orderitem.productid = product.id
I don't quite get how to add the values correctly to get the maximum. Happy for every help :)
You can use aggregated function sum and limit, following query will give only one orderId with most amount of quantities.
SELECT orderid, sum(quantity) as quantity
From "Order"
JOIN orderitem
ON "Order".id = orderitem.orderid
JOIN product
ON orderitem.productid = product.id
group by
orderid
order by
quantity desc
limit 1
Related
I have two tables, let's say OrderPlaced and OrderDelivered.
The OrderPlaced table looks like this:
In a single order we can have multiple products(which is defined by sku in the table) and each product can have multiple quantity.
The OrderDelivered table looks like this:
So technically 3 products have not been delivered. Orderid 1000 - product S101, Orderid 1001 - product S102(as 3 quantity required, but 2 delivered) and Orderid 1002 - product S100.
I am trying to write a SQL query that can give me the OrderId and sku those have not been delivered. For now I have written something like
select OrderPlaced.orderid,OrderPlaced.sku
from OrderPlaced
left join OrderDelivered
on OrderPlaced.Orderid = OrderDelivered.orderid and OrderPlaced.sku = OrderDelivered.sku
where OrderDelivered.sku is NULL;
This is giving me Orderid 1000 - product S101 and Orderid 1002 - product S100, but Orderid 1001 - product S102 is missing. I understand I have to do a check on qty as well, but couldn't think how to do that. I would really appreciate it if someone can help me with that part.
Add up the deliveries per order and sku and then outer join the delivered quantities to the order table so you can compare the quantities.
select
p.orderid,
p.sku,
p.qty as ordered,
coalesce(d.sum_qty, 0) as delivered
from orderplaced p
left join
(
select orderid, sku, sum(qty) as sum_qty
from orderdelivered
group by orderid, sku
) d on d.orderid = p.orderid and d.sku = p.sku
where p.qty > coalesce(d.sum_qty, 0)
order by p.orderid, p.sku;
Your query works for any items that have not been delivered at all, this is your WHERE OrderDelivered.sku IS NULL. But you can also have a scenario in which fewer items are delivered than ordered, and importantly, you can have multiple records related to your deliveries even if they refer to the same order and sku (two rows with 1 qty each).
In this case you will need to sum up all the deliveries per placed order id, sku and quantity (GROUP BY clause in the query below) check if that sum (or 0 if nothing is found) differs from the placed order (HAVING clause). You could use such a query:
SELECT OrderPlaced.orderid, OrderPlaced.sku,
OrderPlaced.qty - COALESCE(SUM(OrderDelivered.qty), 0) AS qty_missing,
CASE
WHEN SUM(OrderDelivered.qty) IS NULL
THEN 'Yes'
ELSE 'No'
END AS is_missing_completely
FROM OrderPlaced
LEFT
JOIN OrderDelivered
ON OrderPlaced.Orderid = OrderDelivered.orderid
AND OrderPlaced.sku = OrderDelivered.sku
GROUP BY OrderPlaced.orderid, OrderPlaced.sku, OrderPlaced.qty
HAVING OrderPlaced.qty != COALESCE(SUM(OrderDelivered.qty), 0)
Here's a live demo on dbfiddle
I would create two aggregated representations of your ordered and delivered products, and then outer join them to get the differences. If you are using MySql 8 you can represent these as a CTE, otherwise just use two equivalent sub-queries
with op as (
select OrderId, Sku, Sum(qty) Qty
from OrderPlaced
group by OrderId, Sku
), od as (
select OrderId, Sku, Sum(qty) Qty
from OrderDelivered
group by OrderId, Sku
)
select op.OrderId, op.Sku, op.Qty - Coalesce(od.qty,0) notDelivered
from op
left join od on od.orderid = op.orderid and od.sku = op.sku
where op.Qty - Coalesce(od.qty,0)>0;
Example DB<>Fiddle
So I have the following 3 tables:
Table: Products
Columns: id, name, description, price, currency
Table: Orders
Columns: id, firstName, lastName, phoneNumber
Table: Order_Products
Columns: orderId, productId, quantity
Now I'm trying to figure out where to put the total price of the order and I have 2 ideas:
Add a totalPrice column to the Orders table that will contain the sum of the price * quantity of all products in the order, or:
Add a price column to the Order_Products table that will contain the the price * quantity of that specific product, and then I'd have to get all Order_Products records for that order and sum their price columns.
I'm not quite sure which option is better, hence why I'm asking for recommendations here.
I would recommend that you store the order total in the orders table.
Why? Basically, order totals are not necessarily the same as the sum of all the prices on the items:
The prices might change over time.
The order itself might have discounts.
In addition, the order might have additional charges:
Discounts applied to the entire order.
Taxes.
Delivery charges.
For these reasons, I think it is safer to store financial information on the order when the order is placed.
I woulnd't recommend storing this. This is derived information, that can be computed on the fly whenever needed. If you are going to do the computation often, you can use a view:
create view orders_view as
select o.*, sum(p.price * op.quantity) total_price
from orders o
inner join order_products op on op.orderid = o.id
inner join products p on p.id = op.productid
group by o.id
I have two tables; One contains for products stats and another one contains additional stats
StatsHourly:
id
product_id (can be multiple)
amount
cost
time
StatsValues:
id
product_id (can be multiple)
value (double)
I need to join those two tables and get something like this in the result:
product_id
sum (amount)
sum (cost)
sum (value)
I'm trying to do this:
"SELECT
SUM(s.amount) as amount,
SUM(s.cost) as cost
FROM StatsHourly s
LEFT JOIN (
SELECT
COALESCE(SUM(value), 0) as value
FROM StatsValues
GROUP BY product_id
) value v ON v.product_id = s.product_id
WHERE 1
AND s.product_id = :product_id";
This doesn't work. Could someone show me the right way to do it?
You have an extra comma after as cost:
SUM(s.cost) as cost, <-- here
You also use 2 aliases for the subquery, you should remove value from there:
) value v
You do not use any output from the subquery.
Coalesce() is unnecessary in the subquery.
This works (tested):
SELECT
s.product_id as product_id,
s.amount_s as amount,
s.cost_s as cost,
v.value_v as value
FROM
(SELECT
product_id,
SUM(amount) as amount_s,
SUM(cost) as cost_s
FROM StatsHourly
GROUP BY product_id) as s
LEFT JOIN
(SELECT
product_id,
SUM(value) as value_v
FROM StatsValues
GROUP BY product_id) as v
ON v.product_id = s.product_id;
WHERE s.product_id = 'product_id';
The point is:
As you have multiple equal product_id in BOTH table you have to make two aggregated tables through subqueries that makes the product_id unique and sum all appropriate rows.
After that you can join and you select the already aggregated values.
Regards
Order Table
Id
OrderDate
Total
Item Table
Id
Price
Quantity
OrderId (fkey -> order.Id)
Order has many Items.
In mysql SQL, is there a way to update order.total, so that it's the total sum of the product item.price and item.quantity for each item?
That is-
orders.each:
order.items.each:
sum += item.price * item.quantity;
order.total = sum;
I could write a simple script for this, but I'd like to learn how to do this in SQL.
Yes. You can do this with an update/join. You need to aggregate the items to get the total and then join the result back to orders to do the update:
update orders o join
(select i.orderid, sum(i.price * i.quantity) as total
from items i
group by i.orderid
) oi
on o.orderid = oi.orderid
set o.total = oi.total;
I want to get all order id numbers for selected customer which not paid till now, my data show as following:
What I want is Write a SELECT statement that answers this question:
select orderID
from order
where customer id = #custID
and Total cashmovementValue
for current order id
is less than total (sold quantity * salePrice )
for current order id
How to do it?
Thanks.
You need to compare the sum of each order line with the sum of each payment per order. GROUP BY and a few sub-queries is what you need to get the job done.
Something like this should work:
SELECT
O.OrderID
FROM [Order] O
INNER JOIN (
-- Add up cost per order
SELECT
OrderID,
SUM(SoldQuantity * P.SalePrice) AS Total
FROM OrderLine
INNER JOIN Product P ON P.ProductID = OrderLine.ProductID
GROUP BY OrderID
) OL ON OL.OrderID = O.OrderID
LEFT JOIN (
-- Add up total amount paid per order
SELECT
OrderID,
SUM(CashMovementValue) AS Total
FROM CashMovement
GROUP BY OrderID
) C ON C.OrderID = O.OrderID
WHERE
O.CustomerID = #custID
AND ( C.OrderID IS NULL OR C.Total < OL.Total )
EDIT
I've just noticed you're not storing the sale price on each order line. I've updated my answer accordingly, but this is a very bad idea. What will happen to your old orders if the price of an item changes? It is okay (and actually best practice) to denormalise the data by storing the price at the time of sale on each order line.