Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 7068C632DF4 for ; Mon, 1 Feb 2010 12:34:56 -0400 (AST) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 10270-07 for ; Mon, 1 Feb 2010 16:34:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-yw0-f179.google.com (mail-yw0-f179.google.com [209.85.211.179]) by mail.postgresql.org (Postfix) with ESMTP id D89C2632A73 for ; Mon, 1 Feb 2010 12:34:45 -0400 (AST) Received: by ywh9 with SMTP id 9so4550721ywh.19 for ; Mon, 01 Feb 2010 08:34:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:cc:content-type; bh=Dj3ujXStk0Z3MurqqE1LdYDqUn1ysNBOjUC2gpwTMII=; b=naOFQLwqpS1F0uIrxGImdZzp8E0ARx7WKjieM6pblwb+6rWOuBbfnsb+dd9YlOGvEs 1QB1Krik3FP5TsCCdptOi4QclXR5urMB5etnnWCzZek3e4gdva/zZZkejqbLCQS5TMhR Lan7ijoaySaJ95GhVHn02xsRpUjy7MQ35Ys48= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; b=OuCJNegA1JkR6Z0DH8ct100tyylVB8ownMncF+dw1VvYY2nJfSDE7XmfvUsDKDICyH 4ucVQUrYJWKMqIaZGD5ndIrDt2SKBQV/EtfxCsziwE+ZeI7bQuXCRTmdkrHYJ1eMyDgY 35ZezxQF/LeZmNt/O+QXNb1NX7/bGl40JAxLk= MIME-Version: 1.0 Received: by 10.90.246.19 with SMTP id t19mr4013749agh.119.1265042085025; Mon, 01 Feb 2010 08:34:45 -0800 (PST) In-Reply-To: References: Date: Mon, 1 Feb 2010 11:34:44 -0500 Message-ID: <5ab13581002010834k11c1be7ci4b4aef1b6778be4f@mail.gmail.com> Subject: Re: Crosstab Confusion From: Lee Hachadoorian To: Adam Sherman Cc: pgsql-sql@postgresql.org Content-Type: multipart/alternative; boundary=001636283dce1a98af047e8c908e X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-2.598 tagged_above=-10 required=5 tests=BAYES_00=-2.599, HTML_MESSAGE=0.001 X-Spam-Level: X-Archive-Number: 201002/17 X-Sequence-Number: 33616 --001636283dce1a98af047e8c908e Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: quoted-printable I'm flying blind here since I have nothing that looks like the structure yo= u described to experiment on, but based on some crosstabs I have set up this should get you started. Explanatory notes follow. SELECT pivot.* FROM crosstab(' --row header, column header, cell value SELECT customer_id, extract(day FROM date), sum(amount) WHERE extract(month FROM date) =3D 1 --desired month, 1=3DJan, 2=3DFeb,= etc. FROM your_table GROUP BY 1, 2 ORDER BY 1, 2 ',' --list of column headers SELECT 1, 2, 3, [=85] 31 ') --list of column names for final result set --does not have to match column names from crosstab() section! pivot(customer_id integer, day1 numeric(10,4), day2 numeric(10,4), day3 numeric(10,4), [=85] day31 numeric(10,4)) ; You basically have three parts: 1) SELECT query in the form (row header, column header, cell value). In thi= s case it is an aggregate query so that you can sum the transactions over a given day. 2) List of column headers. If you want, this can SELECT from another table, so you can have a table with rows 1, 2, 3, etc and use it to select the day= s from the month instead of listing them manually. 3) List of output columns, which follows "pivot" in the text above. Note that "pivot" is an arbitrary name. You can use foo, bar, or whatever, but that will be the name of the table which must be used to reference the columns in the top SELECT list. Note that my somewhat bizarre indenting / end of line structure is designed so that, when using pgAdmin, I can very quickly select and execute just the value query or column header query, which lets me experiment as I build the crosstab. Note, finally, that the list of output columns (following "pivot") should b= e one more than the number of columns in section 2 (technically, you can circumvent this limitation, but it's complicated and seems unnecessary for your use case). That could be problematic when running this query in the middle of the month and the number of value rows per customer doesn't match the number expected in the list of column headers and list of output columns. I don't know of any way to make the list of output columns vary dynamically, but perhaps someone else here does? Otherwise, you would have to either (a) make 31 different crosstab queries and choose which one to ru= n based on the day of the month, or (b) come up with some way to "pad" the value table created in part 1 so that it lists customer_id, day, 0 for all days which have no customer transactions. (Perhaps create a dummy customer_id that has no transactions for all days in the month, which shoul= d be enough to trick the crosstab function into thinking it has something to fill the last columns. --Lee --=20 Lee Hachadoorian PhD Student, Geography Program in Earth & Environmental Sciences CUNY Graduate Center --001636283dce1a98af047e8c908e Content-Type: text/html; charset=windows-1252 Content-Transfer-Encoding: quoted-printable I'm flying blind here since I have nothing that looks like the structur= e you described to experiment on, but based on some crosstabs I have set up= this should get you started. Explanatory notes follow.

SELECT pivot= .*
FROM crosstab('
=A0=A0=A0 --row header, column header, cell value=A0=A0=A0 SELECT customer_id, extract(day FROM date), sum(amount)
=A0= =A0=A0 WHERE extract(month FROM date) =3D 1 --desired month, 1=3DJan, 2=3DF= eb, etc.
=A0=A0=A0 FROM your_table
=A0=A0=A0 GROUP BY 1, 2
=A0=A0=A0 ORDER BY 1, 2
=A0=A0=A0 ','=
=A0=A0=A0 --list of column headers
=A0=A0=A0 SELECT 1, 2, 3, [=85] 3= 1
=A0=A0=A0 ')
=A0=A0=A0 --list of column names for final result= set
=A0=A0=A0 --does not have to match column names from crosstab() sec= tion!
=A0=A0=A0 pivot(customer_id integer, day1 numeric(10,4), day2 numeric(10,4)= , day3 numeric(10,4), [=85] day31 numeric(10,4))
;

You basically = have three parts:

1) SELECT query in the form (row header, column he= ader, cell value). In this case it is an aggregate query so that=A0 you can= sum the transactions over a given day.

2) List of column headers. If you want, this can SELECT from another ta= ble, so you can have a table with rows 1, 2, 3, etc and use it to select th= e days from the month instead of listing them manually.

3) List of o= utput columns, which follows "pivot" in the text above. Note that= "pivot" is an arbitrary name. You can use foo, bar, or whatever,= but that will be the name of the table which must be used to reference the= columns in the top SELECT list.

Note that my somewhat bizarre indenting / end of line structure is desi= gned so that, when using pgAdmin, I can very quickly select and execute jus= t the value query or column header query, which lets me experiment as I bui= ld the crosstab.

Note, finally, that the list of output columns (following "pivot&q= uot;) should be one more than the number of columns in section 2 (technical= ly, you can circumvent this limitation, but it's complicated and seems = unnecessary for your use case). That could be problematic when running this= query in the middle of the month and the number of value rows per customer= doesn't match the number expected in the list of column headers and li= st of output columns. I don't know of any way to make the list of outpu= t columns vary dynamically, but perhaps someone else here does? Otherwise, = you would have to either (a) make 31 different crosstab queries and choose = which one to run based on the day of the month, or (b) come up with some wa= y to "pad" the value table created in part 1 so that it lists cus= tomer_id, day, 0 for all days which have no customer transactions. (Perhaps= create a dummy customer_id that has no transactions for all days in the mo= nth, which should be enough to trick the crosstab function into thinking it= has something to fill the last columns.

--Lee

--
Lee HachadoorianPhD Student, Geography
Program in Earth & Environmental SciencesCUNY Graduate Center
--001636283dce1a98af047e8c908e--