Subtotal of all items in a query - mysql

Query below currently shows the total as item by item but what I want is to calculate subtotal of all items in a purchase order.
Thanks
Output should be:
POID Item ItemQTY ItemPrice ItemTotal SubTotal
1 A 1 15.00 15.00 80.50
1 B 1 25.50 25.50 80.50
1 C 2 20.00 40.00 80.50
2 X 6 5.00 30.00 50.00
2 Y 2 10.00 20.00 50.00
Relationship: purchase_order 1 - N purchase_order_items
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal
/* Here, Subtotal should be calculated and displayed */
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
I looked at MySQL finding subtotals and Subtotals and SQL but couldn't apply to my query.

You can use the WITH ROLLUP feature to get subtotals:
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
SUM(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
GROUP BY POID, Item WITH ROLLUP
This will create a result set that has Item = NULL for the PO subtotal, and POID = NULL for a grand total. These subtotals and grand totals go in the ItemTotal column of those rows.

Try
SELECT i.fk_purchase_order POID,
description Item,
quantity ItemQTY,
price ItemPrice,
quantity * price ItemTotal,
s.subtotal SubTotal
FROM purchase_order_items i JOIN
(
SELECT fk_purchase_order, SUM(quantity * price) subtotal
FROM purchase_order_items
GROUP BY fk_purchase_order
) s ON i.fk_purchase_order = s.fk_purchase_order
Output:
| POID | ITEM | ITEMQTY | ITEMPRICE | ITEMTOTAL | SUBTOTAL |
------------------------------------------------------------
| 1 | A | 1 | 15 | 15 | 80.5 |
| 1 | B | 1 | 25.5 | 25.5 | 80.5 |
| 1 | C | 2 | 20 | 40 | 80.5 |
| 2 | X | 6 | 5 | 30 | 50 |
| 2 | Y | 2 | 10 | 20 | 50 |
Here is SQLFiddle demo

Afraid I think the best solution is to cross join against a subselect:-
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal,
Sub1.FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
CROSS JOIN
(
SELECT SUM(purchase_order_items.quantity*purchase_order_items.price) AS FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
) Sub1
To bring it back for grouped purchase order ids
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal,
Sub1.FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
INNER JOIN
(
SELECT purchase_order.id, SUM(purchase_order_items.quantity*purchase_order_items.price GROUP BY purchase_order.id) AS FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
) Sub1
ON purchase_order.id = Sub1.id

Related

Mysql select query for 3 tables

I have a 3 tables order, order_option, product_option
order
order_id | cus_name | cus_phone
-------------------------------
1 | Test-1 | 9876543211
2 | Test-2 | 9876543212
3 | Test-3 | 9876543213
4 | Test-4 | 9876543214
order_option
product_option_id | order_id
-------------------------------
11 | 1
12 | 1
13 | 2
14 | 4
15 | 3
product_option
product_id | product_option_id | sku | qty
------------------------------------------
1 | 11 | TS01 | 3
2 | 12 | TS02 | 2
3 | 13 | TS033 | 3
4 | 14 | TS023 | 3
Here I want to select order table and product_option table values with a where condition on the sku field.
i tried to join the query like below:
SELECT o.order_id, o.cus_name, o.cus_phone,po.sku,po.qty FROM order o
LEFT JOIN order_option op
ON (o.order_id = op.order_id)
LEFT JOIN product_option po
ON (op.product_option_id = po.product_option_id)
WHERE po.sku = "TS023"
But it's not showing the correct answer. I don't know what I have missed.
order is a reserved word, use backticks ``.
SELECT o.order_id, o.cus_name, o.cus_phone, po.sku, po.qty
FROM `order` o
LEFT JOIN order_option op ON o.order_id = op.order_id
LEFT JOIN product_option po ON op.product_option_id = po.product_option_id
WHERE po.sku = "TS023"
Output:
order_id cus_name cus_phone sku qty
4 Test-4 9876543214 TS023 3
SQL Fiddle: http://sqlfiddle.com/#!9/9b76b/2/0
Move the po condition from WHERE to ON to get true LEFT JOIN result:
SELECT o.order_id, o.cus_name, o.cus_phone,po.sku,po.qty FROM order o
LEFT JOIN order_option op
ON (o.order_id = op.order_id)
LEFT JOIN product_option po
ON (op.product_option_id = po.product_option_id)
AND po.sku = "TS023"
(When in WHERE, you'll get regular INNER JOIN result.)
#Matt is correct, here's another way of doing this.
SELECT o.order_id, o.cus_name, o.cus_phone, po.sku, po.qty
FROM `order` o, order_option op, product_option po
WHERE o.order_id = op.order_id
AND op.product_option_id = po.product_option_id
AND po.sku = "TSO23"

MySQL: left join only one row and sum

It's possible left join only one row without sub query?
I need to get product statistics and some of products have multiple groups.
Therefore, the amount of products is incorrect.
SELECT COUNT(p.id) AS total_product, SUM(p.price) AS total_price
FROM product p
LEFT JOIN attribute_group a ON
a.product_id = p.id
WHERE p.created_at >= "2018-01-01" AND (a.id = 1 OR a.id = 2)
GROUP BY p.id
LIMIT 0, 30;
product
id | price
1 | 100
2 | 150
3 | 250
attribute_group
id | product_id | title
1 | 1 | a1
2 | 1 | a2
3 | 2 | a3
4 | 3 | a4
Should be:
1| 100
But i get:
2 | 200
You appear to want all products or the counts/sum of them that have attributes of both 1 and 2. Here is one method:
SELECT COUNT(*) as num_products, SUM(p.price) as total_price
FROM product p
WHERE p.created_at >= '2018-01-01' AND
EXISTS (SELECT 1
FROM attribute_group ag
WHERE ag.product_id = p.id AND ag.id = 1
) AND
EXISTS (SELECT 1
FROM attribute_group ag
WHERE ag.product_id = p.id AND ag.id = 2
);

MySQL SUM over a virtual subquery field (with another SUM) with GROUP BY

I have two tables: invoices and items.
invoices
id | timest
items
id | invoice_id | price | qty
It is apparent an invoice may have several items - items.invoice_id = invoices.id.
I have the following query that selects all invoices with the total sum of theirs items:
SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`
This generates something like:
id| _period | total
-------------------
1 | 2014-06 | 100
4 | 2014-06 | 200
5 | 2014-07 | 660
6 | 2014-07 | 300
7 | 2014-07 | 30
9 | 2015-02 | 225
Now I want to group it by the period to have output as:
_period | qty | total_price
---------------------------
2014-06 | 2 | 300
2014-07 | 3 | 990
2015-02 | 1 | 224
I can easily do it for the quantity field as
SELECT DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
COUNT(inv.id) as qty
FROM `invoices` `inv`
GROUP BY _period
But I can't figure out how the similar thing could be done for the total_price field, which results from a subquery virtual field? Does anyone have any idea?
Thank you!
You should do this using a LEFT JOIN and GROUP BY:
SELECT DATE_FORMAT(FROM_UNIXTIME(i.time, '%Y-%m') AS _period,
COUNT(DISTINCT i.id) as num_invoices
SUM(i.price * it.quantity) as total
FROM invoices i LEFT JOIN
items it
ON it.invoice_id = i.id
GROUP BY _period
ORDER BY _period;
try this
SELECT InnerTable._period, Count(InnerTable.id) as id, Sum(InnerTable.total) as total FROM
(SELECT id, DATE_FORMAT(FROM_UNIXTIME(inv.time), "%Y-%m" ) AS _period,
(SELECT SUM(it.price*it.quantity) FROM items AS it WHERE it.invoice_id=inv.id) as total
FROM `invoices` `inv`) as InnerTable FROM GROUP BY InnerTable._period.
Making sub table from the query and then put group by on it.

Mysql query with multiple join

I have the following tables and would like to get the result as follow
Table po
ID | Date
1 | 20-Jun-2016
Table podetails
ID | poid | itemcode | quantity
1 | 1 | SOAP123 | 100
Table poreceived
ID | poid | itemcode | quantity
1 | 1 | SOAP123 | 20
2 | 1 | SOAP123 | 60
Result should be:
PO | Date | itemcode | quantity
1 | 20-Jun-2016 | SOAP123 | 80
What I have done is:
SELECT
po.id, podetails.itemcode, poreceived.quantity
FROM
po
LEFT JOIN
podetails ON podetails.poid = po.id
LEFT JOIN
poreceived ON poreceived.poid = podetails.poid
But the result is not what I expected.
Any help would be appreciate it.
It looks like you need to do an aggregation of the poreceived table by poid. You can use a subquery for this:
SELECT po.id, COALESCE(podetails.itemcode, 'NA'), COALESCE(t.quantity, 0)
FROM po
LEFT JOIN podetails
ON podetails.poid = po.id
LEFT JOIN
(
SELECT poid, itemcode, SUM(quantity) AS quantity
FROM poreceived
GROUP BY poid, itemcode
) t
ON t.poid = podetails.poid AND t.itemcode = podetails.itemcode
Other than the aggregation problem, your query strategy looked correct. I also added COALESCE to the columns from the podetails and poreceived tables in case the id from po does not match to anything.

Select and summarize data from three tables

i have three tables
customer
id | name
1 | john
orders
id | customer_id | date
1 | 1 | 2013-01-01
2 | 1 | 2013-02-01
3 | 2 | 2013-03-01
order_details
id | order_id | qty | cost
1 | 1 | 2 | 10
2 | 1 | 5 | 10
3 | 2 | 2 | 10
4 | 2 | 2 | 15
5 | 3 | 3 | 15
6 | 3 | 3 | 15
i need to select data so i can get the output for each order_id the summary of the order
sample output. I will query the database with a specific customer id
output
date | amount | qty | order_id
2013-01-01 | 70 | 7 | 1
2013-02-01 | 50 | 4 | 2
this is what i tried
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT OUTER JOIN order_details ON order_details.order_id=orders.id AND orders.customer_id = 1
GROUP BY orders.date
but this returns the same rows for all customers, only that the qty and cost dont hav values
Maybe
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT JOIN order_details ON order_details.order_id=orders.id
AND orders.customer_id = 1
GROUP BY orders.date
HAVING amount is not null AND qty is not null
SQL Fiddle
NOTE: In the following query, it is assumed that the dates are stored in the database as a string in the format specified in the OP. If they are actually stored as some type of date with time then you'll want to modify this query such that the time is truncated from the date so the date represents the whole day. You can use the date or date_format functions. But then you'll need to make sure that you modify the query appropriately so the group by and select clauses still work. I added this modification as comments inside the query.
select
o.date -- or date(o.date) as date
, sum(odtc.total_cost) as amount
, sum(odtc.qty) as qty
, o.order_id
from
orders o
inner join (
select
od.id
, od.order_id
, od.qty
, od.qty * od.cost as total_cost
from
order_details od
inner join orders _o on _o.id = od.order_id
where
_o.customer_id = :customer_id
group by
od.id
, od.order_id
, od.qty
, od.cost
) odtc on odtc.order_id = o.id
where
o.customer_id = :customer_id
group by
o.date -- or date(o.date)
, o.order_id
;
I don't think you want an outer join just a simple inner join on all 3 tables:
FROM orders, order_details, customer
WHERE orders.customer_id=customer.id
AND order_details.order_id=orders.id