我正在使用 MySQL 8.0(在 Azure Database for MySQL Server 中)。
我在使用“json_extract”功能进行查询时注意到一些奇怪的行为。在下面的示例中,我正在查询包含有效 JSON 文本的 VARCHAR 字段:{"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
奇怪的是 json_extract 返回的值似乎表现不同,具体取决于与之交互的比较:
- raw_extract ->“123456”
- raw_extract_length -> 8
- matches_no_quotes -> true
- matches_with_quotes -> false
- matches_wildcard_dbl_quotes -> true
正如您所看到的,基本上有两种返回值:一种包含双引号,一种不包含双引号。LENGTH()、立即返回值和 LIKE 运算符的作用就好像双引号存在一样。等式 (=) 的作用并不像引号存在一样。
我最好的理论是,直接返回类型不是 VARCHAR,而是某种 JSON 数据类型,但 MySQL 文档没有确认或否认这一点。作为第一次遇到这种情况的人,这种矛盾的行为非常令人困惑。有人能解释一下吗?
这是正确的,JSON_EXTRACT() 返回 JSON 类型的列,即使它看起来像字符串,并且客户端可以将其转换为字符串。
您可以使用 MySQL 命令行工具通过检查查询结果数据类型来确认这一点:
JSON_UNQUOTE() 函数可以将 JSON 值转换为更传统的字符串或整数类型。
这意味着在您的测试查询中:
返回 JSON 类型,如上所述。
JSON 值在作为参数传递给 LENGTH() 之前会被强制转换回字符串,然后 LENGTH() 返回 8,这是该字符串中的字符数(包括字符)
"
。这个很古怪。字符串标量
'123456'
被转换为 JSON 值,然后对它们进行比较。这是有记录的:这会返回 false,这是意料之外的。这似乎表明隐式转换
'"123456"'
为 JSON 与显式使用不同CAST()
。我们可以尝试将 JSON 显式转换为字符串,或将字符串转换为 JSON,它会给出不同的结果:
返回真。
返回真。
我不知道怎么了
LIKE
。我链接到的文档中没有涵盖它。它似乎将 JSON 值强制转换为字符串(包括"
字符),然后应用LIKE
模式匹配。我只能说,在 MySQL 中使用 JSON 充满了复杂性。这是抽象泄漏定律的一个很好的例子。我尽可能避免使用 JSON 作为数据类型。