Received: from maia.hub.org (maia-2.hub.org [200.46.204.251]) by mail.postgresql.org (Postfix) with ESMTP id 08AAF1337B67 for ; Tue, 23 Nov 2010 00:11:52 -0400 (AST) 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 95015-10 for ; Tue, 23 Nov 2010 04:11:40 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from elizabeth.gransy.com (elizabeth.gransy.com [89.187.132.199]) by mail.postgresql.org (Postfix) with ESMTP id 0D6331337B58 for ; Tue, 23 Nov 2010 00:11:39 -0400 (AST) Received: from sq.gransy.com (localhost [127.0.0.1]) by elizabeth.gransy.com (Postfix) with ESMTP id 20E6A15E42AA; Tue, 23 Nov 2010 05:11:37 +0100 (CET) Received: from 89.103.152.5 (SquirrelMail authenticated user tv@fuzzy.cz) by sq.gransy.com with HTTP; Tue, 23 Nov 2010 05:11:37 +0100 Message-ID: In-Reply-To: <4CEB38B0.8050901@gmx.net> References: <4CEB38B0.8050901@gmx.net> Date: Tue, 23 Nov 2010 05:11:37 +0100 Subject: Re: Howto "insert or update" ? From: tv@fuzzy.cz To: "Andreas" Cc: pgsql-sql@postgresql.org User-Agent: SquirrelMail/1.4.21 MIME-Version: 1.0 Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: 8bit X-Priority: 3 (Normal) Importance: Normal X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-1.9 tagged_above=-5 required=5 tests=BAYES_00=-1.9 X-Spam-Level: X-Archive-Number: 201011/47 X-Sequence-Number: 34785 > Currently I have a trigger function that should store a value in tableX > whenever a certain column in tableY gets changed. > I do it with: > a) delete from tableX where key = ( A, B ) ( regardless if there is one > ) > b) insert into tableX > > This seems not very efficient though it works. > Is there a better way? Efficiency matters only if the solution is correct, and that's not the case of your function - there's a quite trivial race condition. Imagine there are two transactions running at the same time, executing the function concurrently. The first one will succeed, while the other one will fail because of unique constraint violation. A correct solution is something like this BEGIN INSERT INTO ... EXCEPTION -- the key already exists, so let's update WHEN unique_violation THEN UPDATE ... END; Regarding efficiency - I'm not aware of a better solution. There are plans to implement true MERGE but that's in the future. All you can do right now is to make sure the key is indexed (I guess it's a PK anyway) so that the INSERT/UPDATE are fast. Well, actually there's one other thing you could do - you can do a BEFORE INSERT trigger that checks if the key already exists, and in case it does switch to UPDATE. Something like CREATE OR REPLACE FUNCTION my_trigger() RETURNS trigger as $$ BEGIN UPDATE my_table SET .... WHERE key = NEW.key; IF (FOUND) THEN -- updated, do not execute the insert RETURN NULL; END IF; -- execute the insert RETURN NEW; END; $$ language plpgsql; CREATE TRIGGER merge_trigger BEFORE INSERT ON my_table FOR EACH ROW EXECUTE PROCEDURE my_trigger(); This is probably more elegant - just execute INSERT statements and it will handle all the work. The only problem is it does not report the number of updated rows (it just returns 0 in that case). But generally it's just as efficient as the solution described above. regards Tomas