【问题标题】:How to aggregate multiple rows in nested SELECT query Postgresql如何在嵌套的 SELECT 查询 Postgresql 中聚合多行
【发布时间】:2021-08-01 10:00:47
【问题描述】:

我对复杂的 SQL 请求很陌生...

我想要实现的是在传单地图页面上显示活动天气警报的地图。

首先使用来自国家气象机构的 RSS 提要填充 Postgis 表,然后通过选择过期日期晚于实际日期的 ROW 并通过 Geoserver WFS 服务发布此视图来创建视图。

看起来不错,只是每个地理区域都添加了多个事件有效过期功能,从而形成了一种仅显示顶部事件的多层。

我遇到的问题是,对于每个区域/多边形,我都有多条线用于我必须整理的杂项事件/日期。

初始表的结构如下:

     areadesc(county)|event(type of alert)|effective(date)|expires(date)|severity(low,medium,severe)

我为解决这个问题所做的尝试是:首先为每个事件创建一个视图,以便每个位置只有“此类事件”的最新过期警报:

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;

我对每个我感兴趣的事件都这样做了。

其次,我为每个区域创建了一个聚合视图,其中包含相关事件类型的内容:

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;

所有这些东西都可以完成这项工作,但看起来就像是一把锤子可以杀死一只苍蝇。

我确信有一种方法可以通过嵌套 SELECT 在一次运行中实现这一点,但绝对不知道如何:-(

欢迎任何建议,感谢您的帮助。

【问题讨论】:

  • 目前还不清楚您要达到的目标
  • 好吧,我尝试在单行上移动,按区域分组,只有每种类型事件的最新:-(
  • 还不是很清楚。看起来您正在寻找group by
  • 样本数据和期望的结果真的很有帮助。
  • 我作为答案发布了示例数据和期望的结果

标签: sql postgresql nested distinct-on


【解决方案1】:

我不确定我是否已经回答了您的问题,但您可以尝试使用诸如 dense_rank() 之类的窗口函数来对您的行进行排名。

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

然后在其上编写一个外部查询以仅获得第一名。

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

编辑

根据您的回答,我了解到您正在寻找如下所示的数据透视结果。

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

【讨论】:

  • 谢谢Pradeep,这种方法对排序非常有效,我设法得到了一个按区域和事件排序的表格,只有最后一个相关警报。现在我需要离开:国家 |事件类型 |生效日期 |过期|严重程度:国家 | event_type1_severity | event_type1_effective | event_type1_expires | event_type2_severity | event_type2_effective | event_type2_expires |等等....
  • 嗨@rafiosan,我已经在我的回答中添加了新信息,如果它解决了您的问题,您可以查看它。
  • 亲爱的 Pradeep,这是完美的,正是我想要的!非常感谢您的帮助!!!!
  • @Rafiosan,我很乐意为您提供帮助,如果对您有帮助,您可以将答案标记为已接受。
  • 我做了,但作为新手我还不能为答案评分,但是系统提到我的反馈已被考虑在内。
猜你喜欢
  • 2019-08-08
  • 1970-01-01
  • 1970-01-01
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
相关资源
最近更新 更多