MySQL : weekly and monthly SUM - mysql

The below given is my TOUR table:
tour_id | tour_date | amount
------------------------------
ABC | 2016-03-07 | 100
ABC | 2016-03-15 | 200
DEF | 2016-03-07 | 300
DEF | 2016-03-15 | 100
GHI | 2016-03-07 | 30
I want to get the following:
sum total per week
sum total per month.
This final data must look like this:
tour_id| weekly sum. | monthly sum.
--------------------------------
ABC | 100 | 300
DEF | 300 | 400
GHI | 30 | 30

SELECT
tour_id, WEEKLY, MONTHLY
FROM
TOUR T1
INNER JOIN
(SELECT
tour_id, SUM(amount) WEEKLY
FROM
TOUR
GROUP BY tour_id , WEEK(tour_date)) WEEK ON WEEK.tour_id = T1.tour_id
INNER JOIN
(SELECT
tour_id, SUM(amount) MONTHLY
FROM
TOUR
GROUP BY tour_id , DATE_FORMAT(tour_date, '%m')) MONTH ON WEEK.tour_id = MONTH.tour_id
Try above query.

SELECT WEEK.*
, MONTH.MONTHLY
FROM (SELECT tour_id
, WEEK(tour_date) week
, YEAR(tour_date) year
, SUM(amount) WEEKLY
FROM TOUR
GROUP BY tour_id , WEEK(tour_date), YEAR(tour_date)) WEEK
INNER JOIN (SELECT tour_id
, YEAR(tour_date) year
, MONTH(tour_date) month
, SUM(amount) MONTHLY
FROM TOUR
GROUP BY tour_id , MONTH(tour_date), YEAR(tour_date)) MONTH ON WEEK.tour_id = MONTH.tour_id AND WEEK.year = MONTH.year

Related

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.

How to group by month and return zero if no value for certain month?

This is my mysql income table.
+----+------------------+---------------------------+------------+---------+
| id | title | description | date | amount |
+----+------------------+---------------------------+------------+---------+
| 1 | Vehicle sales up | From new sale up | 2016-09-09 | 9999.99 |
| 2 | Jem 2 Sales | From rathnapura store | 2016-05-15 | 9545.25 |
| 3 | Jem 2 Sales 2 | From rathnapura store | 2016-05-15 | 9545.25 |
| 4 | Jem 2 Sales 2 | From rathnapura store 234 | 2016-05-15 | 9545.25 |
+----+------------------+---------------------------+------------+---------+
The field 'date' is standard sql date. And I executed this query in order to take sum of incomes by month and return zero if no income from a certain month. I want zeros if no income from a certain month because i want to display these data in a chart.
This is the query.
SELECT MONTHNAME(`date`) AS mName, MONTH(`date`) AS mOrder, ifnull(sum(amount),0) AS total_num FROM income GROUP BY mOrder ORDER BY mOrder DESC
But I only get a output like follows. No zeros if no values in other months. This is the output.
+-----------+--------+-----------+
| mName | mOrder | total_num |
+-----------+--------+-----------+
| September | 9 | 9999.99 |
| May | 5 | 28635.75 |
+-----------+--------+-----------+
And I want other months in above table and total_num as zero. How can I do this? There's same kind of question there too. But no working answer.
Group by month and return 0 if data not found
Please help me to solve this issue. The language I use for this application is Node.JS :)
Have a table of all the months and then left join to your table:
SELECT MONTHNAME(m.month) AS mName,
MONTH(m.month) AS mOrder,
ifnull(sum(amount),0) AS total_num
from months m
left join income i
on m.month = i.date
GROUP BY mOrder
ORDER BY mOrder DESC
If you don't want to create a months table then you can:
(select STR_TO_DATE('01/01/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/02/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/03/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/04/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/05/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/06/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/07/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/08/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/09/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/10/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/11/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/12/2016', '%d/%m/%Y') as month)
You should create a CALENDAR table, with the precision you need, in this case months.
+-----------+
| Month |
+-----------+
| January |
| February |
.......
And Join on it
Maybe this it's not the best way to do it, but it will solve your problem. As a quick soution:
SELECT 'January' AS mName, 1 AS mOrder, COALESCE(SUM(amount),0) AS total_num
FROM income i
WHERE month(i.date) = 1
UNION
SELECT 'February' AS mName, 2 AS mOrder, COALESCE(SUM(amount),0) AS total_num
FROM income i
WHERE month(i.date) = 2
UNION
...and go on

MySQL : weekly and monthly average

This is my bill table:
shop_id | billing_date | total
------------------------------
ABC | 2016-03-07 | 100
ABC | 2016-03-14 | 200
DEF | 2016-03-07 | 300
DEF | 2016-03-14 | 100
GHI | 2016-03-07 | 30
I want to get one line per shop, with average total per week, the current month total, and the average total per month. This final data must look like this:
shop | weekly avg. | current month total | monthly avg.
-------------------------------------------------------
ABC | 150 | 300 | 300
DEF | 200 | 500 | 500
GHI | 30 | 30 | 30
My question is: Is it possible to get this informations directly from an SQL query?
Hey you can try this way for current year using WEEK and MONTH of mysql. as per your data entries in table is week wise:
SQLFIDDLE
select shop_id,(sum(total)/(WEEK(MAX(bdate)) - WEEK(MIN(bdate))+1)) as weekly_avg,(sum(total)/(MONTH(MAX(bdate))-MONTH(MIN(bdate))+1)) as mothly_avg, sum( case when MONTH(bdate) = MONTH(NOW()) then total else 0 end) as current_month_total from bill group by shop_id WHERE YEAR(bdate) = 2016
For number of year greater than one
SQL FIDDLE
select shop_id,
sum(total)/(12 * (YEAR(MAX(bdate)) - YEAR(MIN(bdate))) + (MONTH(MAX(bdate)) - MONTH(MIN(bdate)))+1) as month_avg,
sum(total)/(7 * (YEAR(MAX(bdate)) - YEAR(MIN(bdate))) + (WEEK(MAX(bdate)) - WEEK(MIN(bdate)))+1) as weekly_avg,
sum( case when YEAR(bdate) = YEAR(bdate) and MONTH(bdate) = MONTH(NOW()) then total else 0 end) as current_month_total from bill group by shop_id
Is this the sort of thing you are after??:
SELECT DISTINCT(bill.shop_id),wk as WeeklyTotal,mt as MonthlyTotal,ma as MonthlyAverage
FROM bill
JOIN (SELECT AVG(total) wk,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY shop_id) as weekly ON bill.shop_id = weekly.shop_id
JOIN (SELECT SUM(total) mt,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY CONCAT(shop_id,MONTH(billing_date))
) month_total ON month_total.shop_id = bill.shop_id
JOIN (SELECT AVG(total) ma,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY CONCAT(shop_id,MONTH(billing_date))
) month_avg ON month_avg.shop_id = bill.shop_id
You can do this using conditional aggregation and conditional logic:
select shop_id,
sum(total) / (7 * datediff(max(billing_date), min(billing_date)) + 1) as avg_weekly,
sum(case when year(billing_date) = year(now()) and month(billing_date) = month(now()) then total else 0 end) as curr_Month,
(sum(total) /
(year(max(billing_date)) * 12 + month(max(billing_date)) -
year(min(billing_date)) * 12 + month(min(billing_date))
) + 1
)
) as avg_month
total else 0 end) as week_total
from bill
gropu by shop_id;

MySQL get records what have max value

This is my table named period.
id | year | month
222 | 2014 | 2
345 | 2013 | 5
33 | 2014 | 1
224 | 2014 | 2
I want get only id what have latest month (2014-02). Result should be 222, 224.
I wrote following query.
SELECT id, MAX(year*100 + month) FROM period
But it is returning following result.
222| 201402
How can i get my result
SELECT x.*
FROM period x
JOIN
( SELECT year
, month
FROM period
ORDER
BY year DESC
, month DESC
LIMIT 1
) y
ON y.year = x.year
AND y.month = x.month;
You should you the following query:---
SELECT id FROM period where year=(SELECT max(year) from period) and month=(SELECT max(month) from period);

Combine two tables to display desired output

I'm creating a query which will display projected qty versus qty sold on a monthly basis. Below are my two tables and third one is what i want as an output. The two table is almost the same, except that the date and creation date is in different format (i have converted this to output e.g 201301, so no worries about it).
As you have noticed in my output table, qty sold become 25.00 because it adds the qty if the date falls under the same month and year. I also need to consider these three important conditions:
to display rows with projected qty but without sales (ex. item 206)
To display rows without projected qty but with sales (ex. item 312)
to display row with projection and with sales (ex. item001 & 040)
I don't know if i have to used join or union to be able to achieve my desired output.
Table A (Sales Table)
item code Sold date
001 cust001 10.00 2013-01-20
001 cust001 15.00 2013-01-25
040 cust045 16.00 2013-04-07
312 cust001 20.00 2013-03-13
Table B (Projection Table)
item Custcode ProjectedQty Creation Date
001 cust001 20.00 2013-01-01
040 cust045 50.00 2013-04-01
206 cust121 60.00 2013-04-01
Output
item Custcode sold Date ProjectedQty Creation Date
001 cust001 25.00 201301 20.00 201301
312 cust001 20.00 201303 null null
040 cust045 16.00 201304 50.00 201304
206 cust121 null null 60.00 201304
Thanks guys for helping.
Try
SELECT COALESCE(p.item, s.item) item,
COALESCE(p.code, s.code) code,
sold,
CONCAT(s.year, LPAD(s.month, 2, '0')) date,
ProjectedQty,
CONCAT(p.year, LPAD(p.month, 2, '0')) creationdate
FROM
(
SELECT item, code, YEAR(`date`) year, MONTH(`date`) month
FROM sales
UNION
SELECT item, custcode, YEAR(`creationdate`), MONTH(`creationdate`)
FROM projection
) i LEFT JOIN
(
SELECT item, code, SUM(sold) sold, YEAR(`date`) year, MONTH(`date`) month
FROM sales
GROUP BY item, code, YEAR(`date`), MONTH(`date`)
) s ON i.item = s.item
AND i.code = s.code
AND i.year = s.year
AND i.month = s.month LEFT JOIN
(
SELECT item, custcode code, SUM(ProjectedQty) ProjectedQty, YEAR(`creationdate`) year, MONTH(`creationdate`) month
FROM projection
GROUP BY item, custcode, YEAR(`creationdate`), MONTH(`creationdate`)
) p ON i.item = p.item
AND i.code = p.code
AND i.year = p.year
AND i.month = p.month
ORDER BY code, item
Output:
| ITEM | CODE | SOLD | DATE | PROJECTEDQTY | CREATIONDATE |
------------------------------------------------------------------
| 001 | cust001 | 25 | 201301 | 20 | 201301 |
| 312 | cust001 | 20 | 201303 | (null) | (null) |
| 040 | cust045 | 16 | 201304 | 50 | 201304 |
| 206 | cust121 | (null) | (null) | 60 | 201304 |
SQLFiddle
Why not use a simple join for this?
SELECT * FROM `sales`, `projection` WHERE `code`=`custcode`;
Make a view of the query above, and using WHERE clause, you can alter the data.
Create a view using union. and then you can use the below query:
select *, sum(sold) as sold from view group by item
another is:
select *, sum(sold) from (
select item, code as Custcode, sold, date, 'ProjectedQty' as ProjectedQty, 'Creation Date' as Creation Date from table 1 union select item, Custcode, sold, Date, ProjectedQty, Creation Date, from table 2) group by item