Group records by both month and year in Rails - mysql

I'm on Ruby 1.9.2, Rails 3.0.x and I use MySQL DB. I have a Messages Model, where one can post new messages every day.
I have an index action where I want to display these messages grouped by both month and year. This basically is used to filter messages.
My query looks like this:-
#active_msgs = Messages.where('expiry > ?', Time.now).order('created_at DESC')
I used the group_by function in Rails, after referring to this post
My Group By Query is:-
#msgs_by_month = #active_msgs.all.group_by {|u| u.created_at.month }
I was returned a Hash called #msgs_by_month. This helped me group the messages by month, but I need to taken into account the year, to form a unique key , as it would help me differentiate between for e.g., Sept 2011 and Sept 2012.
My current key only is of type Hash[Month] ( e.g. Hash[9] => for month of September, I can display all appropriate values ). How can i get a unique key of type month, year which I can easily loop though to display all records grouped by Month and Year of creation.
Thank you
EDIT:-
I'm guessing one way to do this, is to make use the created_at.to_date api, provided here
. I only wonder, how I can strip out the day from created_at.to_date to get a unique month and year combination key which could work with the group_by function.

In SQL:
select * from messages group by year(created_at), month(created_at);
In Rails:
Message.all.group_by { |m| m.created_at.beginning_of_month }

Use Group Date.
It supports time zones, so if you ever need to - the code will easily evolve.
https://github.com/ankane/groupdate

Message.select("date_trunc('month', created_at) as month").group("month")

To group by year and by month (e.g. not having december 2020 with december 2021):
Message.group("date_trunc('year', created_at), date_trunc('month', created_at)")
Tested on PostgreSQL

ModelName.all.group_by { |m| m.created_at.month }
This will work, however month will be returned as the index.
Ex. Nov would refer to 11

Related

Laravel/Eloquent: Making archive list for posts (year, month)

I'm trying to create an archive list for a blog. I want something like this:
2020
January (3)
February (2)
2019
January (10)
February (23)
So far I've managed to get the posts sorted out in an array showing the count, however the array has each month as an array alone. I'd like it to be nested so that the year is the parent array and then each month is nested.
$posts_by_date = $blog->hasMany(Post::class)
->where('status', 'published')
->selectRaw('year(created_at) year, month(created_at) month, count(*) count')
->groupBy('year', 'month')
->orderByRaw('created_at') desc')
->get()
->toArray();
Is there a way to make the group by nested instead of separate? I know I can modify the results after, I just think it will be cleaner if I get this directly from the query.
You can use Collection::groupBy which will group the elements by each value of the field specified, and so you will have a subarray for each year with inside the records that belongs to that year.
You just need to first collect() what you get in order to create a Collection, and then call ->groupBy('year').

Simple reports in rails -- from_date to to_date

So basically, I want to create reports for my Attendance Records Table.
Table has :user_id, :clock_in, :clock_out, :seconds columns that are being updated.
Basically my report needs: to calculate (sum of :seconds) for a given period.
I.e. Jan 1, 2014 to Jan 31, 2014 ... I would like to list all records from this daterange, and in the end would calculate sum of :seconds.
Any ideas how would I approach this?
Your question is very general, please, before question try to do some work and come with technical questions.
Tips
Your question is related about SQL, basically you need to perform a select query
select * from your_table where date <= your_date and date >= your_date
Need help on mysql date range query
In rails, where clauses are build by ActiveRecord
YourModel.where('date <= ? and date >= ?', your_date. your_date)
Rails where date is greater than given date query
If you need something more advanced, use Ransack
http://railscasts.com/episodes/370-ransack
Hope I can help you ;)

How can I group data by month, day and hour in mysql?

I have a mysql database that looks like this:
id | userid | timestamp | activity
Timestamp is a datetime data type, I need to get the data grouped by month, day and hour. I am using mysql and php for my scripts.
I am able to do it by month and day with the following query:
$query = "SELECT COUNT(id) as totals FROM security_transactions WHERE YEAR(timestamp) = 2012 GROUP BY MONTH(timestamp), DAY(timestamp)";
I need to do it by month day and hours.
Please help.
Thanks.
You can add , HOUR(TIME(timestamp)) to your group by query providing your column is of DATETIME format
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_hour
Also, from the error messages put in the comments below, it looks like #Aprentice is not using mysql, but I've improved this answer for others looking for mysql.
I have never used mssql, so I can't test this but the following might work to group by nearest hour:
GROUP BY dateadd(hour, datediff(hour, 0, timestamp, 0)
Just take it one step further and use HOUR() as well. You will first need to extract the time portion of the timestamp. But guess what, there is a function for that as well ;)

mysql getting all possible months from datetime field

so i have a table with hundreds records. And a have a filed name "created" type with a datetime format. Now I want to make and archive with the months. For example January, February.... etc. I need to create query to find all possible months. For example if my records start from 2011/05/01 to now I will need to fetch the months that means months 5,6,7,8,9,10,11,12.
Is there a way to that ???
If you are looking at the list of all Months present in the created field (as I understand your query) then do this:
SELECT DISTINCT(MONTH(created)) FROM posts;
The resulting set would be the list of unique months in the field. If this will complain then try:
SELECT DISTINCT(MONTH(DATE(created))) FROM posts;
You can then substitute MONTH for MONTHNAME and get names instead. I did not add the WHERE clause to these queries but you can limit the dataset you are looking at as you see fit.
For more information take a look at http://dev.mysql.com/doc/refman/5.1/en/functions.html this has a list of quite a few functions that MySQL natively provides.
Yes, use the DATE_FORMAT function and other date and time functions.
More details here
For example, if you want all your records for December 2011:
SELECT * FROM posts WHERE YEAR(created) = 2011 AND MONTH(created) = 12

Retrieving Dates in MySql regardless of Years

I have dates stored in my MySQL database . (ex.: 1992-12-12 , 1983-01-02 , 1983-01-05 , 1983-01-10 )
I want to compare these dates only on Date & Month basis regardless of the years .
Also, i want to retrieve records having date between 2nd January and 5th January , whatever the Year be.
How do i do this?
Please help with the MySQL query.
This request should do what you are looking for. But this will not work perfectly after february because of the 29th
SELECT date
FROM ...
WHERE DAYOFYEAR(date) BETWEEN DAYOFYEAR('2011-01-02') AND DAYOFYEAR('2011-01-05');
First create a function to extract only the day and month part of the date(I have written to the best of my knowledge, there may be a more optimized way than this):
CREATE FUNCTION daymonth (date DATE)
RETURNS DATE
RETURN STR_TO_DATE(CONCAT(CONCAT((EXTRACT(MONTH FROM date)),'-'),(EXTRACT(DAY FROM date))),'%m-%d');
Then call the function in your query:
SELECT date
FROM ...
WHERE daymonth(date) BETWEEN daymonth('2011-01-02') AND daymonth('2011-01-05');
I would love to further discuss on this issue. :)
-Sandip