Cómo almacenar matrices en MySQL?


Tengo dos tablas en MySQL. La tabla Person tiene las siguientes columnas:

id | name | fruits

La columna fruits puede contener null o una matriz de cadenas como ('apple', 'orange', 'banana'), o ('strawberry'), etc. La segunda tabla es Table Fruit y tiene las siguientes tres columnas:

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

Entonces, ¿cómo debo diseñar la columna fruits en la primera tabla para que pueda contener una matriz de cadenas que toman valores de la columna fruit_name en la segunda tabla? Dado que no hay un tipo de datos de matriz en MySQL, ¿cómo debería hacerlo?

Author: z0nam, 2013-06-28

7 answers

La forma correcta de hacer esto es usar varias tablas y JOIN en sus consultas.

Por ejemplo:

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

La tabla person_fruit contiene una fila para cada fruta con la que una persona está asociada y efectivamente vincula las tablas person y fruits, es decir,

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

Cuando quieres recuperar a una persona y toda su fruta puedes hacer algo como esto:

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
 101
Author: Bad Wolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-12 12:29:09

La razón por la que no hay matrices en SQL, es porque la mayoría de la gente realmente no lo necesita. Las bases de datos relacionales (SQL es exactamente eso) funcionan utilizando relaciones, y la mayoría de las veces, lo mejor es asignar una fila de una tabla a cada "bit de información". Por ejemplo, donde usted puede pensar "Me gustaría una lista de cosas aquí", en su lugar hacer una nueva tabla, vinculando la fila en una tabla con la fila en otra tabla.[1] De esa manera, puedes representar relaciones M:N. Otra ventaja es que esos enlaces no desordenará la fila que contiene el elemento vinculado. Y la base de datos puede indexar esas filas. Los arrays normalmente no están indexados.

Si no necesita bases de datos relacionales, puede usar, por ejemplo, un almacén de clave-valor.

Lea acerca de normalización de la base de datos, por favor. La regla de oro es " [Cada] [atributo] no clave debe proporcionar un hecho sobre la clave, la clave completa, y nada más que la clave.". Una matriz hace demasiado. Tiene múltiples hechos y almacena el pedido (que no está relacionado con la relación en sí). Y el rendimiento es pobre (ver arriba).

Imagina que tienes una mesa de personas y tienes una mesa con llamadas telefónicas de personas. Ahora puedes hacer que cada persona tenga una lista de sus llamadas telefónicas. Pero cada persona tiene muchas otras relaciones con muchas otras cosas. ¿Eso significa que mi tabla person debe contener una matriz para cada cosa a la que está conectado? No, eso no es un atributo de la persona en sí.

[1]: Está bien si la tabla de enlace solo tiene dos columnas (las claves principales de cada tabla)! Sin embargo, si la relación en sí tiene atributos adicionales, deben representarse en esta tabla como columnas.

 40
Author: Janus Troelsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-08 17:21:31

MySQL 5.7 ahora proporciona un tipo de datos JSON . Este nuevo tipo de datos proporciona una nueva forma conveniente de almacenar datos complejos: listas, diccionarios, etc.

Dicho esto, los rrays no mapean bien las bases de datos, por lo que los mapas objeto-relacionales pueden ser bastante complejos. Históricamente, las personas han almacenado listas/matrices en MySQL creando una tabla que las describe y agregando cada valor como su propio registro. La tabla puede tener solo 2 o 3 columnas, o puede contener muchas más. Cómo almacenar este tipo de los datos realmente dependen de las características de los datos.

Por ejemplo, ¿la lista contiene un número estático o dinámico de entradas? ¿Se mantendrá la lista pequeña, o se espera que crezca a millones de registros? ¿Habrá muchas lecturas en esta mesa? Muchas escrituras? ¿Muchas actualizaciones? Todos estos son factores que deben tenerse en cuenta al decidir cómo almacenar las colecciones de datos.

También, Key: Value data stores / Document stores tales como Cassandra, MongoDB, Redis etc proporcionan una buena solución también. Solo tenga en cuenta dónde se almacenan los datos (si se almacenan en el disco o en la memoria). No es necesario que todos sus datos estén en la misma base de datos. Algunos datos no se asignan bien a una base de datos relacional y es posible que tenga razones para almacenarlos en otro lugar, o es posible que desee usar una base de datos clave:valor en memoria como una caché en caliente para los datos almacenados en el disco en algún lugar o como un almacenamiento efímero para cosas como sesiones.

 33
Author: Charles Addis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-14 15:03:09

Una nota lateral a considerar, puede almacenar matrices en Postgres.

 24
Author: Eric Grotke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-04 22:12:54

En MySQL, utilice el tipo JSON.

Contra las respuestas anteriores, el estándar SQL ha incluido tipos de matriz durante casi veinte años; son útiles, incluso si MySQL no los ha implementado.

En tu ejemplo, sin embargo, es probable que quieras crear tres tablas: persona y fruta, luego person_fruit para unirlas.

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 desea asociar a la persona con una variedad de frutas, puede hacerlo con una vista:

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 vista muestra lo siguiente datos:

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

En 5.7.22, querrás usar JSON_ARRAYAGG, en lugar de hackear el array desde una cadena.

 4
Author: drew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-03 21:06:37

Utilice BLOB de tipo de campo de base de datos para almacenar matrices.

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

Devuelve valores

Devuelve una cadena que contiene una representación de flujo de bytes de valor que se puede almacenar en cualquier lugar.

Tenga en cuenta que esta es una cadena binaria que puede incluir bytes nulos, y necesita ser almacenado y manejado como tal. Por ejemplo, serializar() la salida generalmente debe almacenarse en un campo BLOB en una base de datos, en lugar de un CHAR o campo de TEXTO.

 1
Author: webdevfreak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 12:16:53

Puedes almacenar tu array usando group_Concat así

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

AQUÍ un ejemplo en fiddle

 -3
Author: echo_Me,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-28 18:59:37