I’ve got a PostgreSQL 9.2.1 database, where I’m attempting and failing to compose a SQL query which will show me the count of distinct tests (testname) which failed (current_status='FAILED' and showing 0 if there were no failures), segregated by month (last_update). Here’s the table definition:
Table "public.tests"
Column | Type | Modifiers
----------------+-----------------------------+-------------------------------------------------------------
id | bigint | not null default nextval('tests_id_seq'::regclass)
testname | text | not null
last_update | timestamp without time zone | not null default now()
current_status | text | not null
What I’d like to get back from that is something like this:
testname | Jan2012 | Feb2012 | Mar2012 | Apr2012 | May2012 | Jun2012 | Jul2012 | Aug2012 | Sep2012 | Oct2012 | Nov2012 | Dec2012
-------------+-----------------------------------------------------------------------------------------------------------------------------------------
abq | 2 | 5 | 2 | 0 | 7 | 4 | 8 | 0 | 6 | 15 | 1 | 0
bar | 0 | 0 | 2 | 0 | 9 | 8 | 8 | 2 | 6 | 15 | 1 | 1
cho | 15 | 1 | 2 | 3 | 4 | 8 | 7 | 3 | 6 | 1 | 5 | 6
At this point, the best that I could come up with is the following, which is admittedly not close:
SELECT testname, count(current_status) AS failure_count
FROM tests
WHERE current_status='FAILED'
AND last_update>'2012-09-01'
AND last_update<='2012-09-30'
GROUP by testname
ORDER BY testname ;
I think I’d need to somehow use COALESCE to get 0 values to show up in the results, plus some crazy JOINs to show multiple months of results, and maybe even a window function?
crosstab()function with two parameters.Should work like this, to get values for 2012:
Find detailed explanation under this related question.
I didn’t test.As @Craig commented, sample values would have helped.Tested now with my own test case.
Don’t display NULL values
The main problem (that months without rows wouldn’t show up at all) is averted by the
crosstab()function with two parameters.You cannot use
COALESCEin the inner query, because theNULLvalues are inserted bycrosstab()itself. You could …1. Wrap the whole thing into a subquery:
2.
LEFT JOINthe primary query to the full list of months.In this case, you don’t need the second parameter by definition.
For a bigger range you could use
generate_series()to create the values.Test case with sample data
Here is a test case with some sample data that the OP failed to provide. I used this to test it and make it work.