web-dev-qa-db-fra.com

T-sql - détermine si la valeur est un entier

Je veux déterminer si une valeur est un entier (comme TryParse dans .NET). Malheureusement ISNUMERIC ne me convient pas car je veux analyser uniquement des nombres entiers et non tous les types de nombres. Existe-t-il une chose comme ISINT ou quelque chose?

Voici un code pour clarifier les choses. Si MY_FIELD n'est pas int, ce code échouerait:

SELECT @MY_VAR = CAST(MY_FIELD AS INT)
FROM MY_TABLE
WHERE MY_OTHER_FIELD = 'MY_FILTER'

Je vous remercie

36
zafeiris.m

Voici un article blog décrivant la création d’un fichier UDF IsInteger.

En gros, il est recommandé d’ajouter '.e0' à la valeur et d’utiliser IsNumeric. De cette manière, tout ce qui avait déjà un point décimal a maintenant deux points décimaux, ce qui rend IsNumeric faux, et tout ce qui est déjà exprimé en notation scientifique est invalidé par le e0.

32
Sam DeHaan

Dans son article Puis-je convertir cette chaîne en un entier? , Itzik Ben-Gan fournit une solution en T-SQL pur et une autre qui utilise le CLR.

Quelle solution devriez-vous choisir?

La solution T-SQL ou CLR est-elle meilleure? L’avantage d’utiliser le T-SQL La solution réside dans le fait que vous n’avez pas besoin de sortir du domaine de T-SQL la programmation. Cependant, la solution CLR présente deux avantages importants: C'est plus simple et plus rapide. Quand j'ai testé les deux solutions sur une table avec 1 000 000 de lignes, la solution CLR a pris deux secondes, plutôt moins de sept secondes (pour la solution T-SQL), à exécuter sur mon ordinateur portable. Alors la prochaine fois que vous devez vérifier si une chaîne donnée peut être converti en un entier, vous pouvez inclure la solution T-SQL ou CLR que j'ai fourni dans cet article.

Si vous souhaitez uniquement conserver T-SQL, utilisez la solution pure T-SQL. Si les performances sont plus importantes que la commodité, utilisez la solution CLR.

La solution T-SQL pure est délicate. Il combine la fonction ISNUMERIC intégrée avec la mise en correspondance des modèles et le transtypage pour vérifier si la chaîne représente un int.

SELECT keycol, string, ISNUMERIC(string) AS is_numeric,
  CASE
    WHEN ISNUMERIC(string) = 0     THEN 0
    WHEN string LIKE '%[^-+ 0-9]%' THEN 0
    WHEN CAST(string AS NUMERIC(38, 0))
      NOT BETWEEN -2147483648. AND 2147483647. THEN 0
    ELSE 1
  END AS is_int
FROM dbo.T1;

La partie T-SQL de la solution CLR est plus simple. Vous appelez la fonction fn_IsInt comme vous le feriez avec ISNUMERIC.

SELECT keycol, string, ISNUMERIC(string) AS is_numeric,
  dbo.fn_IsInt(string) AS is_int
FROM dbo.T1;

La partie C # est simplement un wrapper pour la fonction d'analyse Int32.TryParse du .NET. Cela fonctionne car int SQL Server et .NET Int32 sont des entiers signés 32 bits.

using System;
using System.Data.SqlTypes;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlBoolean fn_IsInt(SqlString s)
    {
        if (s.IsNull)
            return SqlBoolean.False;
        else
        {
            Int32 i = 0;
            return Int32.TryParse(s.Value, out i);
        }
    }
};

Veuillez lire l'article d'Itzik pour une explication complète de ces exemples de code.

Avec sqlserver 2005 et versions ultérieures, vous pouvez utiliser des classes de caractères de type regex avec l'opérateur LIKE. Voir ici .

Pour vérifier si une chaîne est un entier non négatif (il s'agit d'une séquence de chiffres décimaux), vous pouvez vérifier qu'elle ne contient pas d'autres caractères.

SELECT numstr
  FROM table
 WHERE numstr NOT LIKE '%[^0-9]%'

Note1: Cela retournera aussi des chaînes vides.

Note2: Utiliser LIKE '%[0-9]%' retournera toute chaîne contenant au moins un chiffre.

Voir violon

13
1010
WHERE IsNumeric(MY_FIELD) = 1 AND CAST(MY_FIELD as VARCHAR(5)) NOT LIKE '%.%'

C'est probablement la solution la plus simple. Sauf si votre MY_FIELD contient .00 ou quelque chose de ce genre. Dans ce cas, lancez-le en float pour supprimer les derniers .00s

5
KevinSwiecicki

Ce qui suit est correct pour une clause WHERE; faire une fonction envelopper dans CASE WHEN.

 ISNUMERIC(table.field) > 0 AND PATINDEX('%[^0123456789]%', table.field) = 0
3
Joshua

Voir si la requête ci-dessous aidera

SELECT *
FROM MY_TABLE
WHERE CHARINDEX('.',MY_FIELD) = 0 AND CHARINDEX(',',MY_FIELD) = 0       
AND ISNUMERIC(MY_FIELD) = 1 AND CONVERT(FLOAT,MY_FIELD) / 2147483647 <= 1
3
Gopakumar N.Kurup

Ce travail avec la fonction IsNumeric fonctionnera:

sélectionnez * de A où ISNUMERIC (x) = 1 et X pas comme '%.%'

ou utiliser

sélectionnez * de A où x ne ressemble pas à '% [^ 0-9]%'

2
Subhash

Je pense qu'il y a quelque chose qui cloche dans la conception de votre base de données. Je pense que c'est une très mauvaise idée de mélanger varchar et des nombres dans une colonne? Quelle est la raison de ceci?

Bien sûr, vous pouvez vérifier s’il existe des caractères autres que [0-9], mais imaginez que vous avez 1 m de lignes dans la table et que vous vérifiez chaque ligne. Je pense que ça ne marchera pas bien. 

Quoi qu'il en soit, si vous voulez vraiment le faire, je vous suggère de le faire du côté client.

1
Krystian Lieber

J'ai le sentiment que le faire de cette façon est l'œuvre de satan, mais au lieu de cela:

Que diriez-vous d'un TRY - CATCH?

DECLARE @Converted as INT
DECLARE @IsNumeric BIT

BEGIN TRY
    SET @Converted = cast(@ValueToCheck as int)
    SET @IsNumeric=1
END TRY
BEGIN CATCH
    SET @IsNumeric=0
END CATCH

select IIF(@IsNumeric=1,'Integer','Not integer') as IsInteger

Cela fonctionne, mais uniquement dans SQL Server 2008 et versions ultérieures.

1
vacip
 declare @ i numérique (28,5) = 12,0001 


 si (@ i/cast (@i comme int)> 1) 
 début 
 sélectionnez 'this is not int' 
 end 
 else 
 begin 
 sélectionnez 'this is int' 
 end 
1
Saravanan A

Nécromancie.
À partir de SQL-Server 2012+, vous pouvez utiliser TRY_CAST, qui renvoie NULL si la conversion a échoué.

Exemple:

DECLARE @foo varchar(200)
SET @foo = '0123' 
-- SET @foo = '-0123' 
-- SET @foo = '+0123' 
-- SET @foo = '+-0123' 
-- SET @foo = '+-0123' 
-- SET @foo = '.123' 
-- SET @foo = '1.23' 
-- SET @foo = '.' 
-- SET @foo = '..' 
-- SET @foo = '0123e10' 

SELECT CASE WHEN TRY_CAST(@foo AS integer) IS NULL AND @foo IS NOT NULL THEN 0 ELSE 1 END AS isInteger 

C'est le seul moyen vraiment fiable. 

Si vous avez besoin de support pour SQL-Server 2008, revenez à la réponse de Sam DeHaan: 

SELECT CASE WHEN ISNUMERIC(@foo + '.e0') = 1 THEN 1 ELSE 0 END AS isInteger 
1
Stefan Steiger

Je ne suis pas un pro en SQL mais que se passe-t-il en vérifiant s'il est divisible par 1.?.

SELECT *
FROM table    
WHERE fieldname % 1 = 0
0
user3665396

Parfois, vous ne devez pas concevoir la base de données, vous devez simplement travailler avec ce que vous avez reçu. Dans mon cas, il s’agit d’une base de données située sur un ordinateur auquel je n’ai qu’un accès en lecture et qui existe depuis 2008. 

Je dois sélectionner une colonne dans une base de données mal conçue qui est une varchar avec des nombres de 1 à 100, mais parfois une chaîne aléatoire. J'ai utilisé ce qui suit pour le contourner (bien que j'aurais aimé pouvoir re-concevoir toute la base de données).

SELECT A from TABLE where isnumeric(A)=1
0
Jackson

Utilisez PATINDEX

DECLARE @input VARCHAR(10)='102030.40'
SELECT PATINDEX('%[^0-9]%',RTRIM(LTRIM(@input))) AS IsNumber

référence http://www.intellectsql.com/post-how-tocheck-if-the-input-is-numeric/

0
Joe