I am quite unfamiliar to complex SQL requests ...
What I am trying to achieve is to display of map of active weather alerts on a leaflet map page.
Started by filling a Postgis table with the RSS feed from national weather agencies, then create a view by selecting the ROWs with an expired date later than the actual date and publishing this view through a Geoserver WFS service.
Looked nice except that each geographic area add multiple event-effective-expires features leading to a sort of multiple layers wher only the top event was displayed.
The issue I have is that for each area/polygon I have multiples lines for miscellaneous events/dates that I have to sort out.
The initial table as a structure like :
areadesc(county)|event(type of alert)|effective(date)|expires(date)|severity(low,medium,severe)
What I did to try sort this mess was: first create a view per event to have only the latest expires alert of "such event" per location:
SELECT DISTINCT ON (country.areadesc)
country.areadesc,
country.event,
country.effective,
country.expires,
country.severity
FROM
country
WHERE
country.expires >= now() AND now() >= country.effective
AND country.event::text = 'Thunderstorms'::text
ORDER BY
country.areadesc, country.expires;
I did this for each event I was interested by.
Second I created an aggregated view for each area with the content of the relevant event type :
SELECT DISTINCT
country.areadesc,
country_thunderstorms.severity AS thunderstorms_severity,
country_thunderstorms.effective AS thunderstorms_effective,
country_rain.effective AS rain_effective,
country_rain.expires AS rain_expires,
country_districts.geom
FROM
country_alerts
LEFT JOIN
country_thunderstorms ON country.areadesc::text = country_thunderstorms.areadesc::text
LEFT JOIN
country_wind ON country.areadesc::text = country_wind.areadesc::text
LEFT JOIN
country_rain ON country.areadesc::text = country_rain.areadesc::text
LEFT JOIN
country_districts ON country.areadesc::text = country_districts.name_en::text
WHERE
country.expires >= now() AND now() >= country.effective
AND (country.title::text = ANY (ARRAY['Thunderstorms'::character varying, 'Wind'::character varying, 'Rain'::character varying]::text[]))
ORDER BY
country.areadesc;
All this stuff sort of do the job but looks to quite of a hammer to kill a fly.
I am sure there is a way to achieve this in a single run with nested SELECT but absolutely can't figure how :-(
Any suggestion is welcome , thanks for your help.
I'm not sure if I have answered your question but you can try window functions, like dense_rank() to rank your row.
SELECT
country,
event_type,
effective_date,
expires,
severity,
dense_rank()
OVER(PARTITION BY country,event_type
ORDER BY effective_date desc, expires desc) as rnk
FROM weather
then write an outer query on it to get only the first rank.
SELECT * FROM (
SELECT
country,
event_type,
effective_date,
expires,
severity,
dense_rank()
OVER(PARTITION BY country,event_type
ORDER BY effective_date desc, expires desc) as rnk
FROM weather) X WHERE rnk=1
country | event_type | effective_date | expires | severity | rnk |
---|---|---|---|---|---|
India | Rain | 2021-08-01T00:30:01Z | 2021-08-01T00:36:34Z | Medium | 1 |
India | Rain | 2021-08-01T00:22:01Z | 2021-08-01T02:03:34Z | Medium | 2 |
India | Rain | 2021-08-01T00:00:01Z | 2021-08-01T00:24:34Z | Medium | 3 |
India | thunderstorm | 2021-08-01T00:32:01Z | 2021-08-01T00:32:34Z | Low | 1 |
India | thunderstorm | 2021-08-01T00:30:01Z | 2021-08-01T00:23:34Z | Medium | 2 |
India | thunderstorm | 2021-08-01T00:11:01Z | 2021-08-01T00:10:34Z | High | 3 |
India | Wind | 2021-08-01T00:10:01Z | 2021-08-01T01:05:34Z | Low | 1 |
India | Wind | 2021-08-01T00:00:01Z | 2021-08-01T04:01:34Z | Low | 2 |
India | Wind | 2021-08-01T00:00:01Z | 2021-08-01T00:25:34Z | Low | 3 |
Edit
Based on your answer I understand that you are looking for a pivot result like below.
select * from weather where rnk=1;
country | event_type | effective_date | expires | severity | rnk |
---|---|---|---|---|---|
India | Rain | 2021-08-01T00:30:01Z | 2021-08-01T00:36:34Z | Medium | 1 |
India | thunderstorm | 2021-08-01T00:32:01Z | 2021-08-01T00:32:34Z | Low | 1 |
India | Wind | 2021-08-01T00:10:01Z | 2021-08-01T01:05:34Z | Low | 1 |
select
country,
max(case when (event_type='Rain') then severity else NULL end) as
Rain_Severity,
max(case when (event_type='Rain') then effective_date else NULL end) as
Rain_Effective_date,
max(case when (event_type='Rain') then expires else NULL end) as
Rain_expires,
max(case when (event_type='thunderstorm') then severity else NULL end)
as Thunderstorm_Severity,
max(case when (event_type='thunderstorm') then effective_date else NULL
end) as Thunderstorm_Effective_date,
max(case when (event_type='thunderstorm') then expires else NULL end) as
Thunderstorm_expires,
max(case when (event_type='Wind') then severity else NULL end) as
Wind_Severity,
max(case when (event_type='Wind') then effective_date else NULL end) as
Wind_Effective_date,
max(case when (event_type='Wind') then expires else NULL end) as
Wind_expires
from weather
where rnk=1
group by country;
country | rain_severity | rain_effective_date | rain_expires | thunderstorm_severity | thunderstorm_effective_date | thunderstorm_expires | wind_severity | wind_effective_date | wind_expires |
---|---|---|---|---|---|---|---|---|---|
India | Medium | 2021-08-01T00:30:01Z | 2021-08-01T00:36:34Z | Low | 2021-08-01T00:32:01Z | 2021-08-01T00:32:34Z | Low | 2021-08-01T00:10:01Z | 2021-08-01T01:05:34Z |