PostgreSQL – Find All Items Where the 2 Latest Statuses Meet Condition

greatest-n-per-grouppostgresqlpostgresql-9.4

I have a table in a PostgreSQL database like this:

ID|Item-FK |timestamp|status
=============================
1 | 123    | ...     | EXPIRED
2 | 123    | ...     | PENDING
...

I want to query all items where the last two statuses are 'EXPIRED' & 'PENDING' like displayed in the sample above – 'PENDING' latest and 'EXPIRED' immediately before that.

Best Answer

You could do it like this to avoid needing to hardcode row numbers into your query:

select * 
  from t as a 
 where status = 'pending'      -- must be pending
   and exists
  (select * 
     from t as b
    where status = 'expired'   -- must have expired
      and a.itemfk = b.itemfk
      and b.id = 
         (select max(c.id)     -- must be the previous entry before pending
            from t as c
           where c.itemfk = b.itemfk
             and c.id < a.id)  -- must have expired before pending
  );

This method performs a lookup to get the maximum id of the entry prior to it being pending and then checks that it is the row marked as expired.

db<>fiddle example.