Estou usando o MySQL 8.0 (dentro do Banco de Dados do Azure para MySQL Server).
Notei um comportamento estranho ao consultar a funcionalidade "json_extract". No exemplo abaixo, estou consultando um campo VARCHAR que contém o texto JSON válido: {"myfield":"123456"}.
SELECT json_extract(jsontext, '$.myfield') raw_extract,
LENGTH(json_extract(jsontext, '$.myfield')) raw_extract_length,
CASE WHEN json_extract(jsontext, '$.myfield') = '123456' THEN 'true' ELSE 'false' END matches_no_quotes,
CASE WHEN json_extract(jsontext, '$.myfield') = '"123456"' THEN 'true' ELSE 'false' END matches_with_quotes,
CASE WHEN json_extract(jsontext, '$.myfield') LIKE '"%"' THEN 'true' ELSE 'false' END matches_wildcard_dbl_quotes
O que é estranho é que o valor retornado por json_extract parece se comportar de maneira diferente dependendo de qual comparação está interagindo com ele:
- extração_prima -> "123456"
- raw_extract_length -> 8
- corresponde_no_quotes -> verdadeiro
- corresponde_com_quotes -> falso
- matches_wildcard_dbl_quotes -> verdadeiro
Como você pode ver, há basicamente dois valores de retorno: um com aspas duplas incluídas e outro sem. LENGTH(), o valor de retorno imediato e os operadores LIKE agem como se existissem aspas duplas. A igualdade (=) não funciona como se as aspas existissem.
Minha melhor teoria é que o tipo de retorno direto não é VARCHAR e, em vez disso, é algum tipo de tipo de dados JSON, mas a documentação do MySQL não confirmou ou negou isso. Como alguém que se depara com isso pela primeira vez, esse comportamento contraditório é muito confuso. Alguém pode lançar alguma luz sobre isso?
Correto, JSON_EXTRACT() retorna uma coluna do tipo JSON, mesmo que pareça uma string, e o cliente pode convertê-la em uma string.
Você pode confirmar isso com a ferramenta de linha de comando do MySQL examinando o tipo de dados do resultado da consulta:
A função JSON_UNQUOTE() pode transformar o valor JSON em uma string ou tipo inteiro mais tradicional.
Isso significa na sua consulta de teste:
Retorna o tipo JSON, conforme descrito acima.
O valor JSON é convertido de volta para uma string antes de ser passado como argumento para LENGTH() e, em seguida, LENGTH() retorna 8, que é o número de caracteres nessa string, incluindo os caracteres
"
.Este é maluco. O escalar da string
'123456'
é convertido como um valor JSON e, em seguida, eles são comparados. Isso está documentado :Isso retorna falso, o que é inesperado. Isso parece mostrar que a conversão implícita
'"123456"'
para JSON não é o mesmo que usarCAST()
explicitamente.Podemos tentar converter explicitamente o JSON em uma string, ou a string em JSON, e isso fornece resultados diferentes:
Retorna verdadeiro.
Retorna verdadeiro.
Não tenho certeza do que está acontecendo
LIKE
. Não é abordado na documentação à qual vinculei. Parece forçar o valor JSON a uma string, incluindo os"
caracteres, e depois aplicar aLIKE
correspondência de padrões.Tudo o que posso dizer é que usar JSON no MySQL é repleto de complexidade. É um ótimo exemplo da Lei das Abstrações com Vazamento . Evito usar JSON como tipo de dados sempre que possível.