如何在 MySQL 中存储数组?

我在 MySQL 中有两个表:

身份证 姓名 水果

fruits列可以包含 null 或者一个字符串数组,比如(‘ apple’、‘ Orange’、‘ banana’)或者(‘ Strawberry’) ,等等。第二个表是 Table Fruit,有以下三列:

水果名称 颜色 价钱
苹果 红色 2
橙色 橙色 3
----------- -------- ------

那么,我应该如何设计第一个表中的 fruits列,以便它能够保存从第二个表中的 fruit_name列获取值的字符串数组?由于 MySQL 中没有数组数据类型,我应该怎么做呢?

498514 次浏览

您可以像这样使用 group _ Concat 存储数组

 INSERT into Table1 (fruits)  (SELECT GROUP_CONCAT(fruit_name) from table2)
WHERE ..... //your clause here

这是 小提琴中的例子

正确的方法是在查询中使用多个表并使用 JOIN

例如:

CREATE TABLE person (
`id` INT NOT NULL PRIMARY KEY,
`name` VARCHAR(50)
);


CREATE TABLE fruits (
`fruit_name` VARCHAR(20) NOT NULL PRIMARY KEY,
`color` VARCHAR(20),
`price` INT
);


CREATE TABLE person_fruit (
`person_id` INT NOT NULL,
`fruit_name` VARCHAR(20) NOT NULL,
PRIMARY KEY(`person_id`, `fruit_name`)
);

person_fruit表包含与人相关联的每个水果的一行,并有效地将 personfruits表连接在一起,即。

1 | "banana"
1 | "apple"
1 | "orange"
2 | "straberry"
2 | "banana"
2 | "apple"

当你想找回一个人和他的所有水果时,你可以这样做:

SELECT p.*, f.*
FROM person p
INNER JOIN person_fruit pf
ON pf.person_id = p.id
INNER JOIN fruits f
ON f.fruit_name = pf.fruit_name

SQL 中没有数组的原因是因为大多数人并不真正需要它。关系数据库(SQL 就是这样)使用关系工作,大多数情况下,最好为每个“信息位”分配一行表。例如,您可能认为“我想要一个东西列表”,而是创建一个新表,将一个表中的行与另一个表中的行链接起来。[1]这样,你就可以表示 M: N 关系。另一个优点是,这些链接不会使包含链接项的行变得凌乱。数据库可以对这些行进行索引。数组通常不被索引。

如果不需要关系数据库,可以使用键值存储。

请阅读 数据库规范化。黄金法则是“[每个]非键[属性]必须提供关于键、整个键的事实,只提供键。”.数组的作用太大了。它有多个事实,并且它存储顺序(与关系本身无关)。而且表现很差(见上文)。

想象一下,你有一个人桌,你有一个人的电话来电表。现在,您可以让每个人行都有一个他的电话通话列表。但是,每个人都有许多其他的关系,许多其他的事情。这是否意味着我的人员表应该包含他所连接到的每一个事物的数组?不,这不是一个人本身的属性。

[1] : 如果链接表只有两列(每个表的主键) ,那么没问题!但是,如果关系本身具有其他属性,那么它们应该在该表中表示为列。

MySQL 5.7现在提供了一个 JSON 数据类型。这种新的数据类型提供了一种方便的新方法来存储复杂的数据: 列表、字典等等。

也就是说,数组不能很好地映射数据库,这就是为什么对象-关系映射可能相当复杂的原因。历史上,人们通过创建一个描述列表/数组的表并将每个值作为自己的记录来存储列表/数组。该表可能只有2或3列,也可能包含更多列。如何存储这种类型的数据实际上取决于数据的特征。

例如,该列表是否包含静态或动态的条目数?这个名单会保持小规模,还是会增长到数百万张唱片?这张桌子上会有很多书吗?很多信?很多新消息吗?这些都是在决定如何存储数据集合时需要考虑的因素。

此外,键/值数据存储、文档存储(如 Cassandra、 MongoDB、 Redis 等)也提供了很好的解决方案。只需要知道数据实际存储在哪里(如果它存储在磁盘或内存中)。并非所有数据都需要在同一个数据库中。有些数据不能很好地映射到关系数据库,你可能有理由将它存储在其他地方,或者你可能想使用内存中的键值数据库作为存储在磁盘某处的数据的热缓存,或者作为会话之类的临时存储。

需要注意的是你可以在 Postgres 存储数组。

使用数据库字段类型 BLOB 存储数组。

档号: http://us.php.net/manual/en/function.serialize.php

返回值

返回一个字符串,该字符串包含 可以储存在任何地方。

注意,这是一个二进制字符串,可能包含空字节,和 需要像这样存储和处理 输出通常应该存储在数据库的 BLOB 字段中, 而不是 CHAR 或 TEXT 字段。

在 MySQL 中,使用 JSON 类型。

与上面的答案相反,SQL 标准包含数组类型已经有将近20年的历史了; 它们是有用的,即使 MySQL 没有实现它们。

然而,在您的示例中,您可能希望创建三个表: person 和 Fruit,然后 person _ Fruit 加入它们。

DROP TABLE IF EXISTS person_fruit;
DROP TABLE IF EXISTS person;
DROP TABLE IF EXISTS fruit;


CREATE TABLE person (
person_id   INT           NOT NULL AUTO_INCREMENT,
person_name VARCHAR(1000) NOT NULL,
PRIMARY KEY (person_id)
);


CREATE TABLE fruit (
fruit_id    INT           NOT NULL AUTO_INCREMENT,
fruit_name  VARCHAR(1000) NOT NULL,
fruit_color VARCHAR(1000) NOT NULL,
fruit_price INT           NOT NULL,
PRIMARY KEY (fruit_id)
);


CREATE TABLE person_fruit (
pf_id     INT NOT NULL AUTO_INCREMENT,
pf_person INT NOT NULL,
pf_fruit  INT NOT NULL,
PRIMARY KEY (pf_id),
FOREIGN KEY (pf_person) REFERENCES person (person_id),
FOREIGN KEY (pf_fruit) REFERENCES fruit (fruit_id)
);


INSERT INTO person (person_name)
VALUES
('John'),
('Mary'),
('John'); -- again


INSERT INTO fruit (fruit_name, fruit_color, fruit_price)
VALUES
('apple', 'red', 1),
('orange', 'orange', 2),
('pineapple', 'yellow', 3);


INSERT INTO person_fruit (pf_person, pf_fruit)
VALUES
(1, 1),
(1, 2),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3);

如果你想把这个人和一系列的水果联系起来,你可以通过一个视图:

DROP VIEW IF EXISTS person_fruit_summary;
CREATE VIEW person_fruit_summary AS
SELECT
person_id                                                                                              AS pfs_person_id,
max(person_name)                                                                                       AS pfs_person_name,
cast(concat('[', group_concat(json_quote(fruit_name) ORDER BY fruit_name SEPARATOR ','), ']') as json) AS pfs_fruit_name_array
FROM
person
INNER JOIN person_fruit
ON person.person_id = person_fruit.pf_person
INNER JOIN fruit
ON person_fruit.pf_fruit = fruit.fruit_id
GROUP BY
person_id;

视图显示了以下数据:

+---------------+-----------------+----------------------------------+
| pfs_person_id | pfs_person_name | pfs_fruit_name_array             |
+---------------+-----------------+----------------------------------+
|             1 | John            | ["apple", "orange"]              |
|             2 | Mary            | ["orange", "pineapple"]          |
|             3 | John            | ["apple", "orange", "pineapple"] |
+---------------+-----------------+----------------------------------+

在5.7.22中,您将希望使用 JSON _ ARRAYAGG,而不是从字符串中将数组拼凑起来。