Received: from maia.hub.org (maia-2.hub.org [200.46.204.251]) by mail.postgresql.org (Postfix) with ESMTP id A853DB5DC3E for ; Fri, 23 Sep 2011 21:06:23 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.251]) (amavisd-maia, port 10024) with ESMTP id 10793-09 for ; Sat, 24 Sep 2011 00:06:17 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.8.0-rc2 Received: from mailout-de.gmx.net (mailout-de.gmx.net [213.165.64.22]) by mail.postgresql.org (Postfix) with SMTP id 31BA4B5DBE0 for ; Fri, 23 Sep 2011 21:06:16 -0300 (ADT) Received: (qmail invoked by alias); 24 Sep 2011 00:06:15 -0000 Received: from mue-88-130-19-086.dsl.tropolys.de (EHLO [192.168.1.113]) [88.130.19.86] by mail.gmx.net (mp052) with SMTP; 24 Sep 2011 02:06:15 +0200 X-Authenticated: #14269776 X-Provags-ID: V01U2FsdGVkX1/TcvBLgnDTptsveyTIQzen2y4GoWf/SJqj/Npc+r aHE1/9AANYPoDN Message-ID: <4E7D1EF8.7040304@gmx.net> Date: Sat, 24 Sep 2011 02:06:16 +0200 From: Andreas User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20110902 Thunderbird/6.0.2 MIME-Version: 1.0 To: pgsql-sql@postgresql.org Subject: Howto build a funtion that selects an id or inserts a value Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Y-GMX-Trusted: 0 X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-2.393 tagged_above=-5 required=5 tests=BAYES_00=-1.9, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RP_MATCHES_RCVD=-0.504, T_TO_NO_BRKTS_FREEMAIL=0.01 X-Spam-Level: X-Archive-Number: 201109/74 X-Sequence-Number: 35874 Hi, I'd like to have a function that looks up an id of an item. In case the item doesn't exist in the table yet it should be inserted and the new id should be returned. From the PG docu, I took the merge_db sample and modified it a bit. This works but I'm wondering if INSERT part could be tuned. Could I have something like i := INSERT INTO _log.computer ( item ) VALUES ( data ) returning id; so I dont have to query the sequence and create another roundtrip on the network? CREATE or replace FUNCTION find_or_insert_item ( data TEXT ) RETURNS integer AS $$ declare i integer; BEGIN LOOP -- first try to select the id of an item select id into i from items where item ilike data; IF found THEN RETURN i; END IF; -- not there, so try to insert the item and retrieve the new id. -- if someone else inserts the same item concurrently, -- we could get a unique-key failure BEGIN INSERT INTO items ( item ) VALUES ( data ); select currval('items_id_seq') into i; RETURN i; EXCEPTION WHEN unique_violation THEN -- Do nothing, and loop to try the SELECT again. END; END LOOP; END; $$ LANGUAGE plpgsql;