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').
Related
I want to get the previous month date for specific dates in SQL. For example: 6.21.19 has a previous month date of 5.21.19.
I am just trying to get comps from this.
MONTH( curdate() ) -1
I need to return the previous month date.
Welcome to the board Arie. Judging from your question and responses, you need a range of dates and their prior month relations. The easiest way would be for all of the dates you need to look up to be in a table, then the answers provided so far would work. Since that doesn't appear to be the case, I'm guessing you are creating date ranges on the fly.
So lets assume you need exactly the data shown in your example, there are two parts to this, first you need to get a list of days that you want to look up, then you need to get the day in the prior month. There are lots of ways to get a sequence of days, but for simplicity I'll use a recursive CTE. Once I have the date range, I'll just select the dates and their prior month date as well.
with Date_CTE as (select cast('6/1/2019' as datetime) as repDate
union all
select dateadd(day, 1, repdate) as repDate
from Date_CTE
where repDate < '06/07/2019')
select repDate, dateadd(month, -1, repDate) as PriorDate
from Date_CTE
CTEs are helpful functions and you can get more details on them here, but it's worth noting there are many ways to do this. Hope this gets you pointed in the right direction.
SELECT yourDateColumn, yourDateColumn-interval 1 month as prevMonthDate
I have a view that list available dates from an online calendar (basically, I created entries for all available dates and then compare this to the dates that have been booked out - the view then show all dates within 'AvailableDates' where 'Date' <> 'BookedDate'.
So far I can get it to run a list that looks like this....
24th January 2014
7th February 2014
8th February 2014
....but this takes up a lot of space and the idea is that the list can be copied and pasted into an email/message for quick reference.
What I'm looking for is a way to group the dates so that the output looks like this...
Jan - 24th
Feb - 7th, 8th
...so that there is a maximum of 12 lines.
Could somebody tell me how to do this? - the field is a 'date' type.
Thanks,
Darren
You might want to have the year in there, too, or you might get false results.
SELECT
YEAR(your_column) AS the_year,
DATE_FORMAT(your_column, '%b') AS the_month_abbreviated,
GROUP_CONCAT(DATE_FORMAT(your_column, '%D') ORDER BY DAY(your_column) SEPARATOR ', ') AS the_days
FROM your_table
GROUP BY YEAR(your_column), DATE_FORMAT(your_column, '%b')
ORDER BY YEAR(your_column), MONTH(your_column)
you can read more about the DATE_FORMAT() function here.
see it working live in an sqlfiddle
SELECT
MONTH(`d`),
GROUP_CONCAT(DAY(`d`))
FROM
a
GROUP BY
YEAR(`d`),
MONTH(`d`)
SQLFiddle
You have to convert the datecolumn to month and use GROUP_CONCAT(). Maybe this can work or at least in the right direction.
SELECT
LEFT(monthname(datecolumn),3),GROUP_CONCAT(DAY(datecolumn))
FROM table
GROUP BY CONCAT(YEAR(datecolumn),MONTH(datecolumn))
Missed to format the DAY. Now fixed
I need to display 2 columns. First column should have the month name. Second column should show me how many times something was released within each month. e.g:
Month number_of_releases
January 4
March 9
December 2
So far, I have this:
SELECT DISTINCT MONTHNAME(date) AS 'Month',
/*Here is where I need help!*/ AS 'number_of_releases'
FROM table_name;
Without knowing how you are calculating number_of_releases, it's hard to say for certain... but you probably want to group your table by monthname and use a suitable aggregate function to yield the number of releases.
For example, to obtain a count of the number of records within each month:
SELECT MONTHNAME(date) AS Month, COUNT(*) AS number_of_releases
FROM table_name
GROUP BY Month
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
I'm trying to work with a database of unemployment figures from the department of labor statistics' data (available at ftp://ftp.bls.gov/pub/time.series/la/)
I need to get the last 12 months of data for any given state, which is trickier then just selecting all data from the last year as they don't always have the last few months of data in yet (right now, the last month's worth of data is November 2010).
I know which record is the newest, and the date fields I have in the database to work with are:
period_name (month name)
year
period (M01, M02, etc for January, February)
My current SQL, which pulls data from a bunch of JOINed tables, is:
USE unemploymentdata;
SELECT DISTINCT series.series_id, period_name, year, value, series.area_code,
footnote_codes, period_name, measure_text, area_text, area_type_text
FROM state_overview
LEFT JOIN series ON state_overview.series_id=series.series_id
LEFT JOIN footnote ON state_overview.footnote_codes = footnote.footnote_code
LEFT JOIN period ON state_overview.period = period.period
LEFT JOIN measure ON series.measure_code = measure.measure_code
LEFT JOIN area ON series.area_code=area.area_code
LEFT JOIN area_type ON area.area_type_code=area_type.area_type_code
WHERE area_text = 'State Name' AND year > 2009
ORDER BY state_overview.period, measure_text;
Any idea?
Since you have textual values to work with for month and year, you'll need to convert them to MySQL-formatted DATE values and can then let MySQL calculate the last year interval like so:
SELECT ... WHERE STR_TO_DATE(CONCAT(period_name,' 1 ',year),'%M %d %Y') >= DATE_SUB(STR_TO_DATE(CONCAT(most_recent_period_name,' 1 ',most_recent_year),'%M %d %Y'), INTERVAL 1 YEAR) ...;
The CONCAT() function is just building a string like "Month 1 YYYY", and the STR_TO_DATE() function is taking that string and a formatting string to tell it how to parse it, and converting it into a DATE.
Note: This query probably sucks index-wise but it should work. : )
I think a few changes to WHERE clause should do it, but for effeciency/simplcity you should also add MAX(year) to the SELECT section.
SELECT ...... MAX(year) as max_year .....
WHERE area_text = 'State Name'
AND year >= max_year - 1
AND period >= (SELECT MAX(period) WHERE year = max_year)
ORDER BY state_overview.period, measure_text;
You can store the year and month as a date, even though you don't have the day information. Just use the first of each month.
{2009, 'M1'} => 2009-01-01
{2009, 'M2'} => 2009-02-01
{2009, 'M3'} => 2009-03-01
This makes date arithmetic much easier than dealing with substrings of (potentially dirty) data. Plus (and this is big), you can index the data much more effective. As a bonus, you can now extract a lot of extra goodies using DATE_FORMAT such as month names, nr of days in month etc.
Does all states have data for all months, and is the data updated at the same time? The answer to that question dictates what query strategy you should use.
The best way is to take the strtotime ($a) of correct 1 year ago and then, when fetching the value from database then find the strtotime ($b) of the date in each result. Now
if($b < $a){
continue;
}
else {
//do something.
}