sql datefromparts not working as expected - sql

I have the following code:
Declare #indDate date = '1/1/2014'
SELECT RecordID AS RID,
Name,
Company,
PhoneNumber,
CONVERT(VARCHAR(10),DateOfInduction,103) AS StartDate,
CONVERT(VARCHAR(10),DateOfExpiry,103) AS DateOfExpiry
FROM Records WHERE DateOfExpiry <= DATEFROMPARTS(DATEPART(YYYY,#indDate),DATEPART(MM,#indDate),DATEPART(DD,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#indDate)+1,0))))
AND DateOfExpiry >= DATEFROMPARTS(DATEPART(YYYY,#indDate),DATEPART(MM,#indDate),1)
Which basically gives me all expiring records for the month of the #indDate parameter.
What I am trying to do is add 1 to the month in the DATEFROMPARTS to get next month's values. Now I don't want to just change the #indDate to the other month because in the report the date will not be selected but only something like Expires This Month, Next Month, Previous Month, etc.
So if I change the WHERE clause to:
WHERE DateOfExpiry <= DATEFROMPARTS(DATEPART(YYYY,#indDate),DATEPART(MM,DATEADD(MM,1,#indDate)),DATEPART(DD,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#indDate)+1,0))))
AND DateOfExpiry >= DATEFROMPARTS(DATEPART(YYYY,#indDate),DATEPART(MM,DATEADD(MM,1,#indDate)),1)
I get error: Cannot construct data type date, some of the arguments have values which are not valid. and I am not sure why, it works fine If I try something like:
Declare #indDate date = '1/1/2014'
select DATEADD(mm,1,#indDate)
Can anyone see the problem?

In your error is coming from trying to create date from invalid date range,
if you run parts of your DATEFROMPARTS in the following manner
DECLARE #indDate DATE = '1/1/2014'
SELECT DATEPART(YYYY, #indDate)
,DATEPART(MM, DATEADD(MM, 1, #indDate))
,DATEPART(DD, DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, #indDate) + 1, 0)))
this generates 2014 2 31 which is not a valid date.
The following three examples will give you all records for previous, current or next month no matter if you passed in '01/01/2014' or '01/15/2014'
This will give you all records for last month.
WHERE DateOfExpiry >= DATEADD(MONTH, -1,DATEADD(dd,-DATEPART(day,#indDate)+1,#indDate)) AND
DateOfExpiry < DATEADD(dd,-DATEPART(day,#indDate)+1,#indDate)
This will give you all records for current month
WHERE DateOfExpiry >= DATEADD(dd,-DATEPART(day,#indDate)+1,#indDate)
and DateOfExpiry < DATEADD(MONTH, 1,DATEADD(dd,-DATEPART(day,#indDate)+1,#indDate))
Finally all records for next month
WHERE DateOfExpiry >= DATEADD(MONTH, 1, DATEADD(dd, -DATEPART(day, #indDate) + 1, #indDate))
AND DateOfExpiry < DATEADD(MONTH, 2, DATEADD(dd, -DATEPART(day, #indDate) + 1, #indDate))

why not use:
WHERE DateOfExpiry >= #indDate AND DateOfExpiry < DATEADD(month,1,#indDate)

Related

Automate a sql query for specific dates

I am writing a 'select, from, where' query in SQL and I want the query to be valid only between specific monthly dates the last day of each month to the second last day of the next month. Is there a way to automate that query so that I do not have to change the dates every month?
assuming that you have a date field on whatever table/tables you are querying
you can just add this where clause to any of your queries to keep the results between "the last day of the current month" and "the second to last day of the next month"
WHERE
dateField >= CAST(DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, GETDATE()) + 1, 0)) as date)
AND dateField <= CAST(DATEADD(d, -2, DATEADD(m, DATEDIFF(m, 0, GETDATE()) + 2, 0)) as date)

Function to go back 2 years, first day of last month

I'm hoping to find a solution for this to automate a report I have. Basically what I'm trying to accomplish here is grabbing a date (first day of previous month, two years ago through last day of previous month current year).
So the date span if running this month would look like this: between 4/1/2013 and 3/31/2015
I have found code to get the date two years ago but I'm not able to also incorporate the month functions... Any help is very much appreciated!
For year I'm using this:
SELECT CONVERT(VARCHAR(25),DATEADD(year,-2,GETDATE()),101)
First day of previous month 2 years ago:
SELECT CONVERT(DATE,dateadd(day, -1, dateadd(day, 1 - day(GETDATE()), GETDATE())))
Last day of last month:
SELECT CONVERT(DATE,DATEADD(month, DATEDIFF(month, 0, DATEADD(year,-2,GETDATE())), 0))
Then just do whatever logic you need with them
Your where clause can look something like this:
where date >= cast(dateadd(year, -2,
dateadd(month, -1, getdate() - day(getdate()) + 1)
) as date) and
date < cast(getdate() - day(getdate()) + 1 as date)
This makes use of the handy convenience that subtracting/adding a number to a datetime is the same as adding a date. The start date says: get the first day of the month, then subtract one month, then subtract two years. This could have been done as dateadd(month, -25, . . .), but I think separating the logic is clearer.
This gives you two dates you are looking for:
SELECT
CAST((DATEADD(yy, -2, DATEADD(d, -1 * DATEPART(dd, getdate()) + 1 , GETDATE() ))) as date) as yourTwoYearsAgoDate,
CAST((DATEADD(d, -1 * DATEPART(dd, GETDATE()), GETDATE())) as date) as yourEndOfLastMonthDate
Given a reference date (e.g. "today"),
declare #today date = '23 April 2015'
The 1st of the month is computed by subtracting 1 less than the day number of the current month:
select first_of_current_month = dateadd(day,1-day(#today),#today)
The last day of the previous month is day 0 of the current month, so to get the last day of the previous month, just subtract the current day number:
select last_of_previous_month = dateadd(day,-day(#today),#today)
Moving two years back is easy:
select two_years_back = dateadd(year,-2, #today )
Putting it all together, this should do you:
declare #today date = '23 April 2015'
select *
first_day_of_current_month = dateadd(day,1-day(#today),#today),
last_day_of_previous_month = dateadd(day, -day(#today),#today) ,
date_from = dateadd(year,-2, dateadd(day,1-day(#today),#today) ) ,
date_thru = dateadd(day, -day(#today),#today)
yielding the expected results:
first_day_of_current_month: 2015-04-01
last_day_of_previous_month: 2015-03-31
date_from : 2013-04-01
date_thru : 2015-03-31
So you should be able to say something like this:
select *
from foo t
where t.transaction_date between dateadd(year,-2, dateadd(day,1-day(#today),#today) )
and dateadd(day, -day(#today),#today)
If you have to deal with datetime values rather than date, its easier to not use between and say something like this:
declare #today date = current_timestamp -- get the current date without a time component
select *
from foo t
where t.transaction_date >= dateadd(year,-2, dateadd(day,1-day(#today),#today) )
and t.transaction_date < dateadd(year, 0, dateadd(day, -day(#today),#today)
[superfluous addition of 0 years added for clarity]

Why do I get different results with this SQL Date Part and date parameters

When I run this where clause on my table I get 2 different results and to me its seems like I should get the same number of records back.
The one I'm using just a static date to test and the other should also retrieve the same results where I'm trying to get last month results
I idea the query is a report that will automatic load the previous months records.
WHERE
(OrderReceiptedDate >= '2015-03-01')
AND (OrderReceiptedDate <= '2015-03-31')
WHERE
(DATEPART(mm, OrderReceiptedDate) = DATEPART(mm, DATEADD(mm, - 1, GETDATE())))
AND
(DATEPART(yy, OrderReceiptedDate) = DATEPART(yy, DATEADD(mm, - 1, GETDATE())))
These are the two statements
WHERE (OrderReceiptedDate >= '2015-03-01' AND
OrderReceiptedDate <= '2015-03-31'
)
WHERE (DATEPART(month, OrderReceiptedDate) = DATEPART(month, DATEADD(month, - 1, GETDATE()))) AND
(DATEPART(year, OrderReceiptedDate) = DATEPART(year, DATEADD(month, - 1, GETDATE())))
Given that today is April 2015, you are expecting that both of these get all dates for March. And, they would, if your dates had no time components. The problem is that almost any datetime on March 31st is not going to match the first condition. The one exception is exactly at midnight: 2015-03-01 00:00:00.000.
The first is better written as:
WHERE (OrderReceiptedDate >= '2015-03-01' AND
OrderReceiptedDate < '2015-04-01'
)
A better way to write "get me last months date" is something like:
WHERE OrderReceiptedDate >= dateadd(month, -1, cast(getdate() - day(getdate()) + 1 as date)) and
OrderReceiptedDate < cast(getdate() - day(getdate()) + 1 as date)
This does all the calculations on getdate() so the query could still take advantage of an index on OrderReceiptDate.

Keyword for "Last Month" in SQL Server 2008

I have a query (pasted below), and I would like to make it so that people don't need to update the completed date range. I would like for it to automatically just get results from last month. So if it is run in February, for example, it will give me results for all completed items that meet my criteria for January. Can anyone think of a way to do that?
select External_ID__c,
Ewrk_Tracking_Number__c,
PIF_Branch_Name,
Distribution_Branch_Name,
Transaction_Type__C,
submitter_date__c, Completed_Date__C,
COUNT(External_ID__c)
from Business_Solutions_D.dbo.Reporting_SalesForce_AspireBaseData
where PIF_Branch_Code = 977
and Completed_Date__C >= '2015-01-01'
and Completed_Date__C < '2015-02-01'
and Delete_Flag__C = 'FALSE'
group by External_ID__c,
Ewrk_Tracking_Number__c,
PIF_Branch_Name,
Distribution_Branch_Name,
Transaction_Type__C,
submitter_date__c,
Completed_Date__C
There is no "keyword" for last month. You have to put that in your predicates.
Here is an example of how to get some date values for this.
select dateadd(MONTH, datediff(MONTH, 0, GETDATE()), 0) as BeginningOfThisMonth
select dateadd(MONTH, datediff(MONTH, 0, GETDATE()) - 1, 0) as BeginningOfPreviousMonth
If you want to see a number of other date routines here is an excellent blog post with quite a few of them. http://www.sqlservercentral.com/blogs/lynnpettis/2009/03/25/some-common-date-routines/
If you mean the last month prior to this one, you can do it in two steps: first, find the first day of the current month
#firstDayOfThisMonth = DATEADD(day, DAY(GETDATE())-1, GETDATE())
then subtract one month:
#firstDayOfLastMonth = DATEADD(month, -1, #firstDayOfThisMonth)
Then your query would be:
and Completed_Date__C >= #firstDayOfLastMonth
and Completed_Date__C < #firstDayOfThisMonth
Another way would be to query where the difference (in months) between Completed_Date__C and the current date is 1:
and DATEDIFF(Completed_Date__C, GETDATE()) = 1
You can do this with date arithmetic. One trick to get the first date of the month is to subtract the current day of the month from the date and add one day. SQL Server allows you to do this with + and - instead of dateadd(), on a datetime value. Of course, you need to remove the time component as well (using cast( as date)).
The logic looks like this for the current month:
where Completed_Date__C >= cast(getdate() - day(getdate()) + 1 as date) and
Completed_Date__C < dateadd(month, 1, cast(getdate() - day(getdate()) + 1 as date))
And like this for the previous month:
where Completed_Date__C >= dateadd(month, -1, cast(getdate() - day(getdate()) + 1 as date)) and
Completed_Date__C < cast(getdate() - day(getdate()) + 1 as date)
This has the nice property that it is a sargeable as your original code, so it will take advantage of an index on the column, if appropriate.
You just need to have it do some date math to calculate it.
--Go to last day of prev month - 'Day' to account for varying month day counts
and Completed_Date__C >= GETDATE() - DATEPART(DAY, GETDATE()) - DATEPART(DAY, GETDATE() - DATEPART(DAY, GETDATE())) + 1
and Completed_Date__C < GETDATE() - DATEPART(DAY, GETDATE()) + 1
When you do additions on DateTimes + integer it assumes it day based addition.

How do I calculate the last day of the month in SQL?

Specifically MSSQL 2005.
Here's a solution that gives you the last second of the current month. You can extract the date part or modify it to return just the day. I tested this on SQL Server 2005.
select dateadd( s, -1, dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 ) );
To understand how it works we have to look at the dateadd() and datediff() functions.
DATEADD(datepart, number, date)
DATEDIFF(datepart, startdate, enddate)
If you run just the most inner call to datediff(), you get the current month number since timestamp 0.
select datediff(m, 0, getdate() );
1327
The next part adds that number of months plus 1 to the 0 timestamp, giving you the starting point of the next calendar month.
select dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 );
2010-09-01 00:00:00.000
Finally, the outer dateadd() just subtracts one second from the beginning timestamp of next month, giving you the last second of the current month.
select dateadd( s, -1, dateadd( mm, datediff( m, 0, getdate() ) + 1, 0 ) );
2010-08-31 23:59:59.000
This old answer (below) has a bug where it doesn't work on the last day of a month that has more days than the next month. I'm leaving it here as a warning to others.
Add one month to the current date, and then subtract the value returned by the DAY function applied to the current date using the functions DAY and DATEADD.
dateadd(day, -day(getdate()), dateadd(month, 1, getdate()))
SELECT DATEADD(M, DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP), '1990-01-31T00:00:00.000')
Explanation:
General approach: use temporal functionality.
SELECT '1990-01-01T00:00:00.000', '1990-01-31T00:00:00.000'
These are DATETIME literals, being the first time granule on the first day and last day respectively of the same 31-day month. Which month is chosen is entirely arbitrary.
SELECT DATEDIFF(M, '1990-01-01T00:00:00.000', CURRENT_TIMESTAMP)
This is the difference in whole months between the first day of the reference month and the current timestamp. Let's call this #calc.
SELECT DATEADD(M, #calc, '1990-01-31T00:00:00.000')
This adds #calc month granules to the last day of the reference month, the result of which is the current timestamp 'rounded' to the last day of its month. Q.E. D.
Try this:
DATEADD (DAY, -1, DATEADD (MONTH, DATEDIFF (MONTH, 0, CURRENT_TIMESTAMP) + 1, 0)
They key points are if you can get first day of current month,Last Day of Last Month and Last Day of Current Month.
Below is the Step by Step way to write query:
In SQL Server Date Starts from 1901/01/01( Date 0) and up to now each month can be identified by a number. Month 12 is first month of 1902 means January. Month 1200 is January of 2001. Similarly each day can be assigned by unique number e.g Date 0 is 1901/01/01. Date 31 is 1901/02/01 as January of 1901 starts from 0.
To find out First day of Current Month(Current Date or a given date)
First we need to check how many months have passed since date 0(1901/01/01).
SELECT DATEDIFF(MM,0,GETDATE())
Add same number of month to date 0(1901/01/01)
SELECT DATEADD(MM, DATEDIFF(MM,0,GETDATE()),0)
Then we will get first day of current month(Current Date or a given date)
To get Last Day of Last Month
We need to subtract a second from first day of current month
SELECT DATEADD(SS,-1,DATEADD(MM, DATEDIFF(MM,0,GETDATE()),0))
To get Last Day of Current Month
To get first day of current month first we checked how many months have been passed since date 0(1901/01/01). If we add another month with the total months since date 0 and then add total months with date 0, we will get first day of next month.
SELECT DATEADD(MM, DATEDIFF(MM,0,GETDATE())+1,0)
If we get first day of next month then to get last day of current month, all we need to subtract a second.
SELECT DATEADD(SS,-1,DATEADD(MM, DATEDIFF(MM,0,GETDATE())+1,0))
Hope that would help.
Using SQL2005, you do not have access to a helpful function EOMONTH(), So you must calculate this yourself.
This simple function will works similar to EOMONTH
CREATE FUNCTION dbo.endofmonth(#date DATETIME= NULL)
RETURNS DATETIME
BEGIN
RETURN DATEADD(DD, -1, DATEADD(MM, +1, DATEADD(DD, 1 - DATEPART(DD, ISNULL(#date,GETDATE())), ISNULL(#date,GETDATE()))))
END
Query to perform:
SELECT dbo.endofmonth(DEFAULT) --Current month-end date
SELECT dbo.endofmonth('02/25/2012') --User-defined month-end date
Some links to possible answers:
http://www.extremeexperts.com/sql/Tips/DateTrick.aspx
http://www.devx.com/tips/Tip/14405
http://blog.sqlauthority.com/2007/08/18/sql-server-find-last-day-of-any-month-current-previous-next/
http://www.sqlservercurry.com/2008/03/find-last-day-of-month-in-sql-server.html
DECLARE
#Now datetime,
#Today datetime,
#ThisMonth datetime,
#NextMonth datetime,
#LastDayThisMonth datetime
SET #Now = getdate()
SET #Today = DateAdd(dd, DateDiff(dd, 0, #Now), 0)
SET #ThisMonth = DateAdd(mm, DateDiff(mm, 0, #Now), 0)
SET #NextMonth = DateAdd(mm, 1, #ThisMonth)
SET #LastDayThisMonth = DateAdd(dd, -1, #NextMonth)
Sometimes you really do need the last day of this month, but frequently what you really want is to describe the time interval of this month. This is the best way to describe the time interval of this month:
WHERE #ThisMonth <= someDate and someDate < #NextMonth
For completeness, in Oracle you'd do something like ...
select add_months(trunc(sysdate,'MM'),1) ...
or
select last_day(sysdate)+1 ...
DATEADD(dd, -1, DATEADD(mm, +1, DATEADD(dd, 1 - DATEPART(dd, #myDate), #myDate)))