SQL IsNumeric не работает - PullRequest
       25

SQL IsNumeric не работает

7 голосов
/ 27 сентября 2011

Резервный столбец - это varchar, для суммирования я хочу привести его к deciaml.Но приведенный ниже SQL дает мне ошибку

select
cast(Reserve as decimal)
from MyReserves

Ошибка преобразования типа данных varchar в числовой.

Я добавил isnumeric, а не null, чтобы попытаться избежать этой ошибки, но она все еще сохраняется, любаяидеи почему?

select
cast(Reserve as decimal)
from MyReserves
where isnumeric(Reserve ) = 1
and MyReserves is not null

Ответы [ 11 ]

8 голосов
/ 27 сентября 2011

См. Здесь: CAST и IsNumeric

Попробуйте это:

WHERE IsNumeric(Reserve + '.0e0') = 1 AND reserve IS NOT NULL

UPDATE

Десятичное число по умолчанию - (18,0), поэтому

declare @i nvarchar(100)='12121212121211212122121'--length is>18 
SELECT ISNUMERIC(@i) --gives 1
SELECT CAST(@i as decimal)--throws an error
4 голосов
/ 22 января 2013

Черт возьми, кажется, никто не объяснил это правильно. SQL - это описательный язык. Не указывается порядок операций.

Проблема, с которой вы (ну, были), заключается в том, что where не выполняет фильтрацию до преобразования. Порядок операций, тем не менее, гарантирован для описания случая. Итак, будет работать следующее:

select cast(case when isnumeric(Reserve) = 1 then Reserve end as decimal)
from MyReserves
where isnumeric(Reserve ) = 1 and MyReserves is not null

Эта проблема не имеет отношения к конкретному числовому формату, который вы конвертируете, или к функции isnumeric(). Просто порядок операций не гарантирован.

3 голосов
/ 27 сентября 2011

Кажется, что у числовых есть некоторые проблемы:

http://www.sqlhacks.com/Retrieve/Isnumeric-problems (через интернет-архив)

По этой ссылке вы можете решить эту проблему так:

select
cast(Reserve as decimal)
from MyReserves
where MyReserves is not null
and MyReserves * 1 = MyReserves 
2 голосов
/ 03 июня 2015

Использовать try_cast (sql 2012)

select
try_cast(Reserve as decimal)
from MyReserves
1 голос
/ 04 августа 2015

IsNumeric - это проблемный дочерний объект - в SQL 2012 и более поздних версиях TRY_CAST и TRY_CONVERT

Если вы работаете в более ранней версии, вы можете написать функцию, которая преобразуется вдесятичный (или NULL, если он не будет преобразован).При этом используются функции преобразования XML, которые не выдают ошибок, когда число не подходит;)

-- 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

Затем просто измените запрос на:

select dbo.ToDecimal(Reserve) from MyReserves
1 голос
/ 17 сентября 2013

У меня была та же самая проблема, и это оказалось научной нотацией, такой как '1.72918E-13'. Чтобы найти это, просто сделайте, где Резервный НРАВИТСЯ '% E%'.Попробуйте обойти это и посмотреть, если это работает.Вам нужно будет написать код, чтобы преобразовать их во что-нибудь пригодное для использования или переформатировать исходный файл, чтобы он не сохранял никаких чисел с использованием научной записи.

1 голос
/ 08 января 2013

Просто один на один числовой; если строка содержит несколько чисел и 'E', за которыми следуют несколько чисел, это рассматривается как показатель степени. Например, select isnumeric ('123E0') возвращает 1.

1 голос
/ 27 сентября 2011

isnumeric не является на 100% надежным в SQL - см. Этот вопрос Почему ISNUMERIC ('.') Возвращает 1?

Я думаю, у вас есть значение в резервестолбец, который проходит тест isnumeric, но не преобразуется в десятичное число.

0 голосов
/ 18 мая 2018

Я также столкнулся с этой проблемой, и я решил по методу ниже.Я делюсь этим, потому что это может быть полезно для кого-то.

declare @g varchar (50)
 set @g=char(10)
 select isnumeric(@g),@g, isnumeric(replace(replace(@g,char(13),char(10)),char(10),''))
0 голосов
/ 27 сентября 2011

Попробуйте (например):

select
cast(Reserve as decimal(10,2))
from MyReserves

Числовые / десятичные, как правило, требуют точности шкалы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...