Esto debe manejar todos los casos sin lanzar ninguna excepción:
--This handles dollar-signs, commas, decimal-points, and values too big or small,
-- all while safely returning an int.
DECLARE @IntString as VarChar(50) = '$1,000.'
SELECT CAST((CASE WHEN --This IsNumeric check here does most of the heavy lifting. The rest is Integer-Specific
ISNUMERIC(@IntString) = 1
--Only allow Int-related characters. This will exclude things like 'e' and other foreign currency characters.
AND @IntString NOT LIKE '%[^ $,.\-+0-9]%' ESCAPE '\'--'
--Checks that the value is not out of bounds for an Integer.
AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) BETWEEN -2147483648 AND 2147483647
--This allows values with decimal-points for count as an Int, so long as there it is not a fractional value.
AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) = CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38,2))
--This will safely convert values with decimal points to casting later as an Int.
THEN CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10))
END) as Int)[Integer]
Throw esto en un escalar UDF y llamarlo ReturnInt().
Si el valor regresa como NULL, entonces no es un int (lo que no es su EsEntero() requisito)
Si no te gusta escribir "DONDE ReturnInt (SomeValue) NO ES NULO", usted podría tírelo en otra UDF escalar llamada IsInt() para llamar a esta función y simplemente devuelva "ReturnInt (SomeValue) IS NOT NULL".
Lo bueno es que la UDF puede cumplir una doble función devolviendo el valor int "de forma segura".
Sólo porque algo puede ser un int no significa que convertirlo en int no arrojará una gran excepción. Esto se ocupa de eso por ti.
Además, evitaría las otras soluciones porque este enfoque universal manejará comas, decimales, signos de dólar y verifica el rango aceptable del valor Int mientras que las otras soluciones no lo hacen o requieren varias operaciones SET que le impiden usando la lógica en una función escalar para un rendimiento máximo.
Véanse los ejemplos a continuación y prueba de ellos en contra de mi código y otros:
--Proves that appending "e0" or ".0e0" is NOT a good idea.
select ISNUMERIC('$1' + 'e0')--Returns: 0.
select ISNUMERIC('1,000' + 'e0')--Returns: 0.
select ISNUMERIC('1.0' + '.0e0')--Returns: 0.
--While these are numeric, they WILL break your code
-- if you try to cast them directly as int.
select ISNUMERIC('1,000')--Returns: 1.
select CAST('1,000' as Int)--Will throw exception.
select ISNUMERIC('$1')--Returns: 1.
select CAST('$1' as Int)--Will throw exception.
select ISNUMERIC('10.0')--Returns: 1.
select CAST('10.0' as Int)--Will throw exception.
select ISNUMERIC('9999999999223372036854775807')--Returns: 1. This is why I use Decimal(38) as Decimal defaults to Decimal(18).
select CAST('9999999999223372036854775807' as Int)--Will throw exception.
Actualización:
leí un comentario aquí que desea ser capaz de analizar un valor como '123. ' en un Entero. He actualizado mi código para manejar esto también.
Nota: Esto convierte "1.0", pero devuelve nulo en "1.9".
Si desea permitir el redondeo, modifique la lógica en la cláusula "THEN" para agregar Round() como sigue:
ROUND (CAST (REPLACE (REPLACE (@IntString, '$', ''), ' , ',' ') como Decimal (10)), 0)
Usted debe también elimine la "AND" que busca "puntos decimales" para permitir el redondeo o el truncamiento.
Para ser sincero, el truco aquí es que tiene datos en una columna de texto que desea tratar como números. Realmente no deberías hacer eso, pero supongo que ya has descubierto por qué. –