2010-08-04 16 views
1

Salutations,INSERT ou d'une ligne de retour si l'entrée existe déjà dans une table avec contrainte UNIQUE

Je cette table, sur un serveur postgreSQL 8.4:

CREATE TABLE tags (
tagid  bigserial     PRIMARY KEY, 
name   text      NOT NULL, 
value  text      NOT NULL, 
UNIQUE(name,value) 
); 

Le comportement normal INSERT est de jeter une erreur lorsque de nouvelles valeurs rompent la contrainte d'unicité. Je préférerais ne pas lancer l'erreur et retourner soit le nouveau tagid si l'insertion a réussi, soit le tagid de l'entrée existante correspondant à la contrainte d'unicité.

J'utilise cette fonction pour le faire:

CREATE OR REPLACE FUNCTION insert_tags(my_name text, my_value text) 
RETURNS bigint AS $$ 
DECLARE 
retval bigint; 
BEGIN 
SELECT tagid INTO retval FROM tags WHERE name = my_name AND value = my_value; 
IF FOUND THEN 
    RETURN retval; 
END IF; 
INSERT INTO tags (name, value) VALUES (my_name, my_value) RETURNING tagid INTO retval; 
RETURN retval; 
END; 
$$ LANGUAGE plpgsql; 

Dans le pire des cas, deux tables de référence sont effectuées avant l'insertion. Existe-t-il une meilleure façon de le faire, éventuellement en une seule recherche?

Répondre

3

Il suffit d'insérer et de faire une gestion des exceptions:

CREATE OR REPLACE FUNCTION insert_tags(my_name text, my_value text) 
RETURNS bigint AS $$ 
DECLARE 
retval bigint; 
BEGIN 
    INSERT INTO tags (name, value) VALUES (my_name, my_value) RETURNING tagid INTO retval; 
    RETURN retval; 

    EXCEPTION 
     WHEN unique_violation THEN 
      SELECT tagid INTO retval FROM tags WHERE name = my_name AND value = my_value; 
      RETURN retval; 
END; 
$$ LANGUAGE plpgsql; 

Vous pouvez trouver plus d'informations à ce sujet dans le manuel: http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING

+0

Selon la liste de diffusion postogresql général, la fonctionnalité UPSERT (qui est très proche de cela) devrait être ajouté dans postgresql 9.1. – user304965