Невозможно привести значение как float - PullRequest
5 голосов
/ 25 августа 2011

У нас есть SQL, который выполняет функцию CAST (для FLOAT) в ColumnA. SQL имеет фильтр, который в конце концов косвенно отфильтрует те строки, которые имеют нечисловые значения в ColumnA. Однако из-за того, что, по моему мнению, происходит из-за запуска частей SQL в paralell, я считаю, что CAST даже применяется к отфильтрованным строкам, и это приводит к сбою SQL при «невозможности приведения значения как float ...» "

Я знаю, что если я запускаю один процесс, добавив подсказку запроса

OPTION (MAXDOP 1)

что SQL работает так, как ожидалось. Я подозреваю, что при запуске в 1 proc принудительно будет применен фильтр, чтобы отсеять строку с нечисловыми значениями в columnA так, чтобы CASTING его значений был успешным. Я также обнаружил, что с помощью подсказки запроса

OPTION (FORCE ORDER)

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

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

Я работаю на

Microsoft SQL Server 2008 R2 (окончательная первоначальная версия) - 10.50.1720.0 (X64) 12 июня 2010 г. 01:34:59 Copyright (c) Microsoft Corporation Enterprise Edition (64-разрядная версия) в Windows NT 5.2 (сборка 3790: пакет обновления 2)

Запоздалая мысль:

Кажется, было бы неплохо, если бы T-SQL имел следующие функции, чтобы проверить, можно ли преобразовать строку в конкретный тип данных.

IsFloat IsNumeric IsInteger и т.д.

Меня действительно раздражает, сколько столбцов всех видов данных, которые я нахожу в нашей базе данных, которые определены как varchar (255). Я думаю, что решение "не делать этого!"

Ответы [ 2 ]

4 голосов
/ 25 августа 2011

Относительно твоей запоздалой мысли.

Кажется, было бы неплохо, если бы T-SQL имел следующие функции для проверьте, можно ли преобразовать строку в конкретный тип данных.

SQL Server 2012 действительно вводит TRY_CONVERT для этой необходимости. Поэтому следующий запрос вернет NULL, а не ошибку.

SELECT TRY_CONVERT ( FLOAT, 'Fish')

Даже при последовательных планах не гарантируется, что предложение WHERE произойдет до оценки SELECT. Как объяснено в этом посте начиная с SQL Server 2005 и выше, это происходит чаще, чем в предыдущих версиях. Изменения в поведении функций компонента Database Engine в SQL Server 2005 , в частности, вызывают это следующим образом.

SQL Server 2005 иногда оценивает выражения в запросах раньше, чем когда они оцениваются в SQL Server 2000. Это поведение обеспечивает следующие важные преимущества:

  • Возможность сопоставлять индексы в вычисляемых столбцах с выражениями в запросе, которые совпадают с выражением вычисляемого столбца.
  • Предотвращение избыточного вычисления результатов выражений.

Подробнее об этом поведении читайте в другом хорошем блоге Крейга Фридмана Преобразования и арифметические ошибки .

В версиях до 2012 и TRY_CONVERT вам нужно заключить CAST AS FLOAT в оператор CASE. например,

  SELECT CASE WHEN ISNUMERIC(Col)=1 THEN CAST(Col AS FLOAT) END AS Col
  FROM Table
  WHERE ISNUMERIC(Col)=1

Это по-прежнему абсолютно не гарантирует, что вы не получите ошибки, так как ISNUMERIC сам просто проверяет, что значение будет приведено к одному из числовых типов данных, а не специально к плавающему Пример ввода, который завершится ошибкой: '.'

CASE задокументировано в основном для короткого замыкания в книгах онлайн ( здесь обсуждаются некоторые исключения )

Вы также можете найти дополнительные обсуждения / жалобы по этому поводу в пункте подключения SQL Server не должен вызывать нелогичные ошибки и хорошее объяснение аналогичной проблемы от SQLKiwi

1 голос
/ 25 августа 2011

Я верю, что вы правы. Функция CONVERT () применяется до того, как предикаты «косвенно отфильтровывают» строки.

Чтобы избежать исключения, вы правы, один из подходов состоит в том, чтобы попытаться получить хоть какой-то контроль над порядком операций в плане выполнения. Если подсказка для заявления работает на вас, то вы можете пойти с этим. (Лично для меня подсказки - последнее средство.)

Обратите внимание, что SQL Server имеет функцию IsNumeric.

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

Лично я бы склонялся к такому подходу:

select convert(float,case when isnumeric( t.foo )=1 then t.foo else null end)

, а не намеки на уровне операторов.

Или я бы указал другие предикаты, которые должны «отфильтровывать» значения, которые не следует преобразовывать.

select convert(float,case when t.fi in ('fo','fum') then t.foo else null end)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...