Received: from localhost (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 7D5426341D4 for ; Thu, 9 Apr 2009 12:14:09 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by localhost (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 89146-04-3 for ; Thu, 9 Apr 2009 12:14:06 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from starfish.geekisp.com (mail.geekisp.com [216.168.135.169]) by mail.postgresql.org (Postfix) with ESMTP id 063246347CD for ; Thu, 9 Apr 2009 12:13:48 -0300 (ADT) Received: (qmail 9428 invoked by uid 1003); 9 Apr 2009 15:13:47 -0000 Received: from localhost (HELO ?10.21.10.111?) (public@misuse.org@127.0.0.1) by mail.geekisp.com with SMTP; 9 Apr 2009 15:13:46 -0000 Message-ID: <49DE10A9.2000400@misuse.org> Date: Thu, 09 Apr 2009 08:13:45 -0700 From: Steve Midgley User-Agent: Thunderbird 2.0.0.21 (Windows/20090302) MIME-Version: 1.0 To: pgsql-sql@postgresql.org Subject: Re: Nested selects References: <20090409032029.1F26C1E80C9F@mx2.hub.org> In-Reply-To: <20090409032029.1F26C1E80C9F@mx2.hub.org> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0 tagged_above=0 required=5 tests=none X-Spam-Level: X-Archive-Number: 200904/49 X-Sequence-Number: 32395 pgsql-sql-owner@postgresql.org wrote: > Date: Tue, 7 Apr 2009 22:34:38 -0400 > From: Glenn Maynard > To: pgsql-sql@postgresql.org > Subject: Nested selects > Message-ID: > > I'm deriving high scores from two tables: one containing data for each > time a user played (rounds), and one containing a list of stages: > > CREATE TABLE stage (id SERIAL NOT NULL PRIMARY KEY, name VARCHAR); > CREATE TABLE round (id SERIAL NOT NULL PRIMARY KEY, score REAL, > stage_id INTEGER REFERENCES stage (id)); > INSERT INTO stage (name) VALUES ('stage 1'), ('stage 2'), ('stage 3'); > INSERT INTO round (stage_id, score) VALUES > (1, 100), (1, 150), (1, 175), > (2, 250), (2, 275), (2, 220), > (3, 350), (3, 380), (3, 322); > > SELECT r.* FROM round r > WHERE r.id IN ( > -- Get the high scoring round ID for each stage: > SELECT > ( > -- Get the high score for stage s: > SELECT r.id FROM round r > WHERE r.stage_id = s.id > ORDER BY r.score DESC LIMIT 1 > ) > FROM stage s > ); > > This works fine, and with a (stage_id, score DESC) index, is > reasonably fast with around 1000 stages. round may expand to millions > of rows. > > Unfortunately, it doesn't generalize to getting the top N scores for > each stage; LIMIT 2 isn't valid ("more than one row returned by a > subquery used as an expression"). > > I fiddled with putting the inner results in an array, without much > luck, and I'm not sure how well that'd optimize. Having the results > in any particular order isn't important. (In practice, the inner > select will often be more specific--"high scores on the west coast", > "high scores this month", and so on.) > > This seems embarrassingly simple: return the top rounds for each > stage--but I'm banging my head on it for some reason. > > How about this: select round.*, stage.name from round left join stage on stage.id = round.stage_id ORDER BY round.score DESC; Steve