PostgreSQL Help
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsDatabasesPostgreSQL Help

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old December 19th, 2003, 01:38 PM
nednieuws nednieuws is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Sep 2003
Posts: 70 nednieuws User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 7 m 58 sec
Reputation Power: 6
Trigger example needed.

Just starting out with PostgreSQL, and as I learn best by dissecting examples, I'm hoping for someone to give me the answer to the following:

Upon insertion of a new row a table entry, I'd like to insert an additional row in table thread. The tables are laid out as follows (only relevant columns shown):

Code:
entry
(
  entry_id int4,
  entry_title varchar(255)
)

thread
(
  thread_entry_id int4,
  thread_title varchar(255)
)


After the insert on table entry, I want the following insert on table thread:

Code:
INSERT INTO thread
(thread_entry_id, thread_title)
VALUES
(NEW.entry_id, NEW.entry_title)


If someone can give me the complete statements for the function and the trigger I'm sure I'll be able to figure out how to do the rest of the triggers. Btw, I've been succesful in creating functions, but this baffles me.

Thanks.

--
Charles.

Reply With Quote
  #2  
Old December 19th, 2003, 03:27 PM
metaBarf metaBarf is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Posts: 373 metaBarf User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 3 h 49 m 6 sec
Reputation Power: 6
you can probably use AFTER INSERT in the trigger creation, but if you use BEFORE it will just put that record in thread just how you want. you're not doing any iteration or any dependent INSERTion into thread, so you don't need any control structures or cursors (by not including these ideas in this example you are missing out on some of the key concepts of plpgsql). If you are repeatedly dropping and recreating the triggers on your db then you will have to do a dropdb and createdb for each time, because if you drop a trigger and then create a new one with the same name then run it, the function will be looking for the wrong OID.


CREATE OR REPLACE FUNCTION fill_thread_too RETURNS OPAQUE AS '
DECLARE
BEGIN
INSERT INTO thread
(thread_entry_id, thread_title)
VALUES
(NEW.entry_id, NEW.entry_title);
RETURN NEW;
END;
' LANGUAGE 'plpgsql';



CREATE TRIGGER fill_thread_trigger
BEFORE INSERT
ON entry
FOR EACH ROW
EXECUTE PROCEDURE fill_thread_too();

Reply With Quote
  #3  
Old December 19th, 2003, 03:37 PM
metaBarf metaBarf is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Posts: 373 metaBarf User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 3 h 49 m 6 sec
Reputation Power: 6
don't think I am trying to be an *** or something, but I am going to post a slightly more involved trigger procedure that may assist you in the future. I have posted these functions before so it's sort of redundant for others who may read this so I am sorry I don't want to write any new ones ri now (it's friday)

Although it pretty clearly represents our schema here at work I think it is an abstract enough notion (and really a small piece of the db) that it is no matter to them (and it's code that I wrote)

Code:

CREATE OR REPLACE FUNCTION mbc_update_function () RETURNS OPAQUE AS '
       DECLARE
              old_key_refcursor          refcursor;
              new_key_refcursor          refcursor;
              old_count_refcursor        refcursor;
              new_count_refcursor        refcursor;
              get_current_key CURSOR FOR SELECT MAX(combination_key) FROM mediacombinations;
              old_key                    INT4;
              new_key                    INT4;
              old_new_count              INT4;
              new_new_count              INT4;
              new_combination_key        INT4;
       BEGIN
           	OPEN old_key_refcursor FOR SELECT combination_key FROM mediacombinations WHERE media_type = OLD.media_type AND media_size = OLD.media_size AND media_orientation = OLD.media_orientation AND sheets_per_media_cassette = OLD.sheets_per_media_cassette AND target_printer = OLD.target_printer AND allocated = OLD.allocated;
		 FETCH old_key_refcursor INTO old_key;
                CLOSE old_key_refcursor;
                IF (old_key IS NOT NULL) THEN
                    OPEN old_count_refcursor FOR SELECT total_count FROM mediacombinations WHERE combination_key = old_key;
                    FETCH old_count_refcursor INTO old_new_count;
                    old_new_count:=old_new_count-1;
                   -- UPDATE mediacombinations SET total_count = old_new_count WHERE  media_type = OLD.media_type AND media_size = OLD.media_size AND media_orientation = OLD.media_orientation AND sheets_per_media_cassette = OLD.sheets_per_media_cassette AND target_printer = OLD.target_printer AND allocated = OLD.allocated;
                    UPDATE mediacombinations SET total_count = old_new_count WHERE combination_key = old_key;
		    CLOSE old_count_refcursor;
                    OPEN new_key_refcursor FOR SELECT combination_key FROM mediacombinations WHERE media_type = NEW.media_type AND media_size = NEW.media_size AND media_orientation = NEW.media_orientation AND sheets_per_media_cassette = NEW.sheets_per_media_cassette AND target_printer = NEW.target_printer AND allocated = NEW.allocated;
                    FETCH new_key_refcursor INTO new_key;
                    CLOSE new_key_refcursor;
		    IF (new_key IS NOT NULL) THEN
                    	OPEN new_count_refcursor FOR SELECT total_count FROM mediacombinations WHERE combination_key = new_key;
                    	FETCH new_count_refcursor INTO new_new_count;
                    	new_new_count:=new_new_count+1;
                    	UPDATE mediacombinations SET total_count = new_new_count WHERE  media_type = NEW.media_type AND media_size = NEW.media_size AND media_orientation = NEW.media_orientation AND sheets_per_media_cassette = NEW.sheets_per_media_cassette AND target_printer = NEW.target_printer AND allocated = NEW.allocated;
                    	CLOSE new_count_refcursor;
		    ELSE --new_key was null and that combination not added yet
			  OPEN get_current_key;
                          FETCH get_current_key INTO new_combination_key;
                    	  CLOSE get_current_key;
                    	  new_combination_key:=new_combination_key+1;
                    	  INSERT INTO mediacombinations ( combination_key, media_size, media_type, media_orientation, sheets_per_media_cassette, target_printer, total_count, legal_flag, allocated) VALUES ( new_combination_key, NEW.media_size, NEW.media_type, NEW.media_orientation, NEW.sheets_per_media_cassette, NEW.target_printer, 1, ''f'', NEW.allocated);
		    END IF;
                ELSE
                    OPEN old_count_refcursor FOR SELECT total_count FROM mediacombinations WHERE combination_key = old_key;
                    FETCH old_count_refcursor INTO old_new_count;
                    old_new_count:=old_new_count-1;
                    UPDATE mediacombinations SET total_count = old_new_count WHERE  media_type = OLD.media_type AND media_size = OLD.media_size AND media_orientation = OLD.media_orientation AND sheets_per_media_cassette = OLD.sheets_per_media_cassette AND target_printer = OLD.target_printer AND allocated = OLD.allocated;
                    CLOSE old_count_refcursor;
                    OPEN get_current_key;
                    FETCH get_current_key INTO new_combination_key;
                    CLOSE get_current_key;
                    new_combination_key:=new_combination_key+1;
                    INSERT INTO mediacombinations ( combination_key, media_size, media_type, media_orientation, sheets_per_media_cassette, target_printer, total_count, legal_flag, allocated) VALUES ( new_combination_key, NEW.media_size, NEW.media_type, NEW.media_orientation, NEW.sheets_per_media_cassette, NEW.target_printer, 1, ''f'', NEW.allocated);
                END IF;
                RETURN NEW;
       END;
       ' LANGUAGE 'plpgsql';                 --return to single quote

DROP TRIGGER mbc_update_trigger ON mediabarcodes;
CREATE TRIGGER mbc_update_trigger
BEFORE UPDATE
ON mediabarcodes
FOR EACH ROW
EXECUTE PROCEDURE mbc_update_function();

Reply With Quote
  #4  
Old December 19th, 2003, 04:59 PM
nednieuws nednieuws is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Sep 2003
Posts: 70 nednieuws User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 7 m 58 sec
Reputation Power: 6
Quote:
Originally posted by metaBarf
If you are repeatedly dropping and recreating the triggers on your db then you will have to do a dropdb and createdb for each time, because if you drop a trigger and then create a new one with the same name then run it, the function will be looking for the wrong OID.


Huh? So if I drop a trigger and wish to recreate it using the same name I need to dump/reload the whole db?

Quote:
CREATE OR REPLACE FUNCTION fill_thread_too RETURNS OPAQUE


I assume I can safely use RETURNS TRIGGER instead of RETURNS OPAQUE? I'm using 7.4 and that's how I interpret this page.

Anyway, thanks a million. The code I had tried was really different (translated from Oracle).

Reply With Quote
  #5  
Old December 19th, 2003, 05:17 PM
nednieuws nednieuws is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Sep 2003
Posts: 70 nednieuws User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 7 m 58 sec
Reputation Power: 6
The statements were accepted, but it fails on execution :-(. The error message is:

ERROR: syntax error at or near "NEW" at character 261

Here's the code:
Code:
CREATE OR REPLACE FUNCTION dvnl.create_matching_thread() RETURNS TRIGGER AS '
DECLARE
BEGIN
INSERT INTO dvnl.dvnl_thread
(thread_id, thread_is_active, thread_user_id, thread_total_messages, thread_entry_id, thread_forum_id, thread_last_modified, thread_date_opened, thread_label)
VALUES
(DEFAULT, true, 100000, 0, NEW.entry_id, 100000, DEFAULT, DEFAULT, NEW.entry_title)
RETURN NEW;
END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER create_matching_thread_trigger
BEFORE INSERT
ON dvnl.mt_entry
FOR EACH ROW
EXECUTE PROCEDURE dvnl.create_matching_thread();


Here's the definition of the threads table:
Code:
CREATE TABLE dvnl.dvnl_thread
(
  thread_id serial NOT NULL,
  thread_is_active bool NOT NULL DEFAULT false,
  thread_user_id int4 NOT NULL,
  thread_total_messages int4 NOT NULL DEFAULT 0,
  thread_entry_id int4,
  thread_forum_id int4 NOT NULL,
  thread_last_modified timestamp(0) NOT NULL DEFAULT now(),
  thread_date_opened timestamp(0) NOT NULL DEFAULT now(),
  thread_date_closed timestamp(0),
  thread_label varchar(255) NOT NULL,
  CONSTRAINT pk_thread_id PRIMARY KEY (thread_id),
  CONSTRAINT fk_forum_id FOREIGN KEY (thread_forum_id) REFERENCES dvnl.dvnl_forum (forum_id) ON UPDATE RESTRICT ON DELETE RESTRICT,
  CONSTRAINT fk_user_id FOREIGN KEY (thread_user_id) REFERENCES dvnl.dvnl_user (user_id) ON UPDATE RESTRICT ON DELETE RESTRICT,
  CONSTRAINT not_empty_thread_label CHECK thread_label::text <> ''::text
) WITH OIDS;


I checked the manual, and I believe the NEW syntax is correct. I should tell you that all tables reside in schema 'dvnl', but I guess for an expert like you that's clear from the code.

--
Charles.

Reply With Quote
  #6  
Old December 19th, 2003, 05:55 PM
nednieuws nednieuws is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Sep 2003
Posts: 70 nednieuws User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 7 m 58 sec
Reputation Power: 6
Solved!

Of course, it was a typo on my end:
Code:
CREATE OR REPLACE FUNCTION dvnl.create_matching_thread() RETURNS TRIGGER AS '
DECLARE
BEGIN
INSERT INTO dvnl.dvnl_thread
(thread_id, thread_is_active, thread_user_id, thread_total_messages, thread_entry_id, thread_forum_id, thread_last_modified, thread_date_opened, thread_label)
VALUES
(DEFAULT, true, 100000, 0, NEW.entry_id, 100000, DEFAULT, DEFAULT, NEW.entry_title); <-- missing colon!
RETURN NEW;
END;
' LANGUAGE 'plpgsql';


--
Charles.

Reply With Quote
  #7  
Old December 19th, 2003, 06:00 PM
nednieuws nednieuws is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Sep 2003
Posts: 70 nednieuws User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 7 m 58 sec
Reputation Power: 6
Now, when the entry is deleted, the thread and all the entries in the message table should also be deleted. What would be best:

1. cascaded delete
2. trigger

--
Charles.

Reply With Quote
  #8  
Old December 19th, 2003, 06:37 PM
metaBarf metaBarf is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Posts: 373 metaBarf User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 3 h 49 m 6 sec
Reputation Power: 6
Quote:
Originally posted by nednieuws
Now, when the entry is deleted, the thread and all the entries in the message table should also be deleted. What would be best:

1. cascaded delete
2. trigger

--
Charles.


1. It depends on how strongly you have defined the referential integrity of the tables. I believe using ON DELETE CASCADE would have to be using tables that can be NATURAL JOINed (i.e. foreign keys have the same column names)
also, have you defined the tables with explicit CONSTRAINT syntax foreign keys, or how is it mentioned in the table creation? Either one will work just fine in fact I think there are 3 ways to make a foreign key in the table creation but I just wanted to see if that is what you had done.

2. Sure, you can write a trigger to do a delete. Remember to return the appropriate value RETURN OLD or RETURN NULL depending on if you want the DELETE to succeed or not.

Reply With Quote
  #9  
Old December 19th, 2003, 06:50 PM
metaBarf metaBarf is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Posts: 373 metaBarf User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 3 h 49 m 6 sec
Reputation Power: 6
Quote:
Originally posted by nednieuws
Huh? So if I drop a trigger and wish to recreate it using the same name I need to dump/reload the whole db?



I have had trouble in the past, yes. If you delete the trigger and the function, then it should be ok. I do'nt know if it really does the CREATE OR REPLACE thing well though, anyways just make a copy with createdb --template=somedb and then test your triggers in there

Reply With Quote
Reply

Viewing: Dev Shed ForumsDatabasesPostgreSQL Help > Trigger example needed.


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

 Free IT White Papers!
 
How to Present Effectively Online
This white paper offers practical and actionable advice on the key steps that any presenter should consider as they plan and execute a Webinar or online meeting.

 
Open Source Security Myths
Open Source Software (OSS) is computer software whose source code is available to the general public with relaxed or non-existent intellectual property restrictions (or arrangement such as the public domain), and is usually developed with the input of many contributors.

 
Power and Cooling Capacity Management for Data Centers
This paper describes the principles for achieving power and cooling capacity management.

 
Scalable, Fault-Tolerant NAS for Oracle - The Next Generation
For several years NAS has been evolving as a storage alternative for Oracle databases, and for good reason: NAS is quite often the simplest, most cost-effective storage approach for Oracle. Learn about the benefits that HP's approach to scalable NAS brings to Oracle environments in this comprehensive white paper.

 
Understanding Web Application Security Challenges
This white paper discusses many common threats and preventive measures for Web application security, and explains what you can do to help protect your organization.

 

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 





© 2003-2008 by Developer Shed. All rights reserved. DS Cluster 1 hosted by Hostway
Stay green...Green IT