148

Given a table with a timestamp on each row, how would you format the query to fit into this specific json object format.

I am trying to organize a json object into years / months.

json to base the query off:

{ "2009":["August","July","September"], "2010":["January", "February", "October"] } 

Here is the query I have so far -

SELECT MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year FROM trading_summary t GROUP BY MONTH(t.summaryDateTime) DESC"; 

The query is breaking down because it is (predictably) lumping together the different years.

14 Answers 14

259
GROUP BY YEAR(t.summaryDateTime), MONTH(t.summaryDateTime); 

is what you want.

Sign up to request clarification or add additional context in comments.

4 Comments

+1: Another alternative using DATE_FORMAT: DATE_FORMAT(t.summaryDateTime, '%Y-%m')
Further on this, FROM_UNIXTIME is needed if you have a UNIX timestamp in your DB DATE_FORMAT( FROM_UNIXTIME(t.summaryDateTime), '%Y-%m' )
Thanks @OMGPonies , with your syntax I'm able to perform conditional GROUP BY.
Performance... my test of GROUP BY YEAR(date), MONTH(date) DESC; (~450 ms) and GROUP BY DATE_FORMAT(date,'%Y-%m') (~850 ms) on a InnoDB table with > 300,000 entries showed the former (the marked answer to this question) took ~half the time as the latter.
104
GROUP BY DATE_FORMAT(summaryDateTime,'%Y-%m') 

2 Comments

Welcome to StackOverflow! This is an old and already answered question. We'll be happy if you could contribute to more pressing questions too. You can find tips on to provide good answers here.
See my comment on the answer above... On large-ish tables this method takes twice as long.
17

I prefer

SELECT MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year FROM trading_summary t GROUP BY EXTRACT(YEAR_MONTH FROM t.summaryDateTime); 

Comments

15

I know this is an old question, but the following should work if you don't need the month name at the DB level:

 SELECT EXTRACT(YEAR_MONTH FROM summaryDateTime) summary_year_month FROM trading_summary GROUP BY summary_year_month; 

See EXTRACT function docs

You will probably find this to be better performing.. and if you are building a JSON object in the application layer, you can do the formatting/ordering as you run through the results.

N.B. I wasn't aware you could add DESC to a GROUP BY clause in MySQL, perhaps you are missing an ORDER BY clause:

 SELECT EXTRACT(YEAR_MONTH FROM summaryDateTime) summary_year_month FROM trading_summary GROUP BY summary_year_month ORDER BY summary_year_month DESC; 

4 Comments

please note that the output from EXTRACT(YEAR_MONTH FROM summaryDateTime) is 201901
@EdgarOrtega Yep, but that should be enough to generate the desired JSON object in the original question using application logic. Assuming that some form of looping over the query result is already happening, my approach aims to get the minimum required information from the DB as simply and quickly as possible
You're right, that should be enough. My comment was only to indicate what the output from that function is like, maybe someone does not like that format.
@EdgarOrtega No worries, thanks, a worthy contribution!
10
SELECT MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year FROM trading_summary t GROUP BY YEAR(t.summaryDateTime) DESC, MONTH(t.summaryDateTime) DESC 

Should use DESC for both YEAR and Month to get correct order.

Comments

4

You must do something like this

SELECT onDay, id, sum(pxLow)/count(*),sum(pxLow),count(`*`), CONCAT(YEAR(onDay),"-",MONTH(onDay)) as sdate FROM ... where stockParent_id =16120 group by sdate order by onDay 

Comments

4

This is how I do it:

GROUP BY EXTRACT(YEAR_MONTH FROM t.summaryDateTime); 

Comments

3

use EXTRACT function like this

mysql> SELECT EXTRACT(YEAR FROM '2009-07-02'); -> 2009 

Comments

3

You cal also do this

SELECT SUM(amnt) `value`,DATE_FORMAT(dtrg,'%m-%y') AS label FROM rentpay GROUP BY YEAR(dtrg) DESC, MONTH(dtrg) DESC LIMIT 12 

to order by year and month. Lets say you want to order from this year and this month all the way back to 12 month

Comments

2

You are grouping by month only, you have to add YEAR() to the group by

Comments

0
SELECT YEAR(t.summaryDateTime) as yr, GROUP_CONCAT(MONTHNAME(t.summaryDateTime)) AS month FROM trading_summary t GROUP BY yr 

Still you would need to process it in external script to get exactly the structure you're looking for.

For example use PHP's explode to create an array from list of month names and then use json_encode()

Comments

0

As this data is being pulled for a trade summary by month, I had to do the same thing and would just like to add the code I use. The data I have is saved in the database as a string so your query may be simpler. Either way, as a trader, this is in essence what most people would be looking for:

select DATE(DATE_FORMAT(STR_TO_DATE(closeDate, '%Y-%m-%d'), '%Y-%m-01')) AS month_beginning, COUNT(*) AS trades, TRUNCATE(sum(profitLoss)/count(*),2) as 'avgProfit', TRUNCATE(sum(percentGain)/count(*),2) as 'avgPercent', sum(profitLoss) as 'gi', sum(profitLoss > 0)/count(*) AS winPercent, sum(profitLoss < 0)/count(*) as 'lossPercent', max(profitLoss) as bigWinner, min(profitLoss) as bigLoser from tradeHistory group by month_beginning order by month_beginning DESC 

However, it will skip months that are missing in your data. So if there is no data for Jan, there won't be a row.

Comments

-1

I would like add difference between group by year(datetime),month(datetime) and groupb by extract(year_month from datetime). here is the query i tried with these two cases.

select year(datetimecol) as Year,monthname(datetimecol) as Month from table
group by year(datetimecol) and month(datetimecol) order by year(datetimecol) desc;

result:

Year, Month

2020, May

select year( datetimecol) as Year,monthname(datetimecol) as Month from table GROUP BY EXTRACT(YEAR_MONTH FROM datetimecol) order by year(datetimecol) desc,month(datetimecol) asc;

result:

Year, Month

2021, January 2021, February 2021, March 2021, April 2021, May 2020, May 2020, June 2020, July 2020, August 2020, September 2020, October 2020, November 2020, December

(this is the result i need)

My observation 1.when i am using with group by year(datetimecol),month(datetimecol) , not giving desired result ..might be because of datetime feild... 2.when i tired second query with GROUP BY EXTRACT(YEAR_MONTH FROM datetimecol) order by year(datetimecol)...its working absolutely fine.

in conclusion, for getting months by year wise use the following query.

select year( datetimecol) as Year,monthname(datetimecol) as Month from table GROUP BY EXTRACT(YEAR_MONTH FROM datetimecol) order by year(datetimecol) desc,month(datetimecol) asc;

2 Comments

If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review
i tried this context and given my observation.i didnt give without tested.
-3

Use

GROUP BY year, month DESC"; 

Instead of

GROUP BY MONTH(t.summaryDateTime) DESC"; 

1 Comment

although it appears that GROUP BY MONTH(t.summaryDateTime) DESC doesn't order the months properly for some reason...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.