I am trying to parse a date together for the previous fiscal year. The fiscal year start month is stored in our database as FiscalYearStartMonth.
This is what I had, but it doesn't work.
CONVERT(varchar,dateadd(year,0,CONVERT(varchar,Year(GetDate())+ FiscalYearStartMonth + '01',106)))
Any suggestions?
This will give you the start of your fiscal year in the current year
SELECT CONCAT(YEAR(NOW()), '-', FiscalYearStartMonth, '-01');
If you want to find the date in the past, I'm afraid my answer is a bit complicated. I'm sure there is a better solution:
SELECT date
FROM (
SELECT CONCAT(YEAR(NOW()), '-', FiscalYearStartMonth, '-01') AS date
UNION ALL SELECT CONCAT(YEAR(NOW()) - 1, '-', FiscalYearStartMonth, '-01')
) AS dates
WHERE date < NOW()
ORDER BY date DESC
LIMIT 1;
Related
I have table months:
id name
=============
1 January
2 February
3 March
.. ........
I have the year stored in a variable:
SET #year = YEAR(CURDATE());
I now want 2 new columns: start_date and end_date - both of these columns will contain the start date and end date of the month based on the id and #year variable. This will be in the standard MySQL date column format. Currently I have this:
CONCAT(#year, '-', LPAD(months.id, 2, '0'), '-', '01') AS start_date,
CONCAT(#year, '-', LPAD(months.id, 2, '0'), '-', '31') AS end_date
This does work but is there a better/cleaner way? Is there a way to automatically get the actual last day of the month?
You can get the first day of the year using date() and strings. The rest can be done using date functions and operators:
select m.*,
date(concat(year(curdate()), '-01-01')) + interval (id - 1) month as month_start,
last_day(date(concat(year(curdate()), '-01-01')) + interval (id - 1) month) as month_end
from months m;
Here is a small db<>fiddle.
I am looking at getting certain data from our user sign-ups. We have data from 2013 up to now, but I need data from the last six months of how many users have signed up each month.
I don't know where to begin with starting the SQL query as what I have done so far is all wrong and doesn't come up with what I need.
I have a c_date (CURRENT_TIMESTAMP) column with the dates the user signed up.
All I have managed to do is get the data for a single month
SELECT
COUNT(c_date) AS total
FROM
accounts
WHERE
c_date BETWEEN '2017-05-01 00:00:00' AND '2017-05-31 23:59:59'
I am using MySQL
Depending on your SQL flavor, I would suggest using the current_date SQL keyword and the interval datatype:
where c_date >= current_date - interval '180 day'
I don't know what system you're using but here is how you might do it in SQL Server. This sums up the counts by month and year
select datepart(month, c_date) as month, datepart(year, c_date) as year, count(*)as total
from accounts
where c_date > dateadd(month, -6, getdate())
group by datepart(month, c_date), datepart(year, c_date)
order by month desc
You want to aggregate the data. Something like this:
SELECT YEAR(c_date) as yyyy, MONTH(c_date) as mm, COUNT(*) AS total
FROM accounts a
WHERE c_date >= (CURDATE() - INTERVAL (1 - DAY(CURDATE())) )- INTERVAL 6 MONTH
GROUP BY yyyy, mm;
The WHERE clause calculates the first day of the month starting six months ago.
I have the following columns in my table Log:
year, month, day, info
I need a query that selects the rows in a range of date determined by the user. The user will select the initial day, month and year and also the final day, month and year. At the moment, my query is:
SELECT
CONCAT(LPAD(`day`,2, 0),'/',LPAD(`month`,2, 0),'/',`year`) AS data,
info
FROM
Log
WHERE
(year > :initial_year OR (year = :initial_year AND month >= :initial_moth AND day >= :initial_day))
AND (year < :final_year OR (year = :final_year AND month <= :final_month AND day <= :final_day))
GROUP BY
year, month, day
ORDER BY
year DESC, month DESC, day DESC
But this query doesn't display any results, even that they are in the database! What is wrong and how can I fix it?
Your logic is wrong:
WHERE (
year > :initial_year OR (
year = :initial_year AND month >= :initial_moth AND day >= :initial_day
)
)
Will exclude any dates in your initial year where the day portion is greater than the initial day portion. e.g. yyyy-01-31 as the initial day will exclude all results for yyyy where the day portion is not 31.
Similar problems exist with the final date.
As suggested in the comments, use one DATE field in your database and do the other fiddling in your application code; it will save a lot of drama.
If you can't change the database, find and berate the person who designed it until they change it. If you can't do that then:
WHERE (year>:initial_year OR (year=:initial_year AND (month>:initial_month OR (month=:initial_month AND day>=:initial_day))))
and similar for the final date
What about:
select
concat(year,month,day) as thedate, info
from
log
where
thedate >= :startdate and thedate <= :enddate
order by
thedate desc;
I have a table with a year and month in different columns, and I need to find all rows between 3 months ago and now.
SELECT * FROM `table`
WHERE DATE(CONCAT(`year`, '-', `month`, '-01')) >=
DATE_FORMAT(NOW() - INTERVAL 3 MONTH, '%Y-%m-01')
It just seems rather verbose, and possibly inefficient as this is a very large table. Is there a better way to do this?
There isn't much optimization to be had when the date is stored as separate fields, but I would re-write your query as:
SELECT *
FROM `table`
WHERE STR_TO_DATE(`year`+ '-'+ `month` + '-01', '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 3 MONTH)
The concatenation renders indexing on the year and month columns useless.
For more info about MySQL date functions, see: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
Well, I had the same issue and I have figured what I think is the solution for this case.
SELECT *
FROM table
WHERE (month >= (month(curdate()) - 3 AND year >= year(curdate()))
AND (month >= month(curdate()) AND year >= year(curdate())))
Supposing you have columns named year and month.
I have two columns in a MySQL table:
DateOfService (datetime)
BirthDate (date)
I want to run a MySQL query that will provide date difference between these two fields in months.
How can I do this in a MySQL select query?
Thanks.
Have a look at the TIMESTAMPDIFF() function in MySQL.
What this allows you to do is pass in two TIMESTAMP or DATETIME values (or even DATE as MySQL will auto-convert) as well as the unit of time you want to base your difference on.
You can specify MONTH as the unit in the first parameter:
SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-04')
-- 0
SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-05')
-- 1
SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-15')
-- 1
SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-12-16')
-- 7
It basically gets the number of months elapsed from the first date in the parameter list. This solution accounts for the varying amount of days in each month (28,30,31) as well as leap years.
If you want decimal precision in the number of months elapsed, it's a little more complicated, but here is how you can do it:
SELECT
TIMESTAMPDIFF(MONTH, startdate, enddate) +
DATEDIFF(
enddate,
startdate + INTERVAL
TIMESTAMPDIFF(MONTH, startdate, enddate)
MONTH
) /
DATEDIFF(
startdate + INTERVAL
TIMESTAMPDIFF(MONTH, startdate, enddate) + 1
MONTH,
startdate + INTERVAL
TIMESTAMPDIFF(MONTH, startdate, enddate)
MONTH
)
Where startdate and enddate are your date parameters, whether it be from two date columns in a table or as input parameters from a script:
Examples:
With startdate = '2012-05-05' AND enddate = '2012-05-27':
-- Outputs: 0.7097
With startdate = '2012-05-05' AND enddate = '2012-06-13':
-- Outputs: 1.2667
With startdate = '2012-02-27' AND enddate = '2012-06-02':
-- Outputs: 3.1935
This could work:
SELECT 12 * (YEAR(DateOfService)
- YEAR(BirthDate))
+ (MONTH(DateOfService)
- MONTH(BirthDate)) AS months
FROM table
Try this:
SELECT DATEDIFF(DateOfService, BirthDate) / 30 as months FROM ...
TRY with
PERIOD_DIFF(P1,P2)
Returns the number of months between periods P1 and P2. P1 and P2 should be in the format YYMM or YYYYMM. Note that the period arguments P1 and P2 are not date values.
mysql> SELECT PERIOD_DIFF(200802,200703);
-> 11
TIMESTAMPDIFF(MONTH, Start_date, End_date)
Example:
SELECT TIMESTAMPDIFF(MONTH, BirthDate, DateOfService) AS Months FROM Table
Based on a summary of all answers and a Google search, I think there are four almost similar ways to write it:
1)
TIMESTAMPDIFF(MONTH, Start_date, End_date) AS Period
E.g.
TIMESTAMPDIFF(MONTH, MIN(r.rental_date), MAX(r.rental_date)) AS Period
2)
PERIOD_DIFF(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months
Or
PERIOD_DIFF(date_format(End_date(), '%Y%m'), date_format(Start_date, '%Y%m')) as months
E.g.
PERIOD_DIFF(date_format(MAX(r.rental_date), '%Y%m'), date_format(MIN(r.rental_date), '%Y%m')) as months
3)
PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months
OR
PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM End_date()), EXTRACT(YEAR_MONTH FROM Start_date)) AS months
E.g.
PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM MAX(r.rental_date)), EXTRACT(YEAR_MONTH FROM MIN(r.rental_date))) as Months
4)
PERIOD_DIFF(concat(year(d1),if(month(d1)<10,'0',''),month(d1)), concat(year(d2),if(month(d2)<10,'0',''),month(d2))) as Months**
E.g.
PERIOD_DIFF(
concat(year(MAX(r.rental_date)),if(month(MAX(r.rental_date))<10,'0',''),month(MAX(r.rental_date))),
concat(year(MIN(r.rental_date)),if(month(MIN(r.rental_date))<10,'0',''),month(MIN(r.rental_date)))
) as Months
The 'right' answer depends on exactly what you need. I like to round to the closest whole number.
Consider these examples:
1st January -> 31st January: It's 0 whole months, and almost 1 month long.
1st January -> 1st February? It's 1 whole month, and exactly 1 month long.
To get the number of whole months, use:
SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-01-31'); => 0
SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-02-01'); => 1
To get a rounded duration in months, you could use:
SELECT ROUND(TIMESTAMPDIFF(DAY, '2018-01-01', '2018-01-31')*12/365.24); => 1
SELECT ROUND(TIMESTAMPDIFF(DAY, '2018-01-01', '2018-01-31')*12/365.24); => 1
This is accurate to +/- 5 days and for ranges over 1000 years. Zane's answer is obviously more accurate, but it's too verbose for my liking.