sql >> Base de Datos >  >> RDS >> Mysql

Esquema de base de datos para libros, autores, editores y usuarios con estanterías

Necesitarás un enlace N:M entre books y authors , ya que un libro puede tener varios autores y cada autor puede haber escrito más de un libro. En un RDBMS eso significa que necesitará un written_by mesa.

El enlace entre books y publishers sin embargo es diferente. Cualquier libro determinado solo puede tener un editor (a menos que en su sistema las diferentes ediciones de un libro se consideren el mismo libro). Así que todo lo que necesitas aquí es un publisher_id clave foránea en books

Por último, y lo más importante, está mirando a los lectores/usuarios. Y su relación con los libros. Naturalmente, esta también es una relación N:M. Espero que la gente lea más de un libro (todos sabemos lo que pasa si solo lees uno...) y seguro que un libro lo lee más de una persona. Eso requiere un book_users tabla de conexion La verdadera pregunta aquí es cómo diseñarlo. Hay tres diseños básicos.

  1. Separar tablas por tipo de relación . (como lo describe @just_somebody) Ventajas:solo tiene INSERCIONES y ELIMINACIONES, nunca ACTUALIZACIONES. Si bien esto parece un poco ordenado y de alguna manera ayuda con la optimización de consultas, la mayoría de las veces no tiene otro propósito real que mostrar un gran gráfico de base de datos.

  2. Una tabla con un status indicador . (como se describe en @Hardcoded) Ventajas:solo tiene una tabla. Desventajas:tendrá INSERCIONES, ACTUALIZACIONES y ELIMINACIONES, algo que RDBMS puede manejar fácilmente, pero que tiene sus fallas por varias razones (más sobre eso más adelante) Además, un solo status implica que un lector solo puede tener una conexión con el libro en cualquier momento, lo que significa que solo podría estar en el plan_to_read , is_reading o has_read estado en cualquier punto en el tiempo, y asume un orden en el tiempo esto sucede. Si esa persona alguna vez planeara leerlo otra vez , o hacer una pausa, luego volver a leer desde el principio, etc., una serie tan simple de indicadores de estado puede fallar fácilmente, porque de repente esa persona is_reading ahora, pero también has_read la cosa. Para la mayoría de las aplicaciones, este sigue siendo un enfoque razonable y, por lo general, hay formas de diseñar campos de estado para que sean mutuamente excluyentes.

  3. Un registro . INSERTAR cada estado como una nueva fila en una tabla:la misma combinación de libro y lector aparecerá más de una vez. INSERTAR la primera fila con plan_to_read y una marca de tiempo. Otro con is_reading . Luego otro con has_read . Ventajas:solo tendrá que INSERTAR filas y obtendrá una cronología ordenada de las cosas que sucedieron. Desventajas:las uniones de tablas cruzadas ahora tienen que manejar muchos más datos (y ser más complejas) que en los enfoques anteriores más simples.

Puede preguntarse, ¿por qué se enfatiza si INSERTAR, ACTUALIZAR o ELIMINAR en qué escenario? En resumen, cada vez que ejecuta una instrucción UPDATE o DELETE, es muy probable que, de hecho, pierda datos. En ese punto, debe detenerse en su proceso de diseño y pensar "¿Qué es lo que estoy perdiendo aquí?" En este caso, se pierde el orden cronológico de los hechos. Si lo que los usuarios están haciendo con sus libros es el centro de su aplicación, es posible que desee recopilar la mayor cantidad de datos posible. Incluso si no importa en este momento, ese es el tipo de datos que podrían permitirle hacer "magia" más adelante. Puede averiguar qué tan rápido está leyendo alguien, cuántos intentos necesita para terminar un libro, etc. Todo eso sin pedirle al usuario ninguna entrada adicional.

Entonces, mi respuesta final es en realidad una pregunta:

Editar

Dado que es posible que no quede claro cómo se vería un registro y cómo funcionaría, he aquí un ejemplo de una tabla de este tipo:

CREATE TABLE users_reading_log (
  user_id INT,
  book_id INT,
  status ENUM('plans_to_read', 'is_reading', 'has_read'),
  ts TIMESTAMP DEFAULT NOW()
)

Ahora, en lugar de actualizar la tabla "user_read" en su esquema diseñado cada vez que cambia el estado de un libro, ahora INSERTE esos mismos datos en el registro que ahora se llena con una cronología de información:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='plans_to_read';

Cuando esa persona empieza a leer, haces otra inserción:

INSERT INTO users_reading_log SET 
  user_id=1,
  book_id=1,
  status='is_reading';

y así. Ahora tiene una base de datos de "eventos" y dado que la columna de marca de tiempo se llena automáticamente, ahora puede saber qué sucedió y cuándo. Tenga en cuenta que este sistema no garantiza que solo exista un 'está_leyendo' para un par específico de libro de usuario. Alguien podría dejar de leer y luego continuar. Sus uniones tendrán que dar cuenta de eso.