PostgreSQL: insertar / actualizar viola las restricciones de clave externa

12

Soy nuevo en postgreSQL. Tengo 3 tablas, una tabla hace referencia a las otras 2 claves principales de la tabla. Pero no pude insertar datos en el Table3. Vea el código a continuación:

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

ERROR: insertar o actualizar en la tabla "Tabla3" viola la restricción de clave externa "Tabla3_DataID_fkey" DETALLE: Clave (DataID) = (27856) no está presente en la tabla "Tabla1".

Cuando intenté insertar datos en las 3 tablas, ocurrió un error. Me he referido la documentación de PostgreSQL y cambiado de código como sigue: (Por desgracia, mostró otro error)

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL REFERENCES Table1 ON DELETE RESTRICT,
  "Address" numeric(20) DEFAULT NULL REFERENCES Table2 ON DELETE CASCADE, 
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   PRIMARY KEY("DataID", "Address")
);

ERROR: no se permiten varias claves principales para la tabla "Tabla3" LÍNEA 65: CLAVE PRIMARIA ("ID de datos", "Dirección")

Por favor, ayúdame ... ¿Cómo puedo crear la referencia?

Cambié el IDas UNIQUEy eliminé la línea PRIMARY KEY ("ID"). En ese momento muestra otro error como:

ERROR: el valor de clave duplicada viola la restricción única "Table3_pkey"

Haseena
fuente

Respuestas:

17

Hay algunos problemas con sus tablas. Primero trataré de abordar las claves externas, ya que preguntas sobre ellas :)

Pero antes de eso, debemos darnos cuenta de que los dos conjuntos de tablas (los primeros tres que creó y el segundo conjunto, que creó después de soltar el primer conjunto) son los mismos. Por supuesto, la definición de Table3en su segundo intento tiene sintaxis y errores lógicos, pero la idea básica es:

CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

Esta definición le dice a PostgreSQL aproximadamente lo siguiente: "Cree una tabla con cuatro columnas, una será la clave primaria (PK), las otras pueden ser NULL. Si se inserta una nueva fila, verifique DataIDy Address: si contienen un valor no NULL ( decir 27856), a continuación, comprobar Table1por DataIDy Table2para Address. Si no hay tal valor en esas tablas, a continuación, devuelve un error." Este último punto que has visto primero:

ERROR: insert or update on table "Table3" violates foreign key constraint 
    "Table3_DataID_fkey" DETAIL: Key (DataID)=(27856) is not present in table "Table1".

Tan simple: si no hay una fila en Table1dónde DataID = 27856, entonces no puede insertar esa fila en Table3.

Si necesita esa fila, primero debe insertar una fila en Table1con DataID = 27856, y solo luego intentar insertar en Table3. Si le parece que esto no es lo que quiere, describa en algunas oraciones lo que desea lograr, y podemos ayudarlo con un buen diseño.


Y ahora sobre los otros problemas.

Usted define sus PK como

CREATE all_your_tables (
    first_column NOT NULL DEFAULT '0',   
    [...]
    PRIMARY KEY ("ID"),  

Una clave primaria significa que todos los elementos que contiene son diferentes entre sí, es decir, los valores son UNIQUE. Si le das un estático DEFAULT(como '0') a una UNIQUEcolumna, experimentarás malas sorpresas todo el tiempo. Esto es lo que obtuvo en su tercer mensaje de error.

Además, '0'significa una cadena de texto, pero no un número ( biginto numericen su caso). Use simplemente en su 0lugar (o no lo use en absoluto, como escribí anteriormente).

Y un último punto (puedo estar equivocado aquí): en Table2, su Addresscampo está configurado en numeric(20). Al mismo tiempo, es el PK de la tabla. El nombre de la columna y el tipo de datos sugieren que esta dirección puede cambiar en el futuro. Si esto es cierto, entonces es una muy mala elección para un PK. Piense en el siguiente escenario: tiene una dirección '1234567890454', que tiene un elemento secundario Table3como

ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569

Ahora esa dirección pasa a cambiar a otra. ¿Cómo haces que tu hijo Table3siga en fila a su padre a la nueva dirección? (Hay soluciones para esto, pero puede causar mucha confusión). Si este es su caso, agregue una columna de ID a su tabla, que no contendrá ninguna información del mundo real, simplemente servirá como un valor de identificación (es decir, , ID) para una dirección.

dezso
fuente
Gracias por tu valiosa sugerencia. Intentaré un mejor diseño basado en sus sugerencias. Ahora se resuelve el primer error.
Haseena el
0

Todo depende de lo que quieras hacer con los datos.

Primer ejemplo: desea tener datos consistentes en todas las tablas, pero intenta insertar valores que no coinciden con Table1.

Segundo ejemplo: no desea tener datos consistentes, pero intente hacer otra cosa, no saber exactamente qué. La tabla no puede tener más de una clave primaria.

Tercer ejemplo: aún no sabe lo que quiere lograr y coloca una restricción ÚNICA en la columna que puede tener el mismo valor varias veces.

Si solo desea insertar sus datos, elimine las referencias de claves externas en el primer ejemplo. Si desea tener datos consistentes en todas las tablas, realice la limpieza de los datos y luego insértelos en las tablas CON restricciones de clave externa.

tl; dr: para insertar sus datos en Table3 con el código del primer ejemplo: inserte los valores faltantes en la columna Table1.DataID que existen en Table3.DataId.

BartekR
fuente