SQL IsNumeric not working
The reserve c开发者_运维技巧olumn is a varchar, to perform sums on it I want to cast it to a deciaml. But the SQL below gives me an error
select
cast(Reserve as decimal)
from MyReserves
Error converting data type varchar to numeric.
I added the isnumeric and not null to try and avoid this error but it still persists, any ideas why?
select
cast(Reserve as decimal)
from MyReserves
where isnumeric(Reserve ) = 1
and MyReserves is not null
See here: CAST and IsNumeric
Try this:
WHERE IsNumeric(Reserve + '.0e0') = 1 AND reserve IS NOT NULL
UPDATE
Default of decimal is (18,0), so
declare @i nvarchar(100)='12121212121211212122121'--length is>18
SELECT ISNUMERIC(@i) --gives 1
SELECT CAST(@i as decimal)--throws an error
Gosh, nobody seems to have explained this correctly. SQL is a descriptive language. It does not specify the order of operations.
The problem that you are (well, were) having is that the where
does not do the filtering before the conversion takes place. Order of operations, though, is guaranteed for a case statement. So, the following will work:
select cast(case when isnumeric(Reserve) = 1 then Reserve end as decimal)
from MyReserves
where isnumeric(Reserve ) = 1 and MyReserves is not null
The issue has nothing to do with the particular numeric format you are converting to or with the isnumeric()
function. It is simply that the ordering of operations is not guaranteed.
It seems that isnumeric has some Problems:
http://www.sqlhacks.com/Retrieve/Isnumeric-problems (via internet archive)
According to that Link you can solve it like that:
select
cast(Reserve as decimal)
from MyReserves
where MyReserves is not null
and MyReserves * 1 = MyReserves
Use try_cast (sql 2012)
select
try_cast(Reserve as decimal)
from MyReserves
IsNumeric is a problem child -- SQL 2012 and later has TRY_CAST and TRY_CONVERT
If you're on an earlier version then you can write a function that'll convert to a decimal (or NULL if it won't convert). This uses the XML conversion functions that don't throw errors when the number won't fit ;)
-- Create function to convert a varchar to a decimal (returns null if it fails)
IF EXISTS( SELECT * FROM sys.objects WHERE object_id = OBJECT_ID( N'[dbo].[ToDecimal]' ) AND type IN( N'FN',N'IF',N'TF',N'FS',N'FT' ))
DROP FUNCTION [dbo].[ToDecimal];
GO
CREATE FUNCTION ToDecimal
(
@Value VARCHAR(MAX)
)
RETURNS DECIMAL(18,8)
AS
BEGIN
-- Uses XML/XPath to convert @Value to Decimal because it returns NULL it doesn't cast correctly
DECLARE @ValueAsXml XML
SELECT @ValueAsXml = Col FROM (SELECT (SELECT @Value as Value FOR XMl RAW, ELEMENTS) AS Col) AS test
DECLARE @Result DECIMAL(38,10)
-- XML/XPath will return NULL if the VARCHAR can't be converted to a DECIMAL(38,10)
SET @Result = @ValueAsXml.value('(/row/Value)[1] cast as xs:decimal?', 'DECIMAL(38,10)')
RETURN CASE -- Check if the number is within the range for a DECIMAL(18,8)
WHEN @Result >= -999999999999999999.99999999 AND @Result <= 999999999999999999.99999999
THEN CONVERT(DECIMAL(18,8),@Result)
ELSE
NULL
END
END
Then just change your query to:
select dbo.ToDecimal(Reserve) from MyReserves
isnumeric
is not 100% reliable in SQL - see this question Why does ISNUMERIC('.') return 1?
I would guess that you have value in the reserve column that passes the isnumeric
test but will not cast to decimal.
Just a heads up on isnumeric; if the string contains some numbers and an 'E' followed by some numbers, this is viewed as an exponent. Example, select isnumeric('123E0') returns 1.
I had this same problem and it turned out to be scientific notation such as '1.72918E-13' To find this just do where Reserve LIKE '%E%'. Try bypassing these and see if it works. You'll have to write code to convert these to something usable or reformat your source file so it doesn't store any numbers using scientific notation.
IsNumeric
is possibly not ideal in your scenario as from the highlighted Note on this MSDN page it says "ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($)."
Also there is a nice article here which further discusses ISNUMERIC
.
Try (for example):
select
cast(Reserve as decimal(10,2))
from MyReserves
Numeric/Decimal generally want a precision an scale.
I am also facing this issue and I solved by below method. I am sharing this because it may helpful to some one.
declare @g varchar (50)
set @g=char(10)
select isnumeric(@g),@g, isnumeric(replace(replace(@g,char(13),char(10)),char(10),''))
Please try this:
declare @Value varchar (50)='Test01';
IF @Value LIKE '%[0-9]%'
BEGIN
PRINT 'Its numeric';
END
ELSE
BEGIN
PRINT 'Its not numeric';
END
精彩评论