【问题标题】:Unable to calculate difference between CTE subquery outputs for use in larger PostgreSQL query output column无法计算 CTE 子查询输出之间的差异以用于更大的 PostgreSQL 查询输出列
【发布时间】:2016-10-29 12:24:43
【问题描述】:

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

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 来查看表格:

时刻表

 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 值,它返回具有最新时间戳值的 moment_type 的标志值与第二个的标志值之间的差异最近的时间戳值,并按 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)子查询,作为最后更大的SELECT查询中的临时表。我还使用SQL function 来计算两个子查询输出之间的差异(或者我认为我可以只使用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 $1 - $2;
$$ 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 查询时,它返回以下错误:

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

问题

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

注意:Window Function 可能会以某种方式使用,因为它跨表行执行计算

【问题讨论】:

    标签: sql postgresql common-table-expression window-functions


    【解决方案1】:

    使用lag()窗口函数:

    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)    
    

    【讨论】:

      【解决方案2】:

      一种方法是使用条件聚合。窗口函数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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-14
        • 1970-01-01
        • 2019-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-03
        • 1970-01-01
        相关资源
        最近更新 更多