Ошибка преобразования VARCHAR в float - PullRequest
1 голос
/ 10 ноября 2011

Получение ошибки при конвертации varchar в float.

Иметь таблицу (не моего производства) с колонкой result, имеющую данные varchar.Я хотел бы преобразовать в float, чтобы получить все значения> 180.0.

SELECT result FROM table WHERE result > 180.0

Выдает ошибку.Интересно, что:

WITH temp AS (
  CASE
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT)
    ELSE CAST(-1.0 AS FLOAT)
  END AS result
)

Это работает нормально.Когда я соединяю его с:

SELECT temp.result FROM temp WHERE temp.result > 180.0

, я снова получаю сообщение об ошибке.Мысли?

ОБНОВЛЕНИЕ: Запрошен полный код ...

WITH temp AS (
  SELECT
  CASE
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT)
    ELSE CAST(-1.0 AS FLOAT)
  END AS result
  FROM table)

SELECT temp.result FROM temp WHERE temp.result > 180.0

Использование SQL-SERVER 2008 RC2.

Ответы [ 3 ]

9 голосов
/ 10 ноября 2011

Это означает, что у вас есть хотя бы одна строка в таблице, которую нельзя привести к float. Выполнение CASE безопасно, но объединение CTE и добавление предложения WHERE впадает в общую ошибку программистов при написании T-SQL: такой порядок объявления подразумевает порядок выполнения . Программисты привыкли к императивному процессуальному стилю C-подобных языков и не в состоянии постичь декларативную множественную природу SQL. Я уже писал об этой проблеме и приводил примеры, когда ошибка вызывает ошибки:

Как только вы опубликуете свой полный код, мы увидим, где именно вы допустили ошибку в вашем случае и приняли определенный порядок исполнения.

после обновления

ОК, поэтому я должен сообщить администратору, что в вашем случае код является правильным в порядке выполнения, столбец result нельзя спроецировать без предварительной оценки CASE. Если бы дело было в предложении WHERE, все было бы иначе.

Ваша проблема в другом: ISNUMERIC. Эта функция очень хорошо понимает, что означает NUMERIC, и укусила многих разработчиков раньше. А именно, он принимает значения, которые CAST и CONVERT отклонят. Как те, которые содержат запятую:

declare @n varchar(8000) = '1,000';
select isnumeric(@n);
select cast(@n as float);
select case when isnumeric(@n)=1 then cast(@n as float) else null end;

Итак, у вас есть значения, которые проходят тест ISNUMERIC, но не преобразуются. Просто на голову, чем больше вы будете копаться в этом подходе, тем больше закрытых дверей вы найдете. Это просто не безопасный способ сделать то, что вам нужно на стороне сервера. В идеале исправьте модель данных (сделайте поле плавающим, если оно хранит плавающие числа). Если не считать этого, выполните сортировку данных и удалите все значения, которые не являются правильными, и исправьте интерфейс / приложение, чтобы он больше не вводил новые, затем добавьте ограничение, которое вызовет ошибку, если появятся новые неверные значения. Вы не сможете решить это в запросе, эта дорога усеяна телами.

В следующей версии SQL Server у вас будет новая функция TRY_CONVERT, которая решит вашу проблему.

3 голосов
/ 11 ноября 2011

Проверьте это:

http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html

В принципе, есть некоторые известные проблемы / странности с функцией ISNUMERIC. Автор этой статьи предлагает создать новую функцию и использовать ее вместо ISNUMERIC. Я протестировал его с предложенным вами значением 1,0, и, похоже, оно работает.


CREATE FUNCTION dbo.isReallyNumeric  
(  
    @num VARCHAR(64)  
)  
RETURNS BIT  
BEGIN  
    IF LEFT(@num, 1) = '-'  
        SET @num = SUBSTRING(@num, 2, LEN(@num))  

    DECLARE @pos TINYINT  

    SET @pos = 1 + LEN(@num) - CHARINDEX('.', REVERSE(@num))  

    RETURN CASE  
    WHEN PATINDEX('%[^0-9.-]%', @num) = 0  
        AND @num NOT IN ('.', '-', '+', '^') 
        AND LEN(@num)>0  
        AND @num NOT LIKE '%-%' 
        AND  
        (  
            ((@pos = LEN(@num)+1)  
            OR @pos = CHARINDEX('.', @num))  
        )  
    THEN  
        1  
    ELSE  
    0  
    END  
END  
GO 
2 голосов
/ 12 августа 2013

Просто явное преобразование, но с небольшой изобретательностью ЗАМЕНА

SELECT result FROM table WHERE CONVERT(float,REPLACE(result,',','.')) > 180.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...