web-dev-qa-db-ja.com

T-SQL-値が整数かどうかを判別

値が整数かどうか(.NETのTryParseなど)を判断したい。残念ながらISNUMERICは私には合いません。なぜなら、あらゆる種類の数値ではなく整数だけを解析したいからです。 ISINTなどのようなものはありますか?

わかりやすくするためのコードを次に示します。 MY_FIELDはintではありません。このコードは失敗します:

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

ありがとうございました

39
zafeiris.m

これは ブログ投稿IsInteger UDFの作成を説明しています。

基本的に、'.e0'を値に追加し、IsNumericを使用することをお勧めします。この方法で、すでに小数点があったものはすべて2つの小数点を持ち、IsNumericが偽になり、科学表記法で既に表現されたものはe0によって無効になります。

33
Sam DeHaan

Itzik Ben-Ganは、彼の記事 この文字列を整数に変換できますか? で、純粋なT-SQLとCLRを使用する別のソリューションを提供しています。

どのソリューションを選択する必要がありますか?

T-SQLまたはCLRソリューションの方が優れていますか?T-SQLソリューションを使用する利点は、ドメイン外に移動する必要がないことです。 T-SQLプログラミング。ただし、CLRソリューションには2つの重要な利点があります。それは、よりシンプルで高速なことです。 1,000,000行のテーブルに対して両方のソリューションをテストした場合、CLRソリューションはラップトップで実行するのに(T-SQLソリューションの場合)7秒ではなく2秒かかりました。そのため、次に特定の文字列を整数に変換できるかどうかを確認する必要がある場合、この記事で提供したT-SQLまたはCLRソリューションを含めることができます。

T-SQLのみを管理する場合は、純粋なT-SQLソリューションを使用してください。利便性よりもパフォーマンスが重要な場合は、CLRソリューションを使用してください。

純粋なT-SQLソリューションには注意が必要です。組み込みのISNUMERIC関数とパターンマッチングおよびキャストを組み合わせて、文字列が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;

CLRソリューションのT-SQL部分はよりシンプルです。 ISNUMERICを呼び出すのと同じように、fn_IsInt関数を呼び出します。

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

C#部分は、.NETの解析関数Int32.TryParseの単なるラッパーです。これは、SQL Server intと.NET Int32の両方が32ビット符号付き整数であるため機能します。

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);
        }
    }
};

これらのコードサンプルの詳細については、Itzikの記事をご覧ください。

Sqlserver 2005以降では、LIKE演算子で正規表現のような文字クラスを使用できます。 here を参照してください。

文字列が負でない整数(10進数字のシーケンス)であるかどうかを確認するには、他の文字が含まれていないことをテストできます。

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

注1:これも空の文字列を返します。

注2:LIKE '%[0-9]%'を使用すると、少なくとも数字を含む文字列が返されます。

fiddle を参照してください

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

それがおそらく最も簡単なソリューションです。 MY_FIELDには.00またはその種のものが含まれます。その場合、後続の.00を削除するためにフロートにキャストします

6
KevinSwiecicki

以下はWHERE句に適しています。関数をCASE WHENでラップするようにします。

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

以下のクエリが役立つかどうかを確認してください

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

ネクロマンシング。
SQL-Server 2012+では、TRY_CASTを使用できます。TRY_CASTは、キャストが失敗した場合にNULLを返します。

例:

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 

これが唯一の本当に信頼できる方法です。

SQL-Server 2008のサポートが必要な場合は、Sam DeHaanの答えに戻ってください。

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

SQL-Server <2012(別名2008R2)は、2019-07-09までに(拡張)サポートが終了します。
この時点で、非常にすぐに、<2012のサポートを終了できます。
この時点では、他のハックはもう使用しません。
更新するように質素な顧客に伝えてください-2008年から10年以上経過しています。

3
Stefan Steiger

IsNumeric関数を使用したこの回避策は機能します。

iSNUMERIC(x)= 1のAから*を選択し、Xは '%。%'を好まない

または使用

select * from A where x not like '%[^ 0-9]%'

2
Subhash

データベースの設計に何か問題があると思います。 varcharと数値を1つの列に混在させるのは本当に悪い考えだと思いますか?その理由は何ですか?

もちろん、[0-9]以外の文字があるかどうかを確認できますが、テーブルに1m行あり、すべての行をチェックしていると想像してください。うまくいかないと思います。

とにかく、本当にやりたいのなら、クライアント側でやることをお勧めします。

1
Krystian Lieber

私はこのようにそれをすることは悪魔の仕事であると感じていますが、代替として:

TRY-キャッチはどうですか?

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

これは機能しますが、SQL Server 2008以降でのみ機能します。

1
vacip
 declare @i numeric(28,5)= 12.0001 
 
 
 if(@ i/cast(@i in int)> 1)
 begin 
 select 'this is not int' 
 end 
 else 
 begin 
 select 'this is int' 
 end 
1
Saravanan A

私はSQLのプロではありませんが、1で割り切れるかどうかをチェックするのはどうですか?私にとっては仕事をします。

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

SQL Server 2012の時点で、TRY_CONVERTおよびTRY_CAST関数が実装されました。これは、ISNUMERICソリューションを大幅に改善したもので、偽陽性(または陰性)を引き起こす可能性があります(実際にそうします)。たとえば、以下を実行する場合:

SELECT CONVERT(int,V.S)
FROM (VALUES('1'),
            ('900'),
            ('hello'),
            ('12b'),
            ('1.1'),
            ('')) V(S)
WHERE ISNUMERIC(V.S) = 1;

TRY_CONVERT(またはTRY_CAST)を使用すると、次のことが回避されます。

SELECT TRY_CONVERT(int,V.S),
       V.S,
       ISNUMERIC(V.S)
FROM (VALUES('1'),
            ('900'),
            ('hello'),
            ('12b'),
            ('1.1'),
            ('')) V(S)
--WHERE TRY_CONVERT(int,V.S) IS NOT NULL; --To filter to only convertable values

'1.1'NULLを返したため、以前にエラーが発生しました(10進数の文字列表現はintに変換できないため)。また、''0、たとえISNUMERICは値を「変換できません」と述べています。

0
Larnu

データベースを設計できない場合があります。与えられたもので作業するだけです。私の場合、それは2008年以降に存在していた読み取りアクセス権しか持っていないコンピューター上のデータベースです。

設計が不十分なデータベースの列から選択する必要があります。このデータベースは、1〜100の数字を持つvarcharですが、時にはランダムな文字列です。私はそれを回避するために以下を使用しました(データベース全体を再設計したかったのですが)。

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

PATINDEXを使用する

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

参照 http://www.intellectsql.com/post-how-to-check-if-the-input-is-numeric/

0
Joe