PostgreSQL逐季(北半球和南半球)

时间:2015-09-04 08:17:34

标签: postgresql date postgis between

我的数据点遍布全球。每个数据点都有一个时间戳。

我希望按季节对数据进行分组,如图所示(来源:https://en.wikipedia.org/wiki/Season#/media/File:Seasons1.svg)。

enter image description here

这是我到目前为止所尝试的(北半球2011/2012冬季):

SELECT * FROM my_table 
    WHERE my_date BETWEEN '2011-12-21' AND '2012-03-21'
    AND ST_Y(ST_Centroid(geom)) > 0;

我可以在所有可能的年份做到这一点吗?我试过......或约会BETWEEN ......但这很慢。

如何选择北半球和南半球的冬季?

更新

对于北半球的所有冬季数据,我使用此查询:

CREATE TABLE season_winter_north AS WITH first_step AS (
SELECT
    id,
    extract(month from my_date)::int AS month,
    extract(day from my_date)::int AS day,
    ST_Centroid(geom) AS geom
FROM mytable 
    WHERE ST_Y(ST_Centroid(geom)) > 0)

(SELECT * FROM first_step
    WHERE month = 12
        AND day >= 21)

UNION ALL

(SELECT * FROM first_step
    WHERE month = ANY('{1,2}'))

UNION ALL

(SELECT * FROM first_step
    WHERE month = 3
        AND day<21)

是否有更优雅或更有效的解决方案?

3 个答案:

答案 0 :(得分:1)

更简洁,可能性能更好:

with t(my_date) as (
values ('2012-07-01'::date), ('2013-03-30'), ('2013-10-12'), ('2013-01-10') )
    select 
    case 
        when to_char(my_date,'MMDD') between '0321' and '0620' then 'spring'
        when to_char(my_date,'MMDD') between '0621' and '0922' then 'summer'
        when to_char(my_date,'MMDD') between '0923' and '1220' then 'fall'
        else                                                        'winter'
    end as season,
    my_date
    from t;

答案 1 :(得分:0)

with t(my_date) as (
    values ('2012-07-01'::date), ('2013-03-30'), ('2013-10-12'), ('2013-01-10')
)
select 
    case 
        when my_date between 
            make_date(extract(year from my_date)::int, 3, 21)
            and
            make_date(extract(year from my_date)::int, 6, 20)
        then 'spring'
        when my_date between 
            make_date(extract(year from my_date)::int, 6, 21)
            and
            make_date(extract(year from my_date)::int, 9, 22)
        then 'summer'
        when my_date between 
            make_date(extract(year from my_date)::int, 9, 23)
            and
            make_date(extract(year from my_date)::int, 12, 20)
        then 'fall'
        else 'winter'
    end as season,
    my_date
from t
;
season |  my_date   
--------+------------
summer | 2012-07-01
spring | 2013-03-30
fall   | 2013-10-12
winter | 2013-01-10

答案 2 :(得分:0)

我想在我的问题上发布这个额外的答案。使用此查询,不需要使用函数make_date(仅适用于postgresql 9.4。)。

使用此answer的代码,您可以为其他版本的PostgreSQL创建make_date()函数。

我也创造了这个功能,我发现了速度的显着差异。但我不知道,如果9.4中的make_date()函数。更快。

select 
case 
    when my_date between 
        (extract(year from my_date)::int||'-03-21')::date
        and
        (extract(year from my_date)::int||'-06-20')::date
    then 'spring'
    when my_date) between 
        (extract(year from my_date)::int||'-06-21')::date
        and
        (extract(year from my_date)::int||'-09-22')::date
    then 'summer'
    when my_date) between 
        (extract(year from my_date)::int||'-09-23')::date
        and
        (extract(year from my_date)::int||'-12-20')::date
    then 'fall'
    else 'winter'
end as season,
my_date
from my_table;

没有make_date()的查询比使用make_date快3到4倍。