Related
I get an error return by t-sql because of different type of datetime format store in database.
Datatime format user input will be like this '18-03-2019'
Below are two example table of my DB :
Staff Id No Hex Ref sex update_date_time
1234 4943 01 0x20 SN002 male 2019-03-18 10:31:09.000
1234 4943 01 0x30 SN001 female 2019-03-18 10:32:09.000
1234 4943 01 0x10 SN003 female 2019-03-18 10:33:09.000
1234 4943 01 0x20 SN003 female 2012-06-18 10:34:09.000
Below is the query user input:
This sql will only get the result of three row from the table above
SELECT Staff,Id,No,Hex,Ref,sex, update_date_time FROM workers WHERE update_date_time = CONVERT(date,'18-03-2019',103)
Solution i have try:
Some information come from this link. The result i want is date will input by user and the way i do won't get all the date from the sql table.
The query below will end out with error.
SELECT SELECT Staff,Id,No,Hex,Ref,sex, update_date_time FROM workers WHERE update_date_time = CONVERT(VARCHAR(10),GETDATE(),103)
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value
it is because your update_date_time contains a time component. A normal solution to that is to use >= and <. You use greater or equal to a date and less than the day after.
SELECT Staff,Id,No,Hex,Ref,sex, update_date_time
FROM workers
WHERE update_date_time >= '2019-03-18'
AND update_date_time < '2019-03-19'
OR
DECLARE #input DATE = '2019-03-18'
SELECT Staff,Id,No,Hex,Ref,sex, update_date_time
FROM workers
WHERE update_date_time >= #input
AND update_date_time < DATEADD(DAY, 1, #input)
of-course if you don't care about performance and wants and easier query, convert the column update_date_time to DATE before compare
SELECT Staff,Id,No,Hex,Ref,sex, update_date_time
FROM workers
WHERE CONVERT(DATE, update_date_time) = #input
I have a table called "EventLog" which has the column called nDateTime of type int.
This is the table "EventLog" with some values:
-----------------
| nDateTime |
-----------------
| 978307200 |
-----------------
| 978307219 |
-----------------
| 978513562 |
-----------------
| 978516233 |
-----------------
| 978544196 |
-----------------
| 1450379547 |
-----------------
| 1472299563 |
-----------------
| 1472299581 |
-----------------
| 1472300635 |
-----------------
| 1472300644 |
-----------------
| 1472300673 |
-----------------
I need to get the DateTime value, and I tried the following statements, but I receive these errors:
Test #1:
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), nDateTime), 103) AS 'Formatted date'
FROM EventLog
The error says:
Conversion failed when converting date and/or time from character string.
Test #2: modified from here:
SELECT CONVERT(DATETIME, nDateTime, 103) AS 'Formatted date'
FROM EventLog
And Test #3 goes:
SELECT CAST(nDateTime AS datetime) AS 'Formatted date'
FROM EventLog
The duplicate question doesn't answer my question because (both, test #2 and test #3) generates this error:
Arithmetic overflow error converting expression to data type datetime.
I admit that I never saw such value as a Date, and for that, I'm kind of confused in how to proceed.
My question is: How can get the valid DateTime value from the sample data?
Almost every time you see a date/time represented as an integer, that number represents the passage of time since a known epoch. This is the basis of Unix time which is, put simply, the number of seconds which have elapsed since 1st January 1970 00:00:00
Using this, we can check with some values you have provided
declare #dt DATETIME = '1970-01-01' -- epoch start
print dateadd(second,978307200,#dt ) -- Jan 1 2001 12:00AM
print dateadd(second,1472300673,#dt ) -- Aug 27 2016 12:24PM
Seems possible, but who knows?!
You can check every date in your table simply using
declare #dt DATETIME = '1970-01-01' -- epoch start
SELECT
nDateTime AS OriginalData,
DATEADD(second, nDateTime,#dt) AS ActualDateTime
FROM EventLog
Just for giggles, I took a stab at having the base date of 1970-01-01, but without KNOWING the base, it is just a guess
Declare #Log table (DateInt int)
Insert Into #Log values
(978307200),
(978307219),
(978513562),
(978516233),
(978544196),
(1450379547),
(1472299563),
(1472299581),
(1472300635),
(1472300644),
(1472300673)
Select DateInt,Converted= DateAdd(SECOND,DateInt,'1970-01-01') From #Log
Returns
DateInt Converted
978307200 2001-01-01 00:00:00.000
978307219 2001-01-01 00:00:19.000
978513562 2001-01-03 09:19:22.000
978516233 2001-01-03 10:03:53.000
978544196 2001-01-03 17:49:56.000
1450379547 2015-12-17 19:12:27.000
1472299563 2016-08-27 12:06:03.000
1472299581 2016-08-27 12:06:21.000
1472300635 2016-08-27 12:23:55.000
1472300644 2016-08-27 12:24:04.000
1472300673 2016-08-27 12:24:33.000
The "2038" Problem with Unix Timestamps
There's a serious issue with writing code to convert UNIX Timestamps that are based on seconds... DATEADD can only handle INTs and that brings us to the "2038/Y2K38/Friday the 13th" problem (the day of the week when then "wraparound" to the most negative number an INT can have happens after the date below).
That means that the largest positive value it can handle is 2147483647. If we use DATEADD to add that number of seconds to the UNIX Epoch of the first instant of the year 1970, we end up with a DATETIME that clearly explains what they mean by the "2038" issue.
SELECT DATEADD(ss,2147483647,'1970');
The Standard Fix for the "2038" Problem
The standard way to get around that is to first store the UNIX Timestamp as a BIGINT and do two date adds... one for seconds and one for days.
There are 84600 seconds in a day. If we do Integer Division and ...
Use the Quotient to derive the number of days to add to
'1970'...
And use the Remainder to derive the number of
seconds to add to '1970'...
... we'll get the correct date not only for the MAX INT value...
DECLARE #SomeUnixTS BIGINT = 2147483647
,#SecsPerDay BIGINT = 86400
;
SELECT DATEADD(ss,#SomeUnixTS%#SecsPerDay,DATEADD(dd,#SomeUnixTS/#SecsPerDay,'1970'))
;
... but also for the last possible date in seconds for SQL Server. If we calculate the UNIX Timestamp (in seconds) for the last possible second that's available in SQL Server...
SELECT DATEDIFF_BIG(ss,'1970','9999-12-31 23:59:59');
... it still works with lots of room to spare and no "2038" problem.
DECLARE #SomeUnixTS BIGINT = 253402300799
,#SecsPerDay BIGINT = 86400
;
SELECT DATEADD(ss,#SomeUnixTS%#SecsPerDay,DATEADD(dd,#SomeUnixTS/#SecsPerDay,'1970'))
;
UNIX Timestamps Based on Milliseconds
Working with UNIX Timestamps that are based on Milliseconds are only slightly different but must be handled the same way...
DECLARE #SomeUnixTS BIGINT = DATEDIFF_BIG(ms,'1970','9999-12-31 23:59:59.999')
,#msUnixEpoch DATETIME2(3) = '1970'
,#msPerDay BIGINT = 86400000
;
SELECT SomeUnixTS = #SomeUnixTS
,msUnixEpoch = #msUnixEpoch
,Converted = DATEADD(ms,#SomeUnixTS%#msPerDay,DATEADD(dd,#SomeUnixTS/#msPerDay,#msUnixEpoch))
;
As a bit of a sidebar, you have to wonder what Microsoft was or was not thinking when they created DATEDIFF_BIG() but didn't create a DATEADD_BIG(). Amazing even more is the they have SQL Server that will work in a UNIX environment and still no CONVERT(ts) functionality.
Here's whats new in 2022 in the area I'm talking about...
https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2022?view=sql-server-ver16#language
And, last but not least, do not convert UNIX Timestamps that are based on milliseconds directly to DATETIME because the rounding in DATETIME can take you to the next day, week, month, and even year. You must do a "units place" detection for "9" and "-1" and make the appropriate substitution of "7" and "-3" respectively.
Your input is > 8 digits hence it is throwing arithmentic overflow error.. If it is 8 digits you will get converted data:
For Example:
DECLARE #ndatetime int = 978307200
SELECT CONVERT(datetime, convert(varchar(10), #ndatetime, 112))
-- this throws arithmetic overflow error
DECLARE #ndatetime int = 97830720 -- with 8 digits only
SELECT CONVERT(datetime, convert(varchar(10), #ndatetime, 112))
This returns converted date
You can try try_convert which will return null if it is wrong date
DECLARE #ndatetime int = 978307200
SELECT TRY_CONVERT(datetime, convert(varchar(10), #ndatetime, 112))
Looking for assistance with a strange issue if anyone has ideas:
I have a SQL that statement works most of the time in a T-SQL script but crashes occasionally. I have identified the data that a crash occurs on and cannot identify any difference between data rows that work.
The goal of this code is to add the time to an already existing datetime value that has 00:00:00 as the time from the second time column (as outlined below). My goal is to combine both columns into YYYY-MM-DD HH:MM:SS format, but I had to convert them to char first to trim off the orignal 00:00:00.
Columns
LogDate - contains date only in DateTime format (YYYY-MM-DD HH:MM:SS)
LogTime - contains the time of the action and is in varchar format (HH:MM)
SQL Conversion
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), LogDate, 112) + ' ' + CONVERT(CHAR(8), LogTime, 108))
FROM TestTable
WHERE EventSerial = '100001'
However, if I change the EventSerial in the above statement to a different row, such as '100002', the statement works.
The data for each row is below:
EventSerial 100001's values:
LogDate: 2015-04-02 00:00:00.000
LogTime: 10:04
EventSerial 100002's values:
LogDate: 2015-04-02 00:00:00.000
LogTime: 10:48
Running with data set 1 fails, running with data set 2 produces output. Also, running the code without the final datetime conversion works, or if I run the code with the string manually it works (as outlined below:)
SELECT CONVERT(CHAR(8), LogDate, 112) + ' ' + CONVERT(CHAR(8), LogTime, 108)
FROM TestTable
WHERE EventSerial = '100001'
SELECT CONVERT(DATETIME, '20150402 10:48')
SELECT CONVERT(DATETIME, '20150402 10:04')
Any suggestions, I'm sure its something silly that I'm missing (and I probably took the long way around the issue anyway. The desired output would be 2015-04-02 10:04:00
First, datetime has no format. (why?)
Second, you don't need to convert the datetime value to char to add hours and minutes, just use DateAdd:
SELECT DATEADD(Minute,
CAST(RIGHT(LogTime, 2) as int),
DATEADD(Hour,
CAST(LEFT(LogTime, 2) as int),
LogDate
)
)
FROM TestTable
WHERE EventSerial = '100001'
Also, note that convert does not hold a style for yyyymmdd hh:mm
Note: code was written directly here, there might be some mistakes.
I'm not sure why you're getting the error... possibly there are some unseen characters in your varchar time field... like a tab or something maybe? Try this query:
SELECT ascii(substring(LogTime,1,1)) Char1,
ascii(substring(LogTime,2,1)) Char2,
ascii(substring(LogTime,3,1)) Char3,
ascii(substring(LogTime,4,1)) Char4,
ascii(substring(LogTime,5,1)) Char5
FROM TestTable
WHERE EventSerial = '100001'
It should show these results:
Char1 Char2 Char3 Char4 Char5
----------- ----------- ----------- ----------- -----------
49 48 58 48 52
(1 row(s) affected)
This would be a bit more efficient:
select dateadd(minute, datediff(minute,0, LogTime), LogDate)
FROM TestTable
But this assumes that your date field always has 00:00:00 time information. If you want to be sure that is stripped out as well you could use:
select dateadd(minute, datediff(minute,0, LogTime), dateadd(day, datediff(day, 0, Logdate),0))
FROM TestTable
Have table where have time like : 15:30 , want select data from table in 15 minute interval but only possitive, I try :
select id from myTbl
where type = 2 and DATEDIFF(mi,my_time,LEFT(CAST(GETDATE() as time),5)) <= 15
For example if my_time = 15:55 and LEFT(CAST(GETDATE() as time),5)) = 16:45 in response i have -50 and its <= 15 but i need comparison only possitive , when i try ABS it dont help me because when time in response is -14 ABS take it +14 and its <=15 . So i have 28 minute interval (-14 and 14). Is it possible tu avoid all negative numbers ? and comparison only if it is possitive
select id
from myTbl
where type = 2
and DATEDIFF(mi,my_time,LEFT(CAST(GETDATE() as time),5)) <= 15
and DATEDIFF(mi,my_time,LEFT(CAST(GETDATE() as time),5)) >=0
A much better approach would be some thing like ...
SELECT id
FROM myTbl
WHERE [TYPE] = 2
AND my_time >= CAST(DATEADD(MINUTE, -15, GETDATE()) AS TIME)
AND my_time <= CAST(GETDATE() AS TIME)
Avoid using DATEDIFF and other scalar functions on your columns in where clause, as it will not allow query optimizer to make use of any indexes even if there is an index that query can benefit from , Read this article for more information SARGable functions in SQL Server
i have a column (nvarchar),there are datetimes in there but as a string.I want to change that column's type into smalldatetime but before i want to format all string dates into a same datetime format.But i cant succeed it.Some of them are like this "2007-07-10",some of them are reverse of this "02.07.2008". How can i change them into one format for example dd.mm.yyyy.
(ms sql server 2008)
If you only have those 2 formats, this is how you can do it.
I am assuming
'02.07.2008' has format 'dd.mm.yyyy'
'2007-07-10' has format 'yyyy-mm-dd'
If you have more formats than that, you have to alter the 'case' in the 'select' clause accordingly
declare #t table (a varchar(12))
insert #t values ('02.07.2008')
insert #t values ('2007-07-10')
select convert(date, a, case when charindex('-',a) = 5 then 21 else 103 end)
from #t
Output
2008-07-02
2007-07-10
The format is standard for a date field, but if you want to store it as a varchar, you can format it as dd.mm.yyyy like this instead.
select replace(convert(varchar, convert(date, a, case when charindex('-',a) = 5
then 21 else 103 end), 103), '/', '.')
from #t
Output
02.07.2008
10.07.2007
I have to point out that you should always store a date as a date and not a varchar in the database when possible.
You can't do it unless you know the exact format.
Think about the different formats - in some countries the month comes first, while in the other it's the day. So if you don't know whether 02.07.2008 means July 2th, or it means Feb 7th, then you can't possibly accomplish your task.