![]() |
|
|
By: Tim Cullen | Read Comments (5) | Print Tim has been working in the IT industry since 2003 and currently works as a SQL Server Reports Developer. Related Tips: 1 | 2 | 3 | 4 | 5 | 6 | More |
|
At the moment I have a project where I have to retrieve SQL Server data based on the difference between two dates. I read the tip on the DATEADD function and wanted to know about other functions available for date/time manipulation. Can you point me in the right direction? Check out this tip to learn more about the SQL Server DateAdd function.
The most common function I use for date/time manipulation is the DATEDIFF function. Instead of adding or subtracting units of time from a specified date/time value, the DATEDIFF function retrieves the number of units of time between a start and end time. The DATEDIFF function can also be used in a WHERE clause as well as ORDER BY and HAVING clauses. The units of time available for the DATEDIFF are the same as those for the DATEADD function.
Below are examples of using the DATEDIFF function:
| Unit of time | Query | Result |
|
| ||
| NANOSECOND | SELECT DATEDIFF(NANOSECOND,'2011-09-23 17:15:22.5500000','2011-09-23 17:15:22.55432133') | 4321300 |
| MICROSECOND | SELECT DATEDIFF(MICROSECOND,'2011-09-23 17:15:22.5500000','2011-09-23 17:15:22.55432133') | 4321 |
| MILLISECOND | SELECT DATEDIFF(MILLISECOND,'2011-09-23 17:15:22.004','2011-09-23 17:15:22.548') | 544 |
| SECOND | SELECT DATEDIFF(SECOND,'2011-09-23 17:15:30','2011-09-23 17:16:23') | 53 |
| MINUTE | SELECT DATEDIFF(MINUTE,'2011-09-23 18:03:23','2011-09-23 17:15:30') | -48 |
| HOUR | SELECT DATEDIFF(HH,'2011-09-23 18:03:23','2011-09-23 20:15:30') | 2 |
| WEEK | SELECT DATEDIFF(WK,'09/23/2011 15:00:00','12/11/2011 14:00:00') | 12 |
| DAY | SELECT DATEDIFF(DD,'09/23/2011 15:00:00','08/02/2011 14:00:00') | -52 |
| DAYOFYEAR | SELECT DATEDIFF(DY,'01/01/2011 15:00:00','08/02/2011 14:00:00') | 213 |
| MONTH | SELECT DATEDIFF(MM,'11/02/2011 15:00:00','01/01/2011 14:00:00') | -10 |
| QUARTER | SELECT DATEDIFF(QQ,'01/02/2011 15:00:00','08/01/2011 14:00:00') | 2 |
| YEAR | SELECT DATEDIFF(YY,'01/02/2011 15:00:00','01/01/2016 14:00:00') | 5 |
One practical example of using the DATEDIFF function in SQL Server is in a WHERE clause by selecting all employees in the AdventureWorks2008R2 database whose date of hire was in March 2003. The application passes in two parameters: a string representing the number of the desired month (i.e. January=1, February=2, etc.) and the string representing the desired year. Then we use the DATEDIFF function with the MONTH unit of time:
DECLARE @Month VARCHAR(2), @Year CHAR(4) SELECT @Month = '3', @Year = '2003' DECLARE @Date DATE = @Month + '/1/' + @Year SELECT LoginID, OrganizationNode, OrganizationLevel, JobTitle, BirthDate, MaritalStatus, Gender, HireDate, SalariedFlag, VacationHours, SickLeaveHours, CurrentFlag, rowguid, ModifiedDate FROM AdventureWorks2008R2.HumanResources.Employee WHERE DATEDIFF(MONTH,@Date,HireDate) = 0; GO
| Share: | Share | Tweet |
|
![]() |
![]() |
Free SQL Server Learning |
| Monday, October 10, 2011 - 9:28:38 AM - Usman Butt | Read The Tip |
|
Hi, It was a nice article with a simple example and was very easy to understand the basic functionality. But one should not use functions in a WHERE clause (against the best practices). It should rather be used only in SELECT clause. WHERE clause can be re-written something like WHERE HireDate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, @Date), 0) -- START OF MONTH OF SEARCHED DATE in order to hit the index. Cheers.
Best Regards, |
|
| Monday, October 10, 2011 - 4:06:38 PM - Tim Cullen | Read The Tip |
|
Hey Usman: Thanks for the comments. When I originally executed the SQL statement the table count was small and there was relatively no difference in the performance. However, I executed a query on a table with 17 million records and noticed a significant difference in the IO price (see statistics below). You are correct in that using the BETWEEN clause refers to an index. You also revealed a good point in that SQL statements can be executed more than once, and it is good to analyze each statement's performance and cost to make sure you either making good use of indexes or create an index.
Tim
DATEDIFF (151208 row(s) affected) Table 'tbl_WeatherObservations'. Scan count 5 , logical reads 174086, physical reads 510 , read-ahead reads 173341, lob logical reads 0 , lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times: CPU time = 4585 ms, elapsed time = 26785 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
BETWEEN DATES (151208 row(s) affected) Table 'tbl_WeatherObservations'. Scan count 1 , logical reads 173624, physical reads 346 , read-ahead reads 173341, lob logical reads 0 , lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times: CPU time = 2028 ms, elapsed time = 25933 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. |
|
| Monday, October 10, 2011 - 4:57:26 PM - Anna | Read The Tip |
|
Thanks for the tip. A question when you say: It should rather be used only in SELECT clause. WHERE clause can be re-written something like But I see the example still have dateAdd and dateDif in the where clause. So in the rewritten where clause, the index is the hiredate?
Thanks |
|
| Tuesday, October 11, 2011 - 1:52:45 AM - Usman Butt | Read The Tip |
|
Hi Anna, I should rather re-state that Wrapping table columns of WHERE or JOIN clause inside of any type of function (system or user defined) can dramatically decrease query performance because this practice create hurdles in query optimizer work of proper index selection. But In my example the dateadd and datediff are used to just create the date range (no column of the table is used in the functions). I did use these functions in WHERE clause to keep the resemblance with the code and it would not affect the index hit. To make it clear we can re-write the code something like Declare @StartOfMonth DATETIME, @EndOfMonth DATETIME SET @StartOfMonth = DATEADD(mm, DATEDIFF(mm, 0, @Date), 0) SET @EndOfMonth = DATEADD(ms, -3, DATEADD(mm, 1, @StartOfMonth)) And then the WHERE clause becomes WHERE HireDate BETWEEN StartOfMonth AND @EndOfMonth Hope this will clarify the situation. And as far as index is concerned, yes, the index should be on hire date. Moreover, you can also use a TALLY table OR Calendar table for such queries and may get better performance. Cheers. Best Regards,
|
|
| Tuesday, October 11, 2011 - 11:14:12 AM - Anna | Read The Tip |
|
Thanks Usman, this clearly answers my question. It is very helpful. |
|
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |