Thread: Updating a table via a view

Updating a table via a view

From
Glen Eustace
Date:
I am trying to maintain a history of rows. The base table has a start
and end date. I am updating the table using a view and a rule.  The
rule, updates the end date on the current record and then inserts a new
row with the modified columns, or at least thats what I want to happen.

The update is occuring but the insert doesn't.  I get no error but no
row. The rule looks like this;

CREATE RULE a_update
    AS ON UPDATE TO a DO INSTEAD
        (UPDATE a_hist
            SET tend = now()
            WHERE (a.x = old.x)
              AND (a.tend = 'infinity'::timestamptz);
         INSERT INTO a_hist (
            x,
            tstart,
            tend,
            y,
            z
         ) VALUES (
            new.x,
            now(),
            'infinity'::timestamptz,
            new.y,
            new.z
         );
        );

Any pointer as to what I am doing wrong ?

--

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Glen and Rosanne Eustace,
GodZone Internet Services, a division of AGRE Enterprises Ltd.,
P.O. Box 8020, Palmerston North, New Zealand 5301
Ph/Fax: +64 6 357 8168, Mob: +64 21 424 015



Re: Updating a table via a view

From
ahoward
Date:
On Mon, 10 Feb 2003, Glen Eustace wrote:

glen-

there is a package in the contrib directory :

  postgresql-7.2.2/contrib/spi/timetravel.*

or something similar, which does this autoamtically for you.  it is very
slick.

-a

> I am trying to maintain a history of rows. The base table has a start
> and end date. I am updating the table using a view and a rule.  The
> rule, updates the end date on the current record and then inserts a new
> row with the modified columns, or at least thats what I want to happen.
>
> The update is occuring but the insert doesn't.  I get no error but no
> row. The rule looks like this;
>
> CREATE RULE a_update
>     AS ON UPDATE TO a DO INSTEAD
>         (UPDATE a_hist
>             SET tend = now()
>             WHERE (a.x = old.x)
>               AND (a.tend = 'infinity'::timestamptz);
>          INSERT INTO a_hist (
>             x,
>             tstart,
>             tend,
>             y,
>             z
>          ) VALUES (
>             new.x,
>             now(),
>             'infinity'::timestamptz,
>             new.y,
>             new.z
>          );
>         );
>
> Any pointer as to what I am doing wrong ?
>
>

--

 ====================================
 | Ara Howard
 | NOAA Forecast Systems Laboratory
 | Information and Technology Services
 | Data Systems Group
 | R/FST 325 Broadway
 | Boulder, CO 80305-3328
 | Email: ahoward@fsl.noaa.gov
 | Phone:  303-497-7238
 | Fax:    303-497-7259
 ====================================


Re: Updating a table via a view

From
"Shridhar Daithankar"
Date:
> > I am trying to maintain a history of rows. The base table has a start
> > and end date. I am updating the table using a view and a rule.  The
> > rule, updates the end date on the current record and then inserts a new
> > row with the modified columns, or at least thats what I want to happen.
> >
> > The update is occuring but the insert doesn't.  I get no error but no
> > row. The rule looks like this;
> > CREATE RULE a_update
> >     AS ON UPDATE TO a DO INSTEAD
> >         (UPDATE a_hist
> >             SET tend = now()
> >             WHERE (a.x = old.x)
> >               AND (a.tend = 'infinity'::timestamptz);
> >          INSERT INTO a_hist (
> >             x,
> >             tstart,
> >             tend,
> >             y,
> >             z
> >          ) VALUES (
> >             new.x,
> >             now(),
> >             'infinity'::timestamptz,
> >             new.y,
> >             new.z
> >          );
> >         );

I suggest you put all things in a pl/pgsql function and callt that function in
instead rule. It might be that it takes that ';' as end of the SQL command.

HTH

Bye
 Shridhar

--
We'll pivot at warp 2 and bring all tubes to bear, Mr. Sulu!


Re: Updating a table via a view

From
Tom Lane
Date:
Glen Eustace <geustace@godzone.net.nz> writes:
> I am trying to maintain a history of rows. The base table has a start
> and end date. I am updating the table using a view and a rule.  The
> rule, updates the end date on the current record and then inserts a new
> row with the modified columns, or at least thats what I want to happen.

> The update is occuring but the insert doesn't.  I get no error but no
> row. The rule looks like this;

> CREATE RULE a_update
>     AS ON UPDATE TO a DO INSTEAD
>         (UPDATE a_hist
>             SET tend = now()
>             WHERE (a.x = old.x)
>               AND (a.tend = 'infinity'::timestamptz);
>          INSERT INTO a_hist (
>             x,
>             tstart,
>             tend,
>             y,
>             z
>          ) VALUES (
>             new.x,
>             now(),
>             'infinity'::timestamptz,
>             new.y,
>             new.z
>          );
>         );

> Any pointer as to what I am doing wrong ?

Is the base table actually a table?  Or is it a view on a_hist?
(Given that you say "DO INSTEAD", I'm suspicious it's a view.)
If it's a view, then the likely problem is that after the first
UPDATE, the view row that the notional UPDATE is for doesn't exist
anymore.  Then the INSERT doesn't fire, because it's really been
rewritten into something along the lines of

INSERT INTO a_hist (...)
  SELECT new.x, now(), 'infinity'::timestamptz, new.y, new.z
  FROM view WHERE view-conditions AND original-update's-conditions

If I'm guessing correctly that the view-conditions include something
about "a.tend < infinity", then this will produce no rows to insert.

I would recommend that you turn "a" into an actual table that actually
stores the current values of x,y,z.  Then the rule would become DO
instead of DO INSTEAD, but it should work the way you expect.
(You'd also have the option of using a trigger instead of a rule to
update the history table, which might be better for performance.)

BTW, another common gotcha with rules is that since they're really
macros, you have to worry about multiple evaluations of arguments.
In this example, if you tried using something like nextval() as the
new value in an UPDATE, say
    UPDATE a SET x = nextval('foo') WHERE ...
then you'd find the nextval() being evaluated twice, once in the
rule and once when the A table is actually updated (assuming you
you take my advice and change it to a non-INSTEAD rule).  The only
way around that is to use a trigger instead.

            regards, tom lane

Re: Updating a table via a view

From
Glen Eustace
Date:
Thanks Tom,

> Is the base table actually a table? Or is it a view on a_hist?

It is a view.

> (Given that you say "DO INSTEAD", I'm suspicious it's a view.)
> If it's a view, then the likely problem is that after the first
> UPDATE, the view row that the notional UPDATE is for doesn't exist
> anymore.  Then the INSERT doesn't fire, because it's really been
> rewritten into something along the lines of
>
> INSERT INTO a_hist (...)
>   SELECT new.x, now(), 'infinity'::timestamptz, new.y, new.z
>   FROM view WHERE view-conditions AND original-update's-conditions
>
> If I'm guessing correctly that the view-conditions include something
> about "a.tend < infinity", then this will produce no rows to insert.

Very good guess :-) Thats very close. Given the above logic, I am not
sure I can do what I want with a view. I have previously done this sort
of things with triggers on a table but this technique was suggested by a
colleage so I thought I'd give it a try. Now that I am aware of the way
the rule is constructing the query, I might try to restructure it a bit.

--

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Glen and Rosanne Eustace,
GodZone Internet Services, a division of AGRE Enterprises Ltd.,
P.O. Box 8020, Palmerston North, New Zealand 5301
Ph/Fax: +64 6 357 8168, Mob: +64 21 424 015