2015-09-04 65 views
2

我有遍佈全球的數據點。每個數據點都有一個時間戳。PostgreSQL按季節分組(北半球和南半球)

我想按照季節分組數據,如圖所示(來源: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; 

我怎樣才能做到這一點對所有可能的年?我嘗試過...或者在...之間約會......但是這很慢。

怎樣才能在北半球和南半球選擇冬季?

更新

有關北半球冬季的所有數據我使用此查詢:

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) 

是否有一個更優雅的或有效的解決方案?

回答

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 
+0

我使用PostgreSQL 9.3.9。沒有稱爲make_date的函數。 – Stefan

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倍。

0

更簡潔,而且很可能具有更好的性能:

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;