ISNUMERIC
Funkcja ma pewne nieoczekiwane zachowanie. Dokumentacja MSDN mówi:
ISNUMERIC
zwraca 1, gdy wyrażenie wejściowe zwraca poprawny numeryczny typ danych; w przeciwnym razie zwraca 0. Prawidłowe typy danych numerycznych obejmują: int, bigint, smallint, tinyint, dziesiętny, numeryczny, pieniądze, smallmoney, zmiennoprzecinkowy, rzeczywisty .
Ma też przypis:
ISNUMERIC
zwraca 1 dla niektórych znaków, które nie są liczbami, takich jak plus (+), minus (-) oraz prawidłowe symbole walut, takie jak znak dolara ($). Aby uzyskać pełną listę symboli walut, zobacz pieniądze i smallmoney (Transact-SQL) .
Porządku, tak +
, -
oraz oczekuje się, że wymienione symbole waluty należy uznać numeryczne. Jak na razie dobrze.
Teraz część nieparzysta. Po pierwsze, niektóre symbole walut z powiązanego artykułu nie są numeryczne, w tym:
- Znak euro, szesnastkowy 20A0:
₠
- Znak Naira, hex 20A6:
₦
- Znak rial, hex FDFC:
﷼
To dziwne i nie mogę się dowiedzieć, dlaczego? Czy ta wersja lub środowisko jest zależne?
Jednak sprawy stają się coraz dziwniejsze. Oto kilka innych, których nie potrafię wyjaśnić:
/
nie jest numeryczny, ale\
jest ( Huh ?! )REPLICATE(N'9', 308)
jest liczbowy, aleREPLICATE(N'9', 309)
nie jest
Pierwszym i najbardziej podstawowym pytaniem jest: co wyjaśnia powyższe przypadki? Co ważniejsze: jaka jest logikaISNUMERIC
, abym mógł samodzielnie wyjaśnić / przewidzieć wszystkie przypadki?
Oto dobry sposób na odtworzenie rzeczy:
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;
Gdy uruchomię to na moim lokalnym Sql Server 2012 box, otrzymuję następujące wyniki:
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
źródło
0
pięć wartości, które faktycznie pasująmoney
. Pozostałe wydają się dokładne. FIDDLE SQLNCHAR(0) - NCHAR(65535)
widzę 112 rozbieżności. W tym postacie,₁,₂,₃,4,5,6,7,8,9
które wyglądają na liczbowe, ale nie rzucają na mnie niczego. FiddleOdpowiedzi:
Szczegółowe zachowania
ISNUMERIC
nie są udokumentowane i prawdopodobnie nie są w pełni znane nikomu bez dostępu do kodu źródłowego. To powiedziawszy, być może interpretacja zależy od kategoryzacji Unicode (numerycznej lub nie). Podobnie dziwne przypadki, o których wspominasz, mogą być błędami, które zostały zachowane w celu zachowania kompatybilności wstecznej. Tak, wiem, że to brzmi szalenie, ale tak się dzieje.Ponieważ używasz programu SQL Server 2012, nie musisz go używać
ISNUMERIC
. Zamiast tego użyjTRY_CONVERT
lub synonimu,TRY_CAST
aby sprawdzić, czy ciąg znaków można przekonwertować na dany typ. Tam, gdzie zapewniają one odpowiednią funkcjonalność, są one preferowaneTRY_PARSE
, ponieważ te ostatnie wymagają droższego przetwarzania poprzez integrację CLR.źródło
Ukośnik odwrotny ASCII (punkt kodowy 5C) ma ten sam punkt kodowy co znak jena (¥) w kodowaniu Shift-JIS używanym przez japońską wersję systemu Windows, a znak wygranej (₩) w koreańskim EUC-KR. Dlatego jest bardzo prawdopodobne, że jest to kontynuacja motywu znaku waluty.
źródło
money
, że również rzuca.C:¥Program Files¥