I have a date field in my MySQL table and I want to get all rows before the next 1st Of December. So for example the rows I should get back if I run the query today (Nov 2015) would be any date before 1st Dec 2015. If I run the query after 1st Dec 2015 but before 1st December 2016, it should return all rows with a date of before 1st Dec 2016.
Sorry for lack of code, I have literally no idea where to start with this one!
I create the limit date based on the current month (using now() to get the current date). If the current month is 12, then the limit is 1-12 of next year (year(now()+1), otherwise the current year.
select YourDate
from YourTable
where YourDate <
case when month(now())=12 then
date(concat(convert(year(now()+1), char), '-12-01'))
else
date( concat(convert(year(now()), char), '-12-01'))
end;
I think you should use something like this:
SELECT *
FROM Table T
WHERE Some_Date < CASE
WHEN MONTH(CURDATE()) < 12 THEN STR_TO_DATE('01, 12, ' + YEAR(CURDATE())),'%d,%m,%Y')
ELSE STR_TO_DATE('01, 12, ' + YEAR(CURDATE() + 1)),'%d,%m,%Y')
END
Disclaimer: I dont have mysql, so I couldn't test it.
I did manage my own solution too
SELECT *
FROM table
WHERE date < DATE_ADD( MAKEDATE( IF( MONTH( CURRENT_DATE() ) < 12, YEAR( CURRENT_DATE() ), YEAR( CURRENT_DATE() + INTERVAL 1 YEAR ) ), 1), INTERVAL + 11 MONTH )
Related
I have a list of periods during a year, and they are the same every year. You can think of it as a Season. They have a startDate and a endDate.
Because there can be Seasons that leap each other, what I need to to is query all the matching Seasons given a date, no matter what year.
As an example:
Season1: from 1st of January to 10th of January
Season2: from 6th of January to 8th of January
Season3: from 11th of January to 20th of January
Given the date 7th of January, I'd need to retrieve the Season1 and Season2.
I've tried converting all dates to the same year, but It doesn't work when the Start Date of a season in "later" than the End Date (for example, there's a period starting on November and ending of February).
Thanks in advance for the help.
Edit, sample data:
StartDate EndDate SeasonId
2000-08-01 2000-08-31 4
2000-12-29 2000-01-02 3
2000-06-01 2000-07-30 3
2000-09-01 2000-09-30 3
2000-01-06 2000-01-08 3
2000-04-07 2000-04-17 3
2000-04-28 2000-05-01 3
2000-06-02 2000-06-05 3
2000-06-23 2000-06-25 3
2000-09-08 2000-09-11 3
2000-09-22 2000-09-25 3
2000-10-12 2000-10-15 3
2000-11-01 2000-11-05 3
2000-12-01 2000-12-10 3
2000-12-22 2000-12-26 3
2000-03-01 2000-05-31 2
2000-10-01 2000-10-31 2
2000-11-01 2000-02-28 1
And I'd need, for example, the season for the date 2000-02-08, and retrieve seasonId = 1, or the date 2000-10-13and retrive seasonId = 3, seasonId = 2
I would do it in 2 'options': (the following SQL assumes you already got rid of the year in the table, and left only month-date format. )
select ... from seasons s where
(s.startDate <= s.endDate and s.startDate <= #mydate and s.endDate >= #mydate) or
(s.startDate > s.endDate and s.startDate >= #mydate and s.endDate <= #mydate)
You could query like this for the Season1:
select * from myTable where (month(myDate) = 1 and DAY(myDate) between 1 and 10)
If you have a season in more than one month, like start date January 20th, and finish date Febrery 10th, you could query this way:
select * from myTable where (month(myDate) = 1 and DAY(myDate) >= 20) or (month(myDate) = 2 and DAY(myDate) <= 10)
UPDATED WITH YOUR UPDATE
It is a little bit tricky, but it should work...
select * from seasons_table
where cast(cast(day(myDate) as char) + '/' + cast(month(myDate) as char) + '/' + '2000' as date) between
cast(cast(day(StartDate) as char) + '/' + cast(month(StartDate) as char) + '/' + '2000' as date) and
cast(cast(day(EndDate) as char) + '/' + cast(month(EndDate) as char) + '/' + '2000' as date)
given tblSeason with columns Id, startdate, enddate and your date as #myDate you would query as
Select Id From tblSeason WHERE #myDate BETWEEN startdate AND enddate
would give list of Id's of the seasons that match.
if you can't work from that, please give more information in your examples as to the structure you are querying and the expected outcome.
*Edit to ignore the year part you could do similar to
Declare #myDate datetime = '2016-10-13'
SELECT [StartDate]
,[EndDate]
,[SeasonId]
FROM [dbo].[Table_1]
where DATEPART(dy, #myDate) >= DATEPART(dy,StartDate)
AND (DATEPART(dy,#myDate) =< DATEPART(dy,EndDate) OR DATEPART(dy,StartDate) > DATEPART(dy,EndDate))
Why are you including the year in the table? That seems strange.
In any case, you only care about the MM-DD format, so use date_format() to convert the values to strings:
select t.*
from t
where (start_date <= end_date and
date_format(#date, '%m-%d') >= date_format(start_date, '%m-%d') and
date_format(#date, '%m-%d') <= date_format(end_date, '%m-%d')
) or
(start_date > end_date and
date_format(#date, '%m-%d') <= date_format(start_date, '%m-%d') and
date_format(#date, '%m-%d') >= date_format(end_date, '%m-%d')
);
The strings are fine for comparison, because you are only looking at the month and day components of the date.
Given the nature of your problem, I would recommend that you store start_date and end_date in a non-date format, such as MM-DD.
I am trying to select every record between current month and the next 2 months but I am not able to because the year will be changing from 2016 to 2017.
For ex.
I want to get all the records from November 2016 to January 2017.
The current query (shown below) i have has worked fine until this month because November 2016 + 2 months = Jan 2017.
select * from dateTable
where month(t2.`END_DATE`) between month(curdate()) and
month(DATE_ADD(curdate(), INTERVAL 2 MONTH))
and year(t2.`END_DATE`) = year(curdate());
This returns 0 rows because this cannot handle having two years, 2016 and 2017.
How would I go about doing this?
This should be what you need, although there are probably a number of ways of doing this
select * from dateTable
where `END_DATE` BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01')
AND LAST_DAY(DATE_ADD(NOW(), INTERVAL 2 MONTH))
The result of this query will demonstrate the dates being generated
SELECT DATE_FORMAT(NOW() ,'%Y-%m-01') as from_date,
LAST_DAY(DATE_ADD(NOW(), INTERVAL 2 MONTH)) as to_date
Today this will generate
from_date to_date
2016-11-01 2017-01-31
Try to use full datetime with DATE_ADD and DATE_DIFF functions.
select * from dateTable where t2.`END_DATE`
between DATEADD(month,
DATEDIFF(month, 0, getdate() -- get difference to first day
), 0)
and DATEADD(month, 2, -- add 3 months interval to get first day of third
DATEADD(month,
DATEDIFF(month, 0, getdate() -- get difference to first day
), 0))
If you have to remove the first day from last month use DATEADD again and remove 1 second to get 23:59:59
I need to query data with count and sum by multiple date ranges and I am looking for a faster query than what I am doing now.
I have a transaction table with a date and amount. I need to present a table with a count of transactions and total amount by date ranges of today, yesterday, this week, last week, this month, last month. Currently I am doing sub queries, is there a better way?
select
(select count(date) from transactions where date between ({{today}})) as count_today,
(select sum(amount) from transactions where date between ({{today}})) as amount_today,
(select count(date) from transactions where date between ({{yesterday}})) as count_yesterday,
(select sum(amount) from transactions where date between ({{yesterday}})) as amount_yesterday,
(select count(date) from transactions where date between ({{thisweek}})) as count_thisweek,
(select sum(amount) from transactions where date between ({{thisweek}})) as amount_thisweek,
etc...
Is there a better way?
although you have a marked solution, I have another that will probably simplify your query even further using MySQL variables so you don't have to mis-type / calculate dates and such...
Instead of declaring variables up front, you can do them inline as a select statement, then use them as if they were columns in another table. Since it is created as a single row, there is no Cartesian result. First the query, then I'll describe the computations on it.
select
sum( if( t.date >= #today AND t.date < #tomorrow, 1, 0 )) as TodayCnt,
sum( if( t.date >= #today AND t.date < #tomorrow, amount, 0 )) as TodayAmt,
sum( if( t.date >= #yesterday AND t.date < #today, 1, 0 )) as YesterdayCnt,
sum( if( t.date >= #yesterday AND t.date < #today, amount, 0 )) as YesterdayAmt,
sum( if( t.date >= #FirstOfWeek AND t.date < #EndOfWeek, 1, 0 )) as WeekCnt,
sum( if( t.date >= #FirstOfWeek AND t.date < #EndOfWeek, amount, 0 )) as WeekAmt
from
transations t,
( select #today := curdate(),
#yesterday := date_add( #today, interval -1 day ),
#tomorrow := date_add( #today, interval 1 day ),
#FirstOfWeek := date_add( #today, interval +1 - dayofweek( #today) day ),
#EndOfWeek := date_add( #FirstOfWeek, interval 7 day ),
#minDate := least( #yesterday, #FirstOfWeek ) ) sqlvars
where
t.date >= #minDate
AND t.date < #EndOfWeek
Now, the dates. Since the #variables are prepared in sequence, you can think of it as an inline program to set the variables. Since they are a pre-query, they are done first and available for the duration of the rest of the query as previously stated. So to start, I am working with whatever "curdate()" is which gets the date portion only without respect to time. From that, subtract 1 day (add -1) to get the beginning of yesterday. Add 1 day to get Tomorrow. Then, the first of the week is whatever the current date is +1 - the actual day of week (you will see shortly). Add 7 days from the first of the week to get the end of the week. Finally, get whichever date is the LEAST between a yesterday (which COULD exist at the end of the prior week), OR the beginning of the week.
Now look at today for example... Feb 23rd.
Sun Mon Tue Wed Thu Fri Sat Sun
21 22 23 24 25 26 27 28
Today = 23
Yesterday = 22
Tomorrow = 24
First of week = 23 + 1 = 24 - 3rd day of week = 21st
End of Week = 21st + 7 days = 28th.
Why am I doing a cutoff of the dates stripping times? To simplify the SUM() condition for >= AND <. If I stated some date = today, what if your transactions were time-stamped. Then you would have to extract the date portion only to qualify. By this approach, I can say that "Today" count and amount is any date >= Feb 23 at 12am midnight AND < Feb 24th 12 am midnight. This is all time inclusive Feb 23rd up to 11:59:59pm hence LESS than Feb 24th (tomorrow).
Similar consideration for yesterday is all inclusive UP TO but not including whatever "today" is. Similarly for the week range.
Finally the WHERE clause is looking for the earliest date as the range so it does not have to run through the entire database of transactions to the end.
Lastly, if you ever wanted the counts and totals for a prior week / period, whatever, you could just extrapolate and change
#today := '2015-01-24'
and the computations will be AS IF the query was run ON THAT DATE.
Similar if you cared to alter such as for a month, you could compute the first of the month to the first of a following month for MONTHLY totals.
Hope you enjoy this flexible solution to you.
Yes, you can use aggregate functions on conditional expressions, like so:
SELECT SUM(IF(date between ({{today}})), 1, 0) AS count_today
, SUM(IF(date between ({{today}})), amount, 0) AS amount_today
, ...
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
I need to select data from MySQL database between the 1st day of the current month and current day.
select*from table_name
where date between "1st day of current month" and "current day"
Can someone provide working example of this query?
select * from table_name
where (date between DATE_ADD(LAST_DAY(DATE_SUB(CURDATE(), interval 30 day), interval 1 day) AND CURDATE() )
Or better :
select * from table_name
where (date between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW() )
I was looking for a similar query where I needed to use the first day of a month in my query.
The last_day function didn't work for me but DAYOFMONTH came in handy.
So if anyone is looking for the same issue, the following code returns the date for first day of the current month.
SELECT DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY);
Comparing a date column with the first day of the month :
select * from table_name where date between
DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY) and CURRENT_DATE
select * from table_name
where `date` between curdate() - dayofmonth(curdate()) + 1
and curdate()
SQLFiddle example
I have used the following query. It has worked great for me in the past.
select date(now()) - interval day(now()) day + interval 1 day
try this :
SET #StartDate = DATE_SUB(DATE(NOW()),INTERVAL (DAY(NOW())-1) DAY);
SET #EndDate = ADDDATE(CURDATE(),1);
select * from table where (date >= #StartDate and date < #EndDate);
Complete solution for mysql current month and current year, which makes use of indexing properly as well :)
-- Current month
SELECT id, timestampfield
FROM table1
WHERE timestampfield >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY)
AND timestampfield <= LAST_DAY(CURRENT_DATE);
-- Current year
SELECT id, timestampfield
FROM table1
WHERE timestampfield >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFYEAR(CURRENT_DATE)-1 DAY)
AND timestampfield <= LAST_DAY(CURRENT_DATE);
select * from table
where date between
(date_add (CURRENT_DATE, INTERVAL(1 - DAYOFMonth(CURRENT_DATE)) day)) and current_date;
select * from <table>
where <dateValue> between last_day(curdate() - interval 1 month + interval 1 day)
and curdate();
I found myself here after needing this same query for some Business Intelligence Queries I'm running on an e-commerce store. I wanted to add my solution as it may be helpful to others.
set #firstOfLastLastMonth = DATE_SUB(LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH)),INTERVAL DAY(LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH)))-1 DAY);
set #lastOfLastLastMonth = LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH));
set #firstOfLastMonth = DATE_SUB(LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH)),INTERVAL DAY(LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH)))-1 DAY);
set #lastOfLastMonth = LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH));
set #firstOfMonth = DATE_ADD(#lastOfLastMonth, INTERVAL 1 DAY);
set #today = CURRENT_DATE;
Today is 2019-10-08 so the output looks like
#firstOfLastLastMonth = '2019-08-01'
#lastOfLastLastMonth = '2019-08-31'
#firstOfLastMonth = '2019-09-01'
#lastOfLastMonth = '2019-09-30'
#firstOfMonth = '2019-10-01'
#today = '2019-10-08'
A less orthodox approach might be
SELECT * FROM table_name
WHERE LEFT(table_name.date, 7) = LEFT(CURDATE(), 7)
AND table_name.date <= CURDATE();
as a date being between the first of a month and now is equivalent to a date being in this month, and before now. I do feel that this is a bit easier on the eyes than some other approaches, though.
SELECT date_sub(current_date(),interval dayofmonth(current_date())-1 day) as first_day_of_month;
I had some what similar requirement - to find first day of the month but based on year end month selected by user in their profile page.
Problem statement - find all the txns done by the user in his/her financial year. Financial year is determined using year end month value where month can be any valid month - 1 for Jan, 2 for Feb, 3 for Mar,....12 for Dec.
For some clients financial year ends on March and some observe it on December.
Scenarios - (Today is `08 Aug, 2018`)
1. If `financial year` ends on `July` then query should return `01 Aug 2018`.
2. If `financial year` ends on `December` then query should return `01 January 2018`.
3. If `financial year` ends on `March` then query should return `01 April 2018`.
4. If `financial year` ends on `September` then query should return `01 October 2017`.
And, finally below is the query. -
select #date := (case when ? >= month(now())
then date_format((subdate(subdate(now(), interval (12 - ? + month(now()) - 1) month), interval day(now()) - 2 day)) ,'%Y-%m-01')
else date_format((subdate(now(), interval month(now()) - ? - 1 month)), '%Y-%m-01') end)
where ? is year end month (values from 1 to 12).
The key here is to get the first day of the month. For that, there are several options. In terms of performance, our tests show that there isn't a significant difference between them - we wrote a whole blog article on the topic. Our findings show that what really matters is whether you need the result to be VARCHAR, DATETIME, or DATE.
The fastest solution to the real problem of getting the first day of the month returns VARCHAR:
SELECT CONCAT(LEFT(CURRENT_DATE, 7), '-01') AS first_day_of_month;
The second fastest solution gives a DATETIME result - this runs about 3x slower than the previous:
SELECT TIMESTAMP(CONCAT(LEFT(CURRENT_DATE, 7), '-01')) AS first_day_of_month;
The slowest solutions return DATE objects. Don't believe me? Run this SQL Fiddle and see for yourself 😊
In your case, since you need to compare the value with other DATE values in your table, it doesn't really matter what methodology you use because MySQL will do the conversion implicitly even if your formula doesn't return a DATE object.
So really, take your pick. Which is most readable for you? I'd pick the first since it's the shortest and arguably the simplest:
SELECT * FROM table_name
WHERE date BETWEEN CONCAT(LEFT(CURRENT_DATE, 7), '-01') AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN DATE(CONCAT(LEFT(CURRENT_DATE, 7), '-01')) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (DATE(CURRENT_DATE) - INTERVAL (DAYOFMONTH(CURRENT_DATE) - 1) DAY) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (DATE(CURRENT_DATE) - INTERVAL (DAYOFMONTH(CURRENT_DATE)) DAY + INTERVAL 1 DAY) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN DATE_FORMAT(CURRENT_DATE,'%Y-%m-01') AND CURDATE;
I used this one
select DATE_ADD(DATE_SUB(LAST_DAY(now()), INTERVAL 1 MONTH),INTERVAL 1 day) first_day
,LAST_DAY(now()) last_day, date(now()) today_day
All the responses here have been way too complex. You know that the first of the current month is the current date but with 01 as the date. You can just use YEAR() and MONTH() to build the month date by inputting the NOW() method.
Here's the solution:
select * from table_name
where date between CONCAT_WS('-', YEAR( NOW() ), MONTH( NOW() ), '01') and DATE( NOW() )
CONCAT_WS() joins a series of strings with a separator (a dash in this case).
So if today is 2020-08-28, YEAR( NOW() ) = '2020' and MONTH( NOW() ) = '08' and then you just need to append '01' at the end.
Voila!
Get first date and last date from month and year.
select LAST_DAY(CONCAT(year,'.',month,'.','01')) as registerDate from user;
select date_add(date_add(LAST_DAY(end_date),interval 1 DAY),interval -1 MONTH) AS closingDate from user;
SET #date:='2012-07-11';
SELECT date_add(date_add(LAST_DAY(#date),interval 1 DAY),
interval -1 MONTH) AS first_day