From the following table (named status), I need to extract town codes having a status of '01' by the end of year 2015. The column status_date stores the date at which a town changed its status.
gid  | town      | status  | status_date
-----+-----------+---------+-------------
1    | 86001     | 00      | 2000-01-01
2    | 86001     | 01      | 2016-03-01
3    | 86002     | 01      | 2000-01-01
4    | 86003     | 00      | 2000-01-01
5    | 86003     | 01      | 2015-03-01
6    | 86003     | 02      | 2015-09-01
I can achieve that with the following query which is a bit long:
WITH tab AS (SELECT town, MAX(status_date) FROM status GROUP BY town)
  SELECT 
    t.town
  FROM tab t
    LEFT JOIN status s ON t.town = s.town AND t.max = s.status_date 
  WHERE t.max < '2016-01-01' AND s.status = '01' ; 
The result is:
town   
-------
86002
Any idea on how to make this query simpler? Is the WITH essential?
To create the table for testing:
CREATE TABLE status (gid serial NOT NULL, town CHARACTER VARYING(5), status CHARACTER VARYING(2), status_date DATE) ;
INSERT INTO status (town, status, status_date) VALUES
  ('86001', '00', '2000-01-01'),
  ('86001', '01', '2016-03-01'),
  ('86002', '01', '2000-01-01'),
  ('86003', '00', '2000-01-01'),
  ('86003', '01', '2015-03-01'),
  ('86003', '02', '2015-09-01') ;
                You can do this with distinct on:
select s.*
from (select distinct on (s.town) s.*
      from status s
      where s.status_date < '2016-01-01'
      order by s.town, s.status_date desc
     ) s
where status = '01';
This query will get the latest status for each town up to the end of 2015.  The outer query then selects those that are 01.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With