在子查询的FROM中使用Postgres窗口语句

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在子查询的FROM中使用Postgres窗口语句相关的知识,希望对你有一定的参考价值。

我有以下SUB QUERY作为SELECT语句的一部分。这应该花费一个计算时间,远离另一个计算时间。

但Postgres不喜欢在FROM子句中使用Window函数。

(SELECT count(*) AS work_hours
FROM   generate_series (TIMESTAMP 'epoch' + MAX(wog.endtime) OVER(PARTITION     BY woas.workorderid ORDER BY wog.endtime DESC)/1000 * INTERVAL '1 second'
                  , TIMESTAMP 'epoch' + nth_value(wog.endtime,2) OVER(PARTITION BY woas.workorderid ORDER BY wog.endtime DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)/1000 * INTERVAL '1 second' - interval '1h'
                  , interval '1h') h
WHERE  EXTRACT(ISODOW FROM h) < 6
AND    h::time >= '08:00'
AND    h::time <= '18:00') AS "Max minus Second Max",

Postgres返回以下错误:

ERROR: cannot use window function in function expression in FROM

如何重新格式化上述语句,以便它可以无误地解析?

更新:

我不认为查询的结构是问题。如果我用时间戳字符串代替函数它可以正常工作。

 (SELECT count(*) AS work_hours
 FROM generate_series (timestamp '2018-01-06 13:30'
                  , timestamp '2018-01-08 21:29' - interval '1h'
                  , interval '1h') h
 WHERE  EXTRACT(ISODOW FROM h) < 6
 AND    h::time >= '08:00'
 AND    h::time <= '18:00') "Time Difference" from workorder wo
答案

在“FROM”子句之后,需要一个表/视图来查询数据。

您重构查询,如下所示:

select count(*) from (
    select generate_series( ....)
    where (cond1 and cond2..)

当你将函数放在“from”子句中时,它显然不起作用。

另一答案

如果您还没有解决方案,可能需要尝试此操作。我认为它做你想要的。

设置测试:我希望与你的情况相似。

create table work_order_times
(
    work_order_id  integer,
    end_time       bigint     -- milliseconds
);

insert into work_order_times (work_order_id, end_time) values (23, extract(epoch from now()) * 1000);
insert into work_order_times (work_order_id, end_time) values (23, (extract(epoch from now()) - 20000) * 1000);
insert into work_order_times (work_order_id, end_time) values (57, (extract(epoch from now()) - 40000) * 1000);
insert into work_order_times (work_order_id, end_time) values (57, (extract(epoch from now()) - 60000) * 1000);
insert into work_order_times (work_order_id, end_time) values (57, (extract(epoch from now()) - 80000) * 1000);

检查设置:

select
    work_order_id,
    end_time, 
    to_timestamp(end_time / 1000) as end_timestamp
from
    work_order_times
order by
    work_order_id,
    end_time;

 work_order_id |   end_time    |     end_timestamp      
---------------+---------------+------------------------
            23 | 1516251234772 | 2018-01-18 04:53:54+00
            23 | 1516271234769 | 2018-01-18 10:27:14+00
            57 | 1516191234774 | 2018-01-17 12:13:54+00
            57 | 1516211234773 | 2018-01-17 17:47:14+00
            57 | 1516231234772 | 2018-01-17 23:20:34+00
(5 rows)

查询:

select
    work_order_id,
    generate_series (penultimate_timestamp, latest_timestamp, interval '1 hour')
from
    (
        select
            work_order_id,
            to_timestamp(latest_end_time / 1000) as latest_timestamp,
            to_timestamp(penultimate_end_time / 1000) as penultimate_timestamp
        from
            (
                select
                    work_order_id,
                    row_number()  over last_2_timestamps as row_number,
                    max(end_time)  over last_2_timestamps as latest_end_time,
                    lead(end_time) over last_2_timestamps as penultimate_end_time
                from
                    work_order_times
                window
                    last_2_timestamps as (partition by work_order_id order by end_time desc)
            ) x
        where
            row_number = 1
    ) y;

结果:

 work_order_id |    generate_series     
---------------+------------------------
            23 | 2018-01-18 04:53:54+00
            23 | 2018-01-18 05:53:54+00
            23 | 2018-01-18 06:53:54+00
            23 | 2018-01-18 07:53:54+00
            23 | 2018-01-18 08:53:54+00
            23 | 2018-01-18 09:53:54+00
            57 | 2018-01-17 17:47:14+00
            57 | 2018-01-17 18:47:14+00
            57 | 2018-01-17 19:47:14+00
            57 | 2018-01-17 20:47:14+00
            57 | 2018-01-17 21:47:14+00
            57 | 2018-01-17 22:47:14+00
(12 rows)

PostgreSQL文档确实提到了关于如何嵌套窗口函数的一些限制,但它看起来像这样工作。

将endtime存储为时间戳而不是毫秒数会使事情稍微简单一些,这可能就像它看起来那样,但也许你没有机会这样做。

以上是关于在子查询的FROM中使用Postgres窗口语句的主要内容,如果未能解决你的问题,请参考以下文章

使用窗口函数在 Postgres 上使用 SqlAlchemy 限制查询

Oracle --> Postgres 查询

Postgres:计算子查询中的唯一数组条目

FROM 子句中的 Postgres 子查询

在子查询中使用聚合和窗口函数

使用count distinct在postgres中进行慢速查询