如何对 MySQL JSON 列属性进行空检查?

Posted

技术标签:

【中文标题】如何对 MySQL JSON 列属性进行空检查?【英文标题】:How to null check MySQL JSON column property? 【发布时间】:2020-12-14 06:45:49 【问题描述】:

我正在使用 mysql 8.0.21。我需要编写一个适用于 JSON 列类型的查询。 JSON 文档中的一些数据有空值,我想过滤掉这些空值。

为简单起见,删除了可能行的示例,JSON 文档中的大多数属性:

jsonColumn
'"value":96.0'
'"value":null' -- This is the row I am trying to filter out
NULL

这是我尝试过的:

-- Removed columns where jsonColumn was NULL but, NOT columns where jsonColumn->'$.value' was null. 
SELECT * 
FROM <table>
WHERE jsonColumn->'$.value' IS NOT NULL;

-- Note the unquote syntax, ->>. The code above uses ->.
-- Produced the same result as the code above.
SELECT * 
FROM <table>
WHERE jsonColumn->>'$.value' IS NOT NULL;

-- Produced same result as the two above. Not surprised because -> is an alias of JSON_EXTRACT
SELECT * 
FROM <table>
WHERE JSON_EXTRACT(jsonColumn, '$.value') IS NOT NULL;

-- Produced same result as the three above. Not surprised because ->> is an alias of JSON_EXTRACT
SELECT * 
FROM <table>
WHERE JSON_UNQUOTE(JSON_EXTRACT(jsonColumn, '$.value')) IS NOT NULL;

-- Didn't really expect this to work. It didn't work. For some reason it filters out all records from the select.
SELECT *
FROM <table>
WHERE jsonColumn->'$.value' != NULL;

-- Unquote syntax again. Produced the same result as the code above.
SELECT *
FROM <table>
WHERE jsonColumn->>'$.value' != NULL;

-- Didn't expect this to work. Filters out all records from the select.
SELECT *
FROM <table>
WHERE JSON_EXTRACT(jsonColumn, '$.value') != NULL;

-- Didn't expect this to work. Filters out all records from the select.
SELECT *
FROM <table>
WHERE JSON_UNQUOTE(JSON_EXTRACT(jsonColumn, '$.value')) != NULL;

-- I also tried adding a boolean value to one of the JSON documents, '"test":true'. These queries did not select the record with this JSON document.
SELECT * 
FROM <table>
WHERE jsonColumn->'$.test' IS TRUE;
SELECT * 
FROM <table>
WHERE jsonColumn->>'$.test' IS TRUE;

我注意到一些有趣的事情......

比较其他值有效。比如……

-- This query seems to work fine. It filters out all records except those where jsonColumn.value is 96.
SELECT *
FROM <table>
WHERE jsonColumn->'$.value' = 96;

我注意到的另一件有趣的事情,在上面的一些示例的 cmets 中提到,是 null 检查的一些奇怪行为。 如果 jsonColumn 为空,即使知道我正在访问 jsonColumn->'$.value',空检查也会过滤掉记录。

不确定这是否清楚,所以让我详细说明一下......

-- WHERE jsonColumn->>'$.value' IS NOT NULL
jsonColumn
'"value":96.0'
'"value":null' -- This is the row I am trying to filter out. It does NOT get filtered out.
NULL -- This row does get filtered out.

根据this post,使用 ->> 和 JSON_UNQUOTE 和 JSON_EXTRACT 与 IS NOT NULL 比较应该有效。我认为它在当时有效。

老实说,这可能是 IS 语句和 JSON 列类型的错误。在比较 JSON 文档而不是 JSON 文档的值时,已经存在奇怪的行为。

无论如何,有没有办法做到这一点?还是我一直在尝试的方法被证实是正确的方法,而这只是一个错误?

【问题讨论】:

显然这在 8.0.13 之前的某个时候发生了变化。 forums.mysql.com/read.php?176,670072,670072 解决方法在该论坛主题中。太恶心了。 @Barmar 好吧,这很糟糕,但这很有趣......WHERE virtualPCI-&gt;&gt;'$.value' != 'null' 似乎同时过滤了预期值和意外值。将更新 OP 似乎很难完全适合评论。 那个线程已经快 2 年了,oracle 不关心他们系统中的错误吗? 借助 Barmar 发布的论坛信息以及我对字符串比较的测试,我想我会在网站允许的情况下发布答案。 【参考方案1】:

根据 Barmar 的评论...

显然,这在 8.0.13 之前的某个时候发生了变化。 forums.mysql.com/read.php?176,670072,670072

论坛帖子中的解决方法似乎使用 JSON_TYPE。看起来是一个糟糕的解决方法。

SET @doc = JSON_OBJECT('a', NULL);
SELECT JSON_UNQUOTE(IF(JSON_TYPE(JSON_EXTRACT(@doc,'$.a')) = 'NULL', NULL, JSON_EXTRACT(@doc,'$.a'))) as C1,
JSON_UNQUOTE(JSON_EXTRACT(@doc,'$.b')) as C2;

论坛帖子说(关于解决方法之前发布的代码)...

C2 被有效地设置为 NULL,但 C1 作为 4 char 'null' 字符串返回。

所以我开始搞乱字符串比较...

// This filtered out NULL jsonColumn but, NOT NULL jsonColumn->'$.value'
SELECT *
FROM <table>
WHERE jsonColumn->'$.value' != 'null';

jsonColumn
'"value":96.0'
'"value":"null"' -- Not originally apart of my dataset but, this does get filtered out. Which is very interesting...
'"value":null' -- This does NOT get filtered out.
NULL -- This row does get filtered out.

// This filtered out both NULL jsonColumn AND NULL jsonColumn->'$.value'
SELECT *
FROM <table>
WHERE jsonColumn->>'$.value' != 'null';

jsonColumn
'"value":96.0'
'"value":"null"' -- Not originally apart of my dataset but, this does get filtered out.
'"value":null' -- This does get filtered out.
NULL -- This row does get filtered out.

【讨论】:

显然不能接受这两天的答案。 我认为它也会过滤掉"value":"null"。不过,这在您的用例中可能不是问题。 @Barmar 不错,可能对我来说不是问题。我会做一些快速测试以获得更完整的答案。

以上是关于如何对 MySQL JSON 列属性进行空检查?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL如何索引JSON字段

如何检查 MySQL JSON 列是不是包含 laravel 中的值?

如果子查询在 MySQL 中返回多于 1 行,如何将 JSON 放入列数据中

如何检查 MySQL 中的列是不是为空或 null?

如何使用 JPA 和 Hibernate 将 MySQL JSON 列映射到 Java 实体属性

Mysql 返回JSON值属性的函数