从MySql检索数组数据的最佳方法是什么

时间:2018-12-03 08:08:48

标签: mysql sql database mariadb

我正在MySql(实际上是MariaDb)数据库中存储这样的对象/数据结构:

{
  idx: 7,
  a: "content A",
  b: "content B",
  c: ["entry c1", "entry c2", "entry c3"]
}

要存储它,我使用了2个表,非常类似于此答案中描述的方法:https://stackoverflow.com/a/17371729/3958875

表1:

+-----+---+---+
| idx | a | b |
+-----+---+---+

表2:

+------------+-------+
| owning_obj | entry |
+------------+-------+

然后创建一个将它们连接在一起的视图,所以我得到了:

+-----+------------+------------+-----------+
| idx | a          | b          | c         |
+-----+------------+------------+-----------+
|   7 | content A1 | content B1 | entry c11 |
|   7 | content A1 | content B1 | entry c21 |
|   7 | content A1 | content B1 | entry c31 |
|   8 | content A2 | content B2 | entry c12 |
|   8 | content A2 | content B2 | entry c22 |
|   8 | content A2 | content B2 | entry c32 |
+-----+------------+------------+-----------+

我的问题是将其恢复为对象形式的最佳方法是什么? (例如,我想要idx在5到20之间的所有条目上面指定的对象类型的数组)

我可以想到2种方法,但这两种方法似乎都不是很有效。

首先,我们可以将整个表发送回服务器,它可以创建一个以键为主键或其他唯一索引的哈希图,并收集不同的c列,并以此方式进行重建,但是这意味着它必须发送大量重复数据,并花费更多的内存和处理时间才能在服务器上进行重建。如果我们有多个数组,或者数组中有数组,这种方法的缩放也不会很令人满意。

第二种方法是执行多个查询,过滤Table 1并获取所需的idx列表,然后针对每个idx发送针对Table 2的查询,其中owning_obj =当前的IDX。这将意味着发送更多的查询。

这两个选项似乎都不是很好,所以我想知道是否有更好的方法。目前,我认为这可以利用JSON_OBJECT(),但我不确定如何使用。

这似乎是一种常见情况,但我似乎找不到确切的措词来寻找答案。

PS:与MySql / MariaDb接口的服务器是用Rust编写的,尽管在此问题中这并不相关

1 个答案:

答案 0 :(得分:0)

您可以使用GROUP_CONCAT将所有c的值组合成一个逗号分隔的字符串。

SELECT t1.idx, t1.a, t1.b, GROUP_CONCAT(entry) AS c
FROM table1 AS t1
LEFT JOIN table2 AS t2 ON t1.idx = t2.owning_obj
GROUP BY t1.idx

然后在PHP中爆炸字符串:

$result_array = [];
while ($row = $result->fetch_assoc()) {
    $row['c'] = explode(',', $row['c']);
    $result_array[] = $row;
}

但是,如果输入项可能很长,请确保增加group_concat_max_len

如果您使用的是MySQL 8.0,则也可以使用JSON_ARRAYAGG()。这将创建一个entry值的JSON数组,您可以使用json_decode()将其转换为PHP数组。这样比较安全,因为如果任何值包含逗号,GROUP_CONCAT()都会弄乱。您可以更改分隔符,但需要一个永远不会有任何值的分隔符。不幸的是,这不在MariaDB中。