SQL Query to restrict return dates to current month - sql-server-2008

I am trying to restrict my returned data to only those points that have start and end dates in the current month - active projects. It is behaving problematically because today is the last day of the month. I believe that tomorrow will be a problem as well (no June data included in the sample).
Here is my data set (Table 1):
Project User Effort Start_Date End_Date
------- ------- ------ -------- --------
Traffic Control DOMAIN\john.smith 0.1 5/1/2013 5/31/2013
Turboencabulator Analysis DOMAIN\mark.webber 0 5/1/2013 5/31/2013
Widget Calibration DOMAIN\mark.webber 0 5/1/2013 5/31/2013
Gizmo Creation DOMAIN\steve.green 0.1 5/1/2013 5/31/2013
Advanced Toolmaking DOMAIN\steve.green 0.6 5/1/2013 5/31/2013
Diesel Engine Diagnostics DOMAIN\steve.green 0.05 5/1/2013 5/31/2013
Cold Fusion Reactor Creation DOMAIN\steve.green 0.3 5/1/2013 5/31/2013
When using the following query today I get no returned results:
SELECT * FROM dbo.table1
WHERE Start_Date <= (getdate()) AND End_Date >= (getdate())
ORDER BY User, Start_Date
Yesterday it was returning just fine. I have data for June as well (not displayed in my sample) but I need to modify my statement such that it will reliably return data for the current month throughout the entirety of the month.
Answer - Correct WHERE statement (from comments in answer below):
WHERE (Month(Start_Date) <= Month((getdate())) AND Month(End_Date) >= Month((getdate()))) AND (YEAR(Start_Date) <= YEAR((getdate())) AND YEAR(End_Date) >= YEAR((getdate())))

Use TSQL Month function:
SELECT * FROM dbo.table1
WHERE Month(Start_Date) = Month(getdate()) AND Month(End_Date) = Month(getdate())
ORDER BY User, Start_Date

Just consolidate your WHERE statement into something like:
DATEDIFF(m, DATEFIELD, GETDATE()) = 0

The following query can take advantage of indexes since it does not perform calculations on every row. In addition, it returns as "active" any project that is active at any time during the month, e.g. a project that starts in the last week of the month and ends several months hence. And it's easy to test and modify since it separates the date arithmetic from the query.
declare #Today as Date = GetDate()
declare #StartOfMonth as Date = DateAdd( day, 1 - Day( #Today ), #Today )
declare #EndOfMonth as Date = DateAdd( day, -1, DateAdd( month, 1, #StartOfMonth ) )
select #Today as [Today], #StartOfMonth as [StartOfMonth], #EndOfMonth as [EndOfMonth]
select *
from Table1
where Start_Date <= #EndOfMonth and End_Date >= #StartOfMonth

You should try using convert(date, GetDate())GetDate().
Dates are represented as ticks, meaning smaller than seconds. if you compare GetDate() (which is 2013-05-31 11:09:45:1024 for exmaple, unsure about millisecond precision in mssql), it will always be greater than 2013-05-31, because of the hours/minutes/seconds. Your 2 choices are to compare YOURDATE >= Start_Date AND End_Date + 1 > YOURDATE, or YOURDATE >= Start_Date AND End_Date >= convert(date, YOURDATE)
First options asks for it to be stricly less than the morrow of the end date (so basically the very end of that day), second one asks for it to be within the same day as the end date, ignoring ticks. Both yields the exact same result, one of them is probably more performant, however I can't help on that side of things.
EDIT : or you can use the other two's answer, except that it will only work if you always use monthly periods. and in that case it would be simpler to redesign your database to only have a 1-12 field representing the month.

In MySql, I use something similar to update data within x number of days, perhaps something like:
start_date <= DATE_SUB(curdate(), INTERVAL 10 DAY);
Just change 10 to whatever number of days you need.

Try this for MySQL
select date(date_joined),count(*) from users where MONTH(date_joined)=MONTH(now()) and YEAR(date_joined)=YEAR(now()) group by date(date_joined);

Related

Dynamic due date finder in a single query

id start_date interval period
1 2018-01-22 2 month
2 2018-02-25 3 week
3 2017-11-24 3 day
4 2017-07-22 1 year
5 2018-02-25 2 week
the above is my table data sample. start_dates will be expired based on interval and period(i.e id-1 will have due date after 2 months from the start_date, id-2 will have due after 3 weeks vice versa). period is enum of (day,week,month,year). requirement is, Client can give any period of dates. let's say 25-06-2026 to 13-07-2026 like that.. I have to return the ids whose due dates falls under that period.I hope i made my question clear.
I am using mysql 5.7. I found a way to achieve this with recursive CTE's.(not available in mysql 5.7). and there is a way to achieve this by populating virtual records by using inline sub queries along with unions but its a performance killer and we can't do populate virtual records every time a client request comes.(like given in the link Generating a series of dates) I have reached a point to get results for a single date which is very easy. Below is my query.
SELECT b.*
FROM (SELECT a.*,
CASE
WHEN period = 'week' THEN MOD(Datediff('2018-07-22', start_date), 7 * intervals)
WHEN period = 'month'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(YEAR_MONTH FROM start_date)), intervals) = 0 THEN 0
WHEN period = 'year'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(
YEAR_MONTH FROM start_date)) / 12,
intervals) = 0 THEN 0
WHEN period = 'day' THEN MOD(Datediff('2018-07-22', start_date) , intervals)
end filters
FROM kml_subs a)b
WHERE b.filters = 0;
But I need to do this for a period of dates not a single date. Any suggestions or solutions will be much appreciated.
My desired result shoud be like..
if i give two dates.say 2030-05-21 & 2030-05-27. due dates falls under those 6 dates between(2030-05-21 & 2030-05-27) will be shown in the result.
id
1
4
My question is different from Using DATE_ADD with a Column Name as the Interval Value . I am expecting a dynamic way to check due dates based on start_date
Thanks, Kannan
In MySQL, it would seem that a query along these lines would suffice. (Almost) everything else could and should be handled in application level code...
SELECT *
, CASE my_period WHEN 'day' THEN start_date + INTERVAL my_interval DAY
WHEN 'week' THEN start_date + INTERVAL my_interval WEEK
WHEN 'month' THEN start_date + INTERVAL my_interval MONTH
WHEN 'year' THEN start_date + INTERVAL my_interval YEAR
END due_date
FROM my_table;

Select MySQL data starting from a specific date

I have player statistics which I would like to publish from certain dates.
At the moment I can see statistics in the database from the beginning.
SELECT name,
bankmoney AS Bank,
Playerkills AS 'Player Kills',
deathcount AS Deaths ,
aikills AS 'AI Kills',
teamkills AS 'Team Kills',
revivecount AS Revives ,
capturecount AS 'Territories Captured',
LastModified AS 'Last Seen'
FROM playerinfo
JOIN playerstats
ON playerinfo.UID = playerstats.PlayerUID
ORDER BY BankMoney DESC;
But I would like to present statistics from the start of the day and the start of the week.
How would I do that ?
Based on Spitfire's comments, to get the last 24 hours of data you can use INTERVAL and go back the required number of days you want. NOW() will give you the time the query was executed and BETWEEN will allow you to search between two days. So that part of the query could be:
WHERE 'Last Seen' BETWEEN NOW() AND NOW() - INTERVAL 1 DAY;
A week would require a change from 1 day to 7.
Try it.SELECT * from table_name where a.exam_date BETWEEN $date1 AND $date2;
for example if you want to see only statistics with lastModified greater or equal today just add a where clause:
WHERE 'Last Seen' >= CURRENT_DATE()

MySQL select dependant on time of day

I want to select from a MySQL table and filter depending on the time of day:
if now > 10am select uploaded date where created date is today
if now < 10am select uploaded date where created date is yesterday
I think you must use Cron jobs for this.
Then, your sql will look like that:
WHERE tbl.TimeCreated = DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
assuming this format of the field: DateTime(YYYY-MM-DD HH:MM:SS)
This should do what you need.
SELECT
`uploaded_date`
FROM
`table`
WHERE
`created_date` = CASE WHEN CURTIME() > 100000
THEN CURDATE()
ELSE CURDATE() - INTERVAL 1 DAY
END
You can see a similar example in this fiddle which should return a single row of "AM" in the morning, "Noon" at noon, and "PM" in the afternoon (and 2 empty result sets).

SQL Query for reservation dates that break a month end?

I'm using a custom PHP function to produce a visual calendar for a single month that blocks out dates based on a table that contains an start date, and an duration - For example:
...This is produced by data saying that the table should be blocked out for 4 days from the 14th, and 7 days from the 27th.
The query looks something like this:
SELECT GROUP_CONCAT(DATE_FORMAT(start_date,'%d'),':', event_duration) AS info
FROM events
WHERE YEAR(start_date = '2012'
AND MONTH(start_date) = '07'
ORDER BY start_date
(You could safely ignore the group concat and return the data as individual rows, that doesn't really matter).
I'm looking for a modification to the query that would block out dates at the start of the month IF an event starts in the previous month, but its length takes it into the following.
For instance - in the above example, the event on the 27th is actually scheduled to last 7 days in the database, so if I ran the query for MONTH(start_date) = '08' I'd like to say the first two dates blocked out, which they wouldn't currently be, because the start date that would block it out is not in the month being selected.
I'm fairly sure there's a subquery or something in there to grab the rows, but I just can't think of it. Any takers?
EDIT
The answer from Salman below pointed me in the directon I wanted to go, and I came up with this as a way of getting carryovers from the previous month to show as '1st' of the month with the number of remaining days:
SELECT IF(MONTH(start_date) < '08', '2012-08-01', start_date) AS starter,
IF(MONTH(start_date) < '08', duration - DATEDIFF('2012-08-01',start_date), duration) AS duration
FROM EVENTS
WHERE YEAR(start_date) = '2012'
AND (MONTH(start_date) = '08' OR MONTH(start_date + INTERVAL duration DAY) = '08')
Obviously a lot of variables there to replace in PHP, so maybe there's an even better way?
Original Answer:
Assuming that the month in question is 2012-07, you need this query:
SELECT column1, column2, columnN
FROM `events`
WHERE `start_date` <= '2012-07-01'
AND `start_date` + INTERVAL `duration` DAY > '2012-07-01'
ORDER BY start_date
Revised Answer:
Apparently you need a query that checks for overlapping (or conflicting) dates. The example dates are 2012-07-01 through 2012-08-01 and the query is:
SELECT *
FROM events
WHERE '2012-08-01' > start_date
AND start_date + INTERVAL duration DAY > '2012-07-01'
ORDER BY start_date
To constrain the start date and interval, you can use SELECT ... CASE statement:
SELECT
CASE
WHEN start_date < '2012-07-01' THEN '2012-07-01'
ELSE start_date
END AS start_date_copy,
CASE
WHEN start_date < '2012-07-01' THEN duration - DATEDIFF('2012-07-01', start_date)
ELSE duration
END AS duration_copy,
FROM ...
The answer I was looking for, thanks to the other contributor for pointing me in the right direction and enabling me to solve it!
This is based on $yyyy and $mm coming from PHP (in my case, into a function call), and selecting individual rows rather than grouping:
SELECT start_date, duration
FROM reservations
WHERE YEAR(start_date) = '".$yyyy."'
AND MONTH(start_date) = '".$mm."'
UNION
SELECT '".$yyyy."-".$mm."-01',
duration - DATEDIFF('".$yyyy."-".$mm."-01',start_date)
FROM reservations
WHERE YEAR(start_date) = '".$yyyy."'
AND MONTH(start_date) < '".$mm."'
AND MONTH(start_date + INTERVAL duration DAY) = '".$mm."'
ORDER BY start_date

How to get first day of every corresponding month in mysql?

I want to get first day of every corresponding month of current year. For example, if user selects '2010-06-15', query demands to run from '2010-06-01' instead of '2010-06-15'.
Please help me how to calculate first day from selected date. Currently, I am trying to get desirable using following mysql select query:
Select
DAYOFMONTH(hrm_attendanceregister.Date) >=
DAYOFMONTH(
DATE_SUB('2010-07-17', INTERVAL - DAYOFMONTH('2010-07-17') + 1 DAY
)
FROM
hrm_attendanceregister;
Thanks
Is this what you are looking for:
select CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE);
You can use the LAST_DAY function provided by MySQL to retrieve the last day of any month, that's easy:
SELECT LAST_DAY('2010-06-15');
Will return:
2010-06-30
Unfortunately, MySQL does not provide any FIRST_DAY function to retrieve the first day of a month (not sure why). But given the last day, you can add a day and subtract a month to get the first day. Thus you can define a custom function:
DELIMITER ;;
CREATE FUNCTION FIRST_DAY(day DATE)
RETURNS DATE DETERMINISTIC
BEGIN
RETURN ADDDATE(LAST_DAY(SUBDATE(day, INTERVAL 1 MONTH)), 1);
END;;
DELIMITER ;
That way:
SELECT FIRST_DAY('2010-06-15');
Will return:
2010-06-01
There is actually a straightforward solution since the first day of the month is simply today - (day_of_month_in_today - 1):
select now() - interval (day(now())-1) day
Contrast that with the other methods which are extremely roundabout and indirect.
Also, since we are not interested in the time component, curdate() is a better (and faster) function than now(). We can also take advantage of subdate()'s 2-arity overload since that is more performant than using interval. So a better solution is:
select subdate(curdate(), (day(curdate())-1))
This is old but this might be helpful for new human web crawlers XD
For the first day of the current month you can use:
SELECT LAST_DAY(NOW() - INTERVAL 1 MONTH) + INTERVAL 1 DAY;
You can use EXTRACT to get the date parts you want:
EXTRACT( YEAR_MONTH FROM DATE('2011-09-28') )
-- 201109
This works well for grouping.
You can use DATE_FORMAT() function in order to get the first day of any date field.
SELECT DATE_FORMAT(CURDATE(),'%Y-%m-01') as FIRST_DAY_CURRENT_MONTH
FROM dual;
Change Curdate() with any other Date field like:
SELECT DATE_FORMAT(purchase_date,'%Y-%m-01') AS FIRST_DAY_SALES_MONTH
FROM Company.Sales;
Then, using your own question:
SELECT *
FROM
hrm_attendanceregister
WHERE
hrm_attendanceregister.Date) >=
DATE_FORMAT(CURDATE(),'%Y-%m-01')
You can change CURDATE() with any other given date.
There are many ways to calculate the first day of a month, and the following are the performance in my computer (you may try this on your own computer)
And the winner is LAST_DAY(#D - interval 1 month) + interval 1 day
set #D=curdate();
select BENCHMARK(100000000, subdate(#D, (day(#D)-1))); -- 33 seconds
SELECT BENCHMARK(100000000, #D - INTERVAL (day(#D) - 1) DAY); -- 33 seconds
SELECT BENCHMARK(100000000, cast(DATE_FORMAT(#D, '%Y-%m-01') as date)); -- 29 seconds
SELECT BENCHMARK(100000000, LAST_DAY(#D - interval 1 month) + interval 1 day); -- 26 seconds
I'm surprised no one has proposed something akin to this (I do not know how performant it is):
CONCAT_WS('-', YEAR(CURDATE()), MONTH(CURDATE()), '1')
Additional date operations could be performed to remove formatting, if necessary
use date_format method and check just month & year
select * from table_name where date_format(date_column, "%Y-%m")="2010-06"
SELECT LAST_DAY(date) as last_date, DATE_FORMAT(date,'%Y-%m-01') AS fisrt_date FROM table_name
date=your column name
The solutions that use last_day() and then add/subtract a month and a day are not interchangeable.
Example:
date_sub(date_add(last_day(curdate()), interval 1 day), interval 3 month)
always works for any supplied number of months you want to go back
date_add(date_sub(last_day(now()), interval 3 month), interval 1 day)
will fail in some cases, for instance if your current month has 30 days and the month you're subtracting back to (and then adding a day) has 31.
date_add(subdate(curdate(), interval day(?) day), interval 1 day)
change the ? for the corresponding date
This works fine for me.
date(SUBDATE("Added Time", INTERVAL (day("Added Time") -1) day))
** replace "Added Time" with column name
Use Cases:
If you want to reset all date fields except Month and Year.
If you want to retain the column format as "date". (not as "text" or "number")
Slow (17s):
SELECT BENCHMARK(100000000, current_date - INTERVAL (day(current_date) - 1) DAY);
SELECT BENCHMARK(100000000, cast(DATE_FORMAT(current_date, '%Y-%m-01') as date));
If you don't need a date type this is faster:
Fast (6s):
SELECT BENCHMARK(100000000, DATE_FORMAT(CURDATE(), '%Y-%m-01'));
SELECT BENCHMARK(100000000, DATE_FORMAT(current_date, '%Y-%m-01'));
select big.* from
(select #date := '2010-06-15')var
straight_join
(select * from your_table where date_column >= concat(year(#date),'-',month(#date),'-01'))big;
This will not create a full table scan.