Parsing a time span string in sql - sql

I am reading in from a datasource that is giving me time in a varchar in the format d:h:m:s:f, The day portion is always 0, the column represents a time of day. I would like to add this column to a datetime I already have.
Entry_Date Entry_Time
3/3/2009 12:00:00 0:16:17:6:0
8/24/2011 12:00:00 0:8:39:18:0
9/4/2010 12:00:00 0:12:33:18:0
If I was using C# I would just do TimeSpan.ParseExact but I do not know how to handle this in a purely sql fashion.
I would cast to time but I am using Sql Server 2005 and that does not have the time type.
How would I add the time to the neighboring datetime?

As simple as this:
select Entry_Date + cast(Entry_Time as datetime) combinedCol
from YourTable
Here is a working fiddle: http://sqlfiddle.com/#!3/85c3c/1
Enjoy!
Original Asker's note:
SQL can not handle the fractional seconds however they can be trimed off so the query would be
select Entry_Date + cast(left(Entry_Time, len(Entry_Time) - 2) as datetime) combinedCol
from YourTable

Related

SQL Server - add DATE part of DATETIME to TIME part of DATETIME

In SQL Server 2005 I am interrogating some old legacy data and I need to combine the date component of a datetime column with the time component from another column. Here's an example:
DateColumn: 2016-05-09 00:00:00.000
TimeColumn: 1899-12-30 12:26:00.000
I need the end result converted to the following DateTime:
ResultDateTime: 2016-05-09 12:26:00.000
I tried using:
CAST(DateColumn AS DATETIME) + CAST(TimeColumn AS TIME) AS ResultDateTime
But SQL Server 2005 doesn't recognize the type TIME.
Can someone please show me a way of doing that?
Many thanks!
convert the time column to string HH:MM:SS and add to the date column
ResultDatetIme = DateColumn + convert(varchar(10), TimeColumn, 108)
You can just use DATEADD and DATEDIFF, assuming that the time column's date portion is always 30/12/1899:
declare #t table (DateColumn datetime,TimeColumn datetime)
insert into #t(DateColumn,TimeColumn) values
('2016-05-09T00:00:00.000','1899-12-30T12:26:00.000')
select DATEADD(millisecond,DATEDIFF(millisecond,'18991230',TimeColumn),DateColumn)
from #t
Result:
-----------------------
2016-05-09 12:26:00.000
As you can see following data type supported in SQL 2005:
https://msdn.microsoft.com/en-us/library/ms187819(v=sql.90).aspx
Use datetime and smalldatetime, The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.
datetime values are rounded to increments of .000, .003, or .007 seconds, as shown in the following table.
SELECT CAST('2016-05-09 00:00:00.000' AS DATETIME) + CAST('1900-01-01 12:26:00.000' AS smalldatetime) AS ResultDateTime
Result: 2016-05-09 12:26:00.000
So you can use datetime and smalldatetime, hope fully that will work for you.
Let me know if any issue. love to resolve :)

SQL Server : Comparing Time

I am trying to compare time in my SQL query. However, when I run the query, I get zero result but I can see that in the table, there are records that should appear.
The query is as such:
SELECT *
FROM dbo.Alarms
WHERE StartDate <= '26/08/2015'
AND StartTime <= CONVERT(varchar(5), GETDATE(), 108)
The StartDate is stored in the database as YYYY-MM-DD and it seems to work fine when I query only with the date.
However, when I add the StartTime is when things don't work. StartTime stores the value in the 24 hour clock format.
What am not doing right?
Thanks
Use a correct datetime format:
SELECT *
FROM dbo.Alarms
WHERE StartDate <= '2015-08-26' AND StartTime <= cast(GETDATE() as date)
Don't compare date/time values as strings. The data types are built into the language. Use them.
I have not explicitly used this scenario but comparing dates can be a problem depending on how the fields are compared.
eg: '28/07/2015' is not less than your startdate as 28 > 26.
You could try comparing dates reformatted into a YYYYMMDD format.
Cheers.

convert Excel Date Serial Number to Regular Date

I got a column called DateOfBirth in my csv file with Excel Date Serial Number Date
Example:
36464
37104
35412
When i formatted cells in excel these are converted as
36464 => 1/11/1999
37104 => 1/08/2001
35412 => 13/12/1996
I need to do this transformation in SSIS or in SQL. How can this be achieved?
In SQL:
select dateadd(d,36464,'1899-12-30')
-- or thanks to rcdmk
select CAST(36464 - 2 as SmallDateTime)
In SSIS, see here
http://msdn.microsoft.com/en-us/library/ms141719.aspx
The marked answer is not working fine, please change the date to "1899-12-30" instead of "1899-12-31".
select dateadd(d,36464,'1899-12-30')
You can cast it to a SQL SMALLDATETIME:
CAST(36464 - 2 as SMALLDATETIME)
MS SQL Server counts its dates from 01/01/1900 and Excel from 12/30/1899 = 2 days less.
tldr:
select cast(#Input - 2e as datetime)
Explanation:
Excel stores datetimes as a floating point number that represents elapsed time since the beginning of the 20th century, and SQL Server can readily cast between floats and datetimes in the same manner. The difference between Excel and SQL server's conversion of this number to datetimes is 2 days (as of 1900-03-01, that is). Using a literal of 2e for this difference informs SQL Server to implicitly convert other datatypes to floats for very input-friendly and simple queries:
select
cast('43861.875433912' - 2e as datetime) as ExcelToSql, -- even varchar works!
cast(cast('2020-01-31 21:00:37.490' as datetime) + 2e as float) as SqlToExcel
-- Results:
-- ExcelToSql SqlToExcel
-- 2020-01-31 21:00:37.490 43861.875433912
this actually worked for me
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-30')
(minus 1 more day in the date)
referring to the negative commented post
SSIS Solution
The DT_DATE data type is implemented using an 8-byte floating-point number. Days are represented by whole number increments, starting with 30 December 1899, and midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number. However, a floating point value cannot represent all real values; therefore, there are limits on the range of dates that can be presented in DT_DATE. Read more
From the description above you can see that you can convert these values implicitly when mapping them to a DT_DATE Column after converting it to a 8-byte floating-point number DT_R8.
Use a derived column transformation to convert this column to 8-byte floating-point number:
(DT_R8)[dateColumn]
Then map it to a DT_DATE column
Or cast it twice:
(DT_DATE)(DT_R8)[dateColumn]
You can check my full answer here:
Is there a better way to parse [Integer].[Integer] style dates in SSIS?
Found this topic helpful so much so created a quick SQL UDF for it.
CREATE FUNCTION dbo.ConvertExcelSerialDateToSQL
(
#serial INT
)
RETURNS DATETIME
AS
BEGIN
DECLARE #dt AS DATETIME
SELECT #dt =
CASE
WHEN #serial is not null THEN CAST(#serial - 2 AS DATETIME)
ELSE NULL
END
RETURN #dt
END
GO
I had to take this to the next level because my Excel dates also had times, so I had values like this:
42039.46406 --> 02/04/2015 11:08 AM
42002.37709 --> 12/29/2014 09:03 AM
42032.61869 --> 01/28/2015 02:50 PM
(also, to complicate it a little more, my numeric value with decimal was saved as an NVARCHAR)
The SQL I used to make this conversion is:
SELECT DATEADD(SECOND, (
CONVERT(FLOAT, t.ColumnName) -
FLOOR(CONVERT(FLOAT, t.ColumnName))
) * 86400,
DATEADD(DAY, CONVERT(FLOAT, t.ColumnName), '1899-12-30')
)
In postgresql, you can use the following syntax:
SELECT ((DATE('1899-12-30') + INTERVAL '1 day' * FLOOR(38242.7711805556)) + (INTERVAL '1 sec' * (38242.7711805556 - FLOOR(38242.7711805556)) * 3600 * 24)) as date
In this case, 38242.7711805556 represents 2004-09-12 18:30:30 in excel format
In addition of #Nick.McDermaid answer I would like to post this solution, which convert not only the day but also the hours, minutes and seconds:
SELECT DATEADD(s, (42948.123 - FLOOR(42948.123))*3600*24, dateadd(d, FLOOR(42948.123),'1899-12-30'))
For example
42948.123 to 2017-08-01 02:57:07.000
42818.7166666667 to 2017-03-24 17:12:00.000
You can do this if you just need to display the date in a view:
CAST will be faster than CONVERT if you have a large amount of data, also remember to subtract (2) from the excel date:
CAST(CAST(CAST([Column_With_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you need to update the column to show a date you can either update through a join (self join if necessary) or simply try the following:
You may not need to cast the excel date as INT but since the table I was working with was a varchar I had to do that manipulation first. I also did not want the "time" element so I needed to remove that element with the final cast as "date."
UPDATE [Table_with_Date]
SET [Column_With_Excel_Date] = CAST(CAST(CAST([Column_With_Excel_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you are unsure of what you would like to do with this test and re-test! Make a copy of your table if you need. You can always create a view!
Google BigQuery solution
Standard SQL
Select Date, DATETIME_ADD(DATETIME(xy, xm, xd, 0, 0, 0), INTERVAL xonlyseconds SECOND) xaxsa
from (
Select Date, EXTRACT(YEAR FROM xonlydate) xy, EXTRACT(MONTH FROM xonlydate) xm, EXTRACT(DAY FROM xonlydate) xd, xonlyseconds
From (
Select Date
, DATE_ADD(DATE '1899-12-30', INTERVAL cast(FLOOR(cast(Date as FLOAT64)) as INT64) DAY ) xonlydate
, cast(FLOOR( ( cast(Date as FLOAT64) - cast(FLOOR( cast(Date as FLOAT64)) as INT64) ) * 86400 ) as INT64) xonlyseconds
FROM (Select '43168.682974537034' Date) -- 09.03.2018 16:23:28
) xx1
)
For those looking how to do this in excel (outside of formatting to a date field) you can do this by using the Text function https://exceljet.net/excel-functions/excel-text-function
i.e.
A1 = 132134
=Text(A1,"MM-DD-YYYY") will result in a date
This worked for me because sometimes the field was a numeric to get the time portion.
Command:
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-31')

Simple DateTime sql query

How do I query DateTime database field within a certain range?
I am using SQL SERVER 2005
Error code below
SELECT *
FROM TABLENAME
WHERE DateTime >= 12/04/2011 12:00:00 AM
AND DateTime <= 25/05/2011 3:53:04 AM
Note that I need to get rows within a certain time range. Example, 10 mins time range.
Currently SQL return with Incorrect syntax near '12'."
You missed single quote sign:
SELECT *
FROM TABLENAME
WHERE DateTime >= '12/04/2011 12:00:00 AM' AND DateTime <= '25/05/2011 3:53:04 AM'
Also, it is recommended to use ISO8601 format YYYY-MM-DDThh:mm:ss.nnn[ Z ], as this one will not depend on your server's local culture.
SELECT *
FROM TABLENAME
WHERE
DateTime >= '2011-04-12T00:00:00.000' AND
DateTime <= '2011-05-25T03:53:04.000'
You need quotes around the string you're trying to pass off as a date, and you can also use BETWEEN here:
SELECT *
FROM TABLENAME
WHERE DateTime BETWEEN '04/12/2011 12:00:00 AM' AND '05/25/2011 3:53:04 AM'
See answer to the following question for examples on how to explicitly convert strings to dates while specifying the format:
Sql Server string to date conversion
This has worked for me in both SQL Server 2005 and 2008:
SELECT * from TABLE
WHERE FIELDNAME > {ts '2013-02-01 15:00:00.001'}
AND FIELDNAME < {ts '2013-08-05 00:00:00.000'}
You can execute below code
SELECT Time FROM [TableName] where DATEPART(YYYY,[Time])='2018' and DATEPART(MM,[Time])='06' and DATEPART(DD,[Time])='14
SELECT *
FROM TABLENAME
WHERE [DateTime] >= '2011-04-12 12:00:00 AM'
AND [DateTime] <= '2011-05-25 3:35:04 AM'
If this doesn't work, please script out your table and post it here. this will help us get you the correct answer quickly.
select getdate()
O/P
----
2011-05-25 17:29:44.763
select convert(varchar(30),getdate(),131) >= '12/04/2011 12:00:00 AM'
O/P
---
22/06/1432 5:29:44:763PM
Others have already said that date literals in SQL Server require being surrounded with single quotes, but I wanted to add that you can solve your month/day mixup problem two ways (that is, the problem where 25 is seen as the month and 5 the day) :
Use an explicit Convert(datetime, 'datevalue', style) where style is one of the numeric style codes, see Cast and Convert. The style parameter isn't just for converting dates to strings but also for determining how strings are parsed to dates.
Use a region-independent format for dates stored as strings. The one I use is 'yyyymmdd hh:mm:ss', or consider ISO format, yyyy-mm-ddThh:mi:ss.mmm. Based on experimentation, there are NO other language-invariant format string. (Though I think you can include time zone at the end, see the above link).
if you have a type of datetime and you want to check between dates only ,,,use cast to select between two dates ....
example...
... where cast( Datetime as date) >= cast( Datetime as date) AND cast( Datetime as date) <= cast( Datetime as date)

select statement using Between with datetime type does not retrieve all fields?

I'm facing a strange query result and I want to ask you why I'm facing this issue.
I store some datetime data into TestTable as following :
creation_time
-----------------------
2010-07-10 00:01:43.000
2010-07-11 00:01:43.000
2010-07-12 00:01:43.000
This table is created and filled as following :
create table TestTable(creation_time datetime);
Insert into TestTable values('2010-07-10 00:01:43.000');
Insert into TestTable values('2010-07-11 00:01:43.000');
Insert into TestTable values('2010-07-12 00:01:43.000');
when I execute this query , I get two rows only instead of three as I expected:
SELECT * FROM TestTable
WHERE creation_time BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
Or if I execute this query , the same issue ..
SELECT * FROM TestTable
WHERE CONVERT(datetime,creation_time,111) BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
My Question :
Why the last row ('2010-07-12 00:01:43.000') does not appear in
the result even if I set the date range to cover all the day from 2010-07-10 to 2010-07-12?
I use Sql server 2005 express edition with windows xp 32-bits.
I'm trying to don't use a workaround solution such as increasing the date range to cover additional day to get the days I want.
Thanks .
You need to remove the time part from creation_time as well. Just use the same CONVERT if it works.
Currently you're asking if 2010-07-12 00:01:43.000 is less than 2010-07-12 00:00:00.000, which is not true.
it does not show the date because you have removed the time part, which would make the date equivalent to '2010-07-12 00:00:00.000' and since the last row is greater than this, so it is not displaying in the query results.
Your script should look like this:
SELECT *
FROM TestTable
WHERE creation_time BETWEEN
convert(datetime, convert(char, '2010-07-10', 106))-- remove time part
and **DATEADD**(day, 1, convert(datetime, convert(char, '2010-07-**11**', 106))) -- remove time part and add 1 day
This script will return all between 2010-07-10 00:00:00 and 2010-07-12 00:00:00. Basically this means all items created in 2 days: 2010-07-10 and 2010-07-11.
Converting columns in your table for comparison can be costly and cause indexes to not be used. If you have a million rows in your table and you have an index on creation_time, you will be doing an index scan and converting all million values to a string for comparison.
I find it better to use >= the start date and < (end date + 1 day):
SELECT *
FROM TestTable
WHERE creation_time >= '2010-07-10'
AND creation_time < dateadd(day, 1, '2010-07-12')
And the reason your second one may not work is because format 111 uses slashes ("2010/07/10"), format 120 uses dashes ("2010-07-10"). Your converts aren't doing anything to your start and end date because you are converting a string to varchar, not a date. If you did this, it might work, but I would still recommend not doing the conversion:
SELECT * FROM TestTable
WHERE CONVERT(datetime, creation_time, 111) BETWEEN
CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-10'), 111) -- remove time part
and CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-12'), 111) -- remove time part
Date/time inclusive between 7/10/2010 and 7/12/2010:
SELECT * FROM TestTable
WHERE creation_time BETWEEN
CONVERT(VARCHAR,'2010-07-10',101) -- remove time part
and CONVERT(VARCHAR,'2010-07-13',101) -- remove time part