If I understand correctly, you would like to count the number of distinct item ids up to each each row (by date) and return all rows where the count is three.
If Postgres supported this, you could use:
select t.*
from (select t.*,
count(*) filter (where id = min_id) over (order by date desc) as cnt_itemid
from (select t.*,
min(id) over (partition by itemid order by date desc) as min_id
from t
) t
) t
where cnt_itemid <= 3;
Alas, Postgres does not support COUNT(DISTINCT)
as a window function. But you can calculate it using DENSE_RANK()
:
select t.*
from (select t.*,
count(*) over (filter where id = min_id) as cnt_itemid
from (select t.*,
min(id) over (partition by itemid order by date) as min_id
from t
) t
) t
where cnt_itemid <= 3;
However, this returns all the most recent rows up before the 4th item -- so it has extra rows.
To get four rows, you want the first where the item id is "3". One method is:
select t.*
from (select t.*, min(id) filter (where cnt_itemid = 3) over () as min_cnt_itemid_3
from (select t.*,
count(*) filter (where id = min_id) over (order by date desc) as cnt_itemid
from (select t.*,
min(id) over (partition by itemid order by date desc) as min_id
from t
) t
) t
) t
where id <= min_cnt_itemid_3;
You can also do this by identifying the first occurrence of the "third item" and then choosing all rows up to that row:
select t.*
from t join
(select itemid, min(max_date) over () as min_max_date
from (select t.itemid, max(date) as max_date
from t
group by t.itemid
order by max(t.date) desc
limit 3
) t
) tt
on t.itemid = tt.itemid and t.date >= tt.min_max_date;
This fiddle shows each of these.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…