Re: unreferenced primary keys: garbage collection - Mailing list pgsql-sql
From | Jan Wieck |
---|---|
Subject | Re: unreferenced primary keys: garbage collection |
Date | |
Msg-id | 200101222219.RAA15009@jupiter.jw.home Whole thread Raw |
In response to | Re: unreferenced primary keys: garbage collection (Jan Wieck <janwieck@Yahoo.com>) |
Responses |
Re: unreferenced primary keys: garbage collection
|
List | pgsql-sql |
Jan Wieck wrote: > Forest Wilkinson wrote: > > I have a database in which five separate tables may (or may not) reference > > any given row in a table of postal addresses. I am using the primary / > > foreign key support in postgres 7 to represent these references. > > > > My problem is that, any time a reference is removed (either by deleting or > > updating a row in one of the five referencing tables), no garbage > > collection is being performed on the address table. That is, when the > > last reference to an address record goes away, the record is not removed > > from the address table. Over time, my database will fill up with > > abandoned address records. > > While this behaviour makes sense in your case, it's not > subject to referential integrity constraints. You could > arrange for it with custom trigger procedures, checking all > the five tables on DELETE or UPDATE on one of them. > > I'll make up a little example and post it the other day - > need to take a nap now and tomorrow will be one of these > 30-hour days (from MET to EST), so don't expect anything > before Monday afternoon (EST). Here it is: CREATE TABLE t_addr ( a_id integer PRIMARY KEY, a_name text ); CREATE TABLE t_customer ( c_id integer PRIMARY KEY, c_address integer REFERENCES t_addr ); CREATE TABLE t_order ( o_id integer PRIMARY KEY, o_customer integer REFERENCES t_customer ON DELETE CASCADE, o_shipaddr integer REFERENCES t_addr ); CREATE FUNCTION tidy_up_addr(integer) RETURNS bool AS ' DECLARE chk_addr ALIAS FOR $1; BEGIN -- -- Check if address is still referenced from t_customer -- IF count(c_address)> 0 FROM t_customer WHERE c_address = chk_addr THEN RETURN''f''; END IF; -- -- Check if address is still referenced from t_order -- IF count(o_shipaddr) > 0 FROM t_order WHERE o_shipaddr = chk_addr THEN RETURN ''f''; END IF; -- -- Address not required any more - get rid of it. -- DELETE FROM t_addr WHERE a_id = chk_addr; RETURN ''t''; END; ' LANGUAGE'plpgsql'; CREATE FUNCTION customer_upd_or_del() RETURNS opaque AS ' BEGIN PERFORM tidy_up_addr(old.c_address); RETURN NULL; END; ' LANGUAGE 'plpgsql'; CREATE TRIGGER customer_upd_or_del AFTER UPDATE OR DELETE ON t_customer FOR EACH ROW EXECUTEPROCEDURE customer_upd_or_del(); CREATE FUNCTION order_upd_or_del() RETURNS opaque AS ' BEGIN PERFORM tidy_up_addr(old.o_shipaddr); RETURN NULL; END; ' LANGUAGE 'plpgsql'; CREATE TRIGGER order_upd_or_del AFTER UPDATE OR DELETE ON t_order FOR EACH ROW EXECUTE PROCEDUREorder_upd_or_del(); We have two tables referencing the address table. Each of get's it's own trigger, simply calling the tidy-up function that removes the address if it's not referenced any more. Thus, adding a 3rd referencing table to the schema needs to add the check for reference to one central function, plus a very simple trigger on the new table. Hope this works for you. Have fun, Jan -- #======================================================================# # It's easier to get forgiveness for being wrong than for being right. # # Let's break this rule - forgive me. # #================================================== JanWieck@Yahoo.com # _________________________________________________________ Do You Yahoo!? Get your free @yahoo.com address at http://mail.yahoo.com