如何在嵌套 SELECT 查询 Postgresql 中聚合多行
How to aggregate multiple rows in nested SELECT query Postgresql
我对复杂的SQL请求很陌生...
我想要实现的是在传单地图页面上显示活动天气警报的地图。
首先使用来自国家气象机构的 RSS 提要填充 Postgis table,然后通过选择过期日期晚于实际日期的 ROW 并通过 Geoserver WFS 服务发布此视图来创建视图.
除了每个地理区域都添加了多个事件有效过期功能,导致一种只显示顶级事件的多层之外,看起来不错。
我遇到的问题是,对于每个 area/polygon,我都有多行杂项 events/dates 需要整理。
最初的table结构像:
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 来实现这一点,但绝对不知道如何:-(
欢迎提出任何建议,感谢您的帮助。
我不确定我是否回答了您的问题,但您可以尝试 window 函数,例如 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
我对复杂的SQL请求很陌生...
我想要实现的是在传单地图页面上显示活动天气警报的地图。
首先使用来自国家气象机构的 RSS 提要填充 Postgis table,然后通过选择过期日期晚于实际日期的 ROW 并通过 Geoserver WFS 服务发布此视图来创建视图.
除了每个地理区域都添加了多个事件有效过期功能,导致一种只显示顶级事件的多层之外,看起来不错。
我遇到的问题是,对于每个 area/polygon,我都有多行杂项 events/dates 需要整理。
最初的table结构像:
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 来实现这一点,但绝对不知道如何:-(
欢迎提出任何建议,感谢您的帮助。
我不确定我是否回答了您的问题,但您可以尝试 window 函数,例如 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 |