1

我有一个数据库,列中有一个 JSON 数组extra_fields。我需要通过 id 提取一个值。

JSON 看起来像这样,尽管每行的对象数量是随机的:

[
{"id":"1","value":"48768"},
{"id":"2","value" ["String","http:someurl"]},
{"id":"5","value":"somevalue"},
{"id":"6","value":""},
{"id":"8","value":"Op-Ed"},
{"id":"9","value":"8111,13498,15408"},
{"id":"10","value":"30"},
{"id":"11","value":"This is the target string"}
]

我可以提取一个 id 数组:

SELECT extra_fields->>"$[*].id"  FROM esqt7_k2_items;

我可以使用以下方法提取一组值:

SELECT extra_fields->>"$[*].value"  FROM esqt7_k2_items;

我可以在第 n 个零序对象位置提取单个值:

SELECT extra_fields->>"$[2].value"  FROM esqt7_k2_items;

但问题是对象数量可变,我特别需要对象 id = 11 的值。 JSON_EXTRACT 似乎不支持过滤,因为 JSONPATH 的每个变体似乎都失败了。$..[?(@.id=11)].value作为 JSONPATH 工作,但这(和许多变体)失败:

SELECT extra_fields->"$.[?(@.id=11)].value" FROM esqt7_k2_items; #FAILS

这是一个迁移项目,JSON 内容正是 Joomla 选择实现其额外字段的方式。如果你问我,有点痛苦。

4

2 回答 2

1

您可以考虑的一种选择(注意性能问题):

mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.19    |
+-----------+
1 row in set (0.00 sec)

mysql> DROP TABLE IF EXISTS `esqt7_k2_items`;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS `esqt7_k2_items` (
    ->   `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->   `extra_fields` JSON NOT NULL
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `esqt7_k2_items`
    ->   (`extra_fields`)
    -> VALUES
    ->   ('
    '>     [
    '>       {"id": "1", "value": "48768"},
    '>       {"id": "2", "value": ["String","http:someurl"]},
    '>       {"id": "5", "value": "somevalue"},
    '>       {"id": "6", "value": ""},
    '>       {"id": "8", "value": "Op-Ed"},
    '>       {"id": "9", "value": "8111,13498,15408"},
    '>       {"id": "10", "value": "30"},
    '>       {"id": "11", "value": "This is the target string"}
    '>     ]
    '>   '),
    ->   ('
    '>     [
    '>       {"id": "1", "value": ""},
    '>       {"id": "9", "value": "ONE This is the target string"}
    '>     ]
    '>   '),
    ->   ('
    '>     [
    '>       {"id": "6", "value": ""},
    '>       {"id": "11", "value": "TWO This is the target string"}
    '>     ]
    '>   ');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SET @`search_id` := '11';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT `der`.`id`, `der`.`value`
    -> FROM (
    ->   SELECT
    ->     `id`,
    ->     JSON_UNQUOTE(
    ->       JSON_EXTRACT(`extra_fields`,
    ->         CONCAT((SELECT
    ->           JSON_UNQUOTE(
    ->             JSON_SEARCH(`extra_fields` ->> '$[*].id', 'one', @`search_id`)
    ->           )
    ->                 FROM `esqt7_k2_items` `esqt7_k2_items_in`
    ->                 WHERE `esqt7_k2_items_out`.`id` = `esqt7_k2_items_in`.`id`
    ->                ), ".value"
    ->         )
    ->       )
    ->     ) `value`
    ->   FROM `esqt7_k2_items` `esqt7_k2_items_out`
    -> ) `der`
    -> WHERE `der`.`value` IS NOT NULL;
+----+-------------------------------+
| id | value                         |
+----+-------------------------------+
|  1 | This is the target string     |
|  3 | TWO This is the target string |
+----+-------------------------------+
2 rows in set (0.00 sec)

请参阅db-fiddle

于 2017-07-26T11:50:07.903 回答
1

我发现的最简单的方法

对象 id = 11 的值

它通过找到所需对象的正确“索引”,做一些PHP。首先,我们通过您的简单请求获取所有对象 ID:

> SELECT extra_fields->>"$[*].id"  FROM esqt7_k2_items;

然后在 PHP

$rightIndex = array_search($ids, '11');

然后你通过传递这个$rightIndex得到正确的对象:

SELECT extra_fields->>"$[$rightIndex].value"  FROM esqt7_k2_items;

简单得要命!您可以在其他任何地方执行相同的操作,例如,当您需要更新数组中的对象或其值/值等时。也就是说,干杯!

于 2017-08-25T23:43:57.573 回答