pg.ddx.io  pgsql-sql@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Ross Johnson <ross.johnson@homemail.com.au>
To: PostgreSQL SQL List <pgsql-sql@postgresql.org>
Subject: Re: cross tables, SELECT expressions, and GROUP BY problem
Date: Sun, 02 Apr 2006 22:15:26 +1000
Message-ID: <1143980127.8841.254.camel@desk.home> (raw)
In-Reply-To: <1143964809.8841.211.camel@desk.home>
References: <1143960225.8841.187.camel@desk.home>
	<1143964809.8841.211.camel@desk.home>

Following up my own question again, I've realised my error and solved my
problem - in the interests of completing this thread, the working query
(two versions) can be found below...

On Sun, 2006-04-02 at 18:00 +1000, Ross Johnson wrote:
> On Sun, 2006-04-02 at 16:43 +1000, Ross Johnson wrote:
> > Hi,
> > 
> > I'm relatively stretched when it comes to SQL but I'm getting there. I
> > have a question though:
> > 
> > Thanks to various web sites I've succeeded in creating simple cross
> > tables in PostgreSQL. I'm now trying more complicated examples
> > (migrating queries from MS Access to PostgreSQL). I'm stuck on getting
> > grouping to work where the selection element isn't a real table field,
> > where it is generated by a CASE statement. Here's a full actual SELECT
> > statement, that works but isn't quite what I need, followed by the first
> > few rows of output:
> > 
> > SELECT DISTINCT
> > 	CASE
> > 		WHEN lower(c."Order") = 'coleoptera' THEN 5
> > 		WHEN lower(c."Order") = 'trichoptera' THEN 8
> > 		WHEN lower(c."Order") = 'ephemeroptera' THEN 6
> > 		WHEN lower(c."Order") = 'plecoptera' THEN 7
> > 		WHEN lower(c."Class") = 'oligochaeta' THEN 1
> > 		WHEN lower(c."Family") LIKE 'chiron%' THEN 2
> > 		WHEN lower(c."Order") = 'diptera' AND lower(c."Family") NOT LIKE 'chiron%' THEN 3
> > 		ELSE 4
> > 	END AS "Ranking",
> > 	CASE
> > 		WHEN lower(c."Order") = 'coleoptera' THEN 'Coleoptera'
> > 		WHEN lower(c."Order") = 'trichoptera' THEN 'Trichoptera'
> > 		WHEN lower(c."Order") = 'ephemeroptera' THEN 'Ephemeroptera'
> > 		WHEN lower(c."Order") = 'plecoptera' THEN 'Plecoptera'
> > 		WHEN lower(c."Class") = 'oligochaeta' THEN 'Oligochaeta'
> > 		WHEN lower(c."Family") LIKE 'chiron%' THEN 'Chironomidae'
> > 		WHEN lower(c."Order") = 'diptera' AND lower(c."Family") NOT LIKE 'chiron%' THEN 'Diptera (Other)'
> > 		ELSE 'Other'
> > 	END AS "Taxa",
> > 	SUM(CASE WHEN b."LocationCode" = '2222011' THEN c."Count" END) AS "2222011",
> > 	SUM(CASE WHEN b."LocationCode" = '2222012' THEN c."Count" END) AS "2222012",
> > 	SUM(CASE WHEN b."LocationCode" = '2222013' THEN c."Count" END) AS "2222013",
> > 	SUM(CASE WHEN b."LocationCode" = '2222014' THEN c."Count" END) AS "2222014"
> > FROM "tblBugIDSheetInfo" b
> > 	INNER JOIN "tblBugCount" c USING ("BugSheetID")
> > GROUP BY c."Order", c."Class", c."Family"
> > ORDER BY "Ranking"
> > 
> > Generates the following output:
> > 
> > Ranking	Taxa			2222011	2222012	2222013	2222014
> > ---------------------------------------------------------------
> > 1	"Oligochaeta"		487	1711	1759	1078
> > 1	"Oligochaeta"		7			
> > 1	"Oligochaeta"					
> > 2	"Chironomidae"		1385	2335	1500	1513
> > 2	"Chironomidae"					
> > 3	"Diptera (Other)"				5
> > 3	"Diptera (Other)"		1	1	3
> > 3	"Diptera (Other)"	199	19	40	37
> > 3	"Diptera (Other)"				
> > ...
> 
> I should add that I've just tried the following query, which is just a
> rearrangement of the above query using a sub-SELECT, and the result is
> the same as above apart from a slightly different ordering of the rows.
> That is, GROUP BY "Ranking" still doesn't appear to do anything. I was
> under the impression that a sub-SELECT creates a temporary, or at least
> a pseudo-temporary table (a "virtual" table as it's called in the
> documentation), so I would have expected this query to work even if the
> above one doesn't.
> 
> 
> SELECT DISTINCT
> 	"Ranking", "Taxa",
> 	SUM(CASE WHEN b."LocationCode" = '2222011' THEN c."Count" END) AS "2222011",
> 	SUM(CASE WHEN b."LocationCode" = '2222012' THEN c."Count" END) AS "2222012",
> 	SUM(CASE WHEN b."LocationCode" = '2222013' THEN c."Count" END) AS "2222013",
> 	SUM(CASE WHEN b."LocationCode" = '2222014' THEN c."Count" END) AS "2222014"
> FROM "tblBugIDSheetInfo" b
> 	INNER JOIN (
> 		SELECT "BugSheetID",
> 		CASE
> 			WHEN lower("Order") = 'coleoptera' THEN 5
> 			WHEN lower("Order") = 'trichoptera' THEN 8
> 			WHEN lower("Order") = 'ephemeroptera' THEN 6
> 			WHEN lower("Order") = 'plecoptera' THEN 7
> 			WHEN lower("Class") = 'oligochaeta' THEN 1
> 			WHEN lower("Family") LIKE 'chiron%' THEN 2
> 			WHEN lower("Order") = 'diptera' AND lower("Family") NOT LIKE 'chiron%' THEN 3
> 			ELSE 4
> 		END AS "Ranking",
> 		CASE
> 			WHEN lower("Order") = 'coleoptera' THEN 'Coleoptera'
> 			WHEN lower("Order") = 'trichoptera' THEN 'Trichoptera'
> 			WHEN lower("Order") = 'ephemeroptera' THEN 'Ephemeroptera'
> 			WHEN lower("Order") = 'plecoptera' THEN 'Plecoptera'
> 			WHEN lower("Class") = 'oligochaeta' THEN 'Oligochaeta'
> 			WHEN lower("Family") LIKE 'chiron%' THEN 'Chironomidae'
> 			WHEN lower("Order") = 'diptera' AND lower("Family") NOT LIKE 'chiron%' THEN 'Diptera (Other)'
> 			ELSE 'Other'
> 		END AS "Taxa",
> 		"Order", "Class", "Family", "Count"
> 		FROM "tblBugCount") c USING ("BugSheetID")
> GROUP BY c."Ranking", c."Taxa", c."Order", c."Class", c."Family"
> ORDER BY "Ranking"
> 

The problem was I was trying to do too much in one GROUP BY clause.
After getting the right result using a temporary table I backtracked and
found that the following version gives me the result I'm looking for.

SELECT DISTINCT
	"Ranking", "Taxa",
	SUM(CASE WHEN b."LocationCode" = '2222011' THEN c."Count" END) AS "2222011",
	SUM(CASE WHEN b."LocationCode" = '2222012' THEN c."Count" END) AS "2222012",
	SUM(CASE WHEN b."LocationCode" = '2222013' THEN c."Count" END) AS "2222013",
	SUM(CASE WHEN b."LocationCode" = '2222014' THEN c."Count" END) AS "2222014"
FROM "tblBugIDSheetInfo" b
	INNER JOIN (
		SELECT "BugSheetID",
		CASE
			WHEN lower("Order") = 'coleoptera' THEN 5
			WHEN lower("Order") = 'trichoptera' THEN 8
			WHEN lower("Order") = 'ephemeroptera' THEN 6
			WHEN lower("Order") = 'plecoptera' THEN 7
			WHEN lower("Class") = 'oligochaeta' THEN 1
			WHEN lower("Family") LIKE 'chiron%' THEN 2
			WHEN lower("Order") = 'diptera' AND lower("Family") NOT LIKE 'chiron%' THEN 3
			ELSE 4
		END AS "Ranking",
		CASE
			WHEN lower("Order") = 'coleoptera' THEN 'Coleoptera'
			WHEN lower("Order") = 'trichoptera' THEN 'Trichoptera'
			WHEN lower("Order") = 'ephemeroptera' THEN 'Ephemeroptera'
			WHEN lower("Order") = 'plecoptera' THEN 'Plecoptera'
			WHEN lower("Class") = 'oligochaeta' THEN 'Oligochaeta'
			WHEN lower("Family") LIKE 'chiron%' THEN 'Chironomidae'
			WHEN lower("Order") = 'diptera' AND lower("Family") NOT LIKE 'chiron%' THEN 'Diptera (Other)'
			ELSE 'Other'
		END AS "Taxa",
		"Order", "Class", "Family", SUM("Count") AS "Count"
		FROM "tblBugCount"
		GROUP BY "BugSheetID", "Order", "Class", "Family") c USING ("BugSheetID")
GROUP BY "Ranking", "Taxa"
ORDER BY "Ranking"

And modifying the original query gives the faster performance:

SELECT	"Ranking",
	"Taxa",
	SUM("2222011") AS "2222011",
	SUM("2222012") AS "2222012",
	SUM("2222013") AS "2222013",
	SUM("2222014") AS "2222014"
FROM (
	SELECT DISTINCT
	CASE
		WHEN lower(c."Order") = 'coleoptera' THEN 5
		WHEN lower(c."Order") = 'trichoptera' THEN 8
		WHEN lower(c."Order") = 'ephemeroptera' THEN 6
		WHEN lower(c."Order") = 'plecoptera' THEN 7
		WHEN lower(c."Class") = 'oligochaeta' THEN 1
		WHEN lower(c."Family") LIKE 'chiron%' THEN 2
		WHEN lower(c."Order") = 'diptera' AND lower(c."Family") NOT LIKE 'chiron%' THEN 3
		ELSE 4
	END AS "Ranking",
	CASE
		WHEN lower(c."Order") = 'coleoptera' THEN 'Coleoptera'
		WHEN lower(c."Order") = 'trichoptera' THEN 'Trichoptera'
		WHEN lower(c."Order") = 'ephemeroptera' THEN 'Ephemeroptera'
		WHEN lower(c."Order") = 'plecoptera' THEN 'Plecoptera'
		WHEN lower(c."Class") = 'oligochaeta' THEN 'Oligochaeta'
		WHEN lower(c."Family") LIKE 'chiron%' THEN 'Chironomidae'
		WHEN lower(c."Order") = 'diptera' AND lower(c."Family") NOT LIKE 'chiron%' THEN 'Diptera (Other)'
		ELSE 'Other'
	END AS "Taxa",
	SUM(CASE WHEN b."LocationCode" = '2222011' THEN c."Count" END) AS "2222011",
	SUM(CASE WHEN b."LocationCode" = '2222012' THEN c."Count" END) AS "2222012",
	SUM(CASE WHEN b."LocationCode" = '2222013' THEN c."Count" END) AS "2222013",
	SUM(CASE WHEN b."LocationCode" = '2222014' THEN c."Count" END) AS "2222014"
	FROM "tblBugIDSheetInfo" b
		INNER JOIN "tblBugCount" c USING ("BugSheetID")
	WHERE b."LocationCode" = '2222011'
	   OR b."LocationCode" = '2222012'
	   OR b."LocationCode" = '2222013'
	   OR b."LocationCode" = '2222014'
	GROUP BY c."Order", c."Class", c."Family") d
GROUP BY "Ranking", "Taxa"
ORDER BY "Ranking"


Both these queries give me the result I was after:

> > I want to GROUP on the "Ranking" field as well so that all rows with the
> > same "Ranking" value are SUMmed. That is, I'm trying to achieve the
> > following:
> > 
> > Ranking	Taxa			2222011	2222012	2222013	2222014
> > ---------------------------------------------------------------
> > 1	"Oligochaeta"		494	1711	1759	1078
> > 2	"Chironomidae"		1385	2335	1500	1513
> > 3	"Diptera (Other)"	199	20	41	45
> > ...

Applying the grouping at the appropriate points helps :)

Regards.
Ross Johnson





view thread (3+ messages)

Message-ID: <1143980127.8841.254.camel@desk.home>
Permalink:  ../1143980127.8841.254.camel@desk.home/
Also on:    postgresql.org/message-id/1143980127.8841.254.camel@desk.home

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-sql@postgresql.org
  Cc: ross.johnson@homemail.com.au
  Subject: Re: cross tables, SELECT expressions, and GROUP BY problem
  In-Reply-To: <1143980127.8841.254.camel@desk.home>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox