The (2nd form of the) `crosstab()` function expects these columns as input: - 1 `row_name` column - (0-n) `extra` columns - 1 `category` column - **1** `value` column See: - [Pivot on Multiple Columns using Tablefunc][1] Your specific difficulty is that you are trying to process **3** `value` columns at once (`param1`, `param2`, `param3`). Your input table is already "half pivoted". There are various ways to solve this. Joining three crosstab queries is probably cleanest. Demonstrating for **5** weeks: SELECT * FROM crosstab( 'SELECT id, week, param1 FROM tbl ORDER BY 1,2' , 'SELECT generate_series(1,5)' ) ct1 (id int, w1p1 int, w1p2 int, w1p3 int, w1p4 int, w1p5 int) JOIN crosstab( 'SELECT id, week, param2 FROM tbl ORDER BY 1,2' , 'SELECT generate_series(1,5)' ) ct2 (id int, w2p1 int, w2p2 int, w2p3 int, w2p4 int, w2p5 int) USING (id) JOIN crosstab( 'SELECT id, week, param3 FROM tbl ORDER BY 1,2' , 'SELECT generate_series(1,5)' ) ct3 (id int, w3p1 int, w3p2 int, w3p3 int, w3p4 int, w3p5 int) USING (id) *dbfiddle [here](http://dbfiddle.uk/?rdbms=postgres_10&fiddle=26fe344eb026e262f537ec0eda7f07e3)* `[INNER] JOIN` is safe, since all instances are guaranteed to return the same week `id`s. Else we'd use `FULL JOIN`. With over 50 weeks, you get over 150 columns. Is that really what you want? [1]: https://stackoverflow.com/questions/15415446/pivot-on-multiple-columns-using-tablefunc/15421607#15421607