2009-09-04 19 views
5

¿Cómo puedo lograr:SQL Server, donde el campo es int?

select * from table where column_value is int 

Sé que puedo unir probablemente interno a las tablas del sistema y tablas de tipo, pero me pregunto si hay una forma más elegante.

Tenga en cuenta que column_value es un varchar que "podría" tener un int, pero no necesariamente.

Tal vez puedo simplemente lanzarlo y atrapar el error? Pero, de nuevo, parece un truco.

+2

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é. –

Respuesta

2
select * from table 
where column_value not like '[^0-9]' 

Si se permiten enteros negativos, necesita algo así como

where column_value like '[+-]%' 
and substring(column_value,patindex('[+-]',substring(column_value,1))+1,len(column_value)) 
not like '[^0-9]' 

Es necesario más de código si column_value puede ser un número entero que supera los límites del tipo "int", y que desea excluir tales casos.

+0

No estoy seguro de si esto es correcto o no, ¿pero no probará eso el primer caracter para 'no ser un dígito'? ¿No deberías usar: WHERE column_value no como '% [^ 0-9]%'? – VoidKing

+0

O column_value like '% [0-9]%'? – VoidKing

2

Aquí si se desea implementar la función personalizada

CREATE Function dbo.IsInteger(@Value VARCHAR(18)) 
RETURNS BIT 
AS 
BEGIN  
    RETURN ISNULL(  
     (SELECT CASE WHEN CHARINDEX('.', @Value) > 0 THEN 
          CASE WHEN CONVERT(int, PARSENAME(@Value, 1)) <> 0 THEN 0 ELSE 1 END 
        ELSE 1 
        END  
      WHERE  ISNUMERIC(@Value + 'e0') = 1), 0) 

END 

vuelve IsNumeric 1 cuando la expresión de entrada evalúa a un entero válido , número de punto flotante, el dinero o decimal tipo; de lo contrario, devuelve 0. Un valor de retorno de 1 garantiza que la expresión se puede convertir a uno de estos tipos numéricos.

+0

Detecta '123.' como entero pero no podemos convertirlo :( – Faiz

0

que haría una UDF como sugiere Svetlozar Angelov, pero me gustaría comprobar si hay ISNUMERIC primera (y devuelve 0 si no), y para verificar si column_value % 1 = 0 para ver si es un número entero.

Así es como se vería el cuerpo. Debe colocar la lógica del módulo en una rama separada porque arrojará una excepción si el valor no es numérico.

DECLARE @RV BIT 
IF ISNUMERIC(@value) BEGIN 
    IF CAST(@value AS NUMERIC) % 1 = 0 SET @RV = 1 
    ELSE SET @RV = 0 
END 
ELSE SET @RV = 0 
RETURN @RV 
0

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.

0

¿Por qué no utilizar lo siguiente y probar 1?

DECLARE @TestValue nvarchar(MAX) 
SET @TestValue = '1.04343234e5' 

SELECT CASE WHEN ISNUMERIC(@TestValue) = 1 
     THEN CASE WHEN ROUND(@TestValue,0,1) = @TestValue 
      THEN 1 
      ELSE 0 
      END 
     ELSE null 
     END AS Analysis 
0

Si está puramente buscando para verificar una cadena es que todos los dígitos y no sólo CAST capaz de INT que puede hacer esta terrible, terrible:

select LEN(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
'-1.223344556677889900e-1' 
,'0','') ,'1','') ,'2','') ,'3','') ,'4','') ,'5','') ,'6','') ,'7','') ,'8','') ,'9','') 
) 

Devuelve 0 cuando la cadena era dígitos vacíos o puros

Para que sea un valor útil para el entero "pobre", tendrías que ocuparte de una cadena vacía y un signo negativo inicial. Y asegúrese manualmente de que no sea demasiado largo para su variedad de INTEGER.

Cuestiones relacionadas