2011-02-09 28 views
9

Estoy luchando con claves externas en mi base de datos, posiblemente tiene algo que ver con la herencia?
Así que aquí es la configuración básica:No existe la clave externa PostgreSQL, ¿problema de herencia?

-- table address 
CREATE TABLE address 
(
    pk_address serial NOT NULL, 
    fk_gadmid_0 integer NOT NULL, -- this table already exists, no problem here 
    street character varying(100), 
    zip character varying(10), 
    city character varying(50), 
    public boolean, 
    CONSTRAINT address_primarykey PRIMARY KEY (pk_address), 
    CONSTRAINT gadmid_0_primarykey FOREIGN KEY (fk_gadmid_0) 
     REFERENCES adm0 (gadmid_0) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE address OWNER TO postgres; 

-- table stakeholder (parent) 
CREATE TABLE stakeholder 
(
    pk_stakeholder integer DEFAULT nextval('common_stakeholder_seq') NOT NULL, 
    fk_stakeholder_type integer NOT NULL, -- this table also exists, no problem here 
    name character varying(255) NOT NULL, 
    CONSTRAINT stakeholder_primarykey PRIMARY KEY (pk_stakeholder), 
    CONSTRAINT stakeholder_fk_stakeholder_type FOREIGN KEY (fk_stakeholder_type) 
     REFERENCES stakeholder_type (pk_stakeholder_type) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE stakeholder OWNER TO postgres; 

-- table individual (child of stakeholder) 
CREATE TABLE individual 
(
    firstname character varying(50), 
    fk_title integer, -- this table also exists, no problem here 
    email1 character varying (100), 
    email2 character varying (100), 
    phone1 character varying (50), 
    phone2 character varying (50), 
    CONSTRAINT individual_primarykey PRIMARY KEY (pk_stakeholder), 
    CONSTRAINT title_foreignkey FOREIGN KEY (fk_title) 
     REFERENCES title (pk_title) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE CASCADE 
) INHERITS (stakeholder) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE individual OWNER TO postgres; 

-- link between stakeholder and address 
CREATE TABLE l_stakeholder_address 
(
    pk_l_stakeholder_address serial NOT NULL, 
    fk_stakeholder integer NOT NULL REFERENCES stakeholder, 
    fk_address integer NOT NULL REFERENCES address, 
    CONSTRAINT l_stakeholder_address_primarykey PRIMARY KEY (pk_l_stakeholder_address), 
    CONSTRAINT l_stakeholder_address_fk_stakeholder FOREIGN KEY (fk_stakeholder) 
     REFERENCES stakeholder (pk_stakeholder) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION, 
    CONSTRAINT l_stakeholder_address_fk_address FOREIGN KEY (fk_address) 
     REFERENCES address (pk_address) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE l_stakeholder_address OWNER TO postgres; 

Hasta el momento, no hay problema. Luego he intentado añadir algunos valores:

INSERT INTO individual (pk_stakeholder, fk_stakeholder_type, name, firstname, fk_title, email1, email2, phone1, phone2) 
    VALUES (1, 8, 'Lastname', 'Firstname', 1, '[email protected]', '', '', ''); 
INSERT INTO address (pk_address, fk_gadmid_0, street, zip, city, public) 
    VALUES (1, 126, 'Address', '', 'City', FALSE); 
INSERT INTO l_stakeholder_address (pk_l_stakeholder_address, fk_stakeholder, fk_address) 
    VALUES (DEFAULT, 1, 1); 

Y finalmente me acaban de tener un error (estado de SQL 23503) diciendo que la clave (fk_stakeholder) = (1) no está vigente en la tabla "partes interesadas".
Los 2 primeros insertos están muy bien, puedo ver en las bases de datos:

stakeholder: 
pk_stakeholder | ... 
---------------------- 
1    | ... 

address: 
pk_address | ... 
-------------------- 
1   | ... 

¿Qué estoy haciendo mal? Debo admitir que soy bastante nuevo en PostgreSQL (usando 8.4), pero ni siquiera estoy seguro de si eso es un problema de PG, tal vez me faltan algunos entendimientos básicos de diseño de bases de datos ...
De cualquier manera, por ahora, probé casi todo lo que podía pensar, también intenté diferir el FK como en el PostgreSQL : Transaction and foreign key problem, pero de alguna manera eso tampoco funciona.

Respuesta

6

puede solucionar utilizando tabla adicional individual_pks (individual_pk integer primary key) con todas las claves principales de padres e hijos, que se mantienen utilizando disparadores (muy simple - insertar a individual_pks en insertar, eliminar de ella el borrado, actualizarlo en la actualización, si cambia individual_pk).

Luego apuntas llaves foráneas a esta tabla adicional en lugar de a un niño. Habrá un pequeño golpe de rendimiento, pero solo al agregar/eliminar filas.

O olvide la herencia y hágalo a la antigua usanza: simplemente una tabla con algunas columnas que aceptan nulos.

+0

Muchas gracias por su respuesta, logré resolver mi problema de esa manera. Sin embargo, en lugar de 'individual_pks', prefiero 'stakeholder_pk', ya que el stakeholder es la tabla padre. Entonces 'stakeholder_pk' recoge todas las claves principales de 'stakeholder' y sus hijos. ¡Gracias! – Lukas

6

Su análisis es el correcto: se debe a la herencia. Al verificar la clave externa, no se consideran las tablas secundarias.

En general, las claves de herencia y externas no se combinan bien en PostgreSQL. Un problema importante es que no puede tener restricciones únicas en las tablas.

Reference

+0

Gracias por su respuesta rápida. Mi entendimiento solía ser que las tablas secundarias no importan aquí porque no tienen un PK (que no sea el heredado) y el FK hace referencia a la tabla padre (que tiene el PK almacenado correctamente). Pero aparentemente estoy equivocado (aunque no sé exactamente por qué). Entonces, ¿hay alguna manera de hacer lo que quiero? ¿Tal vez usando un disparador para verificar si fk_stakeholder en la tabla de enlaces existe en el PK de la parte interesada? – Lukas

+0

Las claves principales no son la preocupación aquí. La clave foránea fk_stakeholder apunta a la parte interesada de la tabla, pero no hay ninguna fila coincidente allí. La fila en la tabla de individuos no se considera. –

+0

Para ser sincero, todavía no lo entiendo. La clave externa apunta a stakeholder.pk_stakeholder, que existe porque se insertó en su tabla secundaria. Supongo que ahí es donde radica el problema, pero aún así, la fila está ahí. Así como stakeholder_pk.pk_stakeholder está allí en la otra solución anterior. Creo que me faltan algunas comprensiones fundamentales en este tema. Pero no importa, no quiero dedicarle más tiempo y parece funcionar con la solución propuesta por Tometzky. Pero muchas gracias por tu ayuda de todos modos! – Lukas

Cuestiones relacionadas