205 votes

Comment stocker des tableaux dans MySQL ?

J'ai deux tables dans MySQL. La table Person a les colonnes suivantes :

id

nom

fruits

El fruits peut contenir null ou un tableau de chaînes de caractères comme ('apple', 'orange', 'banana'), ou ('strawberry'), etc. La deuxième table est la Table Fruit et possède les trois colonnes suivantes :

nom_fruit

couleur

prix

pomme

rouge

2

orange

orange

3

-----------

--------

------

Alors, comment dois-je concevoir le fruits dans la première table afin qu'elle puisse contenir un tableau de chaînes de caractères qui prennent des valeurs de la colonne fruit_name dans la deuxième table ? Comme il n'y a pas de type de données tableau dans MySQL, comment dois-je faire ?

252voto

Bad Wolf Points 3561

La bonne façon de procéder est d'utiliser plusieurs tables et JOIN dans vos requêtes.

Par exemple :

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`)
);

El person_fruit contient une rangée pour chaque fruit auquel une personne est associée et relie effectivement la table person et fruits tables ensemble, I.E.

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

Lorsque vous souhaitez récupérer une personne et tous ses fruits, vous pouvez procéder comme suit :

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

89voto

Janus Troelsen Points 5121

La raison pour laquelle il n'y a pas de tableaux en SQL est que la plupart des gens n'en ont pas vraiment besoin. Les bases de données relationnelles (c'est exactement cela, SQL) fonctionnent à l'aide de relations et, la plupart du temps, il est préférable d'attribuer une ligne d'une table à chaque "élément d'information". Par exemple, là où vous pourriez penser "j'aimerais avoir une liste de choses ici", créez plutôt une nouvelle table, en reliant la ligne d'une table à la ligne d'une autre table[1]. De cette façon, vous pouvez représenter des relations M:N. Un autre avantage est que ces liens n'encombrent pas la ligne contenant l'élément lié. Et la base de données peut indexer ces rangées. Les tableaux ne sont généralement pas indexés.

Si vous n'avez pas besoin de bases de données relationnelles, vous pouvez utiliser, par exemple, un magasin de valeurs clés.

Lire la suite normalisation de la base de données s'il vous plaît. La règle d'or est la suivante : "[Chaque] [attribut] non clé doit fournir un fait sur la clé, toute la clé, et rien que la clé". Un tableau en fait trop. Il contient plusieurs faits et stocke l'ordre (qui n'est pas lié à la relation elle-même). Et les performances sont médiocres (voir ci-dessus).

Imaginez que vous avez une table de personnes et que vous avez une table avec des appels téléphoniques de personnes. Maintenant, vous pourriez faire en sorte que chaque ligne de personne ait une liste de ses appels téléphoniques. Mais chaque personne a beaucoup d'autres relations avec beaucoup d'autres choses. Cela signifie-t-il que ma table de personnes doit contenir un tableau pour chaque chose à laquelle elle est connectée ? Non, ce n'est pas un attribut de la personne elle-même.

[1] : Il n'y a pas de problème si la table de liaison ne comporte que deux colonnes (les clés primaires de chaque table) ! Cependant, si la relation elle-même possède des attributs supplémentaires, ils doivent être représentés dans cette table sous forme de colonnes.

74voto

Charles Addis Points 744

MySQL 5.7 fournit maintenant un Type de données JSON . Ce nouveau type de données offre un nouveau moyen pratique de stocker des données complexes : listes, dictionnaires, etc.

Cela dit, les tableaux ne mettent pas bien en correspondance les bases de données. C'est pourquoi les mises en correspondance objet-relationnel peuvent être assez complexes. Historiquement, les gens ont stocké des listes/réseaux dans MySQL en créant une table qui les décrit et en ajoutant chaque valeur comme son propre enregistrement. La table peut ne comporter que 2 ou 3 colonnes, ou en contenir beaucoup plus. La façon dont vous stockez ce type de données dépend vraiment des caractéristiques des données.

Par exemple, la liste contient-elle un nombre statique ou dynamique d'entrées ? La liste restera-t-elle petite, ou est-elle appelée à croître jusqu'à des millions d'enregistrements ? Y aura-t-il beaucoup de lectures sur cette table ? Beaucoup d'écritures ? Beaucoup de mises à jour ? Ce sont tous des facteurs à prendre en compte lorsqu'il s'agit de décider comment stocker des collections de données.

Les magasins de données clés/valeurs et les magasins de documents tels que Cassandra, MongoDB, Redis, etc. constituent également une bonne solution. Soyez simplement conscient de l'endroit où les données sont réellement stockées (si elles sont stockées sur le disque ou en mémoire). Toutes vos données ne doivent pas nécessairement se trouver dans la même base de données. Certaines données ne s'adaptent pas bien à une base de données relationnelle et vous pouvez avoir des raisons de les stocker ailleurs, ou vous pouvez vouloir utiliser une base de données clé:valeur en mémoire comme un cache à chaud pour les données stockées sur le disque quelque part ou comme un stockage éphémère pour des choses comme les sessions.

73voto

Eric Grotke Points 1896

Une note complémentaire à prendre en compte : vous pouvez stocker des tableaux dans Postgres.

57voto

drew Points 1149

Dans MySQL, utilisez le type JSON.

Contrairement aux réponses ci-dessus, le standard SQL inclut des types de tableaux depuis presque vingt ans ; ils sont utiles, même si MySQL ne les a pas implémentés.

Dans votre exemple, cependant, vous voudrez probablement créer trois tables : personne et fruit, puis personne_fruit pour les joindre.

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);

Si vous souhaitez associer la personne à un éventail de fruits, vous pouvez le faire avec une vue :

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;

La vue montre les données suivantes :

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

Dans 5.7.22, vous voudrez utiliser JSON_ARRAYAGG plutôt que d'assembler le tableau à partir d'une chaîne de caractères.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X