Concatenate Date and Time as DATETIME in SQL Server - sql

I'm having a trouble in combining date and time to DATETIME. I have an existing table with data so I can't change it to Datetime2.
DECLARE #t1 TABLE(StartDate DATE, StartTime Time)
INSERT INTO #t1
VALUES('2018-02-28','08:00:00')
SELECT
CAST(CONCAT(StartDate, ' ', StartTime) AS DATETIME)
FROM #t1
The error shown is:
Conversion failed when converting date and/or time from character string.

Don't concat(). Just add but they both need to be datetime:
select cast(startdate as datetime) + cast(starttime as datetime)

The cast fails because the time component of the datetime data type has less precision than the time data type, as described on this page, which is a useful reference for the various date and time types offered by SQL Server. As you can also see on that page, SQL Server has a datetime2 data type that offers greater precision; if you had used that in your cast, I don't think you would have had a problem.
Gordon's solution is a good one in that it avoids the need to deal with conversions to and from strings in the first place. Just be aware that combining a date and time into a datetime may involve a loss of precision. See this question on the Stack Exchange DBA site for a solution with datetime2 that retains the precision of the original values.

Related

How to cast the DateTime to Time

I am casting DateTime field to Time by using CAST Syntax.
select CAST([time] as time) as [CSTTime]
DateTime
2015-03-19 00:00:00.000
Present Output : Time
03:05:36.0000000
I need only HH:MM:SS and not Milliseconds or 0000's
How to filter or Cast it to exact HH:MM:SS Format.
Time is not stored with its display format in SQL Server.
Therefore, from the user perspective, you can say that it has no format.
Of course, that's not completely accurate since it does have a storage format, but as an average user you can't really use it.
This is true for all date and time data types:
Date, DateTimeOffset, DateTime2, SmallDateTime, DateTime and Time.
If you need a format then you don't need to cast to time but to a char. Use Convert to get the char you need:
SELECT CONVERT(char(10), [time], 108) as CSTTime
Here is some background data if you're interested:
In this article published in 2000 the writer explains in depth how SQL Server treats dates and times. I doubt if anything significant changed between 2000 and 2015 in the way SQL Server stores date, time and datetime values internally.
Here are the relevant quotes, if you don't want to read all of it:
So how does SQL Server internally store the dates? It uses 8 bytes to store a datetime value—the first 4 for the date and the second 4 for the time. SQL Server can interpret both sets of 4 bytes as integers.
........
........
SQL Server stores the second integer for the time as the number of clock ticks after midnight. A second contains 300 ticks, so a tick equals 3.3 milliseconds (ms).
since time is actually stored as a 4 byte integer, it really doesn't have a format as an integral part of the data type.
You might also want to check out this article for a more detailed explanation with code samples.
You can achieve it with CAST just simple use TIME(0) datatype in following:
SELECT CAST('2015-03-19 01:05:06.289' AS TIME(0))
OUTPUT:
01:05:06
SQL Server 2008:
select cast(MyDate as time) [time] from yourtable
Earlier versions:
select convert(char(5), MyDate , 108) [time] from yourtable
Other Options:
SELECT CONVERT(VARCHAR(20), GETDATE(), 114)
The simplest way to get the time from datetime without millisecond stack is:
SELECT CONVERT(time(0),GETDATE())
Hour and Minute
SELECT substring(CONVERT(VARCHAR, GETDATE(), 108),0,6) AS Time

varchar vs datetime in sql

I was having problem in retrieving from SQL Server so I posted this [question][1]
I did not get any suitable answers. So I have changed the column datatype from datetime to varchar and now it works fine.
SELECT *
FROM test
WHERE (timeStamp BETWEEN '05-09-2013 18:23:57' AND '05-09-2013 18:23:59')
But my query if varchar datatype can play the role of datetime and in varchar we can also store the string then why sql provides datetime datatype? I know varchar occupies more space than datetime. I would like to know other reasons.
Change datatype of your column to datetime. You can do your query IF you'll use datetime instead of varchar in where clause:
select *
from test
where timeStamp between convert(datetime, '2013-09-05 18:23:57', 120) and convert(datetime, '2013-09-05 18:23:59', 120)
I'm pretty sure it would work even with implicit cast if you use ISO format of date:
select *
from test
where timeStamp between '2013-09-05 18:23:57' and '2013-09-05 18:23:59'
Here's more info about cast and convert.
Another reason apart from space is this:
Datetime has other functions like picking up the day, year, month,hours,minutes,seconds etc so that you don't have to write it for yourself. If you use varchar then it will be your responsibility to provide functions for future use. You should use split function to retrive the part of date you want.
Another is that a query on a varchar works slower when compared to Datetime when you use to conditions to compare month / day/ year
Always use proper DATETIME datatype to store date and time values. Refer this for more information
http://beyondrelational.com/modules/2/blogs/70/posts/10902/understanding-datetime-column-part-iv.aspx

SQL - comparing date parameter to datetime

In a SQL Server table, I have a field named Timestamp, which is a 'datetime' field. On a screen I have created, a user will pass in a date (no time), and I need to return all the records for that date.
Just doing Timestamp = #Date doesn't seem to work unless the time in the field is 00:00:00. What is the most efficient way of doing this?
Since you're on SQL Server 2008, you can use the DATE datatype.
Do a comparison between
CAST(Timestamp AS DATE) = #Date
That should work and look just at the date - no time portion.
In general you should think about the data from a specific date as data that falls in a range, not at a single point in time. So ideally your query should use a range, such as:
WHERE [Timestamp] >= #Date
AND [Timestamp] < DATEADD(DAY, 1, #Date)
In this case, luckily, the optimizer is smart and will still use an index if you use CONVERT(DATE, [timestamp]) against the column. However in a lot of cases you need to be careful because this will often make your clause non-sargable.
PS Timestamp is a horrible column name. It's a data type in SQL Server which has nothing to do with date or time.
A common technique for truncating the time part off a datetime value is to use the DATEDIFF and DATEADD functions. In your example it would be used like this to truncate the time part of the Timestamp field.
WHERE #DateEntered = DATEADD(DAY,0, DATEDIFF(DAY, 0, Timestamp))
Bascially it's taking the datetime value and finding the name of days since "the date represented by 0" (for lack of a better description) and then adding that number of days back. This effectively truncates time part.

How do I strip the date off of a datetime string in SQL SSIS?

I'm working on a data warehouse project and would like to know how to (preferably in a Derived Column component in a Data flow) strip the date piece off of a SQL datetime record.
Once I have the datetime converted to just a time I am going to do a lookup on the time to find the related time record in a time dimension table.
Can someone give me a simple function to accomplish this inside a derived column transform?
Example: Transform a datetime such as "12/02/2008 11:32:21 AM" into simply "11:32:21 AM".
I would just do a cast to DT_DBTIME type (using Derived Column transform, or Convert type transform). DT_DBTIME contains just (hours, minutes, seconds) part of the date/time, so you'll get rid of the date part.
If you need to do this in a variable expression Michael's solution won't work, but you can use the following expression:
(DT_DATE)(DT_DBDATE)GETDATE()
(DT_DBDATE) converts the current date and time to a date only. But the new datatype is not compatiple with SSIS's datetime. Therefore you'll have to use (DT_DATE) for converting to a compatible type.
Courtesy of this solution belongs to Russel Loski who has posted it in his blog:
http://www.bidn.com/blogs/RussLoski/ssas/1458/converting-datetime-to-date-in-ssis
Actually if you reverse the first 2 expressions like this: (DT_DBDATE)(DT_DATE)GETDATE()
instead of (DT_DATE)(DT_DBDATE)GETDATE(), then you will TRUNCATE the time off the date field.
If the DT_DATE expression is before the DT_DBDATE expression, you will still have the time portion in your output, but it will be reset to all zeroes.
Ran into this with writing a report for a scheduling app, needed the time that was stored as part of a datetime data type. I formated the datetime as 0 which gives you this mon dd yyyy hh:miAM (or PM), and just did a substring of that which returned the time only in an AM/PM format.
Example below.
DECLARE #S DATETIME = GETDATE()
SELECT SUBSTRING(CONVERT(NVARCHAR(30), #S , 0) , 13 , 10) AS ApptTime
, CONVERT(NVARCHAR(30), #S , 0) AS ApptDate
I personally use a series of functions for this. E.g.:
ALTER FUNCTION [dbo].[TIMEVALUE]
(
#Datetime datetime
)
RETURNS datetime
AS
BEGIN
RETURN (#Datetime - CAST(ROUND(CAST(#Datetime AS float), 0, 1) AS datetime))
END
I'd love to claim all the credit but it should really go to this guy.

Avg on datetime in Access

I am porting some queries from Access to T-SQL and those who wrote the queries used the Avg aggregate function on datetime columns. This is not supported in T-SQL and I can understand why - it doesn't make sense. What is getting averaged?
So I was about to start reverse engineering what Access does when it aggregates datetime using Avg, but thought I would throw the question out here first.
I'd imagine that Access is averaging the numeric representation of the dates. You could do similar in T-SQL with the following...
select AverageDate = cast(avg(cast(MyDateColumn as decimal(20, 10))) as datetime)
from MyTable
I'm more familiar with non-MS DBMS, but... Since you cannot add two DATETIME values, you cannot ordinarily average them. However, you could do something similar to:
SELECT AVG(datetime_column - TIMESTAMP '2000-01-01 00:00:00.000000') +
TIMESTAMP '2000-01-01 00:00:00.000000'
FROM table_containing_datetime_column;
This calculates the average interval between the start of 2000 and the actual datetime values, and then adds that interval to the start of 2000. The choice of 'start of 2000' is arbitrary; as long as the datetime subtracted in the AVG() function is added back, you get a sensible answer.
This does assume that the DBMS used supports SQL standard 'timestamp' notation, and supports the INTERVAL types appropriately. The difference between two DATETIME or TIMESTAMP values should be an INTERVAL (indeed, INTERVAL DAY(9) TO SECOND(6), to be moderately accurate, though the '9' is somewhat debatable).
When appropriately mangled for the DBMS I work with, the expression 'works':
CREATE TEMP TABLE table_containing_datetime_column
(
datetime_column DATETIME YEAR TO FRACTION(5) NOT NULL
);
INSERT INTO table_containing_datetime_column VALUES('2008-11-19 12:12:12.00000');
INSERT INTO table_containing_datetime_column VALUES('2008-11-19 22:22:22.00000');
SELECT AVG(datetime_column - DATETIME(2000-01-01 00:00:00.00000) YEAR TO FRACTION(5)) +
DATETIME(2000-01-01 00:00:00.00000) YEAR TO FRACTION(5)
FROM table_containing_datetime_column;
Answer:
2008-11-19 17:17:17.00000
#David W. Fenton: "A Jet date field is an integer value for the day plus a decimal value for the time" -- no, an ACE/Jet DATETIME column is a FLOAT (synonyms DOUBLE, FLOAT8, IEEEDOUBLE, NUMBER) with limits e.g. the maximum DATETIME value is #9999-12-31:23:59:59# though the maximum FLOAT value that can be cast to DATETIME will be a little larger e.g.
SELECT CDBL(CDATE('9999-12-31 23:59:59'))
returns 2958465.99998843, however
SELECT CDATE(CDBL(2958465.9999999997))
does not error, whereas
SELECT CDATE(CDBL(2958465.9999999998))
does error.
Therefore, to preserve functionality in SQL Server, I suggest casting the DATETIME column to FLOAT e.g.
SELECT CAST(AVG(CAST(MyDateTimeColumn AS FLOAT)) AS DATETIME)
from MyTable