mysql sum column with same id - mysql

I have orders table, order_details table
I join orders table with order_details table to make a temporary table that look like this
order_id | customer_id | Quantity |
2 | 2 | 10 |
2 | 2 | 25 |
2 | 2 | 5 |
2 | 2 | 15 |
3 | 2 | 25 |
What I am trying to achieve is sum Quantity column where order_id is same.
so the end result look like this
order_id | customer_id | Quantity |
2 | 2 | 55 |
3 | 2 | 25 |
my sql statement to get to here look like this
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2) <-- this is needed because I only want to see customer 2.
how do I put a condition on the sum ?

Looks like you are very close!
You should be able to group by order_idto get a list of unique order_ids with the Quantity sum for each order_id
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2)
GROUP BY orders.orders_id,orders.customer_id_fk

use Group by
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2) GROUP BY orders.orders_id,orders.customer_id_fk

Here is OP. Sorry I derped. I put GROUP BY after Order by and it didnt work. the below sovled it
SELECT
orders.orders_id,
orders.customer_id_fk,
sum(order_detail.quantity)
FROM orders
LEFT JOIN order_detail on orders.orders_id = order_detail.orders_id_fk
WHERE customer_id_fk IN(2)
GROUP BY orders_id
ORDER BY customer_id

Related

How do I join multiple (four) tables using sql with conditions?

I am trying to create an SQL query that conditionally pulls data from multiple tables.
I have four tables:
orders
+------+------------+------------+
| id | date_added | currency |
+------+------------+------------+
| 1 | 2018-07-23 | 1 |
+------+------------+------------+
order_items
+------+------------+------------+---------------+---------------+
| id | order_id | price | product_id | product_type |
+------+------------+------------+---------------+---------------+
| 1 | 1 | 100.00 | 1 | ticket |
+------+------------+------------+---------------+---------------+
order_data
+------+--------------+---------------+
| id | order_id | ext_order_ref |
+------+--------------+---------------+
| 1 | 1 | ABC |
+------+--------------+---------------+
products
+------+------------+------------+
| id | date | product_id |
+------+------------+------------+
| 1 | 2020-03-12 | 1 |
+------+------------+------------+
| 2 | 2020-03-18 | 2 |
+------+------------+------------+
| 3 | 2020-03-20 | 3 |
+------+------------+------------+
I need to output orders with the following conditions:
Each order in a row with total (calculated from order items with matching order id)
The 'ext_order_ref' from the order_data table that matches that order
Only include order items that have a specific product type
Only include orders with products from a particular date range
Preferred output would look like this:
+------------+------------+--------------+
| order_id | total | ext_order_ref|
+------------+------------+--------------+
| 1 | 100 | ABC |
+------------+------------+--------------+
My current query is basically like this; please advise
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_ref
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_ref
RIGHT JOIN order_items
ON orders.id = order_items.order_id
LEFT JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
It almost works, but not quite. The date particularly is causing issue.
Thanks in advance!
First decide the driving table for the query and form the query based on the driving table.
Driving table is the one primary table from which other tables join.
More information on driving tables from askTom
In your case, the driving table is Orders table. You are switching between RIGHT OUTER JOIN and LEFT OUTER JOIN. This will cause confusion in the resultset.
I have modified the query. See whether it works.
SELECT
orders.id as order_id,
SUM(order_items.price) as total,
order_data.ext_order_id
FROM orders
INNER JOIN order_data
ON orders.id = order_data.ext_order_id
LEFT OUTER JOIN order_items
ON orders.id = order_items.order_id
LEFT OUTER JOIN products
ON order_items.product_id = products.product_id
WHERE order_items.product_type = 'ticket' AND products.date BETWEEN '2020-03-12' AND '2020-03-18'
GROUP BY orders.id
I don't understand why you would want outer joins at all. If I follow the conditions correctly:
SELECT o.id as order_id,
SUM(oi.price) as total,
od.ext_order_id
FROM orders o INNER JOIN
order_data od
ON o.id = od.ext_order_id INNER JOIN
order_items oi
ON o.id = oi.order_id INNER JOIN
products p
ON oi.product_id = p.product_id
WHERE oi.product_type = 'ticket' AND
p.date >= '2020-03-12' AND
p.date < '2020-03-19'
GROUP BY o.id, od.ext_order_id;
Note the use of table aliases so the query is easier to write and read.

Get all rows from table - with the latest row from another table, with another table based on the latest row

I need to get all the details from the orders table, with the latest status ID in the orders statuses table, and then the name of that status from the states table.
orders
id | customer | product
-----------------------
1 | David | Cardboard Box
Order_to_statuses
id | order | status | updated_at
--------------------------------
1 | 1 | 1 | 2017-05-30 00:00:00
2 | 1 | 3 | 2017-05-28 00:00:00
3 | 1 | 4 | 2017-05-29 00:00:00
4 | 1 | 2 | 2017-05-26 00:00:00
5 | 1 | 5 | 2017-05-05 00:00:00
order_states
id | name
---------
1 | Pending
2 | Paid
3 | Shipped
4 | Refunded
In this instance, I would need to get the customer and product, with the latest status ID from the order statuses table, and then the name of that state.
How can I do this?
I'd break this down by first getting the max(updated_at) for each order, then work to everything else you need. You can get the max date for each order by using subquery:
select
s.`order`,
s.`status`,
s.updated_at
from order_to_statuses s
inner join
(
select
`order`,
max(updated_at) as updated_at
from order_to_statuses
group by `order`
) m
on s.`order` = m.`order`
and s.updated_at = m.updated_at
Once you get this you now have the order, the status id, and the most recent date. Using this you can then JOIN to the other tables, making your full query:
select
o.customer,
o.product,
ots.updated_at,
os.name
from orders o
inner join
(
select
s.`order`,
s.`status`,
s.updated_at
from order_to_statuses s
inner join
(
select
`order`,
max(updated_at) as updated_at
from order_to_statuses
group by `order`
) m
on s.`order` = m.`order`
and s.updated_at = m.updated_at
) ots
on o.Id = ots.`order`
inner join order_states os
on ots.`status` = os.id;
See a demo
It may have some typo, but the idea of the query should be something like this:
select orders.id, orders.customer, orders.product,
order_to_status.status, staus.name
from orders, order_to_status, status
where orders.id = order_to_status.order
and order_to_status.status = status.id
and order_to_status.updated_at in (
SELECT MAX(order_to_status.updated_at)
FROM order_to_status
where order_to_status.order = orders.id
group by order_to_status.order
);
I ussually don't use joins but with joins it should be like this:
select orders.id, orders.customer, orders.product,
order_to_status.status, staus.name
from orders
JOIN order_to_status ON orders.id = order_to_status.order
JOIN status ON order_to_status.status = status.id
where
order_to_status.updated_at in (
SELECT MAX(order_to_status.updated_at)
FROM order_to_status
where order_to_status.order = orders.id
group by order_to_status.order
);
Note I added a group by I had missed.
EDIT 2
I had an error in the subquery condition.
changed to where order_to_status.order = orders.id
also moved the group by after the where clause.

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.

join one row to all row and returning all row

can I get data like this from my table
| id_outlet| date | count(msisdn) |
| 34.10.1 | 2014-08 | 0 |
| 34.10.1 | 2014-09 | 3 |
| 34.10.1 | 2014-10 | 2 |
| 34.10.2 | 2014-08 | 1 |
| 34.10.2 | 2014-09 | 0 |
| 34.10.2 | 2014-10 | 0 |
So I have 2 tables
1. table outlet (unique)
2. table sales (detail of table outlet)
As u see in my second table there are 3 periode (2014-08, 2014-09, 2014-10)
I want join that periode with id_outlet in first table like that example.
Can I?
Please Help me
Using a CROSS JOIN:-
SELECT
o.id_outlet,
s_main.periode,
o.branch,
count(msisdn)
FROM
(
SELECT DISTINCT SUBSTRING(date,1,7) AS periode
FROM sales
) s_main
CROSS JOIN outlet o
LEFT OUTER JOIN sales s
ON s_main.periode = SUBSTRING(s.date,1,7)
AND o.id_outlet = s.id_outlet
WHERE (o.STATUS LIKE 'STREET%')
GROUP BY s_main.periode, o.branch, o.id_outlet
If you have a table of dates then you can just use that rather than the sub query to get the dates (which also avoids the potential problem of not having a date in the results for a month where there has been zero sales for any outlet).
Don't worry, be happy!
SELECT
o.id_outlet,
SUBSTRING(s.date,1,7) AS periode,
o.branch
FROM outlet o LEFT JOIN sales s ON o.id_outlet = s.id_outlet
WHERE (o.STATUS LIKE 'STREET%')
ORDER BY o.id_outlet, YEAR(s.DATE), MONTH(s.DATE), branch
You need this query:
SELECT
o.id_outlet,
d.period AS periode,
o.branch,
count(msisdn)
FROM dates d LEFT JOIN outlet o ON d.period = SUBSTRING(o.date,1,7) LEFT JOIN sales s ON o.id_outlet = s.id_outlet
WHERE (o.STATUS LIKE 'STREET%')
GROUP BY CONCAT(d.period, '#', s.id_outlet)
ORDER BY o.id_outlet, d.period, branch

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