Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><em>First</em> of all, you can have a much simpler <code>generate_series()</code> table expression. Equivalent to yours (except for descending order, that contradicts the rest of your question anyways):</p> <pre><code>SELECT generate_series('2012-01-01'::date, now()::date, '1d')::date </code></pre> <p>The type <code>date</code> is coerced to <code>timestamptz</code> automatically on input. The return type is <code>timestamptz</code> either way. I use a subquery below, so I can cast to the output to <code>date</code> right away.</p> <p><em>Next</em>, <code>max()</code> as window function returns exactly what you need: the highest value since <em>frame</em> start ignoring <code>NULL</code> values. Building on that, you get a <strong>radically simple</strong> query. </p> <h3>For a given widget_id</h3> <p>Most likely faster than involving <code>CROSS JOIN</code> or <code>WITH RECURSIVE</code>:</p> <pre><code>SELECT a.day, s.* FROM ( SELECT d.day ,max(s.for_date) OVER (ORDER BY d.day) AS effective_date FROM ( SELECT generate_series('2012-01-01'::date, now()::date, '1d')::date ) d(day) LEFT JOIN score s ON s.for_date = d.day AND s.widget_id = 1337 -- "for a given widget_id" ) a LEFT JOIN score s ON s.for_date = a.effective_date AND s.widget_id = 1337 ORDER BY a.day; </code></pre> <p><a href="http://www.sqlfiddle.com/#!12/dd2f2/6" rel="noreferrer"><strong>->sqlfiddle</strong></a></p> <p>With this query you can put any column from <code>score</code> you like into the final <code>SELECT</code> list. I put s.* for simplicity. Pick your columns.</p> <p>If you want to start your output with the first day that actually <em>has</em> a score, simply replace the last <code>LEFT JOIN</code> with <code>JOIN</code>.</p> <h3>Generic form for all widget_id's</h3> <p>Here I use a <code>CROSS JOIN</code> to produce a row for every widget on every date ..</p> <pre><code>SELECT a.day, a.widget_id, s.score FROM ( SELECT d.day, w.widget_id ,max(s.for_date) OVER (PARTITION BY w.widget_id ORDER BY d.day) AS effective_date FROM (SELECT generate_series('2012-05-05'::date ,'2012-05-15'::date, '1d')::date AS day) d CROSS JOIN (SELECT DISTINCT widget_id FROM score) AS w LEFT JOIN score s ON s.for_date = d.day AND s.widget_id = w.widget_id ) a JOIN score s ON s.for_date = a.effective_date AND s.widget_id = a.widget_id -- instead of LEFT JOIN ORDER BY a.day, a.widget_id; </code></pre> <p><a href="http://www.sqlfiddle.com/#!12/c3a22/3" rel="noreferrer"><strong>->sqlfiddle</strong></a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload