A ISNUMERIC
função tem algum comportamento inesperado. A documentação do MSDN diz:
ISNUMERIC
retorna 1 quando a expressão de entrada é avaliada para um tipo de dados numérico válido; caso contrário, ele retornará 0. Os tipos de dados numéricos válidos incluem o seguinte: int, bigint, smallint, tinyint, decimal, numeric, money, smallmoney, float, real .
E também tem uma nota de rodapé:
ISNUMERIC
retorna 1 para alguns caracteres que não são números, como mais (+), menos (-) e símbolos de moeda válidos, como o sinal de dólar ($). Para obter uma lista completa dos símbolos de moeda, consulte Dinheiro e dinheiro pequeno (Transact-SQL) .
Ok, então +
, -
e os símbolos de moeda listados devem ser considerados numéricos. Por enquanto, tudo bem.
Agora, a parte estranha. Primeiro, alguns dos símbolos de moeda do artigo vinculado não são numéricos, incluindo:
- Sinal de moeda do euro, hex 20A0:
₠
- Sinal Naira, hexadecimal 20A6:
₦
- Sinal de rial, hexadecimal FDFC:
﷼
Isso é estranho, e eu não consigo descobrir por quê? Esta versão ou ambiente depende?
No entanto, as coisas ficam mais estranhas. Aqui estão alguns outros que não posso explicar:
/
não é numérico, mas\
é ( hein ?! )REPLICATE(N'9', 308)
é numérico, masREPLICATE(N'9', 309)
não é
A primeira e mais básica pergunta é: o que explica os casos acima? Mais importante ainda: qual é a lógica por trásISNUMERIC
, para que eu pudesse explicar / prever todos os casos?
Aqui está uma boa maneira de reproduzir as coisas:
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;
Quando executo isso na minha caixa local do Sql Server 2012, obtenho os seguintes resultados:
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
fonte
0
de cinco dos valores que realmente são válidosmoney
. Os outros parecem precisos. SQL FIDDLENCHAR(0) - NCHAR(65535)
eu veja 112 discrepâncias. Incluindo caracteres como os₁,₂,₃,4,5,6,7,8,9
que parecem numéricos, mas que não são convertidos com êxito em nada para mim. FiddleRespostas:
Os comportamentos detalhados de
ISNUMERIC
não são documentados e provavelmente não são totalmente conhecidos por ninguém sem acesso ao código-fonte. Dito isto, pode ser que a interpretação dependa da categorização Unicode (numérica ou não). Da mesma forma, os casos estranhos que você menciona podem ser bugs preservados para compatibilidade com versões anteriores. Sim, eu sei que parece loucura, mas acontece.Como você está usando o SQL Server 2012, não há necessidade de usar
ISNUMERIC
. UseTRY_CONVERT
ou o sinônimoTRY_CAST
para verificar se uma sequência é convertível para um determinado tipo. Onde eles fornecem funcionalidade adequada, é preferívelTRY_PARSE
, porque o último envolve um processamento mais caro por meio da integração CLR.fonte
A barra invertida ASCII (ponto de código 5C) compartilha o mesmo ponto de código que o sinal de iene (¥) na codificação Shift-JIS usada pela versão japonesa do Windows e o sinal de vitória (₩) no EUC-KR coreano. Portanto, é muito provável que seja apenas uma continuação do tema do sinal de moeda.
fonte
money
que ele lança também.C:¥Program Files¥
no explorer.exe