Trigger function which inserts into table; values from lookup

Started by novnovalmost 19 years ago11 messagesgeneral
Jump to latest
#1novnov
novnovice@gmail.com

Not sure it the title of this post gives a clear message...I need to have a
trigger function insert records into a table under certain conditions, where
the values inserted are partially based on the results of a select query.

table t_item
item_id (pk)
item_name
item_org_id
item_active

table t_koaitem
koaitem_id (pk)
koaitem_koa_id
koaitem_item_id

table t_koa
koa_id (pk)
koa_name
koa_active

Any time a t_item record is created or updated, and item_active = true, I
need to insert records referencing that item into t_koaitem. One record
should be entered into t_koaitem for each t_koa record that has koa_active =
true. The koa_id value in each t_koa rec would be inserted into
koaitem_koa_id.

And additional aspect is that there is a unique key on koaitem_koa_id and
koaitem_item_id; and the pair of values being inserted may already exist in
t_koaitem. I've not looked much yet but have not seen error trapping that
would essentially handle the dupe key by skipping that insert and moving on
to the next.

I can post my own attempt but it lacks any error handling and does not work
in general. If plpgsql is not the best lang for this I could use python. I
know this is a lot to ask for but I'm all thumbs with postres function
syntax. I've written simple functions and trigger functions but this one is
rather stiff.

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10703268
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#2novnov
novnovice@gmail.com
In reply to: novnov (#1)
Re: Trigger function which inserts into table; values from lookup

So, I may have hammered out the basic trigger function. The error trapping
part is a complete mystery to me. I'll post the trigger function below in
the hopes that someone will at least comment on the error handling part.

The error, as expected is 'duplicate key violates unique contraint blah
blah" because the routine tries to append a rec for each item; most items
will already have a t_koaitem record. I am not looping through the tables
and evaluating the need to append a rec because I thought this approach
might be more efficient.

Something else I need to deal with is that when a new record is being
inserted, the old.item_active = false evalualtion blows up. I will probably
have that handled pretty soon but if anyone wishs to spell it out that'd be
great.

CREATE or REPLACE FUNCTION "public"."tproc_handle_item_active"()
RETURNS "pg_catalog"."trigger" AS
$BODY$
DECLARE
rec_item record;
int_org_id integer;

BEGIN

-- whenever an item is set active; create entries in the following
table:
-- t_koaitem

if new.item_active = true and old.item_active = false
then
select * into rec_item from t_item
where item_id = new.item_id;

int_org_id = rec_item.item_org_id;

insert into t_koaitem (koai_koa_id, koai_item_id,
koai_item_locked, koai_user_idm)
SELECT t_koa.koa_id, t_item.item_id, false as lockstatus,
t_item.item_user_idm
FROM t_item INNER JOIN t_koa ON t_item.item_org_id =
t_koa.koa_org_id
WHERE (((t_item.item_active)=True)
AND ((t_koa.koa_koastatus_id)=2 Or
(t_koa.koa_koastatus_id)=3)
AND ((t_item.item_org_id)=int_org_id));
end if;
return null;

END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10709563
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#3novnov
novnovice@gmail.com
In reply to: novnov (#2)
Re: Trigger function which inserts into table; values from lookup

Inching closer; the following handles the dupe key error but doesn't insert
the rows it should either. So, the exception is ending the insert, and not
continuing to insert for rows that don't violate the unique key restraint.
Is there a way around this or will I need to take a different approach?

CREATE or REPLACE FUNCTION "public"."tproc_handle_item_active"()
RETURNS "pg_catalog"."trigger" AS
$BODY$
DECLARE
rec_item record;
int_org_id integer;

BEGIN

-- whenever an item is set active; create entries in the following
table:
-- t_koaitem

if new.item_active = true and old.item_active = false
then
select * into rec_item from t_item
where item_id = new.item_id;
int_org_id = rec_item.item_org_id;
BEGIN
insert into t_koaitem (koai_koa_id, koai_item_id,
koai_item_locked, koai_user_idm)
SELECT t_koa.koa_id, t_item.item_id, false as lockstatus,
t_item.item_user_idm
FROM t_item INNER JOIN t_koa ON t_item.item_org_id =
t_koa.koa_org_id
WHERE (((t_item.item_active)=True)
AND ((t_koa.koa_koastatus_id)=2 Or
(t_koa.koa_koastatus_id)=3)
AND ((t_item.item_org_id)=int_org_id));
EXCEPTION
when unique_violation then
-- do nothing?
END;
end if;
return null;

END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10709966
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#4Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: novnov (#3)
Re: Trigger function which inserts into table; values from lookup

novnov escribi�:

Inching closer; the following handles the dupe key error but doesn't insert
the rows it should either. So, the exception is ending the insert, and not
continuing to insert for rows that don't violate the unique key restraint.
Is there a way around this or will I need to take a different approach?

You have to make the function return NEW, not NULL, if this is a BEFORE
trigger.

--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#5novnov
novnovice@gmail.com
In reply to: Alvaro Herrera (#4)
Re: Trigger function which inserts into table; values from lookup

It's an after trigger.

Any clue re my question?

Alvaro Herrera-7 wrote:

novnov escribió:

Inching closer; the following handles the dupe key error but doesn't
insert
the rows it should either. So, the exception is ending the insert, and
not
continuing to insert for rows that don't violate the unique key
restraint.
Is there a way around this or will I need to take a different approach?

You have to make the function return NEW, not NULL, if this is a BEFORE
trigger.

--
Alvaro Herrera
http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10711732
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: novnov (#5)
Re: Trigger function which inserts into table; values from lookup

novnov <novnovice@gmail.com> writes:

Any clue re my question?

You've placed the INSERT inside the BEGIN/EXCEPTION block, ergo it's
part of the work to be rolled back on exception.

regards, tom lane

#7novnov
novnovice@gmail.com
In reply to: Tom Lane (#6)
Re: Trigger function which inserts into table; values from lookup

OK, but, how do I set this up to do what I need? I want an insert that would
create a dupe key to be rolled back, and inserts that would not create dupe
keys to be committed.

Tom Lane-2 wrote:

novnov <novnovice@gmail.com> writes:

Any clue re my question?

You've placed the INSERT inside the BEGIN/EXCEPTION block, ergo it's
part of the work to be rolled back on exception.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10713002
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

In reply to: novnov (#7)
Re: Trigger function which inserts into table; values from lookup

On 21/05/2007 05:26, novnov wrote:

OK, but, how do I set this up to do what I need? I want an insert that would
create a dupe key to be rolled back, and inserts that would not create dupe
keys to be committed.

Do you specifically need it in a trigger? I seem to recall an example in
the docs for pl/pgsql demonstrating a function to do something like this
- I think it tries an INSERT, and when a duplicate key raises an
exception, it does an update instead. - You could easily adapt this to
your purposes.

Ray.

---------------------------------------------------------------
Raymond O'Donnell, Director of Music, Galway Cathedral, Ireland
rod@iol.ie
---------------------------------------------------------------

#9novnov
novnovice@gmail.com
In reply to: Raymond O'Donnell (#8)
Re: Trigger function which inserts into table; values from lookup

No and update would not be needed; but the capability would be close enough,
I'd just skip the update, do nothing for that record.

But from the sound of it, the example you're suggesting involves a loop or
something of that order. I could have written this using a loop but thought
a bulk operation that essentially worked like "insert new rows for the set
and while doing so, silently skip inserts which would cause dupe key
violations". I explained all of this in the earlier messages. I thought it
might be more effenient to handle without a loop. I've been able to do this
kind of thing with other databases; essentially instruct the routine to
ignore errors silently, commit what it can commit.

Raymond O'Donnell wrote:

On 21/05/2007 05:26, novnov wrote:

OK, but, how do I set this up to do what I need? I want an insert that
would
create a dupe key to be rolled back, and inserts that would not create
dupe
keys to be committed.

Do you specifically need it in a trigger? I seem to recall an example in
the docs for pl/pgsql demonstrating a function to do something like this
- I think it tries an INSERT, and when a duplicate key raises an
exception, it does an update instead. - You could easily adapt this to
your purposes.

Ray.

---------------------------------------------------------------
Raymond O'Donnell, Director of Music, Galway Cathedral, Ireland
rod@iol.ie
---------------------------------------------------------------

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10720190
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

#10William Leite Araújo
william.bh@gmail.com
In reply to: novnov (#9)
Re: Trigger function which inserts into table; values from lookup

Maybe you can use a "LEFT OUTER JOIN" ...

CREATE or REPLACE FUNCTION "public"."tproc_handle_item_active"()
RETURNS "pg_catalog"."trigger" AS
$BODY$
DECLARE
rec_item record;
int_org_id integer;

BEGIN

-- whenever an item is set active; create entries in the following
table:
-- t_koaitem

if new.item_active = true and old.item_active = false
then
select * into rec_item from t_item
where item_id = new.item_id;

int_org_id = rec_item.item_org_id;

insert into t_koaitem (koai_koa_id, koai_item_id,
koai_item_locked, koai_user_idm)
SELECT t_koa.koa_id, t_item.item_id, false as lockstatus,
t_item.item_user_idm
FROM t_item INNER JOIN t_koa ON t_item.item_org_id =
t_koa.koa_org_id
LEFT OUTER JOIN t_koaitem ON (koaitem_koa_id =
t_koa.koa_id AND koaitem_item_id = t_item.item_id)
WHERE (((t_item.item_active)=True)
AND ((t_koa.koa_koastatus_id)=2 Or
(t_koa.koa_koastatus_id)=3)
AND ((t_item.item_org_id)=int_org_id)
AND (t_koaitem.koaitem_item_id IS NULL AND koaitem_item_id
IS NULL)
);
end if;
return null;

END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

2007/5/21, novnov <novnovice@gmail.com>:

No and update would not be needed; but the capability would be close
enough,
I'd just skip the update, do nothing for that record.

But from the sound of it, the example you're suggesting involves a loop or
something of that order. I could have written this using a loop but
thought
a bulk operation that essentially worked like "insert new rows for the set
and while doing so, silently skip inserts which would cause dupe key
violations". I explained all of this in the earlier messages. I thought it
might be more effenient to handle without a loop. I've been able to do
this
kind of thing with other databases; essentially instruct the routine to
ignore errors silently, commit what it can commit.

Raymond O'Donnell wrote:

On 21/05/2007 05:26, novnov wrote:

OK, but, how do I set this up to do what I need? I want an insert that
would
create a dupe key to be rolled back, and inserts that would not create
dupe
keys to be committed.

Do you specifically need it in a trigger? I seem to recall an example in
the docs for pl/pgsql demonstrating a function to do something like this
- I think it tries an INSERT, and when a duplicate key raises an
exception, it does an update instead. - You could easily adapt this to
your purposes.

Ray.

---------------------------------------------------------------
Raymond O'Donnell, Director of Music, Galway Cathedral, Ireland
rod@iol.ie
---------------------------------------------------------------

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

--
View this message in context:
http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10720190
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org/

--
William Leite Araújo
Analista de Banco de Dados - QualiConsult

#11novnov
novnovice@gmail.com
In reply to: William Leite Araújo (#10)
Re: Trigger function which inserts into table; values from lookup

Yes, I think that would work and mabye I'll use that approach. But is there
no way to implement as I orginally intended?

Also, am I right in thinking that this approach is more efficient than a
looping operation?

William Leite Araújo wrote:

Maybe you can use a "LEFT OUTER JOIN" ...

CREATE or REPLACE FUNCTION "public"."tproc_handle_item_active"()
RETURNS "pg_catalog"."trigger" AS
$BODY$
DECLARE
rec_item record;
int_org_id integer;

BEGIN

-- whenever an item is set active; create entries in the following
table:
-- t_koaitem

if new.item_active = true and old.item_active = false
then
select * into rec_item from t_item
where item_id = new.item_id;

int_org_id = rec_item.item_org_id;

insert into t_koaitem (koai_koa_id, koai_item_id,
koai_item_locked, koai_user_idm)
SELECT t_koa.koa_id, t_item.item_id, false as lockstatus,
t_item.item_user_idm
FROM t_item INNER JOIN t_koa ON t_item.item_org_id =
t_koa.koa_org_id
LEFT OUTER JOIN t_koaitem ON (koaitem_koa_id =
t_koa.koa_id AND koaitem_item_id = t_item.item_id)
WHERE (((t_item.item_active)=True)
AND ((t_koa.koa_koastatus_id)=2 Or
(t_koa.koa_koastatus_id)=3)
AND ((t_item.item_org_id)=int_org_id)
AND (t_koaitem.koaitem_item_id IS NULL AND
koaitem_item_id
IS NULL)
);
end if;
return null;

END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

2007/5/21, novnov <novnovice@gmail.com>:

No and update would not be needed; but the capability would be close
enough,
I'd just skip the update, do nothing for that record.

But from the sound of it, the example you're suggesting involves a loop
or
something of that order. I could have written this using a loop but
thought
a bulk operation that essentially worked like "insert new rows for the
set
and while doing so, silently skip inserts which would cause dupe key
violations". I explained all of this in the earlier messages. I thought
it
might be more effenient to handle without a loop. I've been able to do
this
kind of thing with other databases; essentially instruct the routine to
ignore errors silently, commit what it can commit.

Raymond O'Donnell wrote:

On 21/05/2007 05:26, novnov wrote:

OK, but, how do I set this up to do what I need? I want an insert that
would
create a dupe key to be rolled back, and inserts that would not create
dupe
keys to be committed.

Do you specifically need it in a trigger? I seem to recall an example

in

the docs for pl/pgsql demonstrating a function to do something like

this

- I think it tries an INSERT, and when a duplicate key raises an
exception, it does an update instead. - You could easily adapt this to
your purposes.

Ray.

---------------------------------------------------------------
Raymond O'Donnell, Director of Music, Galway Cathedral, Ireland
rod@iol.ie
---------------------------------------------------------------

---------------------------(end of

broadcast)---------------------------

TIP 2: Don't 'kill -9' the postmaster

--
View this message in context:
http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10720190
Sent from the PostgreSQL - general mailing list archive at Nabble.com.

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org/

--
William Leite Araújo
Analista de Banco de Dados - QualiConsult

--
View this message in context: http://www.nabble.com/Trigger-function-which-inserts-into-table--values-from-lookup-tf3784731.html#a10721651
Sent from the PostgreSQL - general mailing list archive at Nabble.com.