Belirli özel karakterler için ISNUMERIC'in ardındaki mantık nedir?


14

ISNUMERICFonksiyon bazı beklenmeyen davranışlar vardır. MSDN belgeleri şunları söylüyor:

ISNUMERICgiriş ifadesi geçerli bir sayısal veri türünü değerlendirdiğinde 1 değerini döndürür; aksi takdirde 0 değerini döndürür. Geçerli sayısal veri türleri şunları içerir: int, bigint, smallint, tinyint, ondalık, sayısal, para, smallmoney, float, real .

Ayrıca bir dipnotu var:

ISNUMERICartı olmayan (+), eksi (-) gibi sayı olmayan bazı karakterler ve dolar işareti ($) gibi geçerli para birimi simgeleri için 1 döndürür. Para birimi simgelerinin tam listesi için bkz. Para ve küçük para (Transact-sql) .

Tamam, yani +, -ve listelenen para birimi simgelerinin sayısal olarak kabul edilmesi bekleniyor. Çok uzak çok iyi.

Şimdi tuhaf kısım için. İlk olarak, bağlı makaledeki para birimi sembollerinden bazıları sayısal değildir , örneğin:

  • Euro para birimi simgesi, altıgen 20A0:
  • Naira işareti, altıgen 20A6:
  • Rial işareti, altıgen FDFC:

Bu garip ve nedenini bulamıyorum. Bu sürüm veya ortama bağlı mı?

Ancak, işler tuhaflaşır. İşte açıklayamadığım birkaç kişi daha:

  • /sayısal değil, ama \( Ha ?! )
  • REPLICATE(N'9', 308)sayısal, ancak REPLICATE(N'9', 309)değil

İlk ve en temel soru: yukarıdaki vakaları açıklayan nedir? Daha da önemlisi: arkasındaki mantık nedirISNUMERIC , böylece tüm vakaları kendim açıklayabilir / tahmin edebilirim?

İşte şeyleri yeniden üretmenin iyi bir yolu:

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;

Bunu yerel Sql Server 2012 kutumda çalıştırdığımda aşağıdaki sonuçları alıyorum:

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

Benim için yanlış görünen tek şey 0, aslında iyi sonuç veren beş değerin yanlış olduğunu bildirmesidir money. Diğerleri doğru görünüyor. SQL FIDDLE
Martin Smith

Yine de NCHAR(0) - NCHAR(65535)112 tutarsızlık görüyorum. ₁,₂,₃,4,5,6,7,8,9Sayısal görünen ancak benim için hiçbir şeye başarılı bir şekilde atılamayan karakterler dahil . Fiddle
Martin Smith

Yanıtlar:


13

Ayrıntılı davranışları ISNUMERICbelgelenmemiştir ve kaynak kodu erişimi olmayanlar tarafından tam olarak bilinmemektedir. Bununla birlikte, yorumlamanın Unicode kategorizasyonuna (sayısal ya da değil) bağlı olduğu söylenebilir. Aynı şekilde, bahsettiğiniz tuhaf durumlar geriye dönük uyumluluk için korunan hatalar olabilir. Evet bunun çılgınca geldiğini biliyorum, ama oluyor.

SQL Server 2012 kullandığınız için kullanmaya gerek yoktur ISNUMERIC. Kullanım TRY_CONVERTveya eşanlamlı TRY_CASTbir dize verilen bir tipe dönüştürülebilir olup olmadığını kontrol etmek yerine. Yeterli işlevsellik sağladıkları yerlerde, bunlar tercih edilir TRY_PARSE, çünkü ikincisi CLR entegrasyonu yoluyla daha pahalı işlemeyi içerir.


2
Ve muhtemelen kaynak kodu erişimi olan birçok insan tarafından tam olarak bilinmemektedir. :-) İkinci paragraf için tekrar + 1'leyebilsem. ISNUMERIC () büyük ölçüde işe yaramaz çünkü amacı bir şeyin en az bir sayısal türe dönüştürülüp dönüştürülemeyeceğini belirlemektir; tek, belirli bir sayısal türe dönüştürebileceğinizi bilmek çok daha önemlidir.
Aaron Bertrand

1
@AaronBertrand Bu niyeti bile karşılamadığı makul derecede önemli sayıda vaka var gibi görünüyor.
Martin Smith

9

ASCII ters eğik çizgi (kod noktası 5C), Windows'un Japonca sürümü tarafından kullanılan Shift-JIS kodlamasında yen işaretiyle (¥) ve Kore EUC-KR'de kazanılan işaretle (₩) aynı kod noktasını paylaşır. Bu nedenle, muhtemelen para birimi işareti temasının bir devamıdır.


Ah bu ilginç bir teori. O moneyda yayınlıyor.
Martin Smith

@Jeroen - Vikipedi'de FWIW
Martin Smith

3
@Jeroen korkmuyorum. Windows kurulumunuzun eski kod sayfasını Japonca olarak değiştirin C:¥Program Files¥ve explorer.exe gibi yolları elde edin
user47620
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.