Thread: need hint for a trigger...

need hint for a trigger...

From
fabrizio.ermini@sysdat.it
Date:
Hi all. I have to write a trigger and I have never did it before, so if
there is someone who could give me a start, I will be very grateful...

I have two tables that I want to keep "partially" synced, i.e.:

table1 (field1,field2,field3)
table2 (field1,field2,field3, ... some other fields).

I've created them using the same data for the common fields, and
then populated the other fields of table2. field1 is unique key for
both tables.

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.

I was presuming this could be done with a trigger on UPDATE on
table1, but I don't know how to write it... I know the first reply that I
can expect is RTFM, but if a gentle soul has the time to write an
example...

TIA,
Ciao


/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

Fabrizio Ermini               Alternate E-mail:
C.so Umberto, 7               faermini@tin.it
loc. Meleto Valdarno          Mail on GSM: (keep it short!)
52020 Cavriglia (AR)          faermini@sms.tin.it

Re: need hint for a trigger...

From
"Richard Huxton"
Date:
From: <fabrizio.ermini@sysdat.it>

> Hi all. I have to write a trigger and I have never did it before, so if
> there is someone who could give me a start, I will be very grateful...
>
> I have two tables that I want to keep "partially" synced, i.e.:
[snip]
> 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.
>
> I was presuming this could be done with a trigger on UPDATE on
> table1, but I don't know how to write it... I know the first reply that I
> can expect is RTFM, but if a gentle soul has the time to write an
> example...

You presume right. A rule might prove more efficient (can't tell from your
example), but a trigger will work just fine.

Check the developer's docs at
http://www.postgresql.org/devel-corner/docs/programmer/

Also try http://techdocs.postgresql.org and look in PostgeSQL Notes for the
Automating Processes chapter - there are examples there (logging changes is
very similar to what you want).

Also see http://www.brasileiro.net/postgres for the brand new plpgsql
cookbook which has several examples already and should be growing all the
time.

Try adapting one of the examples you find, and if you have problems post the
code and table definitions back to the list.

One tip I can give is to build the function and trigger in a text-editor
then execute it with psql -f <file> - makes debugging much easier.

If you have any comments on any of the documentation, please let the
relevant author know, most of this stuff is brand new.

- Richard Huxton


Re: need hint for a trigger...

From
Jan Wieck
Date:
fabrizio.ermini@sysdat.it wrote:
> Hi all. I have to write a trigger and I have never did it before, so if
> there is someone who could give me a start, I will be very grateful...
>
> I have two tables that I want to keep "partially" synced, i.e.:
>
> table1 (field1,field2,field3)
> table2 (field1,field2,field3, ... some other fields).
>
> I've created them using the same data for the common fields, and
> then populated the other fields of table2. field1 is unique key for
> both tables.
>
> 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,

        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

>
> I was presuming this could be done with a trigger on UPDATE on
> table1, but I don't know how to write it... I know the first reply that I
> can expect is RTFM, but if a gentle soul has the time to write an
> example...
>
> TIA,
> Ciao
>
>
> /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
>
> Fabrizio Ermini               Alternate E-mail:
> C.so Umberto, 7               faermini@tin.it
> loc. Meleto Valdarno          Mail on GSM: (keep it short!)
> 52020 Cavriglia (AR)          faermini@sms.tin.it
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
>


--

#======================================================================#
# 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


Re: need hint for a trigger...

From
fabrizio.ermini@sysdat.it
Date:
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...

>         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.

Ciao!


/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

Fabrizio Ermini               Alternate E-mail:
C.so Umberto, 7               faermini@tin.it
loc. Meleto Valdarno          Mail on GSM: (keep it short!)
52020 Cavriglia (AR)          faermini@sms.tin.it

Re: need hint for a trigger...

From
Jan Wieck
Date:
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