X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.2]) by svr1.postgresql.org (Postfix) with ESMTP id 43A14D1C9BD for ; Mon, 9 Feb 2004 16:09:58 +0000 (GMT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (neptune.hub.org [200.46.204.2]) (amavisd-new, port 10024) with ESMTP id 97454-05 for ; Mon, 9 Feb 2004 12:09:48 -0400 (AST) Received: from sss.pgh.pa.us (unknown [192.204.191.242]) by svr1.postgresql.org (Postfix) with ESMTP id 3F1A1D1CCB1 for ; Mon, 9 Feb 2004 12:09:46 -0400 (AST) Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1]) by sss.pgh.pa.us (8.12.11/8.12.11) with ESMTP id i19G9YXr020112; Mon, 9 Feb 2004 11:09:35 -0500 (EST) To: Mark Gibson Cc: pgsql-sql@postgresql.org Subject: Re: Implementation of a bag pattern using rules In-reply-to: <40278022.5070408@cromwell.co.uk> References: <40278022.5070408@cromwell.co.uk> Comments: In-reply-to Mark Gibson message dated "Mon, 09 Feb 2004 12:42:10 +0000" Date: Mon, 09 Feb 2004 11:09:34 -0500 Message-ID: <20111.1076342974@sss.pgh.pa.us> From: Tom Lane X-Virus-Scanned: by amavisd-new at postgresql.org X-Archive-Number: 200402/85 X-Sequence-Number: 16776 Mark Gibson writes: > Alternatively, for the relative option (increase 'apple' by 12), replace > the 'bag_abs' rule with: > CREATE RULE bag_rel AS ON INSERT TO bag_test > WHERE > EXISTS (SELECT 1 FROM bag_test WHERE item = NEW.item) > DO INSTEAD > UPDATE bag_test SET qty = qty + NEW.qty WHERE item = NEW.item; This can't work because an ON INSERT rule fires after the INSERT itself is executed. You have the equivalent of INSERT INTO ... WHERE NOT EXISTS(SELECT ...); UPDATE ... WHERE item = NEW.item AND EXISTS(SELECT ...); The INSERT will execute because there's no row matching the EXISTS(), and then the UPDATE will execute too because now there is a matching row. In some contexts this is a feature. However, you want a single test to control both actions. I think you need to use a BEFORE INSERT trigger instead. It could do something like -- see if there is an existing row, if so update it UPDATE bag_test SET qty = qty + NEW.qty WHERE item = NEW.item; -- if there was one, suppress the INSERT IF found THEN RETURN NULL; END IF; -- else allow the INSERT RETURN NEW; You could also extend the trigger to handle the delete-upon-reaching-zero logic. regards, tom lane