SQL - ¿Repetir Claves Foráneas?

 
Vista:
Imágen de perfil de Lara

¿Repetir Claves Foráneas?

Publicado por Lara (5 intervenciones) el 24/03/2017 04:04:41
¡Buenas! Tengo un problemilla con una pequeña base de datos que nos pidieron en clase.

Se trata de la base de datos de una biblioteca y entre los datos de cada libro, hay que incluir las categorías. Las categorías tienen su propia tabla, hasta ahí todo correcto, el problema ocurre cuando un libro tiene varias categorías a la vez, por ejemplo, una novela que es de categoría autobiográfica e histórica.

He creado las tablas y las claves foráneas correspondientes pero me surge un dilema ¿cóm hacer que si un libro pertenece a dos o tres categrorías figuren sin necesidad de duplicar o triplicar la tabla de cateogrías?

¡Ante todo gracias por vuestra ayuda!

A continuación os adjunto el código de las tablas por si sirve de algo (si veis más errores por favor no dudéis en decírmelo, lo que quiero es aprender). Y de nuevo ¡gracias!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* Creando tabla de categorías */
CREATE TABLE categoria (
  codCategoria INT(5) AUTO_INCREMENT,
  nombre VARCHAR(20) NOT NULL,
  PRIMARY KEY (codCategoria)
);
 
/* Creando tabla de autores */
CREATE TABLE autor (
  codAutor INT(5) AUTO_INCREMENT,
  nombre VARCHAR(40) NOT NULL,
  apellidos VARCHAR(100),
  nacimiento DATE,
  muerte DATE,
  PRIMARY KEY (codAutor)
);
 
/* Creando tabla de colecciones */
CREATE TABLE coleccion (
  codColeccion INT(5) AUTO_INCREMENT,
  nombre VARCHAR(100) NOT NULL,
  numLibros INT(5),
  completa BOOLEAN,
  PRIMARY KEY (codColeccion)
);
 
CREATE TABLE editorial (
  codEditorial INT(5) AUTO_INCREMENT,
  nombre VARCHAR(100) NOT NULL,
  fechaPrimeraEd DATE,
  PRIMARY KEY (codEditorial)
);
 
/* Creando tabla de libros */
CREATE TABLE libro (
  codLibro INT(5) AUTO_INCREMENT,
  titulo VARCHAR(100) NOT NULL,
  idioma VARCHAR(20),
  codAutor INT(5),
  codColeccion INT(5),
  codCategoria INT(5),
  codEditorial INT(5),
  PRIMARY KEY (codLibro),
  CONSTRAINT libros_autor
  FOREIGN KEY (codAutor) REFERENCES autor (codAutor)
  ON DELETE CASCADE,
  CONSTRAINT libros_coleccion
  FOREIGN KEY (codColeccion) REFERENCES coleccion (codColeccion)
  ON DELETE CASCADE,
  CONSTRAINT libros_categoria
  FOREIGN KEY (codCategoria) REFERENCES categoria (codCategoria)
  ON DELETE CASCADE,
  CONSTRAINT libros_editorial
  FOREIGN KEY (codEditorial) REFERENCES editorial (codEditorial)
  ON DELETE CASCADE
);
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

¿Repetir Claves Foráneas?

Publicado por leonardo_josue (1173 intervenciones) el 24/03/2017 16:12:08
Hola Lara:

Cuando tienes una relación muchos a muchos (es decir un libro tiene varias categorías y cada categoría puede tener varios libros), lo que haces para modelarlo es crear una tercer tabla que relacione ambas categorías. Supongamos con tu mismo ejemplo, que tienes la siguiente información:

1
2
3
4
5
6
7
8
9
10
11
+-----------------------------+------------------------------------+
|Libro                        |Categorías                          |
+-----------------------------+------------------------------------+
|El diario de Anna Frank      |Histórico, Autobiográfico           |
+-----------------------------+------------------------------------+
|El hombre en busca de sentido|Histórico, Autobiográfico, Filosofía|
+-----------------------------+------------------------------------+
|Lolita                       |Erótica                             |
+-----------------------------+------------------------------------+
|Filosofía de Tocador         |Erótica, Filosofía                  |
+-----------------------------+------------------------------------+

El tener campos multivaluados (es decir tener las categorías separadas por comas) está completamente prohibido en BD's, lo que haces sería tener tres tablas:

Una para las categorías:

1
2
3
4
5
6
7
8
9
10
11
|------------+--------------+
|Id_categoria|Categorías    |
|------------+--------------+
|           1|Histórico     |
|------------+--------------+
|           2|Autobiográfico|
|------------+--------------+
|           3|Erótica       |
|------------+--------------+
|           4|Filosofía     |
|------------+--------------+

Una para los libros:

1
2
3
4
5
6
7
8
9
10
11
+--------+-----------------------------+
|Id_libro|Libro                        |
+--------+-----------------------------+
|       1|El diario de Anna Frank      |
+--------+-----------------------------+
|       2|El hombre en busca de sentido|
+--------+-----------------------------+
|       3|Lolita                       |
+--------+-----------------------------+
|       4|Filosofía de Tocador         |
+--------+-----------------------------+

y finalmente una tercer tabla que relaciona ambas categorías, donde debes poner tantos registros como relaciones existan, esto quiere decir que Por ejemplo, para el libro "El hombre en busca de sentido" que tiene tres categorías, debes poner tres registros en la tabla, más o menos así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+--------------------+--------+------------+
|Id_libros_categorias|Id_libro|Id_categoria|
+--------------------+--------+------------+
|                   1|       1|           1|
+--------------------+--------+------------+
|                   2|       1|           2|
+--------------------+--------+------------+
|                   3|       2|           1|
+--------------------+--------+------------+
|                   4|       2|           2|
+--------------------+--------+------------+
|                   5|       2|           4|
+--------------------+--------+------------+
|                   6|       3|           3|
+--------------------+--------+------------+
|                   7|       3|           3|
+--------------------+--------+------------+
|                   8|       4|           4|
+--------------------+--------+------------+

¿se entiende?

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de Isaias
Val: 2.542
Oro
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

¿Repetir Claves Foráneas?

Publicado por Isaias (1921 intervenciones) el 24/03/2017 16:18:30
Mas claro, ni el agua ...
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Lara

¿Repetir Claves Foráneas?

Publicado por Lara (5 intervenciones) el 24/03/2017 18:31:14
Muchísimas gracias Leo, me ha quedado perfectamente claro como debe hacerse. Según te estaba leyendo recordaba la Normalización y que no la tuve todo lo en cuenta que debería. Pero con lo que me dices ya se cómo solucionarlo.

Muchas gracias y un saludo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

¿Repetir Claves Foráneas?

Publicado por leonardo_josue (1173 intervenciones) el 24/03/2017 21:50:49
Hola de nuevo Lara:

Tal como lo dices, esto tiene que ver un tanto con cuestiones de normalización...

Antes de que sigas modelando tu BD's te conviene darle una revisión completa a tu modelo, ya que creo que estás pasando por alto otras relaciones muchos a muchos que están implícitas, por ejemplo esta misma situación ocurre con los autores... tal como tienes estás asociando un solo autor para los libros, sin embargo, es posible que en un mismo libro haya sido escrito por varias personas.

Lo mismo pasa con las editoriales, un libro pudo haber sido editado por más de una editorial, o escrito en más de un lenguaje, o estar disponible en más de un formato (pasta dura, edición de bolsillo, pasta blanda, ebook, audiolibro etc.)

Entre más revises tu modelo desde un inicio, será menos probable que tengas que modificarlo más adelante.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de Lara

¿Repetir Claves Foráneas?

Publicado por Lara (5 intervenciones) el 27/03/2017 17:15:40
Lo primero agradecerte la ayuda y que te hayas tomado un tiempo en responder.

Le he dado una vuelta a lo que comentas ya que no me había dado cuenta de que bien es cierto que hay libros escritos por varios autores y demás, y he creado una nueva tabla para las relaciones, te pongo el código a ver qué tal lo verías así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* Creando tabla de categorías */
CREATE TABLE categoria (
  codCategoria INT(5) AUTO_INCREMENT,
  nombre VARCHAR(20) NOT NULL,
  PRIMARY KEY (codCategoria)
);
 
/* Creando tabla de autores */
CREATE TABLE autor (
  codAutor INT(5) AUTO_INCREMENT,
  nombre VARCHAR(40) NOT NULL,
  apellidos VARCHAR(100),
  nacimiento DATE,
  muerte DATE,
  PRIMARY KEY (codAutor)
);
 
/* Creando tabla de colecciones */
CREATE TABLE coleccion (
  codColeccion INT(5) AUTO_INCREMENT,
  nombre VARCHAR(100) NOT NULL,
  numLibros INT(5),
  completa BOOLEAN,
  PRIMARY KEY (codColeccion)
);
 
/* Creando tabla de editorial */
CREATE TABLE editorial (
  codEditorial INT(5) AUTO_INCREMENT,
  nombre VARCHAR(100) NOT NULL,
  fechaPrimera DATE,
  edicion INT(3),
  fechaEdicion DATE,
  PRIMARY KEY (codEditorial)
);
 
/* Creando tabla de libros */
CREATE TABLE libro (
  codLibro INT(5) AUTO_INCREMENT,
  titulo VARCHAR(100) NOT NULL,
  idioma VARCHAR(20),
  formato ENUM ('Tapa Dura', 'Bolsillo'),
  precio FLOAT,
  datosUbicacion VARCHAR(250)
);
 
/* Creando tabla de relaciones */
CREATE TABLE relacion (
  codRelacion INT(10),
  codLibro INT(5),
  codAutor INT(5),
  codColeccion INT(5),
  codCategoria INT(5),
  codEditorial INT(5),
  PRIMARY KEY (codRelacion),
  CONSTRAINT relacion_libro
  FOREIGN KEY (codLibro) REFERENCES libro (codLibro)
  ON DELETE CASCADE,
  CONSTRAINT relacion_autor
  FOREIGN KEY (codAutor) REFERENCES autor (codAutor)
  ON DELETE CASCADE,
  CONSTRAINT relacion_coleccion
  FOREIGN KEY (codColeccion) REFERENCES coleccion (codColeccion)
  ON DELETE CASCADE,
  CONSTRAINT relacion_categoria
  FOREIGN KEY (codCategoria) REFERENCES categoria (codCategoria)
  ON DELETE CASCADE,
  CONSTRAINT relacion_editorial
  FOREIGN KEY (codEditorial) REFERENCES editorial (codEditorial)
  ON DELETE CASCADE
);
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar