СОСТАВ ИСПОЛНИТЕЛЕЙ и IsNumeric

26
задан Aaron Bertrand 15 February 2012 в 00:33
поделиться

9 ответов

IsNumeric возвращается 1, если значение varchar может быть преобразовано в КАКОЙ-ЛИБО тип числа. Это включает интервал, bigint, десятичный, числовой, реальный & плавание.

Экспоненциальное представление могло вызывать Вас проблема. Например:

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
56
ответ дан G Mastros 28 November 2019 в 06:23
поделиться

Справочная информация:

Я использую стороннюю базу данных, которая постоянно получает новые данные от других сторонних поставщиков.
Моя работа состоит в том, чтобы разобрать ужасное поле 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', ' 

Вывод:

Снимок экрана ниже был отформатирован и урезан для соответствия 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.
), ('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. '

Вывод:

Снимок экрана ниже был отформатирован и урезан для соответствия 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.
, ''), ',', ''), '+', ''), '%', ''), '/', '')[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.
7
ответ дан MikeTeeVee 28 November 2019 в 06:23
поделиться

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

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

Иногда, когда я застрял при нахождении неправильных данных, которые аварийно завершают запрос, я поместил данные во временную таблицу и затем попытался обработать в пакетах (использующий интерполяцию), пока я не нахожу тот, на котором это аварийно завершается. Запустите с первых 1000 (не забывайте использовать порядок, или Вы не получите те же результаты, когда Вы удалите хорошие записи, и 1000 только лучшее предположение, если у Вас есть миллионы записей, запускаются с большего числа). Если это передает, удалите те 1 000 записей и выберите следующий пакет. Как только это перестало работать, выберите меньший пакет. Как только Вы до числа, которое может легко быть визуально просканировано, Вы найдете проблему. Я был в состоянии найти проблемные записи справедливо быстро, когда у меня есть миллионы записей и странная ошибка, что ни один из запросов, которые я попробовал (которые являются в основном предположениями относительно того, что могло бы быть неправильным) не нашел проблему.

4
ответ дан HLGEM 28 November 2019 в 06:23
поделиться

Попробуйте это и посмотрите, получаете ли Вы все еще ошибку...

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
3
ответ дан jcolebrand 28 November 2019 в 06:23
поделиться

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

select CASE WHEN IsNumeric(mycolumn) = 1 THEN CAST(mycolumn as bigint) END
FROM stack_table
WHERE IsNumeric(mycolumn) = 1
GROUP BY mycolumn
1
ответ дан Dalin Seivewright 28 November 2019 в 06:23
поделиться

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

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

  • интервал
  • числовой
  • деньги bigint
  • плавание smallint
  • smallmoney
  • tinyint
  • десятичное число
  • реальный

Поэтому как другие указало, что у Вас будут некоторые данные, которые передадут тест ISNUMERIC, но перестанут работать при кастинге к bigint

1
ответ дан kristof 28 November 2019 в 06:23
поделиться

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

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

1
ответ дан Rohit Vipin Mathews 28 November 2019 в 06:23
поделиться

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

0
ответ дан Greg 28 November 2019 в 06:23
поделиться

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

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

-1
ответ дан BenAlabaster 28 November 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: