无法计算用于较大 PostgreSQL 查询输出列的 CTE 子查询输出之间的差异

Unable to calculate difference between CTE subquery outputs for use in larger PostgreSQL query output column

使用 Shell 的 PostgreSQL v9.4.5 我在 运行ning create database moments 中创建了一个名为 moments in psql 的数据库。然后我创建了一个时刻 table:

CREATE TABLE moments
(
  id SERIAL4 PRIMARY KEY,
  moment_type BIGINT NOT NULL,
  flag BIGINT NOT NULL,
  time TIMESTAMP NOT NULL,
  UNIQUE(moment_type, time)
);
INSERT INTO moments (moment_type, flag, time) VALUES (1, 7, '2016-10-29 12:00:00');
INSERT INTO moments (moment_type, flag, time) VALUES (1, -30, '2016-10-29 13:00:00');
INSERT INTO moments (moment_type, flag, time) VALUES (3, 5, '2016-10-29 14:00:00');
INSERT INTO moments (moment_type, flag, time) VALUES (2, 9, '2016-10-29 18:00:00');
INSERT INTO moments (moment_type, flag, time) VALUES (2, -20, '2016-10-29 17:00:00');
INSERT INTO moments (moment_type, flag, time) VALUES (3, 10, '2016-10-29 16:00:00');

我运行select * from moments查看table:

朋友圈Table

 id | moment_type | flag |        time         
----+-------------+------+---------------------
  1 |           1 |    7 | 2016-10-29 12:00:00
  2 |           1 |  -30 | 2016-10-29 13:00:00
  3 |           3 |    5 | 2016-10-29 14:00:00
  4 |           2 |    9 | 2016-10-29 18:00:00
  5 |           2 |  -20 | 2016-10-29 17:00:00
  6 |           3 |   10 | 2016-10-29 16:00:00

然后我尝试编写一个 SQL 查询,它产生以下输出,其中对于每对重复的 moment_type 值,它 returns [的标志值之间的差异=50=] 具有最近的时间戳值,和第二个最近的时间戳值的标志值,并按 moment_type.

升序列出结果

预期SQL查询输出

moment_type | flag | 
------------+------+
          1 |  -37 |  (i.e. -30 - 7)
          2 |   29 |  (i.e.   9 - -20)
          3 |   5  |  (i.e.  10 - 5)

我想出的SQL查询如下,使用WITH查询写多个Common Table Expressions (CET) subqueries for use as temporary tables in the larger SELECT query at the end. I also use an SQL function to calculate the difference between two of the subquery outputs (alternatively I think I could have just used DIFFERENCE DIFFERENCE(most_recent_flag, second_most_recent_flag) AS flag而不是函数):

CREATE FUNCTION difference(most_recent_flag, second_most_recent_flag) RETURNS numeric AS $$
  SELECT  - ;
$$ LANGUAGE SQL;

-- get two flags that have the most recent timestamps
WITH two_most_recent_flags AS (
SELECT moments.flag
FROM moments
ORDER BY moments.time DESC
LIMIT 2
),
-- get one flag that has the most recent timestamp
most_recent_flag AS (
SELECT *
FROM two_most_recent_flags 
ORDER BY flag DESC
LIMIT 1
), 
-- get one flag that has the second most recent timestamp
second_most_recent_flag AS (
SELECT *
FROM two_most_recent_flags 
ORDER BY flag ASC
LIMIT 1
)
SELECT DISTINCT ON (moments.moment_type)
moments.moment_type,
difference(most_recent_flag, second_most_recent_flag) AS flag
FROM moments
ORDER BY moment_type ASC
LIMIT 2;

但是当我在 PostgreSQL 中 运行 上述 SQL 查询时,它 returns 出现以下错误:

ERROR:  column "most_recent_flag" does not exist
LINE 21: difference(most_recent_flag, second_most_recent_flag) AS fla...

问题

我可以使用哪些技术以及如何应用它们来克服此错误,并计算并显示 flag 列中的差异以实现 预期的 SQL 查询输出?

注意:也许 Window Function 可以以某种方式使用,因为它在 table 行中执行计算

一种方法是使用条件聚合。 window函数row_number()可以用来识别第一个和最后一个时间值:

select m.moment_type,
       (max(case when seqnum_desc = 1 then flag end) -
        min(case when seqnum_asc = 1 then flag end)
       )
from (select m.*,
             row_number() over (partition by m.moment_type order by m.time) as seqnum_asc,
             row_number() over (partition by m.moment_type order by m.time desc) as seqnum_desc
      from moments m
     ) m
group by m.moment_type;

使用lag()window函数:

select moment_type, difference
from (
    select *, flag- lag(flag) over w difference
    from moments
    window w as (partition by moment_type order by time)
    ) s
where difference is not null
order by moment_type

 moment_type | difference 
-------------+------------
           1 |        -37
           2 |         29
           3 |          5
(3 rows)