Calculate sum for group records in MySQL - mysql

I have this table of orders
| ORDER_ID | PRODUCT | CUSTOMER | QTY | DATE
---------------------------------------------
| 1 | shoes | Nick | 1 | 01/01/2016
| 2 | shirts | Nick | 5 | 02/02/2016
| 3 | shoes | Paul | 10 | 03/03/2016
| 4 | shirts | Paul | 20 | 04/04/2016
So, How can I achieve this report result with ONE Select Statement?
| Date_of_Order | Customer | Quantity | PRODUCT_TOTAL_SALES |
-----------------------------------------------------------------
| 01/01/2016 | Nick | 1 | shoes : 11 |
| 02/02/2016 | Nick | 10 | shirts : 25 |
| 03/03/2016 | Paul | 5 | shoes : 11 |
| 04/04/2016 | Paul | 20 | shirts : 25 |
I know how to use concat(column1, ' ', column2) to create a combined column but I haven't succeed to add a sum for a grouped item there. When I try with left join I get the sum for a product ...BUT its always the whole sum and its not related to the dates of the order so when I try to filter the results on my query for a certain period I still get 11 for shoes and 25 for shirts...

You can group by multiple columns and get the sum for the smallest group.
If you want the daily sales, then instead of GROUP BY product use GROUP BY product, date
SELECT
o.`date` AS Date_of_Order,
SUM(o.qty) as Total_Quantity,
CONCAT(o.product, ':', SUM(o.qty))
FROM
orders o
GROUP BY product, `date`
ORDER BY `date`

Simple additional SELECT from same table can do that for entire period:
SELECT
o.`date` AS Date_of_Order,
o.Customer,
o.qty as Quantity,
(SELECT
CONCAT(oo.product, ':', SUM(oo.qty))
FROM
orders oo
WHERE
oo.product = o.product
) PRODUCT_TOTAL_SALES
FROM
orders o
Output:
+---------------+----------+----------+---------------------+
| Date_of_Order | Customer | Quantity | PRODUCT_TOTAL_SALES |
+---------------+----------+----------+---------------------+
| 01/01/2016 | Nick | 1 | shoes:11 |
| 02/02/2016 | Nick | 5 | shirts:25 |
| 03/03/2016 | Paul | 10 | shoes:11 |
| 04/04/2016 | Paul | 20 | shirts:25 |
+---------------+----------+----------+---------------------+
4 rows in set
If you want to filter by certain period, you must include it in both:
SELECT
o.`date` AS Date_of_Order,
o.Customer,
o.qty as Quantity,
(SELECT
CONCAT(oo.product, ':', sum(oo.qty))
FROM
orders oo
WHERE
oo.product = o.product
AND STR_TO_DATE(oo.`date`,'%d/%m/%Y') BETWEEN '2016-01-01' AND '2016-03-03'
) PRODUCT_TOTAL_SALES
FROM
orders o
WHERE
STR_TO_DATE(o.`date`,'%d/%m/%Y') BETWEEN '2016-01-01' AND '2016-03-03'
Output:
+---------------+----------+----------+---------------------+
| Date_of_Order | customer | Quantity | PRODUCT_TOTAL_SALES |
+---------------+----------+----------+---------------------+
| 01/01/2016 | Nick | 1 | shoes:11 |
| 02/02/2016 | Nick | 5 | shirts:5 |
| 03/03/2016 | Paul | 10 | shoes:11 |
+---------------+----------+----------+---------------------+
3 rows in set

Related

SQL Query: join with condition

I have the following tables:
Customer
| c_id | name |
| -------- | -------------- |
| 1 | Adam |
| 2 | Bradley |
| 3 | Chandler |
| 4 | Damian |
| 5 | Eric |
| 6 | Frank |
orders
| order_id | c_id | amount
| -------- | -------------- | -------------- |
| 1 | 1 | 50
| 2 | 1 | 2
| 3 | 2 | 15
| 4 | 2 | 22
| 5 | 2 | 10
| 6 | 2 | 7
| 7 | 3 | 7
| 8 | 3 | 2
| 9 | 5 | 18
| 10 | 5 | 24
| 11 | 6 | 60
| 12 | 6 | 1
I want to create a list of users who have order amounts over 50.
This list should include c_id, name and the sum of all their orders including those under 50.
so it should look like this:
| c_id | name | amount
| -------- | -------------- | -------------- |
| 1 |Adam | 52
| 6 | Frank | 61
You can use group by and having:
select c.c_id, c.name, sum(o.amount)
from orders o join
customers c
on o.c_id = c.c_id
group by c.c_id, c.name
having max(o.amount) > 50;
SELECT
c_id
, name
, SUM(amount) AS total_amount
FROM
orders a
INNER JOIN customer b
ON b.c_id = a.user_id
WHERE
c_id IN (
SELECT
user_id
FROM
orders
WHERE
amount >= 50)
GROUP BY c_id, name
Best to break this down into chunks:
Customers who have a total amount over 50:
SELECT user_id FROM orders GROUP BY user_id HAVING sum(amount) >= 50;
Sum of the amounts for each order for customers that meet the criteria above:
SELECT user_id, sum(amount) as order_total
FROM orders
WHERE user_id IN (SELECT user_id FROM orders HAVING sum(amount) >= 50 GROUP BY user_id)
GROUP BY user_id;
You can just join over to your customer table to grab the name. Didn't include since that is the more straightforward ask here.

Trouble in join and alias table

I'm trying to solve a question where each worker from a specific department sells a product and makes 1000 in profit. I want to find out the profit or loss of the company for each month. Assuming that the only profit comes from the sales and costs are the salaries off all workers.
Table dept_worker
+-----------+---------+------------+------------+
| worker_id | dept_n | from_date | to_date |
+-----------+---------+------------+------------+
| 10002 | 25 | 1996-08-03 | 9999-01-01 |
| 10016 | 25 | 1998-02-11 | 9999-01-01 |
| 10034 | 25 | 1995-04-12 | 1999-10-31 |
+-----------+---------+------------+------------+
Table salaries
+----------+--------+------------+------------+
| worker_id| salary | from_date | to_date |
+----------+--------+------------+------------+
| 10001 | 617 | 1986-04-26 | 1987-06-26 |
| 10002 | 600 | 1996-08-03 | 9999-01-01 |
| 10016 | 602 | 1998-02-11 | 9999-01-01 |
| 10034 | 674 | 1995-04-12 | 1999-10-31 |
| 10100 | 900 | 2000-07-25 | 2002-06-25 |
+----------+--------+------------+------------+
I tried two different approaches. I tried using WHERE dept_n = '25' but the result wasn't the expected because I was filtering everything.
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id)*1000 AS 'Profit',
SUM (salary) AS 'Costs', (COUNT(worker_id)*1000-SUM(salary)) AS 'Diff'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY Month
ORDER BY Diff DESC;
The second one (this query doesn't give me any result):
SELECT MONTH(from_date) AS 'Months',
(SELECT COUNT(worker_id)*1000 FROM dept_worker WHERE dept_n = '25') AS 'Profits', SUM(salary)
FROM dept_worker JOIN salaries using(from_date)
GROUP BY Months;
Expected result:
+----------+--------+------------+-------------------+
| Months | Profits| Costs | Profits - Costs |
+----------+--------+------------+-------------------+
| 1 | 4456 |14478 |-10022 |
| 2 | 4105 |14824 |-10719 |
| 3 | 4379 |16130 |-11751 |
| 4 | 4329 |15562 |-11233 |
| (...) | (...) |(...) |(...) |
+----------+--------+------------+-------------------+
Try Starting with this:
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id) over(partition by dept_n order by dept_n) * 1000 AS 'Profit',
SUM (salary) over(partition by dept_n order by dept_n) AS 'Costs'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY MONTH(from_date)

Select total members and amount paid

I need help generating SQL for MySQL database.
I have three tables:
Organisations
Members
Payments
Organisations table:
+------------+---------+--------+
| id | name |website |
+------------+---------+--------+
| 1 | AAA | a.com |
|-------------------------------+
| 2 | BBB | b.com |
+------------+---------+--------+
Members table:
+------------+-------------------+--------+-----------------+-----------+
| id | organisation_id |name | Payment_confirm | join_date |
+------------+-------------------+--------+-----------------+-----------+
| 1 | 1 | james | 1 | 2013-8-02 |
|-----------------------------------------+-----------------+-----------+
| 2 | 1 | Jimmy | 0 | 2013-6-25 |
+------------+-------------------+--------+-----------------+-----------+
| 3 | 2 | Manny | 1 | 2013-07-02|
|-----------------------------------------+-----------------+-----------+
| 4 | 1 | Kim | 1 | 2013-09-02|
+------------+-------------------+--------+-----------------+-----------+
Payments table:
+------------+-------------------+--------+-----------------+----------------+
| id | member_id |amount | transaction_id | transferred_at |
+------------+-------------------+--------+-----------------+----------------+
| 1 | 1 | 100 | T1001 | 2013-8-03 |
|-----------------------------------------+-----------------+--------------- +
| 2 | 2 | 0 | null | Null |
+------------+-------------------+--------+-----------------+----------------+
| 3 | 3 | 200 | T1002 | Null |
|-----------------------------------------+-----------------+----------------+
| 4 | 4 | 50 | T1005 | 2013-09-05 |
+------------+-------------------+--------+-----------------+----------------+
How can I select the following?
Expecting the following output:
+------------+-------------------+--------+-----------------+---------------+--------------+
| Org name | Revenue |untransferred amount | Total members | last 30 days |
+------------+-------------------+--------------------------+---------------+--------------+
| AAA | 150 | 0 | 3 | 2 |
|-----------------------------------------------------------+---------------+--------------+
| BBB | 200 | 200 | 1 | 0 |
+------------+-------------------+--------------------------+---------------+--------------+
Org name = organisation name
Revenue = Total amount received
untransferred amount = transferred_at is null (payments table)
Total members = total members joined till today
last 30 days = total members joined last 30 days
You need to join your tables, group the results and select the desired logic:
SELECT org.name,
SUM(pmt.amount) AS revenue,
SUM(IF(pmt.transferred_at IS NULL, pmt.amount, 0)) AS untransferred
FROM Organisations org
JOIN Members mem ON mem.organisation_id = org.id
JOIN Payments pmt ON pmt.member_id = mem.id
GROUP BY org.id
See it on sqlfiddle.
select o.name,
sum(amount) as Revenue,
sum(if(transferred_at is null, amount, 0)) as untransfered_ammt,
sum(if(join_date>=curdate() - interval 30 day, 1, 0)) as last_30_d
from organisations o
inner join members m on o.id=m.organisation_id
inner join payments p on p.member_id=m.member_id
group by 1

MySQL Select one row with unique attribute value

I'm building a stock keeping system and decided to store each product's balance (everytime it's updated) into the following table:
+------------+--------------+---------+------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+------+
Example:
Staff adds 10 pieces to product_id 123 in warehouse_id 5
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
+------------+--------------+---------+-------------+
Staff then adds 3 pieces to product 234 in warehouse_id 5, and
5 pieces to 123 in warehouse_id 5,
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 15 | 2013-09-21 |
+------------+--------------+---------+-------------+
*Notice the date column
Now let me add a few more rows
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 15 | 2013-09-21 |
| 123 | 5 | 18 | 2013-09-24 |
| 234 | 5 | 10 | 2013-09-26 |
| 123 | 5 | 22 | 2013-09-29 |
+------------+--------------+---------+-------------+
How do i run a query that would get me all products' balances as at 25th of September 2013?
That means i need the following result:
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 18 | 2013-09-24 |
+------------+--------------+---------+-------------+
In short I need the latest row (by date), per product_id.
Any help would be greatly appreciated!
Assuming that products' balances are being maintained per warehouse you can do it like this
SELECT t.product_id, t.warehouse_id, t.balance, t.date
FROM table1 t JOIN
(
SELECT warehouse_id, product_id, MAX(date) date
FROM table1
WHERE date <= '2013-09-25'
GROUP BY warehouse_id, product_id
) q
ON t.warehouse_id = q.warehouse_id
AND t.product_id = q.product_id
AND t.date = q.date
Output:
| PRODUCT_ID | WAREHOUSE_ID | BALANCE | DATE |
|------------|--------------|---------|------------|
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 18 | 2013-09-24 |
Here is SQLFiddle demo
SELECT *
FROM TABLE
WHERE (PRODUCT_ID, DATE) IN
(SELECT PRODUCT_ID, MAX(DATE) FROM TABLE
WHERE DATE <= '2013-09-25'
GROUP BY PRODUCT_ID )
Query:
SQLFIDDLEExample
SELECT *
FROM table1 t
WHERE t.`Date` = (SELECT MAX(t2.`Date`)
FROM Table1 t2
WHERE t2.`Date` <= '2013-09-25'
AND t2.product_id = t.product_id)

Join multiple tables and result multiple records

I have 3 tables with information.
Table1: Orders
+---------+----------------+------------+---------------+
| OrderID | OrderDate | Community | Status |
+-------------------------------------------------------+
1 | 1 march 2013 | S1 | Approved
2 | 5 march 2013 | S2 | Aporoved
3 | 7 march 2013 | Z1 | Approved
+-------------------------------------------------------+
Table2: OrderArtickles
+------------------------------------------------------------------+
|Ordertitem | OrderID | ArtikelID | UnitPrice | Delivered |
+------------------------------------------------------------------+
| 1 | 1 | 20 | 5 | yes
| 2 | 1 | 20 | 5 | yes
| 3 | 2 | 21 | 10 | yes
| 4 | 3 | 30 | 50 | yes
+-------------------------------------------------------------------+
Table3: users
+-----------------------------------------------------+
| Userid | Username | Community | Department |
+-----------------------------------------------------+
| 1 | User1 | S1 | S
| 2 | User2 | S2 | S
| 3 | User3 | Z1 | Z
+-----------------------------------------------------+
I need a MySQL query that give the following output:
+--------------------------------------+
| Department | TotalPriceOfArtikels
+--------------------------------------+
| S | 20
| Z | 50
+--------------------------------------+
I tried with JOIN, SUM, GROUP BY but without result. The problem that I have is that the one order gives multiple articles. Who can help me?
try this
select Department , sum(UnitPrice) as TotalPriceOfArtikels
from users u
inner join Orders o
on o.Community = u.Community
inner join OrderArtickles oa
on oa.OrderId = o.OrderId
group by Department
DEMO HERE
OUTPUT:
Department TotalPriceOfArtikels
S 20
Z 50
Something like this:
select us.Department,
sum ( art.UnitPrice ) as TotalPriceOfArtikels
from user us
left join orders ors
on ( us.Community = ors.Community)
left join OrderArtickles art
on ( ors.OrderID = art.OrderID)
group by us.Department
------------------EDITED------------------------
I copy the same values and structures of your tables in my mysql, and the result is fine, it give me:
Department TotalPriceOfArtikels
S 20
Z 50
Maybe you want to check a condition, like if delivered = yes or status = aprobed??....with this query the result it's the same that you have posted ;)
Saludos ;)