I am running SQL Server 2005. Technically I know how to take the time from a tsql datetime.
CONVERT(VARCHAR(8),GETDATE(),108) AS HourMinuteSecond
The problem is that I have a datetime field and I need to essentially grab the time portion convert that to an integer specifically seconds. Then I need to do a bunch of arithmetic on this integer that I won't discuss here. I have searched on stackoverflow and haven't found a question that is specific to this question. Any ideas? I am really looking for best practices here, I am worried about creating a udf for this specific purpose as it completely throws the query optimizer out the window.
I have seen this webpage so please don't paste this. :
http://forums.devx.com/showthread.php?171561-TSQL-Converting-HH-MM-SS-to-seconds
Use DATEPART:
(DATEPART(HOUR, GETDATE()) * 3600) +
(DATEPART(MINUTE, GETDATE()) * 60) +
(DATEPART(SECOND, GETDATE()))
Just my 2 cents ...another way of doing this
Edit: Added method for SQL Server 2005 (Thank you Michael)
for SQL Server 2008
SELECT DATEDIFF(SECOND, CONVERT(date, GETDATE()), GETDATE())
for sql server 2005+
SELECT DATEDIFF(SECOND, DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())), GETDATE())
The functions you want is DatePart
Declare #d DateTime
Select #d = GetDate()
Select (DatePart(HOUR, #d) * 3600) + (DatePart(MINUTE, #d) * 60) + DatePart(SECOND, #d)
Related
I am trying to write this Excel formula into T-SQL (to write a function).
Expected output is 0.71944444, but currently my output (using T-SQL) is 24.0000.
I am not sure why we have to add a day to same date and subtract the same date.
Bottom is a screenshot from Excel:
This is what I have so far in T-SQL:
CREATE FUNCTION [dbo].[fn_0921] (
#Punch_Start nvarchar(max)
)
RETURNS decimal(36, 8) AS
BEGIN
DECLARE #return_value nvarchar(max);
SET #return_value =
DATEDIFF(
MINUTE, CAST(#Punch_Start AS datetime2),
(
dateadd(
day, 1, CAST(#Punch_Start AS datetime2)
)
)
)
/ (60.0)
RETURN #return_value
END;
Thanks for help.
The Excel formula is returning the difference between the datetime in cell K4 & the start of the next day (i.e. 7/26/2021 00:00) as a fraction of a whole day. The following is the equivalent in T-SQL:
DECLARE #Punch_Start datetime2 = '7/25/2021 06:44';
SELECT DATEDIFF(
MINUTE,
#Punch_Start,
CAST(
CAST(
DATEADD(DAY, 1, #Punch_Start)
AS date) -- Add 1 day to #Punch_Start & cast as date to remove the time component - this is the start of the next day
AS datetime2) -- Cast back to datetime2 to get the difference in minutes
) / 1440.; -- Divide the difference in minutes by the number of minutes in a day (60 minutes per hour, 24 hours per day) to get the difference as a fraction of a day
This can probably help you:
DECLARE #date DATETIME2 = '2021-07-25 06:44'
DECLARE #seconds INT = DATEDIFF(second, CAST(#date AS date), #date)
DECLARE #secondsFromEnd FLOAT = 86400 - #seconds
SELECT #secondsFromEnd / 86400
I'm trying to execute the following stored procedure with a dynamic date parameter so that it picks up 6 months ago to yesterday.
When I run on a server with US language settings it works however when I run on a server with UK language settings I get the error:
Conversion failed when converting date and/or time from character string
I have tried converting the date to YYYYMMDD as this works on all servers however I have been unable to - I have even tried to force into a VARCHAR but no luck :(
Is there a way to get the date as YYYYMMDD format? Hope you can help.
USE Reports
DECLARE #DteStart DATETIME2(3)
DECLARE #DteEnd DATETIME2(3)
SELECT #DteStart = DATEADD(MM, DATEDIFF(MM, 0, CONVERT(DATE,GETDATE(),103))-6,0)
SELECT #DteEnd = DATEADD(DD, DATEDIFF(DD, 0, CONVERT(DATE,GETDATE(),103))-1,0)
EXEC [dbo].[spReportsMyData] #DteStart, #DteEnd;
Try something like this:
Declare
#StartDate as Date
, #EndDate as Date
Set #EndDate = DateAdd(Day, -1, Getdate())
Set #StartDate = DateAdd(Month, -6, #EndDate)
Select
Convert(VARCHAR(10), #StartDate, 112) As StartDate
, CONVERT(VARCHAR(10), #EndDate, 112) As EndDate
Does your stored procedure seriously need the dates specifically in YYYYMMDD format, though?
I want to get all rows 7 days prior from 01/09/2017
I know I can do
Load_DTM <= '2017-01-09' and Load_DTM >= '2017-01-02'
But can I not use DateAdd or DatePart?
i.e. DateAdd(dd, -7, '2017-01-09')
Load_DTM BETWEEN DATEADD(dd,-7,'2017-01-09') AND '2017-01-09 11:59:59'
ought to work.
You should be able to do exactly what you showed in your example:
SELECT * FROM Table WHERE DateField = DATEADD(DAY, -7, '2017-09-01')
Since running:
SELECT DATEADD(DAY, -1, GETDATE())
Gives you:
2017-03-15 19:26:29.833
How to write a sql statement that always returns data from last Monday to the last Sunday? Any guidance is appreciated.
Thanks.
t-clausen.dk's answer does work, but it may not be clear why it works (neither to you nor to the developer who comes after you). Since added clarity sometimes comes at the cost of conciseness and performance, I'd like to explain why it works in case you'd prefer to use that shorter syntax.
SELECT t.*
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(day, 0, getdate() - DATEDIFF(day, 0, getdate()) %7) lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday
How SQL Server Stores datetime Internally
SQL Server stores datetime as two 4-byte integers; the first four bytes represents the number of days since 1/1/1900 (or before 1/1/1900, for negative numbers) and the second four bytes represents the number of milliseconds since midnight.
Using datetime with int or decimal
Because datetime is stored as two 4-byte integers, it is easy to move between numeric and date data types in T-SQL. For example, SELECT GETDATE() + 1 returns the same as SELECT DATEADD(day, 1, GETDATE()), and CAST(40777.44281 AS datetime) is the same as 2011-08-24 10:37:38.783.
1/1/1900
Since the first integer portion of datetime is, as was mentioned above, the number of days since 1/1/1900 (also called the SQL Server Epoch), CAST(0 as datetime) is by definition equivalent to
1900-01-01 00:00:00
DATEDIFF(day, 0, GETDATE())
Here's where things start to get both tricky and fun. First, we've already established that when 0 is treated as a date, it's the same as 1/1/1900, so DATEDIFF(day, '1/1/1900', GETDATE()) is the same as DATEDIFF(day, 0, GETDATE())—both will return the current number of days since 1/1/1900. But, wait: the current number of days is exactly what is represented by the first four bytes of datetime! In a single statement we have done two things: 1) we've removed the "time" portion returned by GETDATE() and we've got an integer value we can use to make the calculation for finding the most recent Sunday and the previous Monday a little easier.
Modulo 7 for Monday
DATEDIFF(day, 0, GETDATE()) % 7 takes advantage of the fact that DATEPART(day, 0) (which, at the risk of overemphasizing the point, is the same as DATEPART(day, '1/1/1900')) returns 2 (Monday).1 Therefore, DATEDIFF(day, 0, GETDATE()) % 7 will always yield the number of days from Monday for the current date.
1 Unless you have changed the default behavior by using DATEFIRST.
Most Recent Monday
It's almost too trivial for its own heading, but at this point we can put together everything we've got so far:
GETDATE() - DATEDIFF(day, 0, GETDATE()) %7 gives you the most recent Monday
DATEDIFF(day, 0, GETDATE() - DATEDIFF(day, 0, GETDATE()) %7) gives you the most recent Monday as a whole date, with no time portion.
But the poster wanted everything from Monday to Sunday...
Instead of using the BETWEEN operator, which is inclusive, the posted answer excluded the last day, so that there was no need to do any shifting or calculating to get the right date range:
t.yourdate >= a.lastmonday - 7 returns records with dates since (or including) midnight on the second-most-recent Monday
t.yourdate < a.lastmonday returns records with dates before (but not including) midnight on the most recent Monday.
I am a big proponent of writing code that is easy to understand, both for you and for the developer who comes after you a year later (which might also be you). I believe that the answer I posted earlier should be understandable even to novice T-SQL programmers. However, t-clausen.dk's answer is concise, performs well, and could be encountered in production code, so I wanted to give some explanation to help future visitors understand why it works.
I realized my code was too complex, so I changed my answer to this. The minus one after getdate() corrects this to return the last Monday on Sunday instead of this weeks Monday (tomorrow if today is Sunday).
SELECT t.*
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(week, 0, getdate() - 1) * 7 lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday
Old code
SELECT t.*
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(day, 0, getdate() - DATEDIFF(day, 0, getdate()) %7) lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday
You did not specify which SQL dialect, so I will answer for T-SQL, which is what I know best, and you've used the tsql tag.
In T-SQL, use the DATEPART function to find the day of the week. When you know the current day of the week, you can get the date of the most recent Sunday and the Monday before it.
In a stored procedure, it's easier—at least, more readable and easier to maintain, in my opinion—to calculate the values for the most recent Sunday and the preceding Monday and store the values in variables. Then those variables can be used in calculations later in the procedure.
CREATE PROCEDURE SomeProcedure
AS
DECLARE #CurrentDayOfWeek int, #LastSunday date, #LastMonday date
SET #CurrentWeekday = DATEPART(weekday, GETDATE())
-- Count backwards from today to get to the most recent Sunday.
-- (#CurrentWeekday % 7) - 1 will give the number of days since Sunday;
-- -1 negates for subtraction.
SET #LastSunday = DATEADD(day, -1 * (( #CurrentWeekday % 7) - 1), GETDATE())
-- Preceding Monday is obviously six days before last Sunday.
SET #LastMonday = DATEADD(day, -6, #LastSunday)
SELECT ReportColumn1, ReportColumn2
FROM ReportTable
WHERE DateColumn BETWEEN #LastMonday AND #LastSunday
If you need to be able to do the calculation in a SELECT statement or a view, it's trivial now that we've worked out the steps, though the query itself is a little messier:
SELECT ReportColumn1, ReportColumn2
FROM ReportTable
WHERE DateColumn
BETWEEN
(
-- Last Monday is six days before...
DATEADD(day, -6,
-- ... last Sunday.
DATEADD(day, -1 * (( DATEPART(weekday, GETDATE()) % 7) - 1), GETDATE())
)
)
AND
(
-- Last Sunday has to be calculated again each time it is used inline.
DATEADD(day, -1 * (( DATEPART(weekday, GETDATE()) % 7) - 1), GETDATE())
)
The parentheses I added are not necessary, but are only there to help you see how the WHERE clause is built.
Finally, note that these use the SQL 2008 date data type; for the datetime data type, you may need to perform your own conversion/truncation to compare whole dates instead of date-plus-time values.
The short code in #t-clausen.dk answer doesn't work for Sunday nor does the first result I found on Google. To test them out, try.
DECLARE #date as DATETIME;
SET #date = '2014-11-23 10:00:00'; -- Sunday at 10a
SELECT DATEADD(wk, DATEDIFF(wk,0,#date), 0) -- 2014-11-24 00:00:00
SELECT CAST(DATEDIFF(week, 0, #date)*7 as datetime) -- 2014-11-24 00:00:00
SELECT CAST(DATEDIFF(day, 0, CAST(#date as DATETIME) - DATEDIFF(day, 0,#date) %7) as DATETIME) --2014-11-17 00:00:00
SELECT DATEADD(wk, DATEDIFF(wk,0,#date-1), 0) --2014-11-17 00:00:00
Thus, you should use the long code from the original answer or modified short code.
SELECT t.*
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(week, 0, getdate() - 1) * 7 lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday
I need to convert Datetime fields to a specifically formatted INT type. For example, I want
2000-01-01 00:00:00.000 to convert to 20010101.
What is the most performant way to make that conversion for comparison in a query?
Something like:
DATEPART(year, orderdate) * 10000 + DATEPART(month, orderdate) * 100 +
DATEPART(day, orderdate)
or
cast(convert(char(8), orderdate, 112) as int)
What's the most performant way to do this?
Your example of cast(convert(char(8), orderdate, 112) as int) seems fine to me. It quickly gets the date down to the format you need and converted to an int.
From an execution plan standpoint, there seems to be no difference between the two.
You can try with TSQL builtin functions.
It's not .NET tick compatible but it's still FAST sortable and you can pick your GRANULARITY on demand:
SELECT setup.DateToINT(GETDATE(), 4) -- will output 2019 for 2019-06-06 12:00.456
SELECT setup.DateToINT(GETDATE(), 6) -- will output 201906 for 2019-06-06 12:00.456
SELECT setup.DateToINT(GETDATE(), 20) -- will output 20190606120045660 for 2019-05-05 12:00.456
CREATE FUNCTION setup.DateToINT(#datetime DATETIME, #length int)
RETURNS
BIGINT WITH SCHEMABINDING AS
BEGIN
RETURN CONVERT(BIGINT,
SUBSTRING(
REPLACE(REPLACE(
REPLACE(REPLACE(
CONVERT(CHAR(25), GETDATE(), 121)
,'-','')
,':','')
,' ','')
,'.','')
,0
,#length+1)
)
END
GO
Is this what you need
SELECT REPLACE(CONVERT(VARCHAR(10),'2010-01-01 00:00:00.000',101),'-','')
When you pass '2010-01-01 00:00:00.000' directly in your code, the SELECT statement looks at it as a string and not a datetime data type. Its not the same as selecting a datetime field directly.
There is no need to do outer CAST because SQL Server will do implicit conversion, here is a proof.
DECLARE #t DATETIME = '2010-01-10 00:00:00.000',#u INT
SELECT #u = CONVERT(CHAR(8), #t, 112)
IF ISNUMERIC(#u) = 1
PRINT 'Integer'