Update a mysql table column with sum of joined table columns value? - mysql

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;

Related

Sum Values that have refer to same column

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

More than 1 rows returned from SELECT inside SELECT

I'm trying to create a query to find what is the total amount owed by each customer to the company. It is the GROUP BY customerNumber in the sub query that is creating the problem.
SELECT customerName,
customers.customerNumber,
SUM(quantityOrdered * priceEach) - ( SELECT SUM(amount) AS MoneyPayed FROM payments GROUP BY customerNumber ) AS AmountOwed
FROM payments
INNER JOIN customers ON payments.customerNumber = customers.customerNumber
INNER JOIN orders ON customers.customerNumber = orders.customerNumber
INNER JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY customerNumber;
The tables I'm trying to link are payments and orderdetails.
When I get rid of the GROUP BY I get results in negatives as the total SUM of amount is subtracted from each row of SUM(quantityOrdered * priceEach).
How can I change this so that I can return multiple rows from payments to subtract from SUM(quantityOrdered * priceEach) from the order details table.
Link to DB as StackOverflow doesn't allow me to post images
Thanks for help, sorry if format is bad, this is my first post.
You will need a couple of subqueries to meet your requirement. Let us break it down.
First, you need the total value of orders from each customer. You're very close to the correct query for that. It should be
SELECT orders.customerNumber,
SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
FROM orders
JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY orders.customerNumber
This subquery's result set gives customerNumber and owed, the amount owed. Notice that orders::orderdetails is a one::many relationship, so we're sure we're counting each detail just once, so the SUMs will be correct.
Next we need the amount paid by each customer. This subquery is fairly simple.
SELECT customerNumber,
SUM(amount) paid
FROM payments
GROUP BY customerNumber
Now for the operation you're missing in your question: we need to join these two subqueries to your customers table.
SELECT customers.customerName, customers.customerNumber
owed.owed - paid.paid balance
FROM customers
LEFT JOIN (
SELECT orders.customerNumber,
SUM(orderdetails.quantityOrdered * orderdetails.priceEach) owed
FROM orders
JOIN orderdetails ON orders.orderNumber = orderdetails.orderNumber
GROUP BY orders.customerNumber
) paid ON customers.customerNumber = paid.customerNumber
LEFT JOIN (
SELECT customerNumber,
SUM(amount) paid
FROM payments
GROUP BY customerNumber
) owed ON customers.customerNumber = owed.customerNumber
See how this works? We join a table and two subqueries. Each subquery has either zero or one rows for each row in the table, so we need not use SUMs or GROUP BY in the outer query.
There's only one complication left: what if a customer has never paid anything? Then the value of paid.paid will be NULL after the LEFT JOIN operation. That will force the value of owed - paid to be NULL. So we need more smarts in the SELECT statement to yield correct sums.
SELECT customers.customerName, customers.customerNumber
COALESCE(owed.owed,0) - COALESCE(paid.paid,0) balance
...
COALESCE(a,b) is equivalent to if a is not null then a else b.
Pro tip In queries or subqueries with JOIN operations, always mention table.column instead of just column. The next person to work on your query will thank you.

SQL Select: How to multiply a column with the count of an ID

I have the following (here simplified) database and want to get the month with the highest revenue.
invoices
- id
- order_id
- issued (timestamp)
orders
- id
orderItems
- id
- order_id
- article_id
articles
- id
- price
So far I got the following statement:
Select articles.price * orderItems.order_id as revenue, Extract(month
from invoices.issued)
FROM orderItems
INNER JOIN articles ON orderItems.article_id = articles.id
Inner JOIN orders ON orderItems.order_id = orders.id
Inner JOIN invoices ON orders.id = invoices.order_id
GROUP BY year(issued), month(issued)
Order by revenue DESC Limit 1
The calculated revenue is wrong as the price is multiplied with the order_id but should be actually multiplied with the count of the respective order_id. I tried to implement count(orderItems.order_id) but it's not working. Any ideas? Thanks!
I think you want:
SELECT year(i.issued), month(i.issued), SUM(a.price) as revenue,
FROM orderItems oi JOIN
articles a
ON oi.article_id = a.id JOIN
orders o
ON oi.order_id = o.id JOIN
invoices i
ON o.id = i.order_id
GROUP BY year(i.issued), month(i.issued)
ORDER BY revenue DESC
LIMIT 1;
In other words, this is a simple aggregation query. There is no need -- ever -- to multiply by orderid. Also note that this query introduces table aliases so the query is easier to write and to read.

Sql query to calculate total cost using 3 tables

Order details table contains catalog id and its quantity.
Catalog has the price of the particular item.
For one order he or she can select only 2 items. The selected items total cost has to be generated and stored in orders table for a particular order using order id.
The columns in my catalogs are id, name, price.
The columns in order details are id, order_id, catalog_id, quantity.
The columns in orders table are id, customer_id, total_cost.
How can I calculate the total cost using 3 tables in mysql?
Try this.
SET SQL_SAFE_UPDATES = 0;
UPDATE orders
INNER JOIN (
SELECT order_id, SUM(quantity*price) total_price
FROM order_details
INNER JOIN my_catalogs
ON order_details.catalog_id = my_catalogs.id
GROUP BY order_id
) d
ON order.id = d.order_id
SET orders.total_cost = d.total_price;
SET SQL_SAFE_UPDATES = 1;

How to get all order ID which not paid in SQL Server 2008?

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.