Thread: unsure of how to query for desired data/output

unsure of how to query for desired data/output

From
Carol Cheung
Date:
Hi,
I have a table with a column of integers called 'status'. A number may
appear 0+ times in this column. For example,

  status
--------
   25
   28
   28
...

I know I can get counts of the each status using select count(status),
status from test_table group by status;

Let's say I have some lists of numbers, like so:

25
3,17
40,28,6
17

25 appears in the status column 3 times.
3 appears in the status column 6 times.
17 appears in the status column 2 times.
40 appears in the status column 0 times.
6 appears in the status column 1 time.
28 appears in the status column 2 times

Is it possible to get the following based on the above list of numbers:

25|3
3,17|8
40,28,6|3
17|2

the first column is the list of status, the second column is the sum of
the counts of the status codes appearing on the left of the "|"

Does anyone have any ideas on how to get this output without executing 4
separate queries?

Thanks.




Re: unsure of how to query for desired data/output

From
"Rodrigo E. De León Plicet"
Date:
On Mon, Dec 1, 2008 at 11:35 AM, Carol Cheung
<cacheung@consumercontact.com> wrote:
> Is it possible to get the following based on the above list of numbers:
>
> 25|3
> 3,17|8
> 40,28,6|3
> 17|2

create table t (
status int
);

insert into t values
(25),(25),(25),(3),(3),(3),(3),(3),(3),(17),(17),(6),(28),(28);

select * from t;

 status
--------
     25
     25
     25
      3
      3
      3
      3
      3
      3
     17
     17
      6
     28
     28
(14 rows)

select replace(replace(x.val::text,'{',''),'}','') as status, count(t.*)
from t, (values ('{25}'::int[]), ('{3,17}'), ('{40,28,6}'), ('{17}')) as x(val)
where t.status=any(x.val)
group by replace(replace(x.val::text,'{',''),'}','');

 status  | count
---------+-------
 25      |     3
 3,17    |     8
 40,28,6 |     3
 17      |     2
(4 rows)

Re: unsure of how to query for desired data/output

From
Mark Roberts
Date:
On Mon, 2008-12-01 at 16:08 -0500, Rodrigo E. De León Plicet wrote:
> On Mon, Dec 1, 2008 at 11:35 AM, Carol Cheung
> <cacheung@consumercontact.com> wrote:
> > Is it possible to get the following based on the above list of numbers:
> >
> > 25|3
> > 3,17|8
> > 40,28,6|3
> > 17|2
>
> create table t (
> status int
> );
>
> insert into t values
> (25),(25),(25),(3),(3),(3),(3),(3),(3),(17),(17),(6),(28),(28);
>
> select * from t;
>
>  status
> --------
>      25
>      25
>      25
>       3
>       3
>       3
>       3
>       3
>       3
>      17
>      17
>       6
>      28
>      28
> (14 rows)
>
> select replace(replace(x.val::text,'{',''),'}','') as status, count(t.*)
> from t, (values ('{25}'::int[]), ('{3,17}'), ('{40,28,6}'), ('{17}')) as x(val)
> where t.status=any(x.val)
> group by replace(replace(x.val::text,'{',''),'}','');
>
>  status  | count
> ---------+-------
>  25      |     3
>  3,17    |     8
>  40,28,6 |     3
>  17      |     2
> (4 rows)
>

Well, if you have a somewhat static list of interesting statuses (such
that you always want to monitor for the same set of statuses), you could
try something like this.  It works by using a table
(interesting_statuses) that groups the statuses into an interesting
group with an array.

The join makes sure that each status (and sum) is joined to the
appropriate array(s), and the final group simply sums the appropriate
status counts by list.

For more information about arrays:
http://www.postgresql.org/docs/8.3/interactive/arrays.html

--- SETUP ---
create temp table status (status integer);
create temp table interesting_statuses (status_list_no integer,
status_list integer[]);

insert into status values
(25),(25),(25),(3),(3),(3),(3),(3),(3),(17),(17),(6),(28),(28);
insert into interesting_statuses values (0, ARRAY[25]), (1, ARRAY[3,
17]), (2, ARRAY[40,28,6]), (3, ARRAY[17]);

-- Query --

select status_list, sum(status_count) as total_status_counts
from (
        select status, count(1) as status_count
        from status
        group by status
    ) x
    left outer join interesting_statuses int on (status =
ANY(status_list))
group by status_list
order by sum(status_count) desc
;

----
CREATE TABLE
Time: 3.839 ms
CREATE TABLE
Time: 62.156 ms
INSERT 0 14
Time: 1.737 ms
INSERT 0 4
Time: 0.579 ms
 status_list | total_status_counts
-------------+---------------------
 {3,17}      |                   8
 {25}        |                   3
 {40,28,6}   |                   3
 {17}        |                   2
(4 rows)


-Mark


Re: unsure of how to query for desired data/output

From
Mark Roberts
Date:
A coworker points out that my status list can be more naturally
expressed as an unkeyed join table:

create table status_groupings (
    status_no,
    grouping_no
);

I also suggest starting with status_groupings and then left joining over
to statuses (so that you catch the case of a status not having any
values), or inner joining so that you cull out unnecessary statuses.

Shout outs to Kane.

-Mark

On Mon, 2008-12-01 at 14:37 -0800, Mark Roberts wrote:
> On Mon, 2008-12-01 at 16:08 -0500, Rodrigo E. De León Plicet wrote:
> > On Mon, Dec 1, 2008 at 11:35 AM, Carol Cheung
> > <cacheung@consumercontact.com> wrote:
> > > Is it possible to get the following based on the above list of numbers:
> > >
> > > 25|3
> > > 3,17|8
> > > 40,28,6|3
> > > 17|2
> >
> > create table t (
> > status int
> > );
> >
> > insert into t values
> > (25),(25),(25),(3),(3),(3),(3),(3),(3),(17),(17),(6),(28),(28);
> >
> > select * from t;
> >
> >  status
> > --------
> >      25
> >      25
> >      25
> >       3
> >       3
> >       3
> >       3
> >       3
> >       3
> >      17
> >      17
> >       6
> >      28
> >      28
> > (14 rows)
> >
> > select replace(replace(x.val::text,'{',''),'}','') as status, count(t.*)
> > from t, (values ('{25}'::int[]), ('{3,17}'), ('{40,28,6}'), ('{17}')) as x(val)
> > where t.status=any(x.val)
> > group by replace(replace(x.val::text,'{',''),'}','');
> >
> >  status  | count
> > ---------+-------
> >  25      |     3
> >  3,17    |     8
> >  40,28,6 |     3
> >  17      |     2
> > (4 rows)
> >
>
> Well, if you have a somewhat static list of interesting statuses (such
> that you always want to monitor for the same set of statuses), you could
> try something like this.  It works by using a table
> (interesting_statuses) that groups the statuses into an interesting
> group with an array.
>
> The join makes sure that each status (and sum) is joined to the
> appropriate array(s), and the final group simply sums the appropriate
> status counts by list.
>
> For more information about arrays:
> http://www.postgresql.org/docs/8.3/interactive/arrays.html
>
> --- SETUP ---
> create temp table status (status integer);
> create temp table interesting_statuses (status_list_no integer,
> status_list integer[]);
>
> insert into status values
> (25),(25),(25),(3),(3),(3),(3),(3),(3),(17),(17),(6),(28),(28);
> insert into interesting_statuses values (0, ARRAY[25]), (1, ARRAY[3,
> 17]), (2, ARRAY[40,28,6]), (3, ARRAY[17]);
>
> -- Query --
>
> select status_list, sum(status_count) as total_status_counts
> from (
>         select status, count(1) as status_count
>         from status
>         group by status
>     ) x
>     left outer join interesting_statuses int on (status =
> ANY(status_list))
> group by status_list
> order by sum(status_count) desc
> ;
>
> ----
> CREATE TABLE
> Time: 3.839 ms
> CREATE TABLE
> Time: 62.156 ms
> INSERT 0 14
> Time: 1.737 ms
> INSERT 0 4
> Time: 0.579 ms
>  status_list | total_status_counts
> -------------+---------------------
>  {3,17}      |                   8
>  {25}        |                   3
>  {40,28,6}   |                   3
>  {17}        |                   2
> (4 rows)
>
>
> -Mark
>
>