Estoy tratando de implementar una relación de personas con direcciones de correo electrónico donde una persona debe tener al menos una dirección de correo electrónico en todo momento. Las tablas se ven así:
CREATE TABLE persons ( id serial PRIMARY KEY, name text NOT NULL ); CREATE TABLE email_addresses ( id serial PRIMARY KEY, person_id integer REFERENCES persons (id) ON DELETE CASCADE ON UPDATE CASCADE, email_address text NOT NULL ); Para implementar la restricción de que una persona debe tener al menos una dirección de correo electrónico, pensé en usar disparadores. Uno de los desencadenantes necesarios para satisfacer la restricción es un desencadenante BEFORE DELETE en la tabla email_addresses que genera un error si DELETE eliminaría la última dirección de correo electrónico de una persona:
CREATE FUNCTION email_addresses_delete_trigger() RETURNS trigger AS $$ DECLARE num_email_addresses integer; BEGIN num_email_addresses := (SELECT count(*) FROM email_addresses WHERE person_id = OLD.person_id); IF num_email_addresses < 2 THEN RAISE EXCEPTION 'A person must have at least one email address'; END IF; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE TRIGGER email_addresses_delete_trigger BEFORE DELETE ON email_addresses FOR EACH ROW EXECUTE FUNCTION email_addresses_delete_trigger(); Este activador hace lo que debe hacer, sin embargo, evita que se elimine a una persona de la tabla de persons . Por ejemplo:
mydb=# DELETE FROM persons WHERE id = 1; ERROR: A person must have at least one email address CONTEXT: PL/pgSQL function email_addresses_delete_trigger() line 7 at RAISE SQL statement "DELETE FROM ONLY "public"."email_addresses" WHERE $1 OPERATOR(pg_catalog.=) "person_id""Si elimino a una persona, también quiero que se eliminen todas sus direcciones de correo electrónico, por lo que no me importa si la restricción representada por el activador se mantiene durante el proceso de eliminación en cascada. ¿Hay alguna forma de "ignorar" este disparador cuando se elimina a una persona? ¿O hay alguna otra forma en que tendría que eliminar a una persona?
Mi recomendación es cambiar el modelo de datos para que tenga una restricción de clave externa no anulable de persons a direcciones de email_addresses electrónico que se vincule a una de las direcciones de la persona. Luego, su requisito se cumple automáticamente y no necesita un disparador.
Eso hará que algunas cosas, como eliminar una dirección de correo electrónico, sean más complicadas, pero no tiene que depender de un activador de integridad, que siempre está sujeto a condiciones de carrera .