X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id 1FC9253B4E for ; Thu, 5 May 2005 14:58:11 -0300 (ADT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 11474-09 for ; Thu, 5 May 2005 17:58:06 +0000 (GMT) Received: from priv-edtnes56.telusplanet.net (outbound01.telus.net [199.185.220.220]) by svr1.postgresql.org (Postfix) with ESMTP id 047615365D for ; Thu, 5 May 2005 14:58:04 -0300 (ADT) Received: from localhost ([199.185.220.240]) by priv-edtnes56.telusplanet.net (InterMail vM.6.01.04.04 201-2131-118-104-20050224) with ESMTP id <20050505175805.TYMX14016.priv-edtnes56.telusplanet.net@localhost> for ; Thu, 5 May 2005 11:58:05 -0600 Received: from 209.17.183.249 ( [209.17.183.249]) as user a3a18850@192.168.200.1 by webmail.telus.net with HTTP; Thu, 5 May 2005 10:58:04 -0700 Message-ID: <1115315884.427a5eacd3ca9@webmail.telus.net> Date: Thu, 5 May 2005 10:58:04 -0700 From: a3a18850@telus.net To: pgsql-sql@postgresql.org Subject: Re: HELP: aggregating insert rule for multirow inserts. References: <1115234855.4279222707401@webmail.telus.net> <45caccdc050505003936efa435@mail.gmail.com> In-Reply-To: <45caccdc050505003936efa435@mail.gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit User-Agent: Internet Messaging Program (IMP) 3.1-cvs X-Originating-IP: 209.17.183.249 X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=2.074 tagged_above=0 required=5 tests=AWL, DNS_FROM_RFC_POST, FORGED_RCVD_HELO, FROM_ENDS_IN_NUMS, FROM_HAS_MIXED_NUMS, NO_REAL_NAME X-Spam-Level: ** X-Archive-Number: 200505/67 X-Sequence-Number: 21380 Quoting Mikey : > What about this as a rule. It seems to work for me. > > create or replace rule critter_counter as > on INSERT to critter do ( > > insert into zoostats > select distinct new.legs > where new.legs not in (select legs from zoostats); > > update zoostats set headcount = ( > select count(*) > from critter > where critter.legs = zoostats.legs > ) where zoostats.legs = new.legs > ); ... Thanks, sorry I didn't mention, I was looking for an efficient solution, given that (I thought) using a RULE that processes the whole (in-memory) NEW set in one operation is faster than a trigger that increments each headcount for each inserted row. It comes from the way of thinking when you work with Sybase/MSSQL triggers, and their INSERTED and DELETED pseudotables --- what you would get in FOR-EACH-STATEMENT triggers that implement NEW_TABLE AS and OLD_TABLE AS. Yes, recalculating each affected leg-count group from scratch will work. But in the above, adding one 4legged animal requires rescan of a large number of animals ... Hope the zoo metaphor isn't getting a bit tedious, folks. > On 5/4/05, Mischa Sandberg wrote: > > I'm having a problem with the use of the NEW rowset, > > in a rule intended to aggregate across inserts. > > > > I've never really grokked how NEW and OLD really work, > > syntactically, other than that they seem to be implicit > > in every top-level FROM clause, and any mention elsewhere > > gets an error: '42P01: relation "*NEW*" does not exist'. > > > > I've tried different flavours of the UPDATE command, > > in the following rule, and they either produce syntax errors > > or the wrong results. > > > > Any suggestions much appreciated ... > > > > ====================== CODE > > "How many critters are in the zoo, of the 4,5,6...-legged varieties?" > > > > create table critter(name text, legs int); > > create table zoostats(legs int, headcount int default 0, > > primary key(legs)); > > > > create or replace rule critter_counter as > > on INSERT to critter do ( > > > > insert into zoostats > > select distinct new.legs > > where new.legs not in (select legs from zoostats); > > > > update zoostats > > set headcount = headcount + (select count(*)) -- "from new" > > where new.legs = zoostats.legs > > ); > > > > insert into critter values('cat',4); > > insert into critter values('starfish',5); > > insert into critter values('ant',6); > > insert into critter values('dog',4); > > > > insert into critter select * from critter; -- double everything. > > > > select * from zoostats; > > > > drop table zoostats cascade; > > drop table critter; > > ====================== EXPECTED OUTPUT > > legs headcount > > ---- --------- > > 4 4 > > 5 2 > > 6 2 > > ====================== ACTUAL OUTPUT > > legs headcount > > ---- --------- > > 4 3 -- !? > > 5 2 > > 6 2