{"id":21836970,"url":"https://github.com/waldohidalgo/prueba_modulo_5_desafio_latam","last_synced_at":"2025-07-15T21:42:04.851Z","repository":{"id":227132315,"uuid":"770539164","full_name":"waldohidalgo/prueba_modulo_5_desafio_latam","owner":"waldohidalgo","description":"Repositorio con el código solución y explicación del desarrollo de la prueba del módulo 5 Fundamentos de Bases de Datos Relacionales","archived":false,"fork":false,"pushed_at":"2024-03-11T21:49:09.000Z","size":36604,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T10:11:54.242Z","etag":null,"topics":["dbeaver","desafiolatam","postgresql"],"latest_commit_sha":null,"homepage":"https://vimeo.com/922130771","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/waldohidalgo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-11T18:13:50.000Z","updated_at":"2024-03-11T21:41:50.000Z","dependencies_parsed_at":"2024-03-11T20:09:09.105Z","dependency_job_id":null,"html_url":"https://github.com/waldohidalgo/prueba_modulo_5_desafio_latam","commit_stats":null,"previous_names":["waldohidalgo/prueba_modulo_5_desafio_latam"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fprueba_modulo_5_desafio_latam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fprueba_modulo_5_desafio_latam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fprueba_modulo_5_desafio_latam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fprueba_modulo_5_desafio_latam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/waldohidalgo","download_url":"https://codeload.github.com/waldohidalgo/prueba_modulo_5_desafio_latam/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244815970,"owners_count":20515023,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dbeaver","desafiolatam","postgresql"],"created_at":"2024-11-27T20:43:50.012Z","updated_at":"2025-03-21T14:42:11.711Z","avatar_url":"https://github.com/waldohidalgo.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Desarrollo Prueba Módulo 5: Fundamentos de bases de datos relacionales\n\nEl presente repositorio contiene el código utilizado para resolver la prueba con la que se finaliza el módulo 5 **Fundamentos de bases de datos relaciones** de la beca **Desarrollo de aplicaciones Full Stack Javascript Trainee** dictada por Desafío Latam.\n\nLos requisitos de la prueba son los siguientes:\n\n![Requisitos Hoja 1 y 2](./screenshots/requisitos_1_2.webp)\n![Requisitos Hoja 3 y 4](./screenshots/requisitos_3_4.webp)\n\nHe grabado el video el cual esta disponible en el siguiente [link](https://vimeo.com/922130771).\n\nA continuación muestro un preview del video el cual es un gif con los primeros 30 segundos. Al hacer click en la imagen, se redirecciona al video que he alojado en la plataforma Vimeo:\n\n[![Video Desarrollo Prueba](/screenshots/thumb_gif.gif)](https://vimeo.com/922130771)\n\nEl desarrollo de cada pregunta se encuentra en los siguientes minutos y segundos:\n\n-Pregunta 1: 00:31\n\n-Pregunta 2: 01:25\n\n-Pregunta 3: 02:19\n\n-Pregunta 4: 02:41\n\n-Pregunta 5: 04:01\n\n-Pregunta 6: 04:54\n\n-Pregunta 7: 05:20\n\n-Pregunta 8: 05:44\n\n-Pregunta 9: 06:34\n\n-Pregunta 10: 07:07\n\nAhora procedo a explicar cada una de mis soluciones a cada pregunta:\n\n## 1. Crea el modelo (revisa bien cuál es el tipo de relación antes de crearlo), respeta las claves primarias, foráneas y tipos de datos\n\nHe utilizado **DBeaver** versión **24.0.0** para crear una base de datos llamada **Modelo1** en la cual trabajaré las tres primeras preguntas que corresponden al modelo físico siguiente:\n\n![Modelo 1](./diagrama_ejercicio_1.webp)\n\nEn dicho modelo he creado una tabla intermedia llamada **clasificacion** de modo tal de modelar la relación de muchos es a muchos vía claves foráneas a las tablas **peliculas** y **tags**.\n\nEn la primera pregunta me piden crear el modelo físico para lo cual he utilizado el siguiente código:\n\n```sql\nCREATE TABLE\n    peliculas (\n        id serial PRIMARY KEY,\n        nombre VARCHAR(255) NOT NULL,\n        anno INT NOT NULL\n    );\n\nCREATE TABLE\n    tags (\n        id serial PRIMARY KEY,\n        tag VARCHAR(32) NOT NULL\n    );\n\nCREATE TABLE\n    clasificacion (\n        id serial PRIMARY KEY,\n        peliculas_id INT NOT NULL,\n        tags_id INT,\n        CONSTRAINT fk_peliculas_id FOREIGN KEY (peliculas_id) REFERENCES peliculas (id),\n        CONSTRAINT fk_tags_id FOREIGN KEY (tags_id) REFERENCES tags (id)\n    );\n```\n\n## 2. Inserta 5 películas y 5 tags, la primera película tiene que tener 3 tags asociados, la segunda película debe tener dos tags asociados\n\nHe creado el siguiente código que realiza lo pedido:\n\n```sql\nINSERT INTO\n    peliculas (nombre, anno)\nVALUES\n    (\n        'pelicula 1',\n        2005\n    ),\n    (\n        'pelicula 2',\n        1987\n    ),\n    (\n        'pelicula 3',\n        1965\n    ),\n    (\n        'pelicula 4',\n        2021\n    ),\n    (\n        'pelicula 5',\n        1997\n    );\n\nINSERT INTO\n    tags (tag)\nVALUES\n    ('acción'),\n    ('drama'),\n    ('aventura'),\n    ('romance'),\n    ('thriller');\n\nINSERT INTO\n    clasificacion (\n        peliculas_id,\n        tags_id\n    )\nVALUES\n    (1, 1),\n    (1, 3),\n    (1, 5),\n    (2, 2),\n    (2, 4),\n    (3, 1),\n    (4, NULL),\n    (5, NULL);\n\n```\n\nDicho código crea 5 peliculas, 5 tags y la pelicula 1 posee 3 tags, la pelicula 2 posee 2 tags, la pelicula 3 posee 1 tag y la pelicula 4 y 5 poseen 0 tag(valor nulo).\n\nLas tablas pobladas las muestro a continuación:\n\n![Tabla Peliculas Poblada](./screenshots/modelo1/tabla_peliculas.webp)\n![Tabla Tags Poblada](./screenshots/modelo1/tabla_tags.webp)\n![Tabla Clasificacion Poblada](./screenshots/modelo1/tabla_clasificacion.webp)\n\n## 3. Cuenta la cantidad de tags que tiene cada película. Si una película no tiene tags debe mostrar 0\n\nHe creado el siguiente código que resuelve lo anterior:\n\n```sql\nSELECT\n    peliculas_id,\n    COUNT(tags_id)\nFROM\n    clasificacion\nGROUP BY\n    peliculas_id\nORDER BY\n    COUNT(tags_id) DESC;\n```\n\nUtilizo la función count la cual no considera los valores nulos, es decir, no los agrega a la cuenta. De este modo las películas que no tienen tags asociados son contadas con 0 tag.\n\nEl resultado de dicha consulta es el siguiente:\n\n![Resultado pregunta 3](./screenshots/modelo1/resultado_ejercicio_3.webp)\n\n## 4. Crea las tablas respetando los nombres, tipos, claves primarias y foráneas y tipos de datos\n\nPara resolver esta pregunta y el resto de preguntas, creo la base de datos llamada **Modelo2**. Una vez creada procedo a crear el modelo físico utilizando el siguiente código:\n\n```sql\nCREATE TABLE\n    preguntas (\n        id serial PRIMARY KEY,\n        pregunta VARCHAR(255),\n        respuesta_correcta VARCHAR\n    );\n\nCREATE TABLE\n    usuarios (\n        id serial PRIMARY KEY,\n        nombre VARCHAR(255),\n        edad INTEGER\n    );\n\nCREATE TABLE\n    respuestas (\n        id serial PRIMARY KEY,\n        respuesta VARCHAR(255),\n        usuario_id INTEGER,\n        pregunta_id INTEGER,\n        CONSTRAINT fk_usuario_id FOREIGN KEY (usuario_id) REFERENCES usuarios (id),\n        CONSTRAINT fk_pregunta_id FOREIGN KEY (pregunta_id) REFERENCES preguntas (id)\n    );\n```\n\n## 5. Agrega datos, 5 usuarios y 5 preguntas, la primera pregunta debe estar contestada dos veces correctamente por distintos usuarios, la pregunta 2 debe estar contestada correctamente sólo por un usuario, y las otras 2 respuestas deben estar incorrectas\n\na. Contestada correctamente significa que la respuesta indicada en la tabla\nrespuestas es exactamente igual al texto indicado en la tabla de preguntas.\n\nPara realizar lo pedido he escrito el siguiente código:\n\n```sql\nINSERT INTO\n    usuarios (nombre, edad)\nVALUES\n    (\n        'usuario_1',\n        15\n    ),\n    (\n        'usuario_2',\n        35\n    ),\n    (\n        'usuario_3',\n        55\n    ),\n    (\n        'usuario_4',\n        47\n    ),\n    (\n        'usuario_5',\n        22\n    );\n\nINSERT INTO\n    preguntas (\n        pregunta,\n        respuesta_correcta\n    )\nVALUES\n    (\n        'pregunta_1',\n        'respuesta_correcta_pregunta_1'\n    ),\n    (\n        'pregunta_2',\n        'respuesta_correcta_pregunta_2'\n    ),\n    (\n        'pregunta_3',\n        'respuesta_correcta_pregunta_3'\n    ),\n    (\n        'pregunta_4',\n        'respuesta_correcta_pregunta_4'\n    ),\n    (\n        'pregunta_5',\n        'respuesta_correcta_pregunta_5'\n    );\n\n\nINSERT INTO\n    respuestas (\n        respuesta,\n        usuario_id,\n        pregunta_id\n    )\nVALUES\n    (\n        'respuesta_correcta_pregunta_1',\n        1,\n        1\n    ),\n    (\n        'respuesta_correcta_pregunta_1',\n        2,\n        1\n    ),\n    (\n        'respuesta_incorrecta_pregunta_1',\n        3,\n        1\n    ),\n    (\n        'respuesta_incorrecta_pregunta_1',\n        4,\n        1\n    ),\n    (\n        'respuesta_incorrecta_pregunta_1',\n        5,\n        1\n    ),\n    (\n        'respuesta_incorrecta_pregunta_2',\n        1,\n        2\n    ),\n    (\n        'respuesta_incorrecta_pregunta_2',\n        2,\n        2\n    ),\n    (\n        'respuesta_correcta_pregunta_2',\n        3,\n        2\n    ),\n    (\n        'respuesta_incorrecta_pregunta_2',\n        4,\n        2\n    ),\n    (\n        'respuesta_incorrecta_pregunta_2',\n        5,\n        2\n    ),\n    (\n        'respuesta_correcta_pregunta_3',\n        1,\n        3\n    ),\n    (\n        'respuesta_incorrecta_pregunta_3',\n        2,\n        3\n    ),\n    (\n        'respuesta_correcta_pregunta_3',\n        3,\n        3\n    ),\n    (\n        'respuesta_incorrecta_pregunta_3',\n        4,\n        3\n    ),\n    (\n        'respuesta_incorrecta_pregunta_3',\n        5,\n        3\n    ),\n    (\n        'respuesta_correcta_pregunta_4',\n        1,\n        4\n    ),\n    (\n        'respuesta_correcta_pregunta_4',\n        2,\n        4\n    ),\n    (\n        'respuesta_incorrecta_pregunta_4',\n        3,\n        4\n    ),\n    (\n        'respuesta_incorrecta_pregunta_4',\n        4,\n        4\n    ),\n    (\n        'respuesta_correcta_pregunta_4',\n        5,\n        4\n    ),\n    (\n        'respuesta_correcta_pregunta_5',\n        1,\n        5\n    ),\n    (\n        'respuesta_correcta_pregunta_5',\n        2,\n        5\n    ),\n    (\n        'respuesta_correcta_pregunta_5',\n        3,\n        5\n    ),\n    (\n        'respuesta_correcta_pregunta_5',\n        4,\n        5\n    ),\n    (\n        'respuesta_correcta_pregunta_5',\n        5,\n        5\n    );\n```\n\nLa data de la tabla **respuestas** la he creado en base al siguiente diagrama:\n\n```sql\n/*\ninserto data siguiendo la siguiente tabla\n_________usuario1 usuario2 usuario3 usuario4 usuario5\npregunta1----y--------y--------n--------n--------n----\npregunta2----n--------n--------y--------n--------n----\npregunta3----y--------n--------y--------n--------n----\npregunta4----y--------y--------n--------n--------y----\npregunta5----y--------y--------y--------y--------y----\n */\n```\n\nDonde **y** significa que la pregunta fue contestada correctamente y **n** significa que la pregunta fue contestada de manera incorrecta.\n\n## 6. Cuenta la cantidad de respuestas correctas totales por usuario (independiente de la pregunta)\n\nHe creado la siguiente consulta:\n\n```sql\nSELECT\n    cruce.id,\n    cruce.nombre,\n    SUM(\n        cruce.resultado\n    ) cuenta_correctas\nFROM\n    (\n        SELECT\n            u.id,\n            u.nombre,\n            CASE\n                WHEN p.respuesta_correcta = r.respuesta THEN 1\n                ELSE 0\n            END AS resultado\n        FROM\n            preguntas AS p\n            INNER JOIN respuestas AS r ON r.pregunta_id = p.id\n            INNER JOIN usuarios AS u ON r.usuario_id = u.id\n    ) cruce\nGROUP BY\n    cruce.id,\n    cruce.nombre\nORDER BY\n    cruce.id;\n```\n\nEn dicho código creo una tabla en una subconsulta con una columna auxiliar de nombre **resultado** que almacena un 1 cuando la respuesta contestada es igual a la respuesta almacenada de manera correcta y registra un 0 en caso contrario. Luego procedo a consultar la tabla que tiene dicha columna auxiliar y realizo una agrupación por id y nombre de la pelicula de modo tal de sumar los valores 1 que corresponden a respuesta certera, cuando no existe una respuesta correcta el valor es cero y su valor no es agregado a la suma total.\n\nEl resultado de dicha consulta es el siguiente:\n\n![Resultado Pregunta 6](./screenshots/modelo2/respuesta_ejercicio_6.webp)\n\n## 7. Por cada pregunta, en la tabla preguntas, cuenta cuántos usuarios tuvieron la respuesta correcta\n\nEl código que responde dicha pregunta es el siguiente:\n\n```sql\nSELECT\n    cruce.pregunta,\n    SUM(\n        cruce.resultado\n    ) cantidad_respuesta_correcta\nFROM\n    (\n        SELECT\n            p.pregunta,\n            r.usuario_id,\n            CASE\n                WHEN p.respuesta_correcta = r.respuesta THEN 1\n                ELSE 0\n            END AS resultado\n        FROM\n            preguntas AS p\n            INNER JOIN respuestas AS r ON r.pregunta_id = p.id\n    ) cruce\nGROUP BY\n    cruce.pregunta\nORDER BY\n    cruce.pregunta;\n\n```\n\nEn dicho código creo una tabla auxiliar en la subconsulta la cual posee una columna auxiliar que establece en 1 cuando la respuesta a la pregunta es igual a la respuesta almacenada de manera correcta para dicha pregunta y establece un 0 en caso contrario. Luego procedo a agrupar por pregunta la suma de la columna resultado que corresponderá a la cantidad de respuestas correctas.\n\nEl resultado de dicha consulta es el siguiente:\n\n![Resultado Pregunta 7](./screenshots/modelo2/respuesta_pregunta_7.webp)\n\n## 8. Implementa borrado en cascada de las respuestas al borrar un usuario y borrar el primer usuario para probar la implementación\n\nEn primer lugar borro la foreign key establecida sobre la columna **usuario_id** de la tabla **respuestas** y procedo a crear una nueva foreign key sobre la misma columna **usuario_id** pero ahora con el agregado **ON DELETE CASCADE** el cual realiza la eliminación en cascada sobre la tabla **respuestas** al borrar registros en la tabla **usuarios**:\n\n```sql\nALTER TABLE respuestas\nDROP CONSTRAINT fk_usuario_id;\n\nALTER TABLE respuestas\nADD CONSTRAINT fk_usuario_id\nFOREIGN KEY (usuario_id)\nREFERENCES usuarios (id) ON DELETE CASCADE;\n```\n\nPosteriormente, procedo a eliminar de la tabla **usuarios** el primer registro y verificar que todos los registros enlazados en la tabla **respuestas** son borrados:\n\n```sql\nDELETE FROM usuarios\nWHERE\n    id = 1;\n```\n\nPrevia eliminación la data en la tabla **respuestas** es la siguiente:\n\n![Previa Eliminacion](./screenshots/modelo2/respuesta_pregunta_8_previa_eliminacion.webp)\n\nPost eliminación la data en la tabla **respuestas** es la siguiente:\n\n![Previa Eliminacion](./screenshots/modelo2/respuesta_pregunta_8_post_eliminacion.webp)\n\n## 9. Crea una restricción que impida insertar usuarios menores de 18 años en la base de datos\n\nHe creado la siguiente restricción:\n\n```sql\nALTER TABLE usuarios\nADD CONSTRAINT edad_constraint CHECK (edad \u003e= 18);\n```\n\nDicha restricción impide insertar registros con edad menor a 18 años en la tabla **usuarios**.\n\nPrevia añadidura de dicha restricción, las restricciones de la tabla **usuarios** son las siguientes:\n\n![Previa Restricción de Edad](./screenshots/modelo2/pregunta_9_sin_restriccion_edad.png)\n\nPost añadidura de dicha restricción, las restricciones de la tabla **usuarios** son las siguientes:\n\n![Previa Restricción de Edad](./screenshots/modelo2/pregunta_9_con_restriccion_edad.jpg)\n\nSi deseo insertar un registro con edad igual a 5 años se me impide debido a la restricción de edad:\n\n```sql\nINSERT INTO\nusuarios (nombre, edad)\nVALUES\n('1', 5);\n```\n\n![Error inserción menores a 18 años](./screenshots/modelo2/error_insercion_edad_menor_18.jpg)\n\n## 10. Altera la tabla existente de usuarios agregando el campo email con la restricción de único\n\nProcedo a alterar la tabla **usuarios** agregando una columna llamada **email** con la restricción de solo permitir el ingreso de valor únicos:\n\n```sql\nALTER TABLE usuarios\nADD COLUMN email VARCHAR UNIQUE;\n```\n\nPrevia añadidura de la columna **email**, la tabla **usuarios** posee las siguientes columnas:\n\n![Constraints Tabla Usuarios Previo Email](./screenshots/modelo2/pregunta_10_sin_email.jpg)\n\nPost añadidura de la columna **email**, la tabla **usuarios** posee las siguientes columnas:\n\n![Constraints Tabla Usuarios Previo Email](./screenshots/modelo2/pregunta_10_con_email.jpg)\n\nProcedo a insertar un registro con email en la tabla usuarios:\n\n```sql\nINSERT INTO\nusuarios (\nnombre,\nedad,\nemail\n)\nVALUES\n(\n'waldo',\n33,\n'abc@mail.com'\n);\n```\n\nLuego intento insertar otro registro con el mismo email:\n\n```sql\nINSERT INTO\nusuarios (\nnombre,\nedad,\nemail\n)\nVALUES\n(\n'maria',\n22,\n'abc@mail.com'\n);\n```\n\nLa inserción del registro anterior falla debido a que posee el mismo email igual a **abc@mail.com**:\n\n![Error inserción mismo email](/screenshots/modelo2/pregunta_10_error_email_duplicado.jpg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fprueba_modulo_5_desafio_latam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwaldohidalgo%2Fprueba_modulo_5_desafio_latam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fprueba_modulo_5_desafio_latam/lists"}