Trouble with single trigger using UUID as key, should I use two triggers?

Jason Aleski <[email protected]>
Newsgroups gmane.comp.db.postgresql.sql
Message-ID <[email protected]>
I'm running into a foreign key constraint when running a BEFORE trigger 
for audit purposes.  My initial goal was to do this in one BEFORE 
trigger, but I'm leaning towards executing using two different 
triggers.  I'm seeking a second opinion!  My initial thought was 
creating a trigger that runs before the data is written to the primary 
table; specifically on updates, as I want to increment the version_count 
before the data is written to the primary table.  Because the audit_id 
(UUID generated) has not been written to the primary table, I get a 
foreign key constraint problem when it tries to first write to the audit 
table.  I understand the error is because audit_id doesn't exist in the 
primary table.  If I were using a SERIAL/SEQUENCE, I could use the 
NEXTVAL function; but I need to use UUID the key and audit_id.

Knowing that, I think my only option is to create an AFTER trigger for 
the INSERT.  Then create a BEFORE trigger when doing UPDATES and 
DELETES.  Before I go this path, I through I'd see if anyone has any 
additional options I should consider; or would this be the suggested 
path?  Thoughts?

-JA-


--Example INSERT
INSERT INTO departments (department_legacyid, department_name) VALUES 
('ACT', 'Accounting');
INSERT INTO departments (department_legacyid, department_name) VALUES 
('HRM', 'Human Resources');
INSERT INTO departments (department_legacyid, department_name) VALUES 
('CSR', 'Customer Service');

--ERROR
ERROR: insert or update on table "departments_audit" violates foreign 
key constraint "departments_audit_audit_id_fkey" DETAIL: Key 
(audit_id)=(241451bd-796e-5add-95b0-18f6098bc08f) is not present in 
table "departments". CONTEXT: SQL statement "INSERT INTO 
departments_audit (audit_id, audit_lastaction, department_legacyid, 
department_name ) VALUES (NEW.audit_id, 'INSERT', 
NEW.department_legacyid, NEW.department_name )" PL/pgSQL function 
process_departments_audit() line 10 at SQL statement SQL state: 23503

--Primary Table
CREATE TABLE IF NOT EXISTS departments (
   row_id                UUID NOT NULL DEFAULT 
uuid_generate_v5(uuid_ns_dns(), 'location1.local'),
   row_created           TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT 
CURRENT_TIMESTAMP,
   audit_id              UUID NOT NULL DEFAULT 
uuid_generate_v5(uuid_ns_dns(), 'location1.local'),
   version_count         INTEGER NOT NULL DEFAULT 1,
   version_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT 
CURRENT_TIMESTAMP,
   department_legacyid   VARCHAR(255) NOT NULL,
   department_name       VARCHAR(255) NOT NULL,
   PRIMARY KEY (row_id)
);

--Creating index on audit_ID to ensure there is only one unique record 
in primary table
CREATE UNIQUE INDEX departments_ref_idx ON departments(audit_id);

--Audit Table
CREATE TABLE IF NOT EXISTS departments_audit (
   row_id                UUID NOT NULL DEFAULT 
uuid_generate_v5(uuid_ns_dns(), 'location1.local'),
   row_created           TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT 
CURRENT_TIMESTAMP,
   audit_id              UUID NOT NULL DEFAULT 
uuid_generate_v5(uuid_ns_dns(), 'location1.local'),
   audit_lastaction      CHARACTER VARYING DEFAULT 'NOT DEFINED',
   version_count         INTEGER NOT NULL DEFAULT 1,
version_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT 
CURRENT_TIMESTAMP,
   department_legacyid   VARCHAR(255) NOT NULL,
   department_name       VARCHAR(255) NOT NULL,
   PRIMARY KEY (row_id),
   FOREIGN KEY (audit_id) REFERENCES departments(audit_id)
);

-- Creating audit trigger for departments
CREATE OR REPLACE FUNCTION process_departments_audit() RETURNS TRIGGER 
AS $departments_audit$
   BEGIN
     IF (TG_OP = 'DELETE') THEN
       --Nothing yet
     ELSEIF (TG_OP = 'UPDATE') THEN
       --Nothing yet
       NEW.version_count = OLD.version_count + 1;
     ELSEIF (TG_OP = 'INSERT') THEN
       INSERT INTO departments_audit (audit_id,
                                      audit_lastaction,
                                      department_legacyid,
                                      department_name
                                     )
                              VALUES (NEW.audit_id,
                                      'INSERT',
                                      NEW.department_legacyid,
                                      NEW.department_name
                                     );
     END IF;
     RETURN NULL;
   END;
$departments_audit$ LANGUAGE plpgsql;

--Applying trigger BEFORE data is written to primary table
CREATE TRIGGER department_audit
   BEFORE INSERT OR UPDATE OR DELETE ON departments
     FOR EACH ROW EXECUTE PROCEDURE process_departments_audit();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.