Pull numbers out of a decimal - sql

Okay so, I have a column that looks something like this:
20140813000000000
It is displaying a date, in the format of decimal(17,0), but I need to take the first 8 characters out of it to convert it to a date so it can be used. I've tried casting and converting and substring but everything leads to an arithmetic overflow. Any help on getting that date out?
Example of what I am using and the error:
CAST(SUBSTRING(CAST([tblDate] as varchar),1,8) as Date)
Conversion failed when converting date and/or time from character string.

I got it working, I added a case to filter out the 0's to NULL before casting it as a date:
Select
CAST(CASE
WHEN SUBSTRING(CAST([tblDate] as varchar),1,8) = 0 THEN NULL
ELSE SUBSTRING(CAST([tblDate] as varchar),1,8)
END as DATE)

Great that you found a solution to your own problem, but note that this won't work if you ever have values like 00000000000000001 in your table as this will be converted to 1, pass the first test in your CASE statement and then throw an exception as 1 won't CAST to DATE.
This is more long-winded, but safer... (full example included):
DECLARE #TestTable TABLE ([tblDate] NUMERIC(17,0));
INSERT INTO #TestTable VALUES(00000000000000001); --Edge case
INSERT INTO #TestTable VALUES(20140831000000001); --Value to parse
SELECT
CASE
WHEN SUBSTRING(REPLACE(RIGHT('00000000000000000' + CAST([tblDate] AS VARCHAR(17)), 17), SPACE(1), '0'), 1, 8) = '00000000' THEN NULL
ELSE SUBSTRING(CAST([tblDate] AS VARCHAR(17)), 1, 8)
END
FROM
#TestTable;
Returns:
NULL
2014-08-31
Your answer would throw an exception for the first value.
If you are sure your data will ALWAYS either be all zeroes or contain a date to be parsed then fine...

Related

Converting strings to date in SQL

I am using SQL Server 2017. I am trying to handle strings from a free format field and either convert them to a date in the format of "dd/mm/yyyy" or if they are not in this format then simply display the text verbatim.
I need this in a VIEW so can not use SET LANGUAGE. Sounds simple using Convert and IsDate but does not seem to work.
So for the snippet of code below (remember this will be in a view), I want to read the text and if the string converts to a date (ie. is in the format dd/mm/yyyy then run the convert to a date as I need it in date format for Excel to pick up (via Connect SQL Server database)), and if it does not convert to a date then display the text as it is.
create table dateTest1
(
idx int,
dateStringTest varchar(15)
);
insert into dateTest1 (idx, dateStringTest)
values (1, '13/01/2021'), (2, 'no');
select
case
when isdate(convert(datetime, dateStringTest, 103)) = 1
then convert(datetime, dateStringTest, 103)
else dateStringTest
end as dtres
from
dateTest1
--where idx = 1
Error:
Msg 241, Level 16, State 1, Line 15
Conversion failed when converting date and/or time from character string.
This error happens for idx = 2. Idx = 1 works ok.
Any assistance with this would be greatly appreciated. Thanks in advance.
You need to cast your resulting date to a varchar. A case expression can only return a single data type and the order-of-precedence means it is still trying to convert the varchar values to datetime
select
case when isdate( dateStringTest) = 1
then Cast(convert(datetime, dateStringTest, 103) as varchar(10))
else dateStringTest
end as dtres
from dateTest1
You can compact into a single statement (the same order of precedence applies)
select IsNull(Cast(Convert(datetime,Try_Cast(dateStringTest as date),103) as varchar(10)),dateStringTest)
from datetest1
Based on the syntax you are using, I assume you are using SQL Server. You should add the appropriate tag to your question.
The only way to do that in one column is to leave it as text.
Your use of ISDATE() is incorrect. If dateStringTest is not a valid date, CONVERT() on SQL Server will throw an error like:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
That's why you get an error for idx=2
You say you "need it in date format for Excel to pick up". How Excel interprets it will probably depend on your locale settings. Assuming mm/dd/yyyy is valid in your locale, Excel probably already sees it as a date. But I assume that's not happening, so mm/dd/yyyy is not valid for your locale. For me, if I have this table in SQL...
create table dateTest1 (
id int identity(1,1) not null,
dateStringTest varchar(20)
)
insert dateTest1
values
('2020-01-01')
, ('2020-21-01')
, ('2020-01-21')
, ('1/1/2020')
, ('1/21/2020')
, ('21/1/2020')
, ('21/01/2020')
, ('other stuff')
...and query it from Excel, adding columns with the functions DATEVALUE, DAY, WEEKDAY, and YEAR, I get...
id
dateStringTest
DATEVALUE
DAY
WEEKDAY
YEAR
1
2020-01-01
43831
1
4
2020
2
2020-21-01
#VALUE!
#VALUE!
#VALUE!
#VALUE!
3
2020-01-21
43851
21
3
2020
4
1/1/2020
43831
1
4
2020
5
1/21/2020
43851
21
3
2020
6
21/1/2020
#VALUE!
#VALUE!
#VALUE!
#VALUE!
7
21/01/2020
#VALUE!
#VALUE!
#VALUE!
#VALUE!
8
other stuff
#VALUE!
#VALUE!
#VALUE!
#VALUE!
That seems to indicate that Excel is recognizing some of the values as dates.
What you need to do is try to convert the value to datetime, then if it fails report the original value. In both cases, output a string.
You should review the documentation for CONVERT().
Try this:
select dateStringTest
, coalesce(cast(try_convert(datetime, dateStringTest, 103) as varchar(20)), dateStringTest) as dtres1
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 103), dateStringTest) as dtres2
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 101), dateStringTest) as dtres3
from dateTest1
UPDATE
If you are considering only values matching the pattern dd/mm/yyyy as dates (so 17/01/2021 is a date and 17/1/2021 is not), this brute force method will work with SQL Server 2008 (compatibility level 100):
(Notice I updated my input, also, above.)
;
with a as (
select id
, dateStringTest
, SUBSTRING(dateStringTest, 7, 4) + '-' + SUBSTRING(dateStringTest, 4, 2) + '-' + SUBSTRING(dateStringTest, 1, 2) as converteDate
from dateTest1
)
select id
, cast(convert(datetime, dateStringTest, 103) as varchar(20)) as dtres
from a
where isdate(converteDate) = 1
union
select id
, dateStringTest as dtres
from a
where isdate(converteDate) = 0

Handling a value of zero in a date datatype

I'm reporting out of a database that is using decimal(17,6) as the datatype for a date field. For example, the current date/time in this field would be 20210820.171900. Unusual, but whatever. I need to convert the original date field from decimal(17,6) to datetime. This is what I have:
SELECT convert(datetime, convert(varchar,convert(int, lastmoddatetime)), 0)
from Table1
The above statement works correctly as long as none of the records have a value of zero in this column. Unfortunately, the column value defaults to zero (0.000000) if no date has been calculated for it. Whenever a column has a zero value, I get the following error:
Conversion failed when converting date from character string.
How can I overcome this issue? Ultimately, I'm needing to apply a dateadd function to the lastmoddatetime field.
Note: Before you suggest changing the column definition, this database originated in the 1990's and I'm not allowed to make any changes to the database structure.
You can use NULLIF to null out those values
convert(datetime, convert(varchar(15), convert(int, NULLIF(lastmoddatetime, 0.0))), 0)
Either use TRY_CONVERT or CASE - depending how you want to handle the zero case.
SELECT
-- If desiring null for 0 and SQL Server 2012+
TRY_CONVERT(date, CONVERT(varchar, CONVERT(int, lastmoddatetime)), 0)
, CASE WHEN lastmoddatetime <> 0
-- If desiring some other valid date or < SQL Server 2012
THEN CONVERT(date, CONVERT(varchar, CONVERT(int, lastmoddatetime)), 0)
ELSE NULL /* Whatever valid datetime value you want */ END
FROM (
VALUES (20210820.171900), (0.0)
) x (lastmoddatetime);
I note that this ignores the time component - so am converting to a date not datetime above. If you need to handle the time component you need to update your question.
Yet another option.
You can thin it out a bit by using left() and try_convert()
Example
Declare #YourTable table (lastmoddatetime numeric(17,6))
Insert into #YourTable values
(20210820.171900)
,(0.0)
Select AsDate = try_convert(date,left(lastmoddatetime,8))
,AsDateTime = try_convert(datetime,left(lastmoddatetime,8))
From #YourTable
Results
AsDate AsDateTime
2021-08-20 2021-08-20 00:00:00.000
NULL NULL
use
convert(datetime,convert(int,lastmoddatetime),0)

Conversion from INT to varchar in sql

I have a table where there are values like 20170730 and also 0 values are there which is INT type
I am trying to convert it to value like 30/07/2017, for which i am using the below code,
Select convert(NVARCHAR(10),convert(date,convert(NCHAR(8),datecolumn)),103) from table
But for the zero values i am getting the below error
Conversion failed when converting date and/or time from character string.
If i delete all the zero this working fine but problem having with zero.
My requirement is to convert when there a date value and if 0 are there then it should be zero only like below,
Result
30/07/2017
0
Can u pls help
As already pointed out in the comments, you can try to use a CASE expression
SELECT CASE
WHEN nmuloc = 0 THEN
'0'
ELSE
convert(varchar(10),
convert(date,
convert(varchar(8),
nmuloc),
112),
103)
END
FROM elbat;
or try_convert() and coalesce().
SELECT coalesce(convert(varchar(10),
try_convert(date,
convert(varchar(8),
nmuloc),
112),
103),
'0')
FROM elbat;
db<>fiddle
The latter one will also correct other "malformed" data like 123 for example. The former will also fail in such cases. You may want that or not.
But, as also already pointed out in the comments, your real problem is that you use an inappropriate data type. Change the column's datatype to some date/time data type to really fix this.

SQL Server - Value passes ISDATE() but fails to CAST as DATE or DATETIME

I have a varchar column in my database table, on the row I would like to return it is populated as '2018-12-26T00:00:00.000' (quotes mine, not included in actual value). When I try to query for this value whenever it is a valid date, e.g.
SELECT
myValue
FROM
myTable
WHERE
ISDATE(myValue) = 1
it returns properly. However, I need this value to be converted to DATE. When I try something like this:
SELECT
CAST(myValue AS DATE) AS myValueFormatted
FROM
myTable
WHERE
ISDATE(myValue) = 1
I get an error
Conversion failed when converting date and/or time from character string
Is there any other way I can convert this varchar value to Date?
UPDATE: I've noticed through trying some different things, the query seems to be fine with me using the value as a date for anything (DATEDIFF, CONVERT back to string, etc.) in the select portion, but trying to do anything with it in the WHERE clause causes the error. To ensure nothing else is interfering, I created a temp table with only 1 row with the data value above, and running the query just against that one value gives the error
UPDATE 2: Ok, I have no idea why this fixes it, but this is what I found. When I run
SELECT
myValue
FROM
myTable
WHERE
TRY_CONVERT(DATE, myValue) IS NOT NULL
it returns EXACTLY the same values as
SELECT
myValue
FROM
myTable
WHERE
ISDATE(myValue) = 1
However, when I then add AND CAST(myValue AS DATE) < GETDATE() to each WHERE clause, only the first one works. I understand why TRY_CONVERT is safer to use, I'm still not sure why it works over GETDATE()
I can't reproduce your error...
declare #dt varchar(256) = '2018-12-26T00:00:00.000'
select cast(#dt as date)
So, there must be another rogue value in there that can't be converted.
To identify what value is causing the issue on versions < 2012, run this:
SELECT
myValue
FROM myTable
WHERE
ISDATE(myValue) = 0
Note, ISDATE is deterministic only if you use it with the CONVERT function, if the CONVERT style parameter is specified, and style is not equal to 0, 100, 9, or 109.
For 2012 onward, use TRY_CONVERT
SELECT
*
FROM myTable
WHERE
TRY_CONVERT(date, myValue) IS NULL
You could also just try something like this:
SELECT CAST(LEFT(MyValue, 10) AS DATE)
If it still doesn't work, you have some formatting issues with your data.
This helped me....
CAST string as varchar(30) then cast the varchar as datetime2
CAST(CAST(REPLACE(['Timestamp' ],'''','') AS varchar(30)) as datetime2)

SQL IsNumeric Returns True but SQL Reports 'Conversion Failed'

Assuming the following data:
Column1 (data type: varchar(50))
--------
11.6
-1
1,000
10"
Non-Numeric String
I have a query, which is pulling data from this column and would like to determine if the value is a number, then return it as such in my query. So I am doing the following
SELECT CASE
WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN Replace(Column1, '"', '')
ELSE 0
END AS NumericValue
SQL is reporting back:
Conversion failed when converting the varchar value '11.6' to data type int.
Why? I have also tried to force cast this:
SELECT CASE
WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN cast(Replace(Column1, '"', '') AS float)
ELSE 0
END AS NumericValue
And I got:
Error converting data type varchar to float.
You need to replace comma with a period:
CAST(REPLACE(column, ',', '.') AS FLOAT)
SQL Server outputs decimal separator defined with locale, but does not unterstand anything but a period in CASTs to numeric types.
First convert the string to money, then covert it to any other numeric format since money type gives a true numeric string always. You will never see an error then.
Try the following in your query, and you'll know what I am talking about. Both will return 2345.5656. The Money datatype is rounded to 4 decimal places, and hence the casting causes rounding to 4 decimal places.
SELECT CAST('2,345.56556' as money), CAST('$2,345.56556' as money)
Cast( cast('2,344' as money) as float) will work perfectly or
cast( cast('2,344' as money) as decimal(7,2)) will also work.
Even cast(CAST('$2,345.56556' as money) as int ) will work perfectly rounding it to nearest integer.
There are many issues with SQL isnumeric. For example:
select isnumeric('1e5')
This will return 1 but in many languages if you try to convert it to a number it will fail. A better approach is to create your own user defined function with the parameters you need to check for:
http://www.tek-tips.com/faqs.cfm?fid=6423
ISNUMERIC returns 1 when the input expression evaluates to a valid integer, floating point number, money or decimal type;
So the problem is it is a valid number but not a valid int.
Kyle,
I think this solves the problem. The problem lies in the fact that the ELSE clause initializes your result to be an INTEGER. By making an explicit typecast to FLOAT and adding the suggestion of Quassnoi, it seems to work.
DECLARE #MyTable TABLE (Column1 VARCHAR(50))
INSERT INTO #MyTable VALUES('11.6')
INSERT INTO #MyTable VALUES('-1')
INSERT INTO #MyTable VALUES('1,000')
INSERT INTO #MyTable VALUES('10" ')
INSERT INTO #MyTable VALUES('Non-Numeric String')
SELECT CASE WHEN ISNUMERIC(REPLACE(Column1,'"','')) = 1 THEN REPLACE(REPLACE(Column1,'"',''), ',', '.') ELSE CAST(0 AS FLOAT) END
FROM #MyTable
Regards,
Lieven
IsNumeric(' ') also returns 1, but then CAST as int blows up. Brendan above says write your own function. He is correct.
This solution does not work in all cases (specifically numbers with money and/or thousand separators). Concatenate an exponent representation to the end of the number which is represented by a string...ISNUMERIC() works fine from there. Examples below:
-- CURRENT ISNUMERIC RESULTS
SELECT ISNUMERIC('11.6'); --1
SELECT ISNUMERIC ('-1'); --1
SELECT ISNUMERIC('1,000'); --1
SELECT ISNUMERIC('10"'); --0
SELECT ISNUMERIC('$10'); --1
-- NEW ISNUMERIC RESULTS
SELECT ISNUMERIC('11.6'+'e+00'); --1
SELECT ISNUMERIC ('-1'+'e+00'); --1
SELECT ISNUMERIC('1,000'+'e+00'); --0
SELECT ISNUMERIC('10"'+'e+00'); --0
SELECT ISNUMERIC('$10'+'e+00'); --0
This, at the very least, standardizes the format for using the REPLACE() function.
I have just meet this issue.
You can try this solution if you don't mind about limitation of decimal length.
CONVERT(numeric, CONVERT(money, '.'))
NOTE:
It is supported in SQL Server 2008 or above.
Money range is : -922,337,203,685,477.5808 to 922,337,203,685,477.5807 - four decimals.