mysql sum results after each sum - mysql

Hello I'm trying to sum the result of two mysql result.
This is my code, it doesn't work.
SELECT
a.* ,
b.* ,
SUM(b.price) as price,
SUM(b.tax) as tax,
price + tax as price_tax --> error
FROM (SELECT name , item_id
FROM items)a
LEFT JOIN (SELECT item_id , price , tax
FROM bank
)b
ON a.item_id = b.item_id
GROUP BY item_id
I want to sum the two results like this: price + tax as price_tax

First
The SQL engine don't know the column alias in select clause during (the specific) query execution so
you can't use alias you must repeat the code
SELECT
SUM(b.price) as price,
SUM(b.tax) as tax,
SUM(b.price) + SUM(b.tax) as price_tax
FROM (
SELECT name , item_id
FROM items
)a
LEFT JOIN (
SELECT item_id , price , tax
FROM bank
)b
ON a.item_id = b.item_id
GROUP BY item_id
Second
in some mysql version is not allowed the use of aggregation function and select column not mentioned in group by so you must remove the column not mention in group by (or add fake aggreation function ) for the others columns
SELECT
a.item ,
SUM(b.price) as price,
SUM(b.tax) as tax,
SUM(b.price) + SUM(b.tax) as price_tax
FROM (
SELECT name , item_id
FROM items
)a
LEFT JOIN (
SELECT item_id , price , tax
FROM bank
)b
ON a.item_id = b.item_id
GROUP BY item_id

Related

Why this code showing invalid use of group function?

CREATE VIEW SALESMAN_WITH_MAX_ORDER AS
(SELECT S.Salesman_id,
S.Name,
S.City,
Commission
FROM SALESMAN S,
CUSTOMER C
WHERE S.Salesman_id=C.Salesman_id
AND Customer_id IN (SELECT Customer_id
FROM ORDERS
GROUP BY Customer_id,
Ord_Date
HAVING SUM(PURCHASE_AMT) = (SELECT MAX(SUM(PURCHASE_AMT))
FROM ORDERS
GROUP BY Customer_id,
Ord_Date)));
You have a problem in the innermost query. You cannot do a MAX with a SUM as argument.
This is how you would do it in T-SQL, sorry I have no mysql to test it on right now.
CREATE VIEW SALESMAN_WITH_MAX_ORDER AS
(
SELECT S.Salesman_id,
S.Name,
S.City,
Commission
FROM SALESMAN S,
CUSTOMER C
WHERE S.Salesman_id=C.Salesman_id
AND Customer_id IN
(
SELECT Customer_id
FROM ORDERS
GROUP BY Customer_id,Ord_Date
HAVING SUM(PURCHASE_AMT)=
(
SELECT MAX(SUM_AMT)
FROM
(
SELECT SUM(PURCHASE_AMT) AS SUM_AMT
FROM ORDERS
GROUP BY Customer_id,Ord_Date
) innerTableName
)
)
);

MySQL - Arithmetic operations with two relations

How do I get the total amount of money paid by each customer minus the amount collected (em_paid_to)?
table customer
cust_id INT
f_name VARCHAR
l_name VARCHAR
email VARCHAR
c_limit INT
table transaction
id INT
em_paid_by VARCHAR
em_paid_to VARCHAR
amount INT
trans_date DATE
I already tried this to get the total paid by each customer but it did not work:
SELECT C.F_NAME, C.L_NAME, COUNT(T.EM_PAID_BY), SUM(T.AMOUNT)
FROM CUSTOMER C
JOIN TRANSACTION T ON C.EMAIL = T.EM_PAID_BY;
...and this to get the total collected by each customer, still the same error and I need to get the difference between the two results.
SELECT C.F_NAME, C.L_NAME, COUNT(T.EM_PAID_TO), SUM(T.AMOUNT)
FROM CUSTOMER C
JOIN TRANSACTION T ON C.EMAIL = T.EM_PAID_TO;
What I am hoping to get is like this Old McDonald oldmcdonald#gmail.com 2000
i.e (2000 + 4000 + 1000) - (2000 + 3000) = 2000
Your existing queries generate errors because they use aggregate functions (SUM(), COUNT()) without a GROUP BY clause to list all non-aggregated columns.
To solve your requirement, one solution would be to use conditional aggregation:
recover all transactions where the customer's email appears in the em_paid_to or in the em_paid_by clause
group by customer (a sensible option is to add the customer id to the GROUP BY clause, eventhough it is not part of the results)
do conditional counts and sums, depending on whether the records was matched on em_paid_to or em_paid_by
The following query gives you detailed information (count of payments by and to, amounts paid by and to, and balance), you can pick what's relevant for you:
SELECT
c.f_name,
c.l_name,
SUM(c.email = t.em_paid_by) count_paid_by,
SUM(c.email = t.em_paid_to) count_paid_to,
SUM(CASE WHEN c.email = t.em_paid_by THEN t.amound ELSE 0 END) total_paid_by,
SUM(CASE WHEN c.email = t.em_paid_to THEN t.amound ELSE 0 END) total_paid_to,
SUM(CASE WHEN c.email = t.em_paid_by THEN t.amound ELSE -1 * t.amount END) balance
FROM
customer c
INNER JOIN transaction t
ON c.email IN (t.em_paid_by, t.em_paid_to)
GROUP BY
c.cust_id,
c.f_name,
c.l_name
;
I would unpivot the data and aggregate:
select t.email, c.fname, c.lname, sum(t.amount)
from ((select em_paid_by as email, -amount as amount
from transaction t
) union all
(select em_paid_to, amount
from transaction t
)
) t
group by email;
You can join to the customer table to get the additional customer information:
select email, sum(amount)
from cusomer c join
((select em_paid_by as email, -amount as amount
from transaction t
) union all
(select em_paid_to, amount
from transaction t
)
) t
on c.email = t.email
group by t.email, c.fname, c.lname;
I would use correlated subqueries in the SELECT clause:
select c.*,
coalesce((
select sum(amount)
from transaction t
where t.em_paid_by = c.email
), 0)
-
coalesce((
select sum(amount)
from transaction t
where t.em_paid_to = c.email
), 0) as paid_balance
from customer c
If you want more information like the count of transactions, I would use subqueries in the FROM clause:
select c.*,
p.cnt_paid,
r.cnt_received
coalesce(p.sum_paid, 0) as sum_paid,
coalesce(r.sum_received, 0) as sum_received,
coalesce(p.sum_paid, 0) - coalesce(r.sum_received, 0) as paid_balance,
p.cnt_paid + r.cnt_received as total_transactions
from customer c
left join (
select em_paid_by as email, sum(amount) as sum_paid, count(*) as cnt_paid
from transaction
group by em_paid_by
) p on p.email = c.email
left join (
select em_paid_to as email, sum(amount) as sum_received, count(*) as cnt_received
from transaction
group by em_paid_to
) r on r.email = c.email

mysql INNER/LEFT JOIN with UNION ALL

I have a question regarding the use of UNION ALL and INNER JOIN.
I found some posts regarding this issue, for example here or there but I did not manage to apply it to my issue.
What I am trying to do is to list 1) the products and 2) the difference between orders and deliveries.
I have 3 table:
product (id, name)
orders (id, product, value)
deliveries (id, product, value)
I managed to get (almost) what I want using the following:
SELECT product
, sum(total)
FROM (
SELECT product
, SUM(value) as total
FROM orders
GROUP BY product
union all
SELECT product
, -1 * SUM(value) as total
FROM deliveries
GROUP BY product)
as alias
GROUP BY product
ORDER BY sum(total) DESC
I obtain the following:
1 23
2 33
When I would like to get:
computer 23
car 33
Meaning the product name instead of the product id.
Anyone would have a solution for that? (my INNER JOIN OR LEFT JOIN attempts failed so far)
Thanks and regards
Join in the product table:
SELECT p.name, sum(total)
FROM (SELECT o.product, SUM(o.value) as total
FROM orders o
GROUP BY o.product
union all
SELECT d.product, -1 * SUM(d.value) as total
FROM deliveries d GROUP BY d.product
) od JOIN
product p
on od.product = p.id
GROUP BY p.name
ORDER BY sum(total) DESC

Select the SUM of two different tables

I have an orders table which consists of the following:
id
order_total
delivery_cost
customer_id
I also have a transactions table which has:
id
amount
customer_id
status
What I'm trying to do is,
SELECT SUM(order_total + delivery_cost) FROM orders WHERE customer_id = '1'
then
SELECT SUM(amount) FROM transactions WHERE customer_id = '1' AND transaction_status = 'Paid'
Then with the data, minus the total amount from the order totals.
I've tried different queries using JOINS, but I just can't get my head around it, for example:
SELECT SUM(OrdersTotal - TransactionTotal) as AccountBalance
FROM (
SELECT SUM(`order_total` + `delivery_cost`) FROM `orders` as OrdersTotal
UNION ALL
SELECT SUM(`amount`) FROM `transactions` WHERE `transaction_status` = 'Paid' as TransactionTotal
)
but this didn't work at all. Any help would be greatly appreciated.
The two datasets are effectively autonomous but assuming that it's unlikely to have transactions for a customer without orders, you can acheive your result with a LEFT JOIN rather than a ful outer join - but if you simply join the base tables then you'll likely get values from one table repeated in the interim result set (this is why Joseph B's answer is wrong when a customer has something other than a single row in each table).
SELECT ordered_value-IFNULL(paid_value,0) AS acct_balance
FROM
(
SELECT customer_id, SUM(order_total + delivery_cost) AS ordered_value
FROM orders
WHERE customer_id = '1'
GROUP BY customer_id
) AS orders
LEFT JOIN
(
SELECT customer_id, SUM(amount) AS paid_value
FROM transactions
WHERE customer_id = '1'
AND transaction_status = 'Paid'
FROUP BY customer_id
) as payments
ON orders.customer_id = payments.customer_id
(here the 'GROUP BY' and 'ON' clauses are redundant since your only looking at a single customer - but are required for multiple customers).
Note that calculating a balance based on a sum of transactions is technically correct, it does not scale well - for large systems a better solution (although it breaks the rules of normalization) is to maintain a unified table of transactions and a balance for for the account along with each transaction amount - alternatively use checkpointing.
You can just name the column in your union all query and sum on that:
SELECT SUM(col) as AccountBalance
FROM (SELECT SUM(`order_total` + `delivery_cost`) as col FROM `orders` as OrdersTotal
UNION ALL
SELECT SUM(`amount`) FROM `transactions` WHERE `transaction_status` = 'Paid' as TransactionTotal
) t;
Try this query using a JOIN:
SELECT
SUM(o.order_total + o.delivery_cost) - SUM(t.amount) AS AccountBalance
FROM orders o
INNER JOIN transactions t
ON o.customer_id = t.customer_id AND o.customer_id = '1' AND t.transaction_status = 'Paid';
This should give you the account balance for each customer?
SELECT
ISNULL(o.customer_id, t.customer_id) AS customer_id
OrdersTotal - TransactionTotal AS AccountBalance
FROM (
SELECT
customer_id,
SUM(order_total + delivery_cost) AS OrdersTotal
FROM
orders
GROUP BY
customer_id) o
FULL OUTER JOIN (
SELECT
customer_id,
SUM(amount) AS TransactionTotal
FROM
transactions
WHERE
transaction_status = 'Paid'
GROUP BY
customer_id) t
ON t.customer_id = o.customer_id
You can join the results of your queries and perform your calculations ,note sum without group by will result as one row so the sum in outer query doesn't mean when you have only one row and according to your logic of calculation union has nothing to do with it
SELECT t1.OrdersTotal - t2 .TransactionTotal AS AccountBalance
FROM (
SELECT SUM(order_total + delivery_cost) OrdersTotal ,customer_id
FROM orders
WHERE customer_id = '1'
) t1
JOIN (
SELECT SUM(amount) TransactionTotal ,customer_id
FROM transactions
WHERE customer_id = '1' AND transaction_status = 'Paid'
) t2 USING(customer_id)
Since you are only concerned about a single customer, just have them listed as two different queries as the source...
select
charges.chg - paid.pay as Balance
from
( SELECT SUM(order_total + delivery_cost) chg
FROM orders
WHERE customer_id = '1' ) charges,
( SELECT SUM(amount) pay
FROM transactions
WHERE customer_id = '1' AND transaction_status = 'Paid' ) paid
Now, if you wanted for all customers to see who is outstanding, add the customer's ID to each query and apply a group by, but then change to a LEFT-JOIN so you get all orders with or
select
charges.customer_id,
charges.chg - coalesce( paid.pay, 0 ) as Balance
from
( SELECT customer_id, SUM(order_total + delivery_cost) chg
FROM orders
group by customer_id ) charges
LEFT JOIN ( SELECT customer_id, SUM(amount) pay
FROM transactions
where transaction_status = 'Paid'
group by customer_id ) paid
on charges.customer_id = paid.customer_id
I think this works best if you try an inline view. In the code block below, check the Group By clause, you might need to add more fields in the Group By depending on what you're selecting in the Inner SELECT statements.Try the code below:
SELECT
SUM(Totals.OrdersTotal-Totals.TransactionTotal)
FROM
(SELECT
SUM(ord.order_total + ord.delivery_cost) AS OrdersTotal
, SUM(trans.amount) AS TransactionTotal
FROM orders ord
INNER JOIN transactions trans
ON ord.customer_id = trans.customer_id
WHERE
ord.customer_id =1
AND trans.transaction_status = 'Paid'
GROUP BY
ord.customer_id
) Totals;

sql statement with min and max

I need to write a statement using min and max together.
SELECT companyname FROM companies JOIN stocklist
USING (companyid) where price =some(
( select max(price) from stocklist) , ( select min(price) from stocklist) ) ;
I need to get the companies name for the most low and max value but this isn't working (because of the last line) what is wrong and how should I do that?
UPDATE:
select companyname from stockList join companies using (companyid) WHERE price IN (select min(price) from stocklist) ;
this is working for me but gets only one operand, how can I get two?
I don't like the idea of having two subqueries in an IN clause. Here is another way with the join being made explicit:
SELECT companyname
FROM companies c JOIN
stocklist s
c.companyid = s.companyid join
(select min(price) as minprice, max(price) as maxprice
from stocklist
) sm
on s.price = minprice or s.price = maxprice
Try this:
SELECT companyname FROM companies c
INNER JOIN stocklist s
ON c.companyid = s.companyid
WHERE price IN
((SELECT MAX(price) FROM stocklist ),
(SELECT MIN(price) FROM stocklist ))
SEE THIS FIDDLE