如何在Postgres中的一个表中划分行

时间:2015-06-27 20:12:50

标签: sql postgresql

我在Postgres工作时有这样一个表:

mon   yyyy   weather
Apr   2014   78.45
Apr   2015   77.32
May   2014   79.56
May   2015   78.43

我希望能够查询一些结果,按照" mon"排序,其中weather列值按年逐月划分。

换句话说,我想查询2015年4月除以2014年4月的天气。

但是,我想以这样的方式编写查询:我不必指定月份或年份,查询会根据以下内容自动划分weather值:2014年4月/ 2014年4月,然后是2014年5月/ 2014年5月,无需每月和每年关键,这很费力。

我有以下代码,但这会扩展不是我想要的列:

select (select "Weather" from yoy 
        where mon = 'Apr' and yyyy = '2015'
     )/(select "American" from yoy 
        where mon = 'Apr' and yyyy = '2014'
     ) as "weather_apr",
     (select "Weather" from yoy 
      where mon = 'May' and yyyy = '2015'
     )/(select "Weather" from yoy 
        where mon = 'May' and yyyy = '2014'
     ) as "weather_may",
from yoy;

4 个答案:

答案 0 :(得分:1)

在我看来,这是利用分析window function的正确方案。这里没有连接的魔力:

SELECT yyyy,       
       weather,
       mon,
       lead( weather ) over (partition by mon order by mon, yyyy desc),
       weather / lead( weather ) over (partition by mon order by mon, yyyy desc)
FROM joy

答案 1 :(得分:0)

我认为你需要一个自我加入,如下例所示:

SELECT j1."yyyy" As year,
       j2."yyyy" As next_year,
       j1."mon",
       j1."weather",
       j2."weather" As "weather from next year",
       j1."weather"::float / j2."weather" As divide
FROM joy j1
JOIN joy j2 
ON j1."yyyy" = j2."yyyy" - 1 AND j1."mon" = j2."mon"

演示:http://sqlfiddle.com/#!15/e02ec/1

答案 2 :(得分:0)

您可以使用表yoy的自联接。请参阅此查询,该查询将当前年与上一个加入:

select *
from yoy a
join yoy b on a.yyyy::int = b.yyyy::int+ 1 and a.mon = b.mon

 mon | yyyy | weather | mon | yyyy | weather
-----+------+---------+-----+------+---------
 Apr | 2015 |   77.32 | Apr | 2014 |   78.45
 May | 2015 |   78.43 | May | 2014 |   79.56
(2 rows)

现在您可以轻松进行计算:

select a.mon, a.weather/ b.weather as weather
from yoy a
join yoy b on a.yyyy::int = b.yyyy::int+ 1 and a.mon = b.mon

 mon |        weather
-----+------------------------
 Apr | 0.98559592096876991714
 May | 0.98579688285570638512
(2 rows)

答案 3 :(得分:0)

我发现条件聚合对于这种类型的查询非常有用:

select mon,
       max(case when yyyy = 2014 then weather end) as weather_2014,
       max(case when yyyy = 2015 then weather end) as weather_2015,
       (max(case when yyyy = 2015 then weather end) /
        max(case when yyyy = 2014 then weather end)
       ) as ratio
from yoy
group by mon

这假设您希望每月减少一行。要获取上一个值,只需使用lag()

select yoy.*,
       lag(weather) over (partition by month order by year) as prev_weather
from yoy;