Re: cross tab confusion - Mailing list pgsql-general

From Joe Conway
Subject Re: cross tab confusion
Date
Msg-id 3E6BD8D5.2030607@joeconway.com
Whole thread Raw
In response to Re: cross tab confusion  (Matt Johnson <johnsonmlw@yahoo.com>)
List pgsql-general
Matt Johnson wrote:
> Please point out any stark errors in my thinking. This
> won't be a huge app (but then these things grow I
> guess so it's best to get these things right).
>

There is no way to completely automate this just using SQL, but I think
you're on track with using an external language like python to automate
the writing of your query.

As an alternative, you could try the contrib/tablefunc function
crosstab. I've posted a new version that includes an improved crosstab
function (see http://www.joeconway.com/ and look for the link
"contrib/tablefunc with hashed crosstab"). Here's what the solution
might look like for a 20 week semester (the example is long, but only
the last sql statement needs to be run each week):

create table pupil(pupil_id integer, name text);
insert into pupil values(1,'jeff');
insert into pupil values(2,'fred');
insert into pupil values(3,'rita');

create table reading_level(record_id integer, pupil_id integer, week
integer, level float8);
insert into reading_level values(1,1,1,6.1);
insert into reading_level values(2,2,1,4.3);
insert into reading_level values(3,1,2,6.2);
insert into reading_level values(4,2,2,4.4);

create or replace function weeks() returns setof integer as'
declare
   weeknum integer;
begin
   for weeknum in 1..20 loop
     return next weeknum;
   end loop;
   return;
end
' language 'plpgsql';

CREATE TYPE weekly_report_tup AS (
   name text,
   w1 float8,
   w2 float8,
   w3 float8,
   w4 float8,
   w5 float8,
   w6 float8,
   w7 float8,
   w8 float8,
   w9 float8,
   w10 float8,
   w11 float8,
   w12 float8,
   w13 float8,
   w14 float8,
   w15 float8,
   w16 float8,
   w17 float8,
   w18 float8,
   w19 float8,
   w20 float8
);

CREATE OR REPLACE FUNCTION weekly_report(text,text)
RETURNS setof weekly_report_tup
AS '$libdir/tablefunc','crosstab_hash'
LANGUAGE 'C' STABLE STRICT;

select * from weekly_report(
   'select p.name, r.week, r.level from pupil p, reading_level r
    where r.pupil_id = p.pupil_id',
   'select * from weeks()'
);
  name | w1  | w2  | w3 | w4 | w5 | w6 | w7 | w8 | w9 | w10 | w11 | w12 |
------+-----+-----+----+----+----+----+----+----+----+-----+-----+-----+
  jeff | 6.1 | 6.2 |    |    |    |    |    |    |    |     |     |
|
  fred | 4.3 | 4.4 |    |    |    |    |    |    |    |     |     |     |
(2 rows)

I've trimmed the output at w12 for clarity in the email, but 13-20 would
be there as well. You could easily extend this to 26 or 52 weeks if you
wanted. Now as more data is added...

insert into reading_level values(5,1,3,6.3);
insert into reading_level values(6,2,3,4.5);
insert into reading_level values(7,3,3,7.2);
select * from weekly_report(
   'select p.name, r.week, r.level from pupil p, reading_level r
    where r.pupil_id = p.pupil_id',
   'select * from weeks()'
);
  name | w1  | w2  | w3  | w4 | w5 | w6 | w7 | w8 | w9 | w10 | w11 | w12
------+-----+-----+-----+----+----+----+----+----+----+-----+-----+-----
  jeff | 6.1 | 6.2 | 6.3 |    |    |    |    |    |    |     |     |
  fred | 4.3 | 4.4 | 4.5 |    |    |    |    |    |    |     |     |
  rita |     |     | 7.2 |    |    |    |    |    |    |     |     |
(3 rows)

...you just run the query.

HTH,

Joe


pgsql-general by date:

Previous
From: Matt Johnson
Date:
Subject: Re: cross tab confusion
Next
From: "Thomas Hood"
Date:
Subject: foreign SERIAL keys in weak entity primary keys