Q: using generate_series to fill in the blanks

Started by Ow Mun Hengover 18 years ago4 messagesgeneral
Jump to latest
#1Ow Mun Heng
Ow.Mun.Heng@wdc.com

I've got a desired output which looks something like this..

vdt | count
------------+-------
1 | 514
2 | 27
3 | 15
4 | <NULL>
5 | 12
6 | 15

the query in psql is something like this..

select vdt, count(*) from footable where c_id = '71' group by vdt order
by vdt

problem is.. since there's not data whatsoever on vdt=4 I get this..

vdt | count
------------+-------
1 | 514
2 | 27
3 | 15
5 | 12
6 | 15

I tried to use generate_series

select generate_series(1,7,1), count(*) from footable where c_id = '71'
group by generate_series(1,7,1),vdt order by generate_series(1,7,1);

(note : the vdt are numbered from 1 to 7 sequence)

generate_series | count
-----------------+-------
1 | 514
1 | 27
1 | 15
1 | 12
1 | 15
2 | 514
2 | 27
2 | 15
2 | 12
2 | 15
3 | 514
3 | 27
3 | 15
3 | 12
3 | 15
4 | 514
4 | 27
4 | 15
4 | 12
4 | 15
.....
[snip]
.....

#2Rodrigo De León
rdeleonp@gmail.com
In reply to: Ow Mun Heng (#1)
Re: Q: using generate_series to fill in the blanks

On Dec 6, 2007 10:44 PM, Ow Mun Heng <Ow.Mun.Heng@wdc.com> wrote:

I've got a desired output which looks something like this..

vdt | count
------------+-------
1 | 514
2 | 27
3 | 15
4 | <NULL>
5 | 12
6 | 15

SELECT i.i AS vdt,
CASE
WHEN COUNT(vdt)=0 THEN NULL
ELSE COUNT(vdt)
END AS COUNT
FROM generate_series (1, 7) i
LEFT JOIN footable f ON i.i = f.vdt AND c_id = '71'
GROUP BY i.i
ORDER BY i.i;

#3Ow Mun Heng
Ow.Mun.Heng@wdc.com
In reply to: Rodrigo De León (#2)
Re: Q: using generate_series to fill in the blanks

On Thu, 2007-12-06 at 23:06 -0500, Rodrigo De León wrote:

On Dec 6, 2007 10:44 PM, Ow Mun Heng <Ow.Mun.Heng@wdc.com> wrote:

I've got a desired output which looks something like this..

vdt | count
------------+-------
1 | 514
2 | 27
3 | 15
4 | <NULL>
5 | 12
6 | 15

SELECT i.i AS vdt,
CASE
WHEN COUNT(vdt)=0 THEN NULL
ELSE COUNT(vdt)
END AS COUNT
FROM generate_series (1, 7) i
LEFT JOIN footable f ON i.i = f.vdt AND c_id = '71'
GROUP BY i.i
ORDER BY i.i;

This is _way_ cool. Thanks. However I still have some additional
questions.

as individual c_ids:
vdt | c_id | count
-----+-------+-------
1 | 71 | 533
2 | 71 | 30
3 | 71 | 15
4 | 71 | 10
5 | 71 | 12
6 | 71 | 15
7 | |

vdt |c_id| count
-----+-------+-------
1 | 48 | 217
2 | 48 | 86
3 | 48 | 46
4 | 48 | 50
5 | 48 | 4
6 | |
7 | |

select i.i as vdt,dcm_evaluation_code as c_id
, case when count(vdt_format) = 0 then NULL else count(vdt_format) end
as count
from generate_series(1,7) i
left join footable f
on i.i = f.vdt_format
and c_id in ('71','48')
group by c_id, i.i
order by c_id,i.i;

When Joined into 1 query
vdt | c_id | count
-----+-------+-------
1 | HMK71 | 533
2 | HMK71 | 30
3 | HMK71 | 15
4 | HMK71 | 10
5 | HMK71 | 12
6 | HMK71 | 15 << What happened to 7?
1 | HML48 | 217
2 | HML48 | 86
3 | HML48 | 46
4 | HML48 | 50
5 | HML48 | 4
7 | |

additionally, if you don't mind, when I substitute

-->and c_id = '71'

with

--> where c_id = '71'

the nulls also disappears.

In any case, it seems to be working for _single_ c_id clauses..

#4Sam Mason
sam@samason.me.uk
In reply to: Ow Mun Heng (#3)
Re: Q: using generate_series to fill in the blanks

On Fri, Dec 07, 2007 at 01:18:13PM +0800, Ow Mun Heng wrote:

select i.i as vdt,dcm_evaluation_code as c_id
, case when count(vdt_format) = 0 then NULL else count(vdt_format) end
as count
from generate_series(1,7) i
left join footable f
on i.i = f.vdt_format
and c_id in ('71','48')
group by c_id, i.i
order by c_id,i.i;

When Joined into 1 query
vdt | c_id | count
-----+-------+-------
1 | HMK71 | 533
2 | HMK71 | 30
3 | HMK71 | 15
4 | HMK71 | 10
5 | HMK71 | 12
6 | HMK71 | 15 << What happened to 7?
1 | HML48 | 217
2 | HML48 | 86
3 | HML48 | 46
4 | HML48 | 50
5 | HML48 | 4
7 | |

You need to start by generating all of the values you consider you
want. In the previous example this was easy as all you wanted was a
set of numbers. Now you want the cartesian product of this series and
something else. So you need to be doing something like:

SELECT x.i, x.j, COUNT(t.k)
FROM (SELECT DISTINCT t.i,s.j FROM table t, generate_series(1,7) s(j)) x
LEFT JOIN table t ON (x.i,x.j) = (t.i,t.j)
GROUP BY x.i, x.j
ORDER BY x.i, x.j;

Sam