Thread: Q: using generate_series to fill in the blanks

Q: using generate_series to fill in the blanks

From
Ow Mun Heng
Date:
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]
.....

Re: Q: using generate_series to fill in the blanks

From
"Rodrigo De León"
Date:
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;

Re: Q: using generate_series to fill in the blanks

From
Ow Mun Heng
Date:
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..









Re: Q: using generate_series to fill in the blanks

From
Sam Mason
Date:
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