Как хранить массивы в MySQL?

у меня есть две таблицы в MySQL. Человека таблица имеет следующие столбцы:

id | name | fruits

на fruits столбец может содержать null или массив строк, таких как ('apple',' orange',' banana') или ('strawberry') и т. д. Вторая таблица-таблица фруктов и имеет следующие три столбца:

____________________________
fruit_name | color  | price
____________________________
apple      | red    | 2
____________________________
orange     | orange | 3
____________________________
...,...

Итак, как я должен проектировать fruits столбец в первой таблице, чтобы он мог содержать массив строк, которые принимают значения из fruit_name столбец во второй таблице? Так как есть нет типа данных массива в MySQL, как я должен это сделать?

7 ответов


правильный способ сделать это-использовать несколько таблиц и 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

причина того, что в SQL нет массивов, заключается в том, что большинству людей это действительно не нужно. Реляционные базы данных (SQL именно так) работают с использованием отношений, и большую часть времени лучше всего назначать по одной строке таблицы каждому "биту информации". Например, где вы можете подумать:" мне нужен список вещей здесь", вместо этого создайте новую таблицу, связав строку в одной таблице со строкой в другой таблице.[1] таким образом, вы можете представлять отношения M:N. Другое преимущество что те ссылки не будут загромождать строку, содержащую связанный элемент. И база данных может индексировать эти строки. Массивы обычно не индексируются.

Если вам не нужны реляционные базы данных,вы можете использовать, например, хранилище ключей.

читать про нормализация базы данных, пожалуйста. Золотое правило: "[каждый] неключевой [атрибут] должен предоставить факт о ключе, весь ключ, и ничего, кроме ключа.". Массив слишком много. Он имеет несколько фактов и сохраняет порядок (который не связан с самим отношением). И производительность плохая (см. выше).

представьте, что у вас есть таблица человек и у вас есть таблица с телефонными звонками людей. Теперь вы можете сделать каждый человек row есть список его телефонных звонков. Но у каждого человека есть много других отношений ко многим другим вещам. Означает ли это, что моя таблица person должна содержать массив для каждой вещи, к которой он подключен? Нет, это не является атрибутом самого человека.

[1]: Это нормально, если таблица ссылок имеет только два столбца (первичные ключи из каждой таблицы)! Если сама связь имеет дополнительные атрибуты, они должны быть представлены в этой таблице в виде столбцов.


MySQL 5.7 теперь предоставляет тип данных JSON. Этот новый тип данных обеспечивает удобный новый способ хранения данных: списки, словари и т. д.

тем не менее, rrays не отображают хорошо базы данных, поэтому объектно-реляционные карты могут быть довольно сложными. Исторически люди сохраняли списки / массивы в MySQL, создавая таблицу, которая описывает их и добавляя каждое значение как свою собственную запись. В таблице может быть только 2 или 3 столбца, или она может содержать гораздо больше. Как вы храните этот тип данных зависит от характеристик данных.

например, содержит ли список статическое или динамическое количество записей? Будет ли список оставаться небольшим, или ожидается, что он вырастет до миллионов записей? На этом столе будет много книг? Много писем? Много обновлений? Это все факторы, которые необходимо учитывать при принятии решения о том, как хранить коллекции данных.

кроме того, ключ: хранилища данных значения / хранилища документов, такие как Cassandra, MongoDB, Redis etc обеспечивает хорошее разрешение также. Просто имейте в виду, где данные фактически хранятся (если они хранятся на диске или в памяти). Не все ваши данные должны быть в одной базе данных. Некоторые данные плохо сопоставляются с реляционной базой данных, и у вас могут быть причины хранить их в другом месте, или вы можете использовать ключ в памяти:база данных значений в качестве горячего кэша для данных, хранящихся на диске где-то или в качестве эфемерного хранилища для таких вещей, как сеансы.


sidenote для рассмотрения, вы можете хранить массивы в Postgres.


в MySQL используйте тип JSON.

Contra ответы выше, стандарт SQL включал типы массивов в течение почти двадцати лет; они полезны, даже если 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, а не взломать массив вместе из строки.


используйте поле базы данных типа BLOB для хранения массивов.

Ref:http://us.php.net/manual/en/function.serialize.php

Возвращаемые Значения

возвращает строку, содержащую байт-потоковое представление значения, которое может храниться где угодно.

отметим, что это двоичная строка, которая может содержать нулевые байты, и необходимо хранить и обрабатывать как таковые. Например, сериализация() выходные данные, как правило, должны храниться в поле BLOB в базе данных, вместо CHAR или текстового поля.


вы можете сохранить свой массив с помощью group_Concat, как это

 INSERT into Table1 (fruits)  (SELECT GROUP_CONCAT(fruit_name) from table2)
 WHERE ..... //your clause here
теги пример в скрипку