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

50

У меня есть две таблицы в MySQL. Таблица. Пользователь имеет следующие столбцы:

id | name | fruits

Столбец fruits может содержать нуль или массив строк, таких как ( "яблоко", "оранжевый", "банан" ) или ( "клубника" ) и т.д. Вторая таблица - "Плоды стола" и имеет следующее три столбца:

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

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

  • 1
    как насчет добавления его в виде отдельных записей: orange, 2, 1, rose, 2, 1 и т. д., а затем вы можете использовать запросы для обработки их, как если бы они были массивами.
Показать ещё 2 комментария
Теги:
database-schema

6 ответов

83
Лучший ответ

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

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
  • 4
    Третья таблица - это таблица связей между Person и Fruit. Так что, если у человека есть 100 фруктов. Мне нужно создать 100 строк в третьей таблице, верно? Это эффективно?
  • 1
    @tonga Точно, каждый из 100 рядов будет иметь один и тот же person_id но разные fruit_name . Это фактически реализация теории из ответа Януса.
Показать ещё 10 комментариев
36

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

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

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

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

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

  • 2
    Спасибо, Янус. В этом есть смысл. Теперь я понимаю, почему MySQL не поддерживает тип массива в столбце.
  • 0
    некоторые ключевые хранилища значений: MongoDB, Elasticsearch, Couch DB, BigTable и т. д.
Показать ещё 8 комментариев
27

Изменить:

(3/10/2016)

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

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

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

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

  • 0
    Большое спасибо за очень подробное объяснение на эту тему.
  • 0
    Ваши предлагаемые решения слишком расплывчаты, учитывая пространство, которое вы заняли, чтобы «ответить» на вопрос.
18

В качестве побочного элемента для рассмотрения вы можете хранить массивы в Postgres.

  • 2
    Не делает это хорошей практикой.
  • 1
    Дополнительное примечание: они могут быть проиндексированы, поэтому проверка запросов на наличие определенных значений в массиве может быть очень быстрой. То же самое касается сложных типов JSON.
1

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

Ссылка: http://us.php.net/manual/en/function.serialize.php

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

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

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

-1

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

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

ЗДЕСЬ пример в скрипте

  • 4
    Не очень хорошо объяснил. Плохие имена столов.
  • 0
    Может быть, удалить этот ответ? : D

Ещё вопросы

Сообщество Overcoder
Наверх
Меню