Re: Insert into ... Select ... From ... too intelligent transaction

From: Roman Neuhauser <neuhauser(at)sigpipe(dot)cz>
To: "Rose, Juergen" <Juergen(dot)Rose(at)sag-el(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Insert into ... Select ... From ... too intelligent transaction
Date: 2005-07-22 10:51:31
Message-ID: 20050722105131.GA16075@isis.sigpipe.cz
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

# Juergen(dot)Rose(at)sag-el(dot)com / 2005-07-22 09:10:01 +0200:
> > # Juergen(dot)Rose(at)sag-el(dot)com / 2005-07-21 19:11:04 +0200:
> > > I use some updateable views to handle my data (which are amazingly
> > > slow), which gives me ultimate flexibility to handle my data.
> > >
> > > there are some insert rules which use currval() to get the last
> > > sequence id for my data which I have to insert.
> > >
> > > The problem now is, it works fine if I do the statement via normal
> > > insert into satatements, even within a transaction block. So far so
> > > good. But If I migrate my old data via **Insert into my_new_view
> > > Select ... From my_old_table**, Only the last retrieved value of the
> > > sequences is used which blows my whole internal logic, because
> > > obviously I want to use the current (for that row) and not the last
> > > id.

> create table olddata(
> id int,
> lastname varchar(50),
> firstname varchar(50)
> );
>
> insert into olddata values (1, 'Picard', 'Jean Luc');
> insert into olddata values (3, 'Spock', 'Harold');
> insert into olddata values (6, 'Zimmerman', 'Doc');
> insert into olddata values (9, 'Lefler', 'Robin');
> insert into olddata values (10, 'Kirk', 'James T.');
>
> create table neworg(
> orgid serial,
> legacyid int,
> orgname varchar(100)
> );
>
> create table newpersons(
> persid serial,
> orgid int,
> lastname varchar(50),
> firstname varchar(50)
> );
>
> create view v_persons as
> select
> P.orgid,
> O.legacyid,
> P.persid,
> P.lastname,
> P.firstname
> from
> neworg O,
> newpersons P
> where
> O.orgid = P.orgid;
>
> create or replace rule r_insert_a_organisation as on insert to v_persons
> do instead
> insert into neworg(
> orgid,
> legacyid,
> orgname)
> values (
> coalesce(new.orgid, nextval('neworg_orgid_seq')),
> new.legacyid,
> coalesce(new.lastname, '') || ', ' || coalesce(new.firstname,
> '')
> );
>
> create or replace rule r_insert_b_persons as on insert to v_persons
> do
> insert into newpersons(
> orgid,
> lastname,
> firstname)
> values (
> coalesce(new.orgid, currval('neworg_orgid_seq')),
> new.lastname,
> new.firstname
> );

> /* test 3 */
> insert into v_persons(legacyid, lastname, firstname) select * from
> olddata;
> select * from v_persons;
>
> /* my result:
>
> orgid | legacyid | persid | lastname | firstname
> -------+----------+--------+-----------+-----------
> 1 | 11 | 1 | Dax | Jadzia
> 2 | 12 | 2 | Bashir | Dr.
> 3 | 13 | 3 | | Odo
> 4 | 14 | 4 | | Worf
> 9 | 10 | 5 | Picard | Jean Luc
> 9 | 10 | 6 | Spock | Harold
> 9 | 10 | 7 | Zimmerman | Doc
> 9 | 10 | 8 | Lefler | Robin
> 9 | 10 | 9 | Kirk | James T.
> (9 rows)
>
> */
>
> And exactly in test 3 you see my problem, it should actually look like
>
> orgid | legacyid | persid | lastname | firstname
> -------+----------+--------+-----------+-----------
> 1 | 11 | 1 | Dax | Jadzia
> 2 | 12 | 2 | Bashir | Dr.
> 3 | 13 | 3 | | Odo
> 4 | 14 | 4 | | Worf
> 5 | 1 | 5 | Picard | Jean Luc
> 6 | 3 | 6 | Spock | Harold
> 7 | 6 | 7 | Zimmerman | Doc
> 8 | 9 | 8 | Lefler | Robin
> 9 | 10 | 9 | Kirk | James T.
>
> Why the heck gets the wrong data inserted if it is an int!!!???
>
> I hope somebody will help me out on this, for me this looks very much
> like a bug.

PostgreSQL did exactly what you told it to do. RULEs *rewrite
queries*, which means the INSERT INTO ... SELECT gets transformed to
something like

insert into neworg( orgid, legacyid, orgname)
select
coalesce(new.orgid, nextval('neworg_orgid_seq')),
new.id as legacyid,
coalesce(new.lastname, '') || ', ' || coalesce(new.firstname, '')
from olddata new;

insert into newpersons ( orgid, lastname, firstname)
select
coalesce(new.orgid, currval('neworg_orgid_seq')),
new.lastname,
new.firstname
from olddata new;

and this is run once, not for every row. IOW, you'll have this
problem with any multi-row inserts.

--
How many Vietnam vets does it take to screw in a light bulb?
You don't know, man. You don't KNOW.
Cause you weren't THERE. http://bash.org/?255991

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Rose, Juergen 2005-07-22 11:04:27 Re: Insert into ... Select ... From ... too intelligent transaction
Previous Message Richard Huxton 2005-07-22 10:08:32 Re: Connection error