Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

[SOLUCIONADO] Error al relacionar claves foraneas en Clave compuesta

Estas en el tema de Error al relacionar claves foraneas en Clave compuesta en el foro de Mysql en Foros del Web. Un saludo, Tengo tablas en una relación N:N así (subrayado es clave primaria): primeratabla( idtabla1 , otrocampo, yotro) segundatabla( idtabla2 ,uncampomas,unomas) relacion-primeratabla-segundatabla( idtabla1,idtabla2 ) El ...
  #1 (permalink)  
Antiguo 14/09/2013, 00:36
 
Fecha de Ingreso: agosto-2008
Mensajes: 23
Antigüedad: 15 años, 8 meses
Puntos: 0
Pregunta Error al relacionar claves foraneas en Clave compuesta

Un saludo,

Tengo tablas en una relación N:N así (subrayado es clave primaria):

primeratabla(idtabla1, otrocampo, yotro)
segundatabla(idtabla2,uncampomas,unomas)
relacion-primeratabla-segundatabla(idtabla1,idtabla2)

El problema es que no consigo hacer las relaciones de las llaves foraneas relacion-primeratabla-segundatabla con los id respectivos, el problema radica en no poder hacer los CONSTRAINT (ON DELETE & ON UPDATE).

Cuando lo intento, únicamente me deja poner UN CONSTRAINT en una clave foránea y ya en la segunda no me lo permite. Puedo hacerlo con ambas, es decir, ponerla a idtabla1 y ya no me deja a idtabla2, o ponerla a idtabla2 y ya no me deja a idtabla1.
  • He probado por interfaz (phpMyAdmin) en ordenes diferentes.
  • He probado creando la tabla sin claves y luego con otra consulta SQL ponerlas, o crear la tabla con indices (INDEX) únicamente y luego lo demás, o crear la tabla con claves foráneas, y todas las combinaciones posibles.
  • Alguna vez he conseguido hacerlo, pero al hacer una prueba (como actualizar un ON DELETE a RESTRIC en vez de CASCADE) desde phpMyAdmin, vuelve y arroja un error y borra toda la cuestión (Pone en blanco el ON DELETE y el ON UPDATE).

No entiendo porque no puedo, si tengo otras bases de datos donde lo he hecho (igual, mismo CHARSET (utf-8), mismo COLLATE(utf8_spanish_ci), mismo motor (INNODB)).

Llevo varios días buscando y probando, ya no tuve más opción.

Muchas gracias.
  #2 (permalink)  
Antiguo 14/09/2013, 06:19
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 5 meses
Puntos: 2658
Respuesta: Error al relacionar claves foraneas en Clave compuesta

Empecemos por el principio: Postea la sentencia con que quieres agregar esas constraint, y en especial postea el CREATE TABLE de cada una de las tres tablas.
Anticipándome a tu respuesta, debes repasar la lista de condiciones necesarias y obligatorias para poder definir una FK:
1) La FK sólo puede apuntar a una PK, y en MySQL puede (alternativamente), hacerlo a un campo definido como UNIQUE.
2) El campo usado como FK deben ser del mismo tipo, longitud y collation (si es de caracteres) que el campo PK de la tabla referida.
3) SI una KF apunta a una tabla cuya PK es compuesta (más de un campo en la definición de la PK), la FK debe ser creada con la misma cantidad de campos, y en el mismo orden de la PK referida.
4) Los charset de las tablas deben ser idénticos.
5) Todas las tablas deben existir en el mismo esquema de bases de datos.

Y finalmente, un detalle poco verificado:
6) Si estás intentando definir una FK en una tabla que ya contiene registros, debes verificar que no existan inconsistencias entre los datos que la tabla contiene, respecto de la FK que estás tratando de definir.
Esto último implica que si hay al menos un registro que contenga un valor nulo, o que no exista entre las PK de la tabla que se referenciará, MySQL no te admitirá crear la FK.
Siempre que en un DBMS se crea una FK, el sistema verifica que los datos existentes cumplan con la constraint a crear. Siempre.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #3 (permalink)  
Antiguo 14/09/2013, 13:32
 
Fecha de Ingreso: agosto-2008
Mensajes: 23
Antigüedad: 15 años, 8 meses
Puntos: 0
Respuesta: Error al relacionar claves foraneas en Clave compuesta

Gracias por tu respuesta.

Te resumo como quiero que quede con el nivel de detalle posible:

primeratabla
idtabla1 - int UNSIGNED AUTOINCREMENT - PRIMARY
otrocampo
yotro

segundatabla
idtabla2 - smallint(3) UNSIGNED AUTOINCREMENT - PRIMARY
uncampomas
unomas

relacion-primeratabla-segundatabla
idtabla1 -> primeratabla.idtabla1 ON DELETE RESTRICT ON UPDATE CASCADE - int UNSIGNED - FOREIGN
idtabla2 -> segundatabla.idtabla2 ON DELETE RESTRICT ON UPDATE CASCADE - smallint(3) UNSIGNED - FOREIGN
[Juntas son la llave primaria: idtabla1,idtabla2 - PRIMARY]

Como te comentaba, he usado muchas combinaciones para hacerlo:
  • Crear la tabla con las llaves foráneas y primaria.
  • Crear la tabla (relacion-primeratabla-segundatabla) sin llaves. Luego crear las llaves.
  • etc.

Asumiento lo anterior, y que las tablas son sencillas, no se si sería inapropiado preguntarte ¿como crearías tu la tabla y las relaciones en MySQL? (Sería crear la tabla 'relacion-primeratabla-segundatabla' y sus relaciones, las otras dos tablas no tienen problema.)

Sobre las condiciones que comentas, todas se cumplen.
Aunque la 3. no estoy seguro de entenderla muy bien; entiendo que si quisiera apuntar a una llave primaria compuesta (ejp: idtabla1,idtabla2) debo hacerlo con ambos campos (iguales, tipo y todo eso). Entendiéndolo así no creo querer esto, sino lo inverso, apuntar cada campo de la llave a su correspondiente tabla y llave primaria.

Gracias de antemano.
  #4 (permalink)  
Antiguo 14/09/2013, 14:05
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 5 meses
Puntos: 2658
Respuesta: Error al relacionar claves foraneas en Clave compuesta

Vamos de vuelta: Las descripciones como la que pones, no nos sirven mucho. en realidad no sirve casi de nada, porque se omite información importante.
Cuando te pido el CREATE TABLE es exactamente eso lo que pido... No un descriptivo.
Básicamente: No me sirve que me digas cómo lo quieres, sino lo que tienes ahora.
Cita:
¿como crearías tu la tabla y las relaciones en MySQL?
Eso no existe. No es cómo yo las crearía, sino cómo se hace. Se hace siempre de la misma forma, sin importar cuál es el diseño.

Haz lo siguiente: Suponiendo que las tablas se llamen "primera", "segunda" y "relacion_primera_segunda":
Código MySQL:
Ver original
  1. SHOW CREATE TABLE primera;
  2. SHOW CREATE TABLE segunda;
  3. SHOW CREATE TABLE relacion_primera_segunda;
Luego, copia el resultado de cada una de ellas y postealo acá, junto con la sentencia ALTER TABLE usada por tí para intentar crear la constraint
Haz eso, y luego seguimos.

Y si no puedes o no quieres aportar esto que te pido, al menos dime por qué, ya que lo que te estoy planteando es por razones concretas: Se necesita para entender el problema y realizar una prueba de verificación.

Respecto al punto 3, si te fijas, te estoy poniendo una lista de requisitos,. No estoy diciendo que los estés necesitando, sino solamente explico cuáles son las posibilidades. COmo no nos estas dando el CREATE TABLE, no puedo estar seguro de si es el caso o no, y no sería la primera vez que alguien omita una información esencial como esa.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #5 (permalink)  
Antiguo 14/09/2013, 16:45
 
Fecha de Ingreso: agosto-2008
Mensajes: 23
Antigüedad: 15 años, 8 meses
Puntos: 0
De acuerdo Respuesta: Error al relacionar claves foraneas en Clave compuesta

Haciendo de nuevo las pruebas, concluyo:

* Previo (tablas iniciales):
Código MySQL:
Ver original
  1. CREATE TABLE `primeratabla` (
  2. `otrocampo` varchar(10) NOT NULL,
  3. `yotro` varchar(10) NOT NULL,
  4. PRIMARY KEY (`idtabla1`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  6.  
  7. CREATE TABLE `segundatabla` (
  8. `uncampomas` varchar(10) NOT NULL,
  9. `unomas` varchar(10) NOT NULL,
  10. PRIMARY KEY (`idtabla2`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

* Funciona:
Cuando la consulta de las llaves foráneas se hace en conjunto.
Ya sea creando la tabla:
Código MySQL:
Ver original
  1. CREATE TABLE `relacion-primeratabla-segundatabla` (
  2. `idtabla1` int unsigned NOT NULL,
  3. `idtabla2` smallint(3) unsigned NOT NULL,
  4. FOREIGN KEY ( `idtabla1` ) REFERENCES `primeratabla` (`idtabla1`) ON DELETE RESTRICT ON UPDATE CASCADE,
  5. FOREIGN KEY ( `idtabla2` ) REFERENCES `segundatabla` (`idtabla2`) ON DELETE RESTRICT ON UPDATE CASCADE,
  6. PRIMARY KEY (`idtabla1`,`idtabla2`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
O modificandola:
Código MySQL:
Ver original
  1. ALTER TABLE `relacion-primeratabla-segundatabla`
  2. ADD FOREIGN KEY ( `idtabla1` ) REFERENCES `primeratabla` (`idtabla1`) ON DELETE RESTRICT ON UPDATE CASCADE,
  3. ADD FOREIGN KEY ( `idtabla2` ) REFERENCES `segundatabla` (`idtabla2`) ON DELETE RESTRICT ON UPDATE CASCADE,
  4. ADD PRIMARY KEY (`idtabla1`,`idtabla2`)

NOTA: es indiferente dónde se cree la llave primaria (en consulta aparte o en la misma).

* No funciona:
Modificando las llaves foráneas por separado:
Código MySQL:
Ver original
  1. ALTER TABLE  `relacion-primeratabla-segundatabla` ADD FOREIGN KEY ( `idtabla1` ) REFERENCES `primeratabla` (`idtabla1`) ON DELETE RESTRICT ON UPDATE CASCADE;
  2. ALTER TABLE  `relacion-primeratabla-segundatabla` ADD FOREIGN KEY ( `idtabla2` ) REFERENCES `segundatabla` (`idtabla2`) ON DELETE RESTRICT ON UPDATE CASCADE;
Por lo tanto tampoco funciona por la interfaz gráfica de phpMyAdmin ya que en la misma para estas acciones siempre usa la consulta que las modifica por separado.

¿Por qué?
Eso es lo que no sé, pero como el problema está resuelto lo marco como tal.

Cita:
gnzsoloyo, eres muy amable en responder estas preguntas en los foros (he visto muchas de tus respuestas), y estructuras las mismas de forma muy clara... pero te comento, solo si lo quieres tener en cuenta (no para discutirlo), no eres nada amable en la forma como respondes, da la impresión de que regañas, que te las sabes todas y mereces un busto, y por más útiles que sean tus respuestas, y por más conocimiento que tengas, lo agradable de un foro es que quién responde no solo siempre está dispuesto (un foro es eso, un mundo de dudas), no solo comparte todo lo que sabe, lo hace porque le gusta y en definitiva suelen ser muy amables, al menos en las primeras respuestas, sobre todo con los novatos, algo que todos somos o fuimos. A pesar de esto, no quiero prejuzgar sin conocerte, mas bien agradecerte por la rapidez con la que respondes. Espero que no te lo tomes a mal y que pena contigo haber planteado así el problema, entiendo que no fui claro.

Última edición por gnzsoloyo; 14/09/2013 a las 16:52 Razón: Usar Highlight "MySQL"
  #6 (permalink)  
Antiguo 14/09/2013, 17:29
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 5 meses
Puntos: 2658
Respuesta: Error al relacionar claves foraneas en Clave compuesta

Bueno, gracias por finalmente poner las sentencias de creación. Ahora algunas cosas resultan más claras.
Por lo pronto, el esquema de creación de todas las tablas, incluyendo las FK en la definición de la última, funciona bien:
Código MySQL:
Ver original
  1. mysql>
  2. mysql> CREATE TABLE `primeratabla` (
  3.     -> `idtabla1` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  4.     -> `otrocampo` VARCHAR(10) NOT NULL,
  5.     -> `yotro` VARCHAR(10) NOT NULL,
  6.     -> PRIMARY KEY (`idtabla1`)
  7.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  8. Query OK, 0 rows affected (0.01 sec)
  9.  
  10. mysql>
  11. mysql> CREATE TABLE `segundatabla` (
  12.     -> `idtabla2` SMALLINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
  13.     -> `uncampomas` VARCHAR(10) NOT NULL,
  14.     -> `unomas` VARCHAR(10) NOT NULL,
  15.     -> PRIMARY KEY (`idtabla2`)
  16.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  17. Query OK, 0 rows affected (0.01 sec)
  18.  
  19. mysql>
  20. mysql> CREATE TABLE `relacion-primeratabla-segundatabla` (
  21.     -> `idtabla1` INT UNSIGNED NOT NULL,
  22.     -> `idtabla2` SMALLINT(3) UNSIGNED NOT NULL,
  23.     -> FOREIGN KEY ( `idtabla1` ) REFERENCES `primeratabla` (`idtabla1`) ON DELETE RESTRICT ON UPDATE CASCADE,
  24.     -> FOREIGN KEY ( `idtabla2` ) REFERENCES `segundatabla` (`idtabla2`) ON DELETE RESTRICT ON UPDATE CASCADE,
  25.     -> PRIMARY KEY (`idtabla1`,`idtabla2`)
  26.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  27. Query OK, 0 rows affected (0.06 sec)
Evidentemente, eso no tiene problemas de tipo de dato, o de sintaxis.
hacerlo en dos etapas requiere, como es evidente, no definirle más que la PK a la tercera tabla desde inicio:
Código MySQL:
Ver original
  1. mysql> CREATE TABLE `primeratabla` (
  2.     -> `idtabla1` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  3.     -> `otrocampo` VARCHAR(10) NOT NULL,
  4.     -> `yotro` VARCHAR(10) NOT NULL,
  5.     -> PRIMARY KEY (`idtabla1`)
  6.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  7. Query OK, 0 rows affected (0.01 sec)
  8.  
  9. mysql>
  10. mysql> CREATE TABLE `segundatabla` (
  11.     -> `idtabla2` SMALLINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
  12.     -> `uncampomas` VARCHAR(10) NOT NULL,
  13.     -> `unomas` VARCHAR(10) NOT NULL,
  14.     -> PRIMARY KEY (`idtabla2`)
  15.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  16. Query OK, 0 rows affected (0.01 sec)
  17.  
  18. mysql>
  19. mysql> CREATE TABLE `relacion-primeratabla-segundatabla` (
  20.     -> `idtabla1` INT UNSIGNED NOT NULL,
  21.     -> `idtabla2` SMALLINT(3) UNSIGNED NOT NULL,
  22.     -> PRIMARY KEY (`idtabla1`,`idtabla2`)
  23.     -> ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
  24. Query OK, 0 rows affected (0.01 sec)
  25.  
  26. mysql>
  27. mysql> ALTER TABLE `relacion-primeratabla-segundatabla`
  28.     -> ADD FOREIGN KEY ( `idtabla1` ) REFERENCES `primeratabla` (`idtabla1`)
  29. Query OK, 0 rows affected (0.03 sec)
  30. Records: 0  Duplicates: 0  Warnings: 0
  31.  
  32. mysql>
  33. mysql> ALTER TABLE  `relacion-primeratabla-segundatabla`
  34.     -> ADD FOREIGN KEY ( `idtabla2` ) REFERENCES `segundatabla` (`idtabla2`)
  35. Query OK, 0 rows affected (0.07 sec)
  36. Records: 0  Duplicates: 0  Warnings: 0
Tampoco causa problemas, por lo cual no se ve defectos en ningún caso.
Francamente, llegado a este punto sólo puedo suponer que el problema está en la versión del phpMyadmin, o algo semejante, ya que al no ser parte de MySQL (es una interfaz programada en PHP), y realizar internamente la creación de las sentencias que envía a MySQL, hay un margen de error probable.
Como sea, ni la definición de las tablas está mal, ni tampoco las de las FK.

Finalmente, es posible que haya resultado demasiado áspera mi reacción, el problema es que me cansa sobremanera pedir específicamente que posteen el CREATE TABLE, para que me terminen contestando con descripciones vagas, que ocultan mas cosas de las que aclaran.
Lo siento si fue excesivo. En algún momento me sacan de las casillas, porque es como si no leyesen lo que se les pide.

Como sea, mis disculpas.

Volviendo al tema, hay sí un par de consejos para que tengas en cuenta:
1) Nunca uses caracteres reservados en los nombres de objetos de bases de datos. No se deben usar dentro de los nombres ni paréntesis, si signos aritméticos, porque en algún momento, por más precauciones que tengas, se producirá un error sintáctico a causa de ellos.
2) No pongas el "rango" de un tipo de dato numérico entero, sólo sirven en el DECIMAL. Ese "(3)" que le pusiste al SMALLINT no genera ningún tipo de efecto al rango de representación, y puede causarte problemas luego si usas VIEWs. Ese valor numérico no representa el ancho de las cifras. Ponerlo, especialmente cuando es menor que el real, lo único que hará es confundirte y crearte problemas en el futuro.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Etiquetas: clave, compuesta, mysql5
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 14:09.