I suggest a radially new approach with `crosstab()` from the additional module tablefunc. You need to install it once per database. Detailed instructions: - [PostgreSQL Crosstab Query][1] </p> SELECT k.name, keyword_id, project_id, now()::date AS the_date , t AS today, y As yesterday, w AS week, m AS month FROM crosstab( $$ SELECT rn , pk.keyword_id , pk.project_id , d.created_at , COALESCE(pr.pos, 0) AS pos FROM (SELECT *, row_number() OVER () AS rn FROM project_keyword) pk CROSS JOIN ( VALUES (now()::date) , (now()::date - 1) , (now()::date - 7) ,((now() - interval '1 month')::date) ) d(created_at) LEFT JOIN ( SELECT keyword_id , project_id , created_at::date AS created_at , min(position) AS pos FROM project_report GROUP BY keyword_id, project_id, created_at::date ) pr USING (keyword_id, project_id, created_at) ORDER BY pk.rn, d.created_at $$ ,$$ VALUES (now()::date) , (now()::date - 1) , (now()::date - 7) , ((now() - interval '1 month')::date) $$ ) ct (rn int, keyword_id int, project_id int , t int, y int, w int, m int) JOIN keyword k USING (keyword_id); Returns: name keyword_id project_id the_date today yesterday week month Cheese 1 1 2014-07-11 1 1 1 0 Monitor 2 1 2014-07-11 2 2 2 0 Apple 3 1 2014-07-11 9 9 9 0 Apple1 4 1 2014-07-11 0 0 0 0 Iphone 5 1 2014-07-11 0 33 34 0 ###Explain - We need a single unique column per group for `crosstab()`. Since you don't have that per `(keyword_id int, project_id)` I am adding a surrogate key with `row_number()` to `project_keyword`. - JOIN that to a set of dates you are interested in (today, yesterday, ...). One row per date. - LEFT JOIN to `project_reports` for said days. - Cross-tabulate to get one column with the position per date. - Finally JOIN to `keyword` just to add the name. Add the current date and remove `rn` from the result while being at it. Can't provide a fiddle, installing additional modules is not allowed there. [1]: http://stackoverflow.com/questions/3002499/postgresql-crosstab-query/11751905#11751905