Re: need hint for a trigger... - Mailing list pgsql-general

From Jan Wieck
Subject Re: need hint for a trigger...
Date
Msg-id 200103162030.PAA07568@jupiter.jw.home
Whole thread Raw
In response to Re: need hint for a trigger...  (fabrizio.ermini@sysdat.it)
List pgsql-general
fabrizio.ermini@sysdat.it wrote:
> On 16 Mar 2001, at 9:51, Jan Wieck wrote:
>
> > fabrizio.ermini@sysdat.it wrote:
> > >
> > > I would like that when a record gets changed in table1, the same
> > > changes reflect on the correspondent record in table2. Eventual
> > > changes made on the first 3 fields of table2 should be overwritten,
> > > leaving the other fields untouched.
> >
> >     Since  field1 is the key, it seems impossible to identify the
> >     row if someone changed field1 in table2. As  long  as  nobody
> >     does that,
> >
> Right. I've taken measures at application level against this
> happening, indeed; However, I'll double check them...

    You might be able to have them at the database level as well.

    If you really have a 1:1 relationship  between  table1.field1
    and table2.field1, so that whenever a key in table1 exists, a
    corresponding row in table2 must  and  vice  versa,  look  at
    this:

        CREATE TABLE table1 (
            field1    integer PRIMARY KEY,
            field2    ...
        );

        CREATE TABLE table2 (
            field1    integer PRIMARY KEY,
            field2    ...

            FOREIGN KEY (field1) REFERENCES table1 (field1)
                ON DELETE CASCADE
                ON UPDATE CASCADE
                INITIALLY DEFERRED
        );

        ALTER TABLE table1 ADD
            FOREIGN KEY (field1) REFERENCES table2 (field1)
                INITIALLY DEFERRED;

    Let's go through step by step.

    1.  Table1  is  created with the usual PRIMARY KEY on field1,
        that guarantees that field1 will be unique.

    2.  Table2 is created,  again  field1  is  guaranteed  to  be
        unique,  plus  the  DB  is  instructed  to check on every
        INSERT or UPDATE to a row if such a key exists in table1.
        The default this foreign key constraint further would be,
        that table1.field1 cannot be changed or the  row  deleted
        as  long  as there is a row in table2 referencing it. The
        ON DELETE CASCADE and ON UPDATE CASCADE told the database
        to  delete  the  referencing  rows  silently  from table2
        instead or  update  their  field1  as  well  to  let  the
        references follow.

        The INITIALLY DEFERRED I'll explain later.

    3.  We  add  a  similar foreign key constraint to table1, now
        telling that for each key in field1 a  corresponding  key
        in  table2.field1  must exist. We omit the ON ... CASCADE
        clauses, so that someone  must  delete  from  table1  and
        cannot from table2.

    What  we  got so far is that all values in table1.field1 must
    be unique, all values in table2.field1 must be  unique,  that
    each  value  in  table1.field1  must  have  a matching row in
    table2 and vice versa. Additionally, if we UPDATE  or  DELETE
    table1,  the changes "to field1" will automatically propagate
    to table2. Nobody can change  table2.field1  and  nobody  can
    delete  from  table2,  all  this  must be done via changes to
    table1 and is automated then.

    Well, now let's think how we get some data into it :-)

    At the time we insert a row into  table1,  the  corresponding
    row  in  table2  cannot  exist (up to now it's empty). So the
    constraint must reject the INSERT.  But the same happens  for
    table2,  because  we aren't able to put it into table1.  This
    is the point where the INITIALLY DEFERRED  comes  into  play.
    This  instructs,  that  the  check  of the constraint will be
    delayed until transaction commit. So the sequence

        BEGIN;
        INSERT INTO table1 ...
        INSERT INTO table2 ...
        COMMIT WORK;

    will work, because the constraints will be checked at  COMMIT
    and by then all the required rows are in place.

    For  your actual application this'd *FORCE* the programmer (I
    assume that'd be you) to use transactions to get  data  into,
    and that he cannot insert one row without the other. Whenever
    he tries to, he'll get an error and an implicit rollback from
    the database.

>
> >         CREATE FUNCTION table1_upd () RETURNS opaque AS '
> >         BEGIN
> >             UPDATE table2 SET field1 = NEW.field1,
> >                               field2 = NEW.field2,
> >                               field3 = NEW.field3
> >                    WHERE field1 = OLD.field1;
> >             RETURN NEW;
> >         END;'
> >         LANGUAGE 'plpgsql';
> >
> >         CREATE TRIGGER table1_upd AFTER UPDATE ON table1
> >             FOR EACH ROW EXECUTE PROCEDURE table1_upd ();
> >
> > Jan
> >
> Now this is what I call a good example!
> Thank you very much Jan, you've saved me a lot of time.

    We're  all  put  onto  this  earth  to accomplish a couple of
    things. Actually, I'm that  far  behind  that  I  might  live
    forever.


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


pgsql-general by date:

Previous
From: Tom Lane
Date:
Subject: Re: Problems with outer joins in 7.1beta5
Next
From: Ron Chmara
Date:
Subject: Re: ssl connections with psql