Ошибка при преобразовании типа данных varchar в плавающий тип данных не varchar - PullRequest
0 голосов
/ 22 мая 2019

Я столкнулся с проблемой (которую я частично решил), но, похоже, не могу найти причину неудачи с самого начала.

У меня есть поле в таблице, которое содержит комбинацию буквенных и числовых значений. Поле имеет тип данных char (20) (который является неправильным, но неизменяемым) и содержит либо значение NULL, либо «Неизвестно», либо «числа» 0, 50, 100 . Поле char дополняет значения конечным пробелом. Это известно, и мы ничего не можем с этим поделать.

Чтобы удалить Неизвестные значения, у нас есть ряд объединенных операторов, и эти два возвращают сообщение об ошибке согласно заголовку.

,coalesce(DHMCC.[HESA Module Total Proportion Taught], 'Missing')
,cast(isnull(DHMCC.[HESA Module Total Proportion Taught] ,'Missing') as varchar(10)) 

У меня возникает вопрос, почему я получаю эту ошибку, когда не преобразовываю тип данных varchar во float (или я?)

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

Ответы [ 2 ]

1 голос
/ 22 мая 2019

Функция STR() принимает тип данных с плавающей точкой в ​​качестве первого аргумента, поэтому SQL Server неявно преобразует все, что вы передаете этой функции, которая в вашем случае является столбцом CHAR(20). Поскольку unknown не может быть преобразовано в число с плавающей точкой, вы получите ошибку. Если вы запустите следующее с активным планом выполнения:

DECLARE @T TABLE (Col CHAR(20));
INSERT @T VALUES (NULL);

SELECT Result = ISNULL(STR(Col, 25, 0), 'Missing')
FROM @T

Затем проверьте план выполнения XML и увидите неявное преобразование:

<ScalarOperator ScalarString="isnull(str(CONVERT_IMPLICIT(float(53),[Col],0),(25),(0)),'Missing')">

Самое простое решение, вероятно, состоит в том, чтобы использовать выражение case и вообще не беспокоиться о каком-либо преобразовании (только если вы знаете, что у вас будут только 5 значений, перечисленных вами:

DECLARE @T TABLE (Col CHAR(20));
INSERT @T VALUES (NULL), ('0'), ('50'), ('100');--, ('Unknown');

SELECT Result = CASE WHEN Col IS NULL OR Col = 'Unknown' THEN 'Missing' ELSE Col END
FROM @T;

Result
---------
Missing
0                   
50                  
100                 
Missing             

Если вам действительно нужна функция STR(), вы можете сделать преобразование явным, но используйте TRY_CONVERT(), чтобы все, что не является плавающей точкой, просто возвращало NULL:

DECLARE @T TABLE (Col CHAR(20));
INSERT @T VALUES (NULL), ('0'), ('50'), ('100');--, ('Unknown');

SELECT Result = ISNULL(STR(TRY_CONVERT(FLOAT, Col), 25, 0), 'Missing')
FROM @T

Result
------------
Missing
        0   
       50
      100
Missing

Хотя, поскольку указанные вами числа являются целыми числами, я был бы склонен преобразовывать их в целые числа, а не в числа с плавающей точкой:

DECLARE @T TABLE (Col CHAR(20));
INSERT @T VALUES (NULL), ('0'), ('50'), ('100'), ('Unknown');

SELECT Result = ISNULL(CONVERT(VARCHAR(10), TRY_CONVERT(INT, Col)), 'Missing')
FROM @T;

Result
---------
Missing
0                   
50                  
100                 
Missing      
0 голосов
/ 22 мая 2019

Благодаря @ GarethD

Я только что натолкнулся на TRY_CONVERT, и это кажется лучшим вариантом, поэтому спасибо ему за этот указатель, также пробующий с TRY_CAST.

данные действительно должны храниться в поле varchar, они ссылочные, а не для расчета, и, похоже, это работает одинаково,

-- Declare @varText as varchar(16) = '10    '
-- Declare @varText as char(16) = 'Unknown'
-- Declare @varText as char(16) = ''

SELECT
ISNULL(NULLIF(TRY_CAST(LTRIM(RTRIM(@varText)) as varchar(16)), ''), 'Missing') AS HESA

Я создал этот тестовый сценарий, который работает нормально.

...