提问人:tonga 提问时间:6/29/2013 最后编辑:self demandtonga 更新时间:4/7/2022 访问量:561414
如何在MySQL中存储数组?
How to store arrays in MySQL?
问:
我在MySQL中有两个表。表 Person 包含以下列:
编号 | 名字 | 水果 |
---|
该列可以保存 null 或字符串数组,如 ('apple', 'orange', 'banana') 或 ('strawberry') 等。第二个表是 Table Fruit,包含以下三列:fruits
fruit_name | 颜色 | 价格 |
---|---|---|
苹果 | 红 | 2 |
橙 | 橙 | 3 |
----------- | -------- | ------ |
那么,我应该如何设计第一个表中的列,以便它可以保存从第二个表中的列中获取值的字符串数组呢?既然MySQL中没有数组数据类型,我应该怎么做呢?fruits
fruit_name
答:
您可以使用这样的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
person
fruits
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
评论
person_id
fruit_name
person
fruits
person_fruit
person_fruit
person
fruits
person_fruit
INT
fruits
INT
person_fruit
fruits
person_fruit
SQL中没有数组的原因是大多数人并不真正需要它。关系数据库(SQL就是这样)使用关系工作,大多数时候,最好将表的一行分配给每个“信息位”。例如,你可能会想“我想要这里的东西列表”,而是创建一个新表,将一个表中的行与另一个表中的行链接起来。[1] 这样,你就可以表示 M:N 关系。另一个优点是,这些链接不会使包含链接项的行混乱。数据库可以索引这些行。数组通常不编制索引。
如果你不需要关系数据库,你可以使用键值存储。
请阅读有关数据库规范化的信息。黄金法则是“[每个]非键[属性]必须提供有关键的事实,整个键,除了键之外什么都没有。数组执行的操作太多。它有多个事实,并存储顺序(与关系本身无关)。而且性能很差(见上文)。
想象一下,你有一张人表,你有一张桌子,上面有人们的电话。现在,您可以让每个人行都有一个他的电话列表。但是每个人与许多其他事物都有许多其他关系。这是否意味着我的 person 表应该包含他所连接的每个事物的数组?不,这不是人本身的属性。
[1]:链接表只有两列(每个表的主键)也没关系!但是,如果关系本身具有其他属性,则应在此表中将它们表示为列。
评论
MySQL 5.7 现在提供 JSON 数据类型。这种新数据类型提供了一种方便的新方法来存储复杂数据:列表、字典等。
也就是说,数组不能很好地映射数据库,这就是为什么对象关系映射可能非常复杂的原因。从历史上看,人们通过创建一个描述列表/数组的表并将每个值添加为自己的记录来存储在 MySQL 中。该表可能只有 2 或 3 列,也可能包含更多列。如何存储此类数据实际上取决于数据的特征。
例如,列表是否包含静态或动态条目数?该列表会保持较小规模,还是有望增长到数百万条记录?这张桌子上会有很多读物吗?很多写?很多更新?这些都是在决定如何存储数据集合时需要考虑的因素。
此外,键/值数据存储、文档存储(如 Cassandra、MongoDB、Redis 等)也提供了一个很好的解决方案。只需注意数据的实际存储位置(如果它存储在磁盘或内存中)。并非所有数据都需要位于同一数据库中。某些数据不能很好地映射到关系数据库,您可能有理由将其存储在其他位置,或者您可能希望使用内存中的键值数据库作为存储在磁盘上某处的数据的热缓存,或者用作会话等内容的临时存储。
需要考虑的一点是,您可以将数组存储在 Postgres 中。
评论
使用数据库字段类型 BLOB 存储数组。
编号: http://us.php.net/manual/en/function.serialize.php
返回值
返回一个字符串,其中包含 value 的字节流表示形式 可以存储在任何地方。
请注意,这是一个二进制字符串,其中可能包含 null 字节,并且 需要这样存储和处理。例如,serialize() 输出通常应存储在数据库的 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,而不是从字符串中将数组组合在一起。
评论