MySQL JSON - 使用 IN 语句 | json_contains

Posted

技术标签:

【中文标题】MySQL JSON - 使用 IN 语句 | json_contains【英文标题】:MySQL JSON - using IN statement | json_contains 【发布时间】:2017-11-01 19:34:54 【问题描述】:

我正在尝试选择 json 列中的 roles 属性包含任何值的所有列。

我尝试过的陈述:

SELECT * FROM components WHERE json->'$.roles' IN(1)

这甚至行不通,但我认为它应该...

SELECT * FROM components WHERE JSON_CONTAINS(components, '1', '$.roles')

这确实有效,但是很严格,所以当我使用1 时,它会像应该的那样拉两个,因为它们都包含 1,但是如果我插入 1,2JSON_ARRAY(1,2) 它只会拉后面的行,因为它不是'不检查每个数组元素...

我有下表components结构数据

+====+========================================================================================================================================================================================================+==+
| id |                                                                                                  json                                                                                                  |  |
+====+========================================================================================================================================================================================================+==+
|  1 | "area": 1, "roles": [1], "elements": ["home": "content": "Home", "attributes": "class": "my_class_1", "dashboard": "content": "Dashboard", "attributes": "class": "my_class_1"]          |  |
+----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--+
|  2 | "area": 1, "roles": [1, 2, 5], "elements": ["home": "content": "Testing", "attributes": "class": "my_class_1", "dashboard": "content": "Dashboard", "attributes": "class": "my_class_1"] |  |
+----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--+

问题:如何修改这些语句中的任何一个,以允许它们根据roles 属性中的值查询行?

【问题讨论】:

json->'$.roles' 是一个数组,1 是一个数字。数组不等于数字。 @Barmar 同意,即使我在JSON_CONTAINS() 中使用[1,2]JSON_ARRAY(1,2) 也会出错,因为它不喜欢value 参数数组。 【参考方案1】:

尝试其中一种它应该可以工作

SELECT * FROM components WHERE JSON_CONTAINS([1],  roles, '$');

SELECT * FROM components WHERE JSON_CONTAINS([1],  CAST(roles as JSON), '$');

【讨论】:

【参考方案2】:

见https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps

JSON_OVERLAPS(json_doc1, json_doc2)

比较两个 JSON 文档。如果两个文档有任何共同的键值对或数组元素,则返回 true (1)。如果两个参数都是标量,则函数执行简单的相等性测试。

此函数与JSON_CONTAINS() 对应,后者要求搜索到的数组的所有元素都存在于搜索到的数组中。因此,JSON_CONTAINS() 对搜索键执行 AND 操作,而 JSON_OVERLAPS() 执行或运算。

在 WHERE 子句中使用 JSON_OVERLAPS() 对 InnoDB 表的 JSON 列的查询可以使用多值索引进行优化。多值索引,提供详细信息和示例。

比较两个数组时,JSON_OVERLAPS() 如果它们共享一个或多个数组元素,则返回 true,否则返回 false。

mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]") |
+---------------------------------------+
|                                     1 |
+---------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]") |
+---------------------------------------+
|                                     1 |
+---------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]") |
+---------------------------------------+
|                                     0 |
+---------------------------------------+
1 row in set (0.00 sec)

【讨论】:

【参考方案3】:

表达式

value in (x, y, z, ...)

等价于

value = x OR value = y OR value = z OR ...

这不适用于像 json->'$.roles' 这样的数组,因为数组不等于它的元素,您需要调用 JSON_CONTAINS() 来测试它。

对于您想要的,您需要为每个要测试的值调用JSON_CONTAINS()

WHERE JSON_CONTAINS(components, '1', '$.roles') OR JSON_CONTAINS(components, '2', '$.roles')

【讨论】:

是的,我已经看到了……它看起来很“骇人听闻”,不是吗?但是,是的,这可能是实现它的唯一方法。不过,这有可能变成动态的吗? 想出了一个更好的答案。 是的,我确实试过了!唯一的问题是它是严格的,所以像 JSON_ARRAY(1,2) 不会返回角色包含 1 的行,前提是它的确切顺序。 哦,对了,它想匹配所有这些,而不是任何一个。我认为它必须回到OR 版本。

以上是关于MySQL JSON - 使用 IN 语句 | json_contains的主要内容,如果未能解决你的问题,请参考以下文章

PHP数组拼接MySQL的in语句

MySQL数据类型 - JSON数据类型

mysql 的 IN 语句 疑问

使用 handlebars.js 制作“if x in dict(json)”语句

没有使用 MySQL Connector/J 的服务器端准备语句

准备好的语句,`WHERE .. IN(..)` 查询和排序 - 使用 MySQL