特定の特殊文字のISNUMERICの背後にあるロジックは何ですか?


14

このISNUMERIC関数には予期しない動作があります。MSDNドキュメントには次のように書かれています。

ISNUMERIC入力式が有効な数値データ型に評価されると1を返します。有効な数値データ型には、int、bigint、smallint、tinyint、decimal、numeric、money、smallmoney、float、realが含まれます。

また、脚注もあります。

ISNUMERICプラス(+)、マイナス(-)などの数字ではない一部の文字、およびドル記号($)などの有効な通貨記号に対して1を返します。通貨記号の完全なリストについては、「money and smallmoney(Transact-SQL)」を参照してください。

わかりましたので+-、と記載されている通貨記号は、数値と見なされることが期待されます。ここまでは順調ですね。

奇妙な部分です。まず、リンクされた記事の通貨記号の一部は数値ではありません

  • ユーロ通貨記号、16進数20A0:
  • ナイラサイン、ヘックス20A6:
  • リアルサイン、16進FDFC:

これは奇妙で、なぜなのかわかりませんか?このバージョンまたは環境に依存していますか?

しかし、物事は奇妙になります。私が説明できない他のいくつかはここにあります:

  • /数値ではありませんが、\です(ハァッ!!
  • REPLICATE(N'9', 308)数値ですが、そうでREPLICATE(N'9', 309)はありません

最初の最も基本的な質問は、上記のケースを説明するものは何ですか?さらに重要なことですが、背後ISNUMERICあるロジックは何ですか?したがって、すべてのケースを自分で説明/予測できますか?

物を再現する良い方法は次のとおりです。

DECLARE @tbl TABLE(txt NVARCHAR(1000));

INSERT INTO @tbl (txt) 
VALUES (N''), (N' '), (N'€'), (N'$'), (N'$$'), 
       (NCHAR(8356)), (NCHAR(8352)), (NCHAR(8358)), (NCHAR(65020)), 
       (N'+'), (N'-'), (N'/'), (N'\'), (N'_'), (N'e'), (N'1e'), (N'e1'), (N'1e1'), 
       (N'1'), (N'-1'), (N'+1'), (N'1+1'), (N''), (N'🄂'), (N'¹'), (N''), (N'½'), 
       (N'🎅'), (REPLICATE(N'9', 307)), (REPLICATE(N'9', 308)), (REPLICATE(N'9', 309)), 
       (REPLICATE(N'9', 310));

SELECT  UNICODE(LEFT(txt, 1)) AS FirstCharAsInt,
        LEN(txt) AS TxtLength,
        txt AS Txt,
        ISNUMERIC(txt) AS [ISNUMERIC]
FROM    @tbl;

これをローカルのSql Server 2012ボックスで実行すると、次の結果が得られます。

FirstCharAsInt   TxtLength   Txt        ISNUMERIC
---------------  ----------  ---------  ----------
NULL             0                      0
32               0                      0
8364             1           €          1
36               1           $          1
36               2           $$         0
8356             1           ₤          1
8352             1           ₠          0  --??
8358             1           ₦          0  --??
65020            1           ﷼‎          0  --??
43               1           +          1
45               1           -          1
47               1           /          0
92               1           \          1  --??
95               1           _          0
101              1           e          0
49               2           1e         0
101              2           e1         0
49               3           1e1        1
49               1           1          1
45               2           -1         1
43               2           +1         1
49               3           1+1        0
9352             1           ⒈         0
55356            2           🄂          0
185              1           ¹          0
9312             1           ①          0
189              1           ½          0
55356            2           🎅         0
57               307        /*...*/     1
57               308        /*...*/     1  --??
57               309        /*...*/     0  --??
57               310        /*...*/     0

私には正しくないと思われる唯一のもの0は、実際にうまくキャストされた5つの値を誤って報告することmoneyです。その他は正確に見えます。SQL FIDDLE
マーティン・スミス

NCHAR(0) - NCHAR(65535)私からは112の不一致があります。₁,₂,₃,4,5,6,7,8,9数字に見えるが、私にとっては何にもうまくキャストされないような文字を含める。フィドル
マーティンスミス14

回答:


13

の詳細な動作はISNUMERIC文書化されておらず、おそらくソースコードにアクセスできない人には完全に知られていません。とはいえ、解釈はUnicodeの分類(数値かどうか)に依存する可能性があります。同様に、あなたが言及する奇妙なケースは、後方互換性のために保存されているバグかもしれません。はい、それはおかしく聞こえますが、実際に起こります。

SQL Server 2012を使用してISNUMERICいるため、を使用する必要はありません。代わりにTRY_CONVERTまたはを使用してTRY_CAST、文字列が特定の型に変換可能かどうかを確認します。それらが適切な機能を提供する場合、これらはTRY_PARSECLR統合によるより高価な処理を伴うため、これらの方が望ましいです。


2
また、おそらくソースコードにアクセスできる多くの人々には完全には知られていません。:-) 2番目の段落でもう一度+1できるようになりたい。ISNUMERIC()は、何かを少なくとも1つの数値型に変換できるかどうかを判断することを目的としているため、ほとんど役に立ちません。単一の特定の数値型に変換できることを理解することは、明らかにはるかに重要です。
アーロンバートランド

1
@AaronBertrandそれがその意図さえ満たしていない場合のかなりかなりの数のケースがあるようです。
マーティンスミス14

9

ASCIIバックスラッシュ(コードポイント5C)は、日本語バージョンのWindowsで使用されるShift-JISエンコードの円記号(¥)と韓国語EUC-KRのウォン記号(₩)と同じコードポイントを共有します。したがって、通貨記号のテーマの単なる継続である可能性が非常に高いです。


ああ、それは興味深い理論です。それはmoneyそれは同様にキャストすることを。
マーティンスミス


3
@Jeroen私は怖くない。Windowsインストールのレガシーコードページを日本語に切り替えるとC:¥Program Files¥、explorer.exe などのパスが表示されます
切り替える
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.