Aprendiendo PHP, parte 23: Introducción a MySQL, tablas y relaciones

Habíamos dicho que una base de datos MySQL está formada por tablas, tablas que nos permiten separar por grupos y sus registros. Pero a su vez estas tablas pueden tener relaciones entre sí. Esto nos permite evitar la redundancia separando cada registro en la tabla a la cual le pertenece.

Vamos a suponer que a nuestra tabla usuario, debemos agregarle un nuevo atributo para guardar la nacionalidad del usuario.

Bien, si seguiste la publicación anterior, verás que no hay nada nuevo en esto, así que simplemente podemos comenzar a simular la inserción de registros:

usuario_id nombre apellido email contrasena nacionalidad
1 Ricardo Caruso Lombardi caruso@mail.com 1234 Argentina
2 Susana Giménez susana@mail.com 1234 Argentina
3 Wilson Sanguinetti wilson@mail.com 1234 Uruguay
4 Ronaldo Santos ronaldo@mail.com 1234 Brasil
5 Marisa Santa Cruz marisa@mail.com 1234 Paraguay

La nacionalidad es un atributo, que si bien no está mal que esté en la tabla usuario, ya que nosotros necesitamos que al guardar cada usuario también guardemos su nacionalidad, sin embargo el guardar la cadena entera: ‘Uruguay’ por ejemplo, no es una buena idea, es redundante y difícil de mantener en el tiempo.

Porque en nuestra base de datos habrá cientos, miles de personas de nacionalidad uruguaya, argentina, brasileña, paraguaya o de otros países. Por tanto deberíamos crear una tabla sólo para guardar las nacionalidades:

Y aquí simplemente guardaremos los registros con todas las nacionalidades posibles:

nacionalidad_id valor
1 Argentina
2 Brasil
3 Paraguay
4 Uruguay

Claves externas

Como se ve en el ejemplo anterior, tenemos una tabla usuario y una nacionalidad, y a su vez dijimos que cada usuario tiene una nacionalidad, por tanto estas tablas deberían estar unidas. Así que para ello vamos a modificar nuestra tabla usuario:


De esta manera la tabla usuario y la tabla nacionalidad estarán relacionadas entre sí. En el caso de la tabla usuario, ésta tendrá un atributo nacionalidad_id, a esto se le llama clave externa, o clave foránea. La clave externa nacionalidad_id de la tabla usuario, coincidirá con la clave primaria nacionalidad_id de la tabla nacionalidad.

Entonces al insertar registros en la tabla usuario, tendremos que modificar lo que hicimos antes por esto:

usuario_id nombre apellido email contrasena nacionalidad_id
1 Ricardo Caruso Lombardi caruso@mail.com 1234 1
2 Susana Giménez susana@mail.com 1234 1
3 Wilson Sanguinetti wilson@mail.com 1234 4
4 Ronaldo Santos ronaldo@mail.com 1234 2
5 Marisa Santa Cruz marisa@mail.com 1234 3

De este modo nosotros unimos el registro del usuario 1, Ricardo Caruso Lombardi de la tabla usuario, con el registro 1 de la tabla nacionalidad.

Y así nos evitamos la redundancia, no necesitamos escribir la palabra ‘Argentina’ cada vez que un usuario sea de ese país. Y si la nacionalidad cambia de nombre, simplemente tendremos que cambiar el registro en la tabla principal nacionalidad, y no cien mil veces en la tabla usuario.

Tipos de relaciones

Ahora que sabemos que dos tablas pueden estar relacionadas, podemos aprender cuáles son los tipos de relación que pueden tener éstas.

Relación de 1 a 1 (uno a uno)

Éstas se dan cuando un registro está relacionado con otro y con ese solamente, y a su vez este segundo también estará relacionado solamente con el primero.

Un ejemplo de esto puede ser un usuario y su teléfono. Es muy común en aplicaciones actuales, con el avance de la telefonía celular, que un usuario pueda registrar su número de celular, por si pierde su contraseña poder recuperarla recibiendo un mensaje de texto. En este caso cada usuario podrá tener un número de teléfono y éste número sólo le va a pertenecer a este usuario.

Relación de 1 a n (uno a muchos)

En este caso un registro estará relacionado sólo con otro, pero este segundo podrá estar relacionado con más de uno.

El ejemplo para esto es la relación de tablas que vimos antes, un usuario tendrá una única nacionalidad, pero esta nacionalidad podrá estar en más de un usuario.

Relación de n a n (muchos a muchos) 

Aquí un registro tendrá relación con muchos registros, y a su vez cada uno de estos también estará relacionado con varios. Estas relaciones generan siempre una tabla intermedia.

Por ejemplo, nosotros podríamos tener una tabla para guardar usuarios y otra para guardar intereses (música, cine, deportes, etc) entonces, un usuario puede tener varios intereses, y cada uno de estos intereses puede estar presente en varios de estos usuarios. A juan le puede gustar el cine y los deportes, pero a su vez el cine también puede gustarle a Pedro.

Para ello tendremos que crear una tabla con dos claves externas, una para guardar el identificador del usuario y otra para el identificador del interés, y obviamente la clave primaria que identificará la unión entre ambas tablas.

Como se ve en el ejemplo la tabla usuario está relacionada con la tabla telefono, de 1 a 1, cada usuario tendrá un teléfono, y cada uno de estos teléfonos le va pertenecer a un único usuario.

Además la tabla usuario tendrá una relación de 1 a n con nacionalidad. Como dijimos antes, cada usuario tendrá una nacionalidad, pero éstas podrán esta presentes en más de un usuario.

Y por último la tabla usuario tendrá una relación de n a n con interes, lo que generará una nueva tabla llamada usuario_interes, para guardar registros que unirán ambas tablas.

Anterior:  Aprendiendo PHP, parte 22: Introducción a MySQL, tablas

Siguiente: Aprendiendo PHP, parte 24: Introducción a MySQL, creación de tablas


13 Respuestas a “Aprendiendo PHP, parte 23: Introducción a MySQL, tablas y relaciones”

  1. Excelente explicación. Tengo una duda, ¿Como podría hacer algo similar? Tengo un tabla usuarios y varias tablas de alimentos. Cada tabla de alimentos tiene 2 columnas: nombre y calorias (ejemplo: arroz 300). Debo relacionar cada usuario al alimento que eligió, con sus calorias incluidas. Evidentemente es una relacion n to n, pero el alimento siempre está asociado a una única cantidad de calorias. ¿Cómo podría hacer? Gracias

    1. Ne sé bien las reglas de negocio de tu aplicación, pero yo lo haría así:

      Tabla usuarios (id_usuario, etc, etc, etc)
      Tabla alimentos (id_alimento, nombre, calorias)
      Tabla usuarios_alimentos (id_usuario, id_alimento)

      Con respecto a lo que decís de que cada alimento está relacionado a una cantidad de calorías, eso no lo entiendo bien. Podrías darme más detalles?

      Saludos!

      1. Despues de tanto tiempo, aclararé esto:
        1) Tabla «comidas»: id_comidas (primaria, autoincrement), nombre, calorias
        2) Tabla «usuario»: id_usuario (primaria, autoincrement), ip.
        3) Tabla «comidas_usuario»: id_comidas_usuario (primaria, autoincrement), id_comidas (foranea), id_usuario (foranea).
        Esto es un ejemplo:
        De la tabla comidas: id_comidas = 234; nombre = azucar; calorias= 300, es elegida por el usuario de la tabla usuarios: id_usuario = 44, ip = 127.333.333.333
        Creo que en la tabla comidas_usuario quedaría: 1, 234, 44.
        Mi pregunta es si quiero recuperar el campo «calorias» nada mas de la tabla comidas_usuario ¿Como haría?. Porque necesito hacer cálculos complejos ¿Se puede hacer a partir de la tabla comidas_usuario?
        Se que me criticaran porque usar la ip no es efectiva, pero antes de hacer un registro de usuario con sesiones necesito poder manejar bien las relaciones entre tablas. Saludos!

        1. Ok, lo que vos necesitas es recuperar las calorías de un usuario x sería algo así (es lo que entiendo):

          select c.calorias
          from comidas_usuario cu
          inner join comidas c
          on cu.id_comidas = c.id_comidas
          inner join usuario u
          on cu.id_usuario = u.id_usuario
          where u.id_usuario = 5

          (5 es el id del usuario)

          También podés hacer una sumatoria de las comidas de ese usuario:

          select SUM(c.calorias)
          from comidas_usuario cu
          inner join comidas c
          on cu.id_comidas = c.id_comidas
          inner join usuario u
          on cu.id_usuario = u.id_usuario
          where u.id_usuario = 5

          Saludos!

  2. Hola, estoy trabajando en una base de datos de un supermercado y pues tengo mis dudas, quisiera saber si me podrías aclarar algunas cosas?

  3. Hola! muy bien explicado el tema!

    Tengo una consulta, que quizá es burda pero me surge. Los registros en la tabla intermedia se crean automáticamente cuando se crean registros en la tabla padre? o hay que insertarlos a medida que trabajamos?

    Y por otro lado, es necesario el id autoincrementable en la tabla intermedia o con las foráneas ya alcanza? he visto el tema en otros sitios y solo ponen las foráneas y no incluyen un id.

    Bueno espero puedas contestarme así aclaro el concepto y desde ya agradezco el tiempo en enseñar estos temas.

    Saludos!

    1. No, los registros de la tabla intermedia hay que insertarlos como en cualquier tabla.

      El primary key a veces es necesario y a veces no, pero siempre es una buena práctica que TODAS las tablas tengan uno.

      Por ejemplo, suponete que tenés que crear la base de datos para una videoteca. Entonces vas a tener tabla cliente y tabla película, ahí vas a tener que crear una tabla cliente_pelicula y va a necesitar un primary key, porque un cliente puede ver muchas películas, pero a su vez puede ver una película muchas veces.
      Entonces ahí vas a tener que guardar el primary key de la tabla intermedia, el id del cliente y el id de la película. Si no ingresas el id de la tabla intermedia, y sólo ingresas los id de las tablas padres, entonces vas a poder guardar un sólo registro por cada cliente y película, y no vas a poder saber cuántas veces vio una película un determinado cliente.

      En el caso de que tengas otra tabla intermedia en donde la combinación de dos o más registros se dé una sola vez, ahí no es necesario tener un primary key.

      Saludos!

  4. Hola excelente tema.
    Tengo una duda demasiado grande con la relación muchos a muchos
    tengo una tabla de vehículos y conductores con sus datos respectivos y una tabla pivote (intermedia) de vehí_cond.
    Con php y html cada una tiene una interfaz ejemplo: una vista para registros de vehículos y conductores, pero la verdad no tengo experiencia ni tampoco tengo una idea clara para que interactue la tabla pivote.
    he estado pensando en colocar en la interfaz de registro de conductores un select multple que recoga los vehículos pero la verdad no estoy muy seguro ,quedaria infinitamente agradecido si me ayuda con una sugerencia muchas gracias por todo.

    la verdad estoy muy agradecido por los tutoriales de esta página
    he aprendido demasiado.

    1. Vas a tener que joinear las tablas, por ejemplo cuando estás en la página de conductores, deberías hacer un join entre las tres tablas, para que te devuelva los vehículos de cada conductor.

      Saludos!

  5. buena noches
    sera que me puedes colaborar dando un ejemplo de como llenar registros a la tabla intermedia ,o tengo que llenar la la tabla intereses y despues la de usuarios y despues la tabla intermedia o como ?? porque si fuera de n:m solo colocaria el id_de intereses en usuario pero si es de una inetermedia

  6. hola muchachos, tengo una pregunta. estoy creando una base de datos de materiales de construccion donde debo relacionar un material con distintos departamentos, es decir, un tornillo puede estar en el departamento de madera y en el de plastico ya que lo puedo usar en esos 2, entonces como hago la insercion de de esos 2 ID en un solo registro que seria el del material, la sentecia SQL acepta 2 parametros o atributos en un solo campo? como la hago?

    1. Vos tendrías una tabla material, y otra departamento, y teniendo en cuenta que la relación entre ambas es de muchos a muchos, se rompería la relación y en su lugar habría que crear una tabla material_departamento, la cual debería tener el id del materila y el id del departamento.

      Saludos!

  7. Buenas Tardes.
    Una pregunta; tengo 2 tablas una de usuario y la otra un registro de sus actividades en el sistema. Quiero mostrar el nombre de las personas i no su id. En la sección de MYsql realizo el código del del select y todo ok. Cuando coloco esta consulta en mi código php no me trae nada. que puede estar ocurriendo?
    El código es el siguiente
    $result = mysql_query(«SELECT idreg, ‘U.usuario’ AS nombre, perfil, ipeqp, nameq, fecha, consulta FROM registro R
    INNER JOIN usuarios U ON ‘R.user’= ‘U.idusuarios’
    WHERE (‘U.usuario’ LIKE ‘%$buscar%’)or (perfil LIKE ‘%$buscar%’) or (nameq LIKE ‘%$buscar%’) or (ipeqp LIKE ‘%$buscar%’)or (fecha LIKE ‘%$buscar%’)ORDER BY fecha», $con);