0

Using postgreSQL 9.1.9, I have some SQL requests like this:

 INSERT INTO "my_table" VALUES(10,'James','California');

Below a simplified table of the original names lookup table...

 names
 name_id name
 --- -----
 3 James

but in fact I don't have to enter (into "my_table") the text value provided by the SQL request (name of person, name of the state) but its corresponding ID located in another table (ex: names table)

So i was thinking on creating a trigger, calling a function that should execute the select SQL request and return the modified row to be inserted.

Is that possible?

CREATE FUNCTION insert_by_ID() RETURNS TRIGGER AS '
 BEGIN
 --Can we execute this query, store the result in a variable to be added
 to the NEW record?
 SELECT name_id from names where name=NEW.name;
 --this request would be...
 --SELECT name_id from names where name='James' 
 RETURN NEW;
 END;
 ' LANGUAGE plpgsql;
CREATE TRIGGER insert_info_ID
 BEFORE INSERT ON my_table
 FOR EACH ROW
 EXECUTE PROCEDURE insert_by_ID();
asked May 14, 2014 at 14:44
4
  • 1
    It is possible, of course, but may be redundant. Complete your question with my_table and names definitions. Commented May 14, 2014 at 16:59
  • Run \d names in psql and post the output. Plus, as always your version of Postgres. And please clarify the fuzzy explanation. Commented May 14, 2014 at 17:07
  • 1
    Your question is still unclear. I can guess you probably need an updateable view. Please read this article: vibhorkumar.wordpress.com/2011/10/28/instead-of-trigger Commented May 15, 2014 at 12:32
  • Are we dealing with names that can always be found in table names or do you want to insert a name if not found and proceed with the newly created name_id? If so, are we dealing with heavy concurrent write load? Commented May 15, 2014 at 21:29

1 Answer 1

1

Seems you want a solution for the "SELECT or INSERT if not exists" problem.

I suggest a PL/pgSQL function like this:

CREATE OR REPLACE FUNCTION f_name_id(_name text, OUT _name_id int)
 LANGUAGE plpgsql AS
$func$
BEGIN
 LOOP
 BEGIN
 SELECT name_id FROM names WHERE name = _name FOR SHARE -- lock!
 INTO _name_id;
 IF NOT FOUND THEN
 INSERT INTO names (name) VALUES (_name) RETURNING name_id
 INTO _name_id;
 END IF;
 EXCEPTION WHEN UNIQUE_VIOLATION THEN -- inserted concurrently!
 RAISE NOTICE 'It actually happened!'; -- hardly ever happens
 END;
 EXIT WHEN _name_id IS NOT NULL; -- else try again
 END LOOP;
END
$func$;

This is a simple version of the function discussed here in more detail:

Then your INSERT statement can look like this:

INSERT INTO my_table(my_table_id, name_id, state) -- always with column list
VALUES (10, f_name_id('James'), 'California');
answered May 15, 2014 at 22:33
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.