CAST и IsNumeric

Почему следующий запрос возвращает «Ошибка преобразования типа данных varchar в bigint»? Разве IsNumeric не делает CAST безопасным? Я перепробовал все числовые типы данных в приведении и получил ту же ошибку «Ошибка преобразования ...». Я не верю, что размер полученного числа является проблемой, потому что переполнение - это другая ошибка.

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

SELECT CAST(myVarcharColumn AS bigint)  
FROM myTable  
WHERE IsNumeric(myVarcharColumn) = 1 AND myVarcharColumn IS NOT NULL  
GROUP BY myVarcharColumn

Какие-нибудь мысли?

Уловка Мастро, объединяющая '.0e0', великолепна (она мне сегодня помогла) ... если вы не против, что это не конвертирует данных. С другой стороны, решение MikeTeeVee действительно преобразует ... все. Для простого подхода, который преобразует научную нотацию и десятичные дроби, теряя только все, что находится после десятичной точки, измените первую строку на SELECT CAST(CAST(myVarcharColumn AS real) AS bigint) или, конечно, SELECT CONVERT(bigint, CONVERT(real, myVarcharColumn)), который для некоторых легче читается.

Doug_Ivison 18.07.2014 17:34
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
28
1
80 578
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Попробуйте это и посмотрите, появляется ли по-прежнему ошибка ...

SELECT CAST(CASE 
            WHEN IsNumeric(myVarcharColumn) = 0
                THEN 0
            ELSE myVarcharColumn
            END AS BIGINT)
FROM myTable
WHERE IsNumeric(myVarcharColumn) = 1
    AND myVarcharColumn IS NOT NULL
GROUP BY myVarcharColumn

это сделало это для меня: D

jcolebrand 07.12.2013 00:49

Попробуйте завернуть его в футляр:

select CASE WHEN IsNumeric(mycolumn) = 1 THEN CAST(mycolumn as bigint) END
FROM stack_table
WHERE IsNumeric(mycolumn) = 1
GROUP BY mycolumn

Какая-нибудь особенно достойная причина, по которой мой ответ был отклонен? (Помимо пункта where, который я редактировал)

Dalin Seivewright 03.12.2008 21:18

Потому что он не решает проблемы, лежащие в основе ISNUMERIC. Вы не можете просто предположить, что, поскольку ISNUMERIC (x) = 1, ваше приведение будет успешным.

harvest316 02.12.2010 05:47

Я наткнулся на это сообщение в блоге, которое может помочь. Я раньше не сталкивался с этой проблемой и не уверен, поможет ли это вам в данном случае:

http://dotmad.blogspot.com/2007/02/cannot-call-methods-on-bigint-error.html

Ответ принят как подходящий

IsNumeric возвращает 1, если значение varchar можно преобразовать в ЛЮБОЙ числовой тип. Сюда входят int, bigint, decimal, numeric, real и float.

Научная нотация может вызвать у вас проблемы. Например:

Declare @Temp Table(Data VarChar(20))

Insert Into @Temp Values(NULL)
Insert Into @Temp Values('1')
Insert Into @Temp Values('1e4')
Insert Into @Temp Values('Not a number')

Select Cast(Data as bigint)
From   @Temp
Where  IsNumeric(Data) = 1 And Data Is Not NULL

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

IsNumeric (YourColumn + 'e0')

IsNumeric (YourColumn + '.0e0')

Попробуйте сами.

SELECT CAST(myVarcharColumn AS bigint)
FROM myTable
WHERE IsNumeric(myVarcharColumn + '.0e0') = 1 AND myVarcharColumn IS NOT NULL
GROUP BY myVarcharColumn

Это сработало. Теперь он возвращает на 1 запись меньше, чем без приведения. Значит, должна была быть одна запись с научным обозначением. Спасибо!

Mark Bostleman 03.12.2008 22:51

Это обрабатывает только BigInt (об этом и спрашивается, но ориентировано только на этот тип данных). Предупреждение: этот код сломается, если он обработает число больше BigInt. Он также возвращает 0 вместо NULL для пустых строк. Это решение выбрасывает любое десятичное значение (например, 1.0), которое вы также можете преобразовать. Полное решение см. В моем сообщении: stackoverflow.com/a/21770230/555798

MikeTeeVee 14.02.2014 07:25

@MikeTeeVee Вы правы во всем, что сказали. Что касается десятичных чисел ... они удалены из-за строки '.0e0'. Если вы измените его на «e0», десятичные числа будут передаваться. Хорошая вещь в этом решении состоит в том, что его просто и легко кодировать, если вы понимаете «трюк». Кроме того, это можно легко преобразовать в пользовательскую функцию. Performace было бы неплохо, потому что ему не нужно было бы получать доступ к чему-либо из таблицы.

George Mastros 14.02.2014 20:04

Это возвращает 1: выберите ISNUMERIC ('0`` 0`` 0')

LINQ2Vodka 12.01.2017 02:13

Согласно BOL ISNUMERIC возвращает 1, когда входное выражение оценивается как допустимый числовой тип данных; в противном случае возвращается 0.

Допустимые числовые типы данных включают следующее:

  • int
  • числовой
  • Bigint
  • Деньги
  • Smallint
  • smallmoney
  • tinyint
  • плавать
  • десятичная дробь
  • настоящий

Итак, как указывали другие, у вас будут некоторые данные, которые пройдут тест ISNUMERIC, но не смогут выполнить приведение к bigint

Лучшим решением было бы перестать хранить целые числа в столбце varchar. Очевидно, что существует проблема с данными, когда данные интерпретируются как числовые, но не могут быть преобразованы как таковые. Вам необходимо найти записи, которые являются проблемой, и исправить их, если данные таковы, что их можно и нужно исправить. В зависимости от того, что вы храните и почему для начала это varchar, вам может потребоваться исправить запрос вместо данных. Но это будет проще сделать, если вы сначала найдете записи, которые взрывают ваш текущий запрос.

Как это сделать - вот в чем вопрос. Относительно легко найти десятичный знак в данных, чтобы увидеть, есть ли у вас десятичные знаки (кроме 0, которые будут преобразовывать), используя charindex. Вы также можете найти любую запись, содержащую e или $ или любой другой символ, который может быть интерпретирован как числовой в соответствии с уже указанными источниками. Если у вас не так много записей, быстрое визуальное сканирование данных, вероятно, найдет их, особенно если вы сначала выполните сортировку по этому полю.

Иногда, когда я застревал на поиске плохих данных, которые взрывают запрос, я помещал данные во временную таблицу, а затем пробовал обрабатывать их партиями (с использованием интерполяции), пока не нашел тот, на котором они взорвались. Начните с первой 1000 (не забудьте использовать order by, иначе вы не получите тех же результатов при удалении хороших записей, а 1000 - лучшее предположение, если у вас есть миллионы записей, начинающиеся с большего числа). Если он прошел, удалите эти 1000 записей и выберите следующий пакет. Если это не удается, выберите меньшую партию. Как только вы найдете число, которое можно легко просканировать визуально, вы обнаружите проблему. Мне удалось довольно быстро найти записи о проблемах, когда у меня есть миллионы записей и странная ошибка, что ни один из запросов, которые я пробовал (которые в основном являются предположениями о том, что может быть неправильным), не нашел проблемы.

Часто вы ничего не можете сделать с формой, в которой поступают исходные данные.

harvest316 02.12.2010 05:44

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

HLGEM 15.02.2012 23:47

Есть сценарии, когда невозможно изменить структуру таблицы. В хранилищах также является распространенным паттерном: взять начальную копию данных неизменный из источника (может использовать сомнительные типы данных или быть плоским файлом), а затем очистить данные по мере их перемещения из промежуточной области. Тогда очень полезен запрос, который имеет дело с этими проблемами. Но даже если грязные данные являются неожиданными и являются результатом плохого дизайна, взгляните на ответ @MikeTeeVee; Вместо того, чтобы тратить время на просмотр данных вручную, можно будет найти с помощью запроса строки с нарушением, если вы узнаете, как работает ISNUMERIC.

Jo Douglass 08.01.2015 12:47

ISNUMERIC просто ... глупо. Вы вообще должны его использовать. Все случаи, указанные ниже, возвращают 1:

ISNUMERIC('-')
ISNUMERIC('.')
ISNUMERIC('-$.') 

Для любых целочисленных типов вместо этого используйте: ISNUMERIC(@Value) = 1 просто используйте: (@Value NOT LIKE '[^0-9]') OR (@Value NOT LIKE '-[^0-9]'

Единственное хорошее решение - не использовать ISNUMERIC.

он упомянул решение для регулярных выражений. и он на 100% о бесчисленных ... плохой разработке программного обеспечения

user1954055 21.11.2013 22:46

это все равно не удается, когда число слишком велико. :(

Shawn Kovac 07.08.2014 03:43

ISNUMERIC также возвращает 1, если ввод также является новой строкой (символы 13 и 10). Не очень полезно. (Особенно, когда он возвращает 0 для ввода 123, за которым следует новая строка.)

Magnus Smith 25.05.2016 13:25

Фон:

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

  1. Некоторые результаты отправляются бесплатно.
  2. Некоторые из них - перечисления (да, нет, синие, черные и т. д.).
  3. Некоторые из них целые.
  4. Другие используют десятичные дроби.
  5. Многие из них представляют собой проценты, которые, если преобразовать их в целое число, могут сбить вас с толку позже.

Если мне нужно запросить заданный десятичный диапазон (скажем, от -1,4 до 3,6, если применимо), мои возможности ограничены. Я обновил свой запрос ниже, чтобы использовать предложение @GMastros для добавления 'e0'.
Спасибо @GMastros, это сэкономило мне лишние 2 строки логики.

Решение:

--NOTE: I'd recommend you use this to convert your numbers and store them in a separate table (or field).
--      This way you may reuse them when when working with legacy/3rd-party systems, instead of running these calculations on the fly each time.
SELECT Result.Type, Result.Value, Parsed.CleanValue, Converted.Number[Number - Decimal(38,4)],
       (CASE WHEN Result.Value IN ('0', '1', 'True', 'False') THEN CAST(Result.Value as Bit) ELSE NULL END)[Bit],--Cannot convert 1.0 to Bit, it must be in Integer format already.
       (CASE WHEN Converted.Number BETWEEN 0 AND 255 THEN CAST(Converted.Number as TinyInt) ELSE NULL END)[TinyInt],
       (CASE WHEN Converted.Number BETWEEN -32768 AND 32767 AND Result.Value LIKE '%\%%' ESCAPE '\' THEN CAST(Converted.Number / 100.0 as Decimal(9,4)) ELSE NULL END)[Percent],
       (CASE WHEN Converted.Number BETWEEN -32768 AND 32767 THEN CAST(Converted.Number as SmallInt) ELSE NULL END)[SmallInt],
       (CASE WHEN Converted.Number BETWEEN -214748.3648 AND 214748.3647 THEN CAST(Converted.Number as SmallMoney) ELSE NULL END)[SmallMoney],
       (CASE WHEN Converted.Number BETWEEN -2147483648 AND 2147483647 THEN CAST(Converted.Number as Int) ELSE NULL END)[Int],
       (CASE WHEN Converted.Number BETWEEN -2147483648 AND 2147483647 THEN CAST(CAST(Converted.Number as Decimal(10)) as Int) ELSE NULL END)[RoundInt],--Round Up or Down instead of Truncate.
       (CASE WHEN Converted.Number BETWEEN -922337203685477.5808 AND 922337203685477.5807 THEN CAST(Converted.Number as Money) ELSE NULL END)[Money],
       (CASE WHEN Converted.Number BETWEEN -9223372036854775808 AND 9223372036854775807 THEN CAST(Converted.Number as BigInt) ELSE NULL END)[BigInt],
       (CASE WHEN Parsed.CleanValue IN ('1', 'True', 'Yes', 'Y', 'Positive', 'Normal')   THEN CAST(1 as Bit)
             WHEN Parsed.CleanValue IN ('0', 'False', 'No', 'N', 'Negative', 'Abnormal') THEN CAST(0 as Bit) ELSE NULL END)[Enum],
       --I couln't use just Parsed.CleanValue LIKE '%e%' here because that would match on "True" and "Negative", so I also had to match on only allowable characters. - 02/13/2014 - MCR.
       (CASE WHEN ISNUMERIC(Parsed.CleanValue) = 1 AND Parsed.CleanValue LIKE '%e%' THEN Parsed.CleanValue ELSE NULL END)[Exponent]
  FROM
  (
    VALUES ('Null', NULL), ('EmptyString', ''), ('Spaces', ' - 2 . 8 % '),--Tabs and spaces mess up IsNumeric().
           ('Bit', '0'), ('TinyInt', '123'), ('Int', '123456789'), ('BigInt', '1234567890123456'),
           --('VeryLong', '12345678901234567890.1234567890'),
           ('VeryBig', '-1234567890123456789012345678901234.5678'),
           ('TooBig',  '-12345678901234567890123456789012345678.'),--34 (38-4) is the Longest length of an Integer supported by this query.
           ('VeryLong', '-1.2345678901234567890123456789012345678'),
           ('TooLong', '-12345678901234567890.1234567890123456789'),--38 Digits is the Longest length of a Number supported by the Decimal data type.
           ('VeryLong', '000000000000000000000000000000000000001.0000000000000000000000000000000000000'),--Works because Casting ignores leading zeroes.
           ('TooLong', '.000000000000000000000000000000000000000'),--Exceeds the 38 Digit limit for all Decimal types after the decimal-point.
           --Dot(.), Plus(+), Minus(-), Comma(,), DollarSign($), BackSlash(\), Tab(0x09), and Letter-E(e) all yeild false-posotives with IsNumeric().
           ('Decimal', '.'), ('Decimal', '.0'), ('Decimal', '3.99'),
           ('Positive', '+'), ('Positive', '+20'),
           ('Negative', '-'), ('Negative', '-45'), ('Negative', '- 1.23'),
           ('Comma', ','), ('Comma', '1,000'),
           ('Money', '$'), ('Money', '$10'),
           ('Percent', '%'), ('Percent', '110%'),--IsNumeric will kick out Percent(%) signs.
           ('BkSlash', '\'), ('Tab', CHAR(0x09)),--I've actually seen tab characters in our data.
           ('Exponent', 'e0'), ('Exponent', '100e-999'),--No SQL-Server datatype could hold this number, though it is real.
           ('Enum', 'True'), ('Enum', 'Negative')
  ) AS Result(Type, Value)--O is for Observation.
  CROSS APPLY
  ( --This Step is Optional.  If you have Very Long numbers with tons of leading zeros, then this is useful.  Otherwise is overkill if all the numbers you want have 38 or less digits.
    --Casting of trailing zeros count towards the max 38 digits Decimal can handle, yet Cast ignores leading-zeros.  This also cleans up leading/trailing spaces. - 02/25/2014 - MCR.
    SELECT LTRIM(RTRIM(SUBSTRING(Result.Value, PATINDEX('%[^0]%', Result.Value + '.'), LEN(Result.Value))))[Value]
  ) AS Trimmed
  CROSS APPLY
  (
    SELECT --You will need to filter out other Non-Keyboard ASCII characters (before Space(0x20) and after Lower-Case-z(0x7A)) if you still want them to be Cast as Numbers. - 02/15/2014 - MCR.
           REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(Trimmed.Value,--LTRIM(RTRIM(Result.Value)),
           (CHAR(0x0D) + CHAR(0x0A)), ''),--Believe it or not, we have people that press carriage return after entering in the value.
           CHAR(0x09), ''),--Apparently, as people tab through controls on a page, some of them inadvertently entered Tab's for values.
           ' ', ''),--By replacing spaces for values (like '- 2' to work), you open the door to values like '00 12 3' - your choice.
           '$', ''), ',', ''), '+', ''), '%', ''), '/', '')[CleanValue]
  ) AS Parsed--P is for Parsed.
  CROSS APPLY
  ( --NOTE: I do not like my Cross-Applies to feed into each other.
    --      I'm paranoid it might affect performance, but you may move this into the select above if you like. - 02/13/2014 - MCR.
    SELECT (CASE WHEN ISNUMERIC(Parsed.CleanValue + 'e0') = 1--By concatenating 'e0', I do not need to check for: Parsed.CleanValue NOT LIKE '%e%' AND Parsed.CleanValue NOT IN ('.', '-')
                 --  If you never plan to work with big numbers, then could use Decimal(19,4) would be best as it only uses 9 storage bytes compared to the 17 bytes that 38 precision requires.
                 --  This might help with performance, especially when converting a lot of data.
                  AND CHARINDEX('.', REPLACE(Parsed.CleanValue, '-', '')) - 1    <= (38-4)--This is the Longest Integer supported by Decimal(38,4)).
                  AND LEN(REPLACE(REPLACE(Parsed.CleanValue, '-', ''), '.', '')) <= 38--When casting to a Decimal (of any Precision) you cannot exceed 38 Digits. - 02/13/2014 - MCR.
                 THEN CAST(Parsed.CleanValue as Decimal(38,4))--Scale of 4 used is the max that Money has.  This is the biggest number SQL Server can hold.
                 ELSE NULL END)[Number]
  ) AS Converted--C is for Converted.

Выход:

Снимок экрана ниже был отформатирован и обрезан, чтобы поместиться на StackOverflow.
. Фактические результаты содержат больше столбцов. MikeTeeVee's IsNumeric Casting

Исследовать:

Рядом с каждым запросом отображается результат. Интересно увидеть недостатки IsNumeric, а также ограничения CASTing. Я показываю это, чтобы вы могли увидеть исходное исследование, которое было использовано при написании запроса выше. Важно понимать каждое дизайнерское решение (на случай, если вы думаете что-то вырезать).

SELECT ISNUMERIC('')--0.  This is understandable, but your logic may want to default these to zero.
SELECT ISNUMERIC(' ')--0.  This is understandable, but your logic may want to default these to zero.
SELECT ISNUMERIC('%')--0.
SELECT ISNUMERIC('1%')--0.
SELECT ISNUMERIC('e')--0.
SELECT ISNUMERIC('  ')--1.  --Tab.
SELECT ISNUMERIC(CHAR(0x09))--1.  --Tab.
SELECT ISNUMERIC(',')--1.
SELECT ISNUMERIC('.')--1.
SELECT ISNUMERIC('-')--1.
SELECT ISNUMERIC('+')--1.
SELECT ISNUMERIC('$')--1.
SELECT ISNUMERIC('\')--1.  '
SELECT ISNUMERIC('e0')--1.
SELECT ISNUMERIC('100e-999')--1.  No SQL-Server datatype could hold this number, though it is real.
SELECT ISNUMERIC('3000000000')--1.  This is bigger than what an Int could hold, so code for these too.
SELECT ISNUMERIC('1234567890123456789012345678901234567890')--1.  Note: This is larger than what the biggest Decimal(38) can hold.
SELECT ISNUMERIC('- 1')--1.
SELECT ISNUMERIC('  1  ')--1.
SELECT ISNUMERIC('True')--0.
SELECT ISNUMERIC('1/2')--0.  No love for fractions.

SELECT CAST('e0'  as Int)--0.  Surpise!  Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST('0e0'  as Int)--0.  Surpise!  Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST(CHAR(0x09) as Decimal(12,2))--Error converting data type varchar to numeric.  --Tab.
SELECT CAST('   1' as Decimal(12,2))--Error converting data type varchar to numeric.  --Tab.
SELECT CAST(REPLACE('   1', CHAR(0x09), '') as Decimal(12,2))--Error converting data type varchar to numeric.  --Tab.
SELECT CAST(''  as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST(''  as Int)--0.  Surpise!  Casting to Decimal errors, but for Int is gives us zero, which is wrong.
SELECT CAST(',' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('.' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('-' as Decimal(12,2))--Arithmetic overflow error converting varchar to data type numeric.
SELECT CAST('+' as Decimal(12,2))--Arithmetic overflow error converting varchar to data type numeric.
SELECT CAST('$' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('$1' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('1,000' as Decimal(12,2))--Error converting data type varchar to numeric.
SELECT CAST('- 1'   as Decimal(12,2))--Error converting data type varchar to numeric.  (Due to spaces).
SELECT CAST('  1  ' as Decimal(12,2))--1.00  Leading and trailing spaces are okay.
SELECT CAST('1.' as Decimal(12,2))--1.00
SELECT CAST('.1' as Decimal(12,2))--0.10
SELECT CAST('-1' as Decimal(12,2))--1.00
SELECT CAST('+1' as Decimal(12,2))--1.00
SELECT CAST('True'  as Bit)--1
SELECT CAST('False' as Bit)--0
--Proof: The Casting to Decimal cannot exceed 38 Digits, even if the precision is well below 38.
SELECT CAST('1234.5678901234567890123456789012345678' as Decimal(8,4))--1234.5679
SELECT CAST('1234.56789012345678901234567890123456789' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric.

--Proof: Casting of trailing zeros count towards the max 38 digits Decimal can handle, yet it ignores leading-zeros.
SELECT CAST('.00000000000000000000000000000000000000' as Decimal(8,4))--0.0000  --38 Digits after the decimal point.
SELECT CAST('000.00000000000000000000000000000000000000' as Decimal(8,4))--0.0000  --38 Digits after the decimal point and 3 zeros before the decimal point.
SELECT CAST('.000000000000000000000000000000000000000' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric.  --39 Digits after the decimal point.
SELECT CAST('1.00000000000000000000000000000000000000' as Decimal(8,4))--Arithmetic overflow error converting varchar to data type numeric.  --38 Digits after the decimal point and 1 non-zero before the decimal point.
SELECT CAST('000000000000000000000000000000000000001.0000000000000000000000000000000000000' as Decimal(8,4))--1.0000

--Caveats: When casting to an Integer:
SELECT CAST('3.0' as Int)--Conversion failed when converting the varchar value '3.0' to data type int.
--NOTE: When converting from character data to Int, you may want to do a double-conversion like so (if you want to Round your results first):
SELECT CAST(CAST('3.5'  as Decimal(10))   as Int)--4.  Decimal(10) has no decimal precision, so it rounds it to 4 for us BEFORE converting to an Int.
SELECT CAST(CAST('3.5'  as Decimal(11,1)) as Int)--3.  Decimal (11,1) HAS decimal precision, so it stays 3.5 before converting to an Int, which then truncates it.
--These are the best ways to go if you simply want to Truncate or Round.
SELECT CAST(CAST('3.99' as Decimal(10)) as Int)--3.  Good Example of Rounding.
SELECT CAST(FLOOR('3.99') as Int)--3.  Good Example fo Truncating.

У меня была такая же проблема, и я придумал скалярную функцию, как Im в 2008 SQL

ALTER Function [dbo].[IsInteger](@Value VarChar(18))
Returns Bit
As 
Begin

  Return IsNull(
     (Select Case When CharIndex('.', @Value) > 0 
                  Then 0
                  Else 1
             End
      Where IsNumeric(@Value + 'e0') = 1), 0)    
End

Если вы находитесь в 2012 году, вы можете использовать TRY_CONVERT

У меня была такая же проблема в MSSQL 2014, вызванная запятой вместо точки: isnumeric ('9090,23') дает 1; cast ('9090,23' как float) не работает

Я заменил ',' на '.'

есть функции DAX (IsError или IfError), которые могут помочь в этой ситуации, но у нас их нет в нашем SQL Server 2008 R2. Похоже, какой-то дополнительный пакет анализа для SQL Server.

Другие вопросы по теме