GROUP BY continuous months in different years - mysql

I have one table (but at many locations):
DATE STUFF
-------------------
2011-12-01 DATA
2011-12-02 DATA
2011-12-03 DATA
...
2011-12-31 DATA
2012-01-01 DATA
2012-01-02 DATA
My table covers multiple years from 2005 to 2012. I want to get AGGREGATE Function values, i.e., SUM/AVG/MAX/MIN, for each month within each year. Easy:
GROUP BY DATE_FORMAT(DATE, '%Y'), DATE_FORMAT(DATE, '%m')
I want go do the same for 3-month time periods within those years... this works for all but one:
GROUP BY DATE_FORMAT(DATE, '%Y'), DATE_FORMAT(DATE, '%m') IN (12, 01, 02)
My other time periods work, because they are in the same year (03, 04, 05), (06, 07, 08), and (09, 10, 11)... but the GROUP BY above is grouping December of 2012 with January/February of 2012. My time period has to be December 2011 and January/February 2012, December 2010 and January/February 2011... ...
I want to keep this generic, so I don't have to update with date spans, in order to put the code in a stored procedure for multiple locations.
I've tried to join the table to it self by shifting the year ahead by one if MONTH 12. This yielded undesirable results.

GROUP BY floor((month(DATE) + year(DATE) * 12 -1 + %month_shift%) / %month_group_period%)
where %month_group_period% is three (3) in your example
and %month_shift% is one (1) to obtain december, january, february together, and so on
EDIT: this works for 5 month period too (if you want)

I'm assuming a little bit here about what you really want to do with DATE_FORMAT(DATE, '%m') IN (12, 01, 02), but:
SELECT IF(DATE_FORMAT(DATE, '%m') = 12, DATE_FORMAT(DATE, '%Y') + 1, DATE_FORMAT(DATE, '%Y')) AS yr,
CASE DATE_FORMAT(DATE, '%m')
WHEN 12 THEN 1
WHEN 1 THEN 1
WHEN 2 THEN 1
WHEN 3 THEN 2
WHEN 4 THEN 2
WHEN 5 THEN 2
WHEN 6 THEN 3
WHEN 7 THEN 3
WHEN 8 THEN 3
WHEN 9 THEN 4
WHEN 10 THEN 4
WHEN 11 THEN 4
END AS qtr
FROM ...
GROUP BY IF(DATE_FORMAT(DATE, '%m') = 12, DATE_FORMAT(DATE, '%Y') + 1, DATE_FORMAT(DATE, '%Y')),
CASE DATE_FORMAT(DATE, '%m')
WHEN 12 THEN 1
WHEN 1 THEN 1
WHEN 2 THEN 1
WHEN 3 THEN 2
WHEN 4 THEN 2
WHEN 5 THEN 2
WHEN 6 THEN 3
WHEN 7 THEN 3
WHEN 8 THEN 3
WHEN 9 THEN 4
WHEN 10 THEN 4
WHEN 11 THEN 4
END

I don't think you want to use GROUP BY how you are trying to do it. You would probably want to write your queries like this
SELECT MONTH(date) as `month`, SUM(stuff) as `sum`
FROM table
WHERE YEAR(date) IN ('2010', '2011', 2012')
GROUP BY `month`
The GROUP BY clause is not where you should be filtering/formatting your data.
Of course, you could use whatever aggregate function you want instead of SUM. Also you can omit the WHERE clause for all years, or modify the years to be included as needed.
If you want year and month, you could simply modify the query like this:
SELECT YEAR(date) as `year`, MONTH(date) as `month`, SUM(stuff) as `sum`
FROM table
WHERE `year` IN ('2010', '2011', 2012')
GROUP BY `year`, `month`

You need to subtract one month from the date for the group by:
GROUP BY DATE_FORMAT(date_add(DATE, interval 1 month), '%Y'),
DATE_FORMAT(date_add(date, interval 1 month), '%m') IN (12, 01, 02)
You will probably also have to modify the select.
select DATE_FORMAT(date_add(date_add(DATE, interval 1 month), interval -1 month), '%Y'),
DATE_FORMAT(date_add(date_add(date, interval 1 month), interval -1 month), '%m')

I would try something like this:
GROUP BY DATE_FORMAT(IF(MONTH(`DATE`)=12,DATE_ADD(`DATE`,INTERVAL 1 YEAR),`DATE`),'%Y')
, DATE_FORMAT(`DATE`,'%m')
Basically, if month is 12, then add 1 year to it.
Actually, I would tend to do it something like this:
GROUP BY DATE_FORMAT(DATE_ADD(`DATE`,INTERVAL IF(MONTH(`DATE`)=12,1,0) YEAR),'%Y')
, CASE WHEN MONTH(`DATE`) IN (12,1,2) THEN 1
WHEN MONTH(`DATE`) IN (3,4,5) THEN 2
WHEN MONTH(`DATE`) IN (6,7,8) THEN 3
WHEN MONTH(`DATE`) IN (9,10,11) THEN 4
END

Related

Getting total sum of previous 3 month record

I need to get the total sum of the mark of previous 3 months. that is if I look on April I would get the sum of Jan, Feb, Mar. Similarly, When I look on Jan it displays the total of previous year Oct, Nov, Dec. I use the below query
SELECT empid,
name,
sum(total) AS total
FROM formresult
WHERE (MONTH(date) = MONTH(now())
OR MONTH(date) = MONTH(now()- INTERVAL 1 MONTH)
OR MONTH(date) = MONTH(now()- INTERVAL 2 MONTH))
AND YEAR(date) = YEAR(now())
GROUP BY empid
But when using this code I got 3-month result but when I look on Jan it does not display previous year result. How could it possible. Please Help me
Something like the following should do what you need.
SELECT empid, name, SUM(total) AS total
FROM formresult
WHERE date BETWEEN
DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 3 MONTH), '%Y-%m-01') AND
LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))
GROUP BY empid
See DATE_FORMAT(), DATE_SUB(), and LAST_DAY() for more information.
So there are a few issues with the date math that's being done here. First it looks like you are getting the current month and previous two months instead of the previous three months. This is getting you the current month MONTH(date) = MONTH(now()). Also you can't assume it's the current year, if you run this on January you'd expect to get October, November and December of the previous year however it will return for the current year.

Last date in quarter MySQL

I have a table with some dates. I need a query which will return the max (last) date from this table and last date of quarter this max date belongs to.
So for data i table
ID| EDATE
--+----------
1|2014-03-06
2|2014-10-12
this query should return 2014-10-12 and 2014-12-31.
As I understand you want the last day of the quarter, so 31 March, 30 June, 30 Sept, 31 Dec? So you can use the answer from Gordon Linoff and adjust it to do that.
You only need a case statement on month(date) and concat that with the year.
http://dev.mysql.com/doc/refman/5.1/de/control-flow-functions.html
str_to_date(
concat(
year(edate),
(case
when month(edate) in (1, 2, 3) then '-03-31'
when month(edate) in (4, 5, 6) then '-06-30'
when month(edate) in (7, 8, 9) then '-09-30'
else '-12-31'
end)
),
'%Y-%m-%d'
)
Getting the day of the last quarter for the date is a bit yucky, but possible. Here is a sort of brute force solution:
select edate,
str_to_date(concat(year(edate), '-', 1 + floor((month(edate) - 1)/ 3)) * 3, '-',
(case when month(edate) in (1, 2, 3, 10, 11, 12) then 31 else 30 end)),
'%Y-%m-%d'
)
from table t
order by edate desc
limit 1;
Here is a SQL Fiddle that demonstrates it.
You can use LAST_DAY to select the last day of a specific month depending on where your quarters end you may have to change the 3,6,9,12 to different months.
select t1.max_date,
(
case
when month(max_date) <= 3
then last_day(concat(year(max_date),'-3-1'))
when month(max_date) <= 6
then last_day(concat(year(max_date),'-6-1'))
when month(max_date) <= 9
then last_day(concat(year(max_date),'-9-1'))
else last_day(concat(year(max_date),'-12-1'))
end
) last_quarter_day
from (
select max(EDATE) max_date from myTable
) t1
I found the simplest answer:
SELECT MAKEDATE(YEAR(edate),1)
+ INTERVAL QUARTER(edate) QUARTER
- INTERVAL 1 DAY
This query takes the first day of year, adds quarters to it and subtracts 1 day to get the last day in wanted quarter. So the required query should look like:
SELECT MAX(edate),
MAKEDATE(YEAR(MAX(edate)),1)
+ INTERVAL QUARTER(MAX(edate)) QUARTER
- INTERVAL 1 DAY
FROM table

Sql Command to sort data as it is stored

select DISTINCT Month, Code
from SalaryRecord
order by Code ASC
The result is
Feb
Jan
Jan
but I want Jan and Feb arranged by month ascending order
I assume the Month column is a string type (VARCHAR(n)), so it's being ordered as a string - and the ordering is perfectly correct (F comes before J in Western European alphabets) in that case.
Do you have the month as a number in your table, too?
If so, you could order by that numerical value instead:
SELECT DISTINCT
Month, Code
FROM
dbo.SalaryRecord
ORDER BY
NumericalMonth, Code ASC
Or maybe you have a DATE (or DATETIME, DATETIME2 column?) and you could order by that:
SELECT DISTINCT
Month, Code
FROM
dbo.SalaryRecord
ORDER BY
MONTH(YourDateColumn), Code ASC
And if you have nothing at all your can easily sort on - well, then you'll need this big ugly CASE:
SELECT DISTINCT
Month, Code
FROM
dbo.SalaryRecord
ORDER BY
CASE MONTH
WHEN 'Jan' THEN 1
WHEN 'Feb' THEN 2
WHEN 'Mar' THEN 3
WHEN 'Apr' THEN 4
WHEN 'May' THEN 5
WHEN 'Jun' THEN 6
WHEN 'Jul' THEN 7
WHEN 'Aug' THEN 8
WHEN 'Sep' THEN 9
WHEN 'Oct' THEN 10
WHEN 'Nov' THEN 11
WHEN 'Dec' THEN 12
ELSE 999
END
Try this code,
select DISTINCT Month, Code
from SalaryRecord
order by DATEPART(mm,CAST([Month]+ ' 1900' AS DATETIME)) asc

Diplaying records of last month and year

I am having a table in MYSQL in which among other fields i am having two fields one for Month (Varchar) and year (int). Months field is used to store the name of the month and year is used to store the year of the entered data. I am confused that how can use the where class to display only the records of max month and year.
For Example
10 records are there for month January 2013
50 records are there for month February 2013
.
.
.
100 records are there for the month of November 2014 --- (LAST ENTRY)
Now
HERE I want to display only the November 2014 records. My code is written in such a way that i can not use the select query, I have to do it using WHERE CLAUSE
SELECT *
FROM tablename
WHERE
(year, month) = (SELECT year, month
FROM tablename
ORDER BY
STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y') DESC
LIMIT 1)
select count(*), year, month
from your_table
group by year, month
order by year,
case when month = 'January' then 1
when month = 'February' then 2
when month = 'March' then 3
when month = 'April' then 4
when month = 'May' then 5
when month = 'June' then 6
when month = 'July' then 7
when month = 'August' then 8
when month = 'September' then 9
when month = 'October' then 10
when month = 'November' then 11
when month = 'December' then 12
end desc
limit 1
Try This
select Count(*),month,year from tablename
group by STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y') order by
STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y')

Mysql date_sub interval 12 month

I'm trying to get all posts from the 12 last month, group by month. I have a quite correct query:
SELECT MONTH(time) as mois, YEAR(time) as annee, count(*) as nbre
FROM touist_stories
WHERE time >= DATE_SUB(now() + INTERVAL 1 MONTH, INTERVAL 2 YEAR)
group by MONTH(time)
order by YEAR(time) DESC, MONTH(time) DESC
But one month is always missing : november 2012
I tryied to add
+ INTERVAL 1 MONTH
to now() but it still missing... How can I get the 12 last month and not the 11 ones please?
Thanks
To get one year ago, here's a technique I've used in the past. Using #mysql variables, create a date based on the first day of a given month/year (via now()), then subtract 12 months. This example will get from Oct 1, 2012 to current -- which will include current Oct 2013. To exclude that, just add to where clause where I re-added 1 year so it goes from Oct 1, 2012 at 12:00:00 am to LESS THEN Oct 1, 2013 12:00:00.
SELECT
MONTH(time) as mois,
YEAR(time) as annee,
count(*) as nbre
FROM
touist_stories,
( select #lastYear := date_add( DATE_FORMAT(NOW(),
'%Y-%m-01'), interval -11 month) ) sqlvar
WHERE
time >= #lastYear
group by
MONTH(time)
order by
YEAR(time) DESC,
MONTH(time) DESC
Revised to make it go 11 months back (to November per example), and include UP TO AND INCLUDING all Current October activity.
For realy want on year data use 11 MONTH not 12
SELECT time
FROM touist_stories
WHERE time
BETWEEN
date_sub(Now(), INTERVAL 11 MONTH)
AND
Now();