查询同一行的 Min、Max 和关联列数据

war*_*ect 5 postgresql aggregate greatest-n-per-group postgresql-9.4

我有一个查询,其中按站点和月份返回平均值。我想知道的是按站点划分的月平均值的最小值和最大值以及(困难的部分)每个发生的月份。

这是一个例子:

SQL Fiddle 的东西在这里

CREATE TABLE events (
    esite     integer NOT NULL,
    edate     timestamp with time zone NOT NULL,
    evalue    integer NOT NULL
);

INSERT INTO events Values
    (1, '2016-01-03', 11),
    (2, '2016-01-05', 90),
    (1, '2016-01-08', 7),
    (2, '2016-01-10', 40),
    (1, '2016-01-15', 12),
    (1, '2016-01-18', 66),
    (2, '2016-01-22', 54),
    (2, '2016-02-03', 70),
    (2, '2016-02-05', 56),
    (1, '2016-02-08', 61),
    (2, '2016-02-10', 23),
    (1, '2016-02-15', 30),
    (1, '2016-02-18', 15),
    (1, '2016-02-22', 41);
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个查询,该查询返回(按站点)最小和最大月平均值evalue以及最小和最大值发生的月份。我可以通过使用下面的查询得到这个:

SQL 摆弄这个

select esite, date_trunc('month', edate) as emonth, round(avg(evalue),2) as evalue_avg from events
  Group by esite, emonth
Run Code Online (Sandbox Code Playgroud)

产生以下输出:

esite | emonth                      | evalue_avg
2     | January, 01 2016 00:00:00   | 61.33
1     | January, 01 2016 00:00:00   | 24
1     | February, 01 2016 00:00:00  | 36.75
2     | February, 01 2016 00:00:00  | 49.67
Run Code Online (Sandbox Code Playgroud)

现在,对于我遇到困难的部分,我需要生成以下结果 - 基本上是最小值、最大值以及每个站点发生的日期(月份)。
期望的输出:

-- (one row per site)
esite | avg_min | eval_avg_min_date          | avg_max | eval_avg_max
1     | 24.00   | January, 01 2016 00:00:00  | 36.75   | February, 01 2016 00:00:00
2     | 49.67   |February, 01 2016 00:00:00  | 61.33   | January, 01 2016 00:00:00
Run Code Online (Sandbox Code Playgroud)

我四处搜索并看到了一些使用窗口和横向连接的示例,但我还没有成功地让它们工作。这可能是一个枢纽,但由于我没有固定数量的站点,这对于 PostgreSQL 来说往往很困难。

我猜是否有人有一个简单的方法使用 Postgres 9.4+ 来做到这一点。

Vér*_*ace 0

我建议你做这样的事情 - 并且不要走每月排行的道路。

当您有 5 (10...15... x) 年的数据时会发生什么?

恕我直言,这是优越的。您始终可以使用CROSSTAB表函数,但我建议不要使用它。

SELECT
  esite,
  MIN(evalue), 
  MAX(evalue),
  AVG(evalue)::INT,
  EXTRACT(MONTH FROM edate) AS emonth,
  CASE
    WHEN EXTRACT(MONTH FROM edate) = 1 THEN 'January'
    WHEN EXTRACT(MONTH FROM edate) = 2 THEN 'February'
    -- <... fill in rest of months here ...>
  END AS litMonth
FROM events
GROUP BY esite, emonth, litMonth
ORDER BY esite, emonth -- , min, max, avg;
Run Code Online (Sandbox Code Playgroud)

这给出了结果:

esite;     min;   max;   avg;    emonth;    litmonth
----------------------------------------------------
    1;       7;    66;    24;     1;         January
    1;      15;    61;    37;     2;        February
    2;      40;    90;    61;     1;         January
    2;      23;    70;    50;     2;        February
Run Code Online (Sandbox Code Playgroud)

请注意,我将CASTAVG 作为INTEGER- 您当然可以ROUND将其关闭到您喜欢的任何内容。您可以EXTRACT(YEAR FROM edate) AS eyear,在后面添加EXTRACT(MONTH...以获得更清晰和更优雅的结果。