查找当前行是否是从数据库中选择的最后一行

时间:2014-03-24 13:08:48

标签: sql postgresql case postgresql-9.1 window-functions

我从数据库中选择句点列表。如果当前行是第一行,那么期间从日期开始,我可以找到期间开始之间的间隔,如下所示:

SELECT
...
CASE WHEN row_number() OVER(ORDER BY r.created_at ASC) = 1 THEN r.created_at - r.created_at::date ELSE NULL END AS period
...
FROM mytable r

如何对最后行执行相同的操作?要查找最后一行的r.created_at与其日期的午夜之间的时间。

我知道PostgreSQL中的firstlast函数(https://wiki.postgresql.org/wiki/First/last_(aggregate)),但它们是聚合函数,在这种情况下没有帮助。

编辑: 这个问题有两个很好的答案。在我的情况下,它们都没有帮助,因为我作为我的问题的一部分提出的这一行是更大查询的一部分,以编程方式组合在一起并使用提供的解决方案将迫使我改变很多代码,我不愿意这样做这点。如果缩放问题受到影响 - 那么我肯定会重新考虑。

2 个答案:

答案 0 :(得分:1)

这可能比窗口函数更快:

with r as (
    select
        min(created_at) as min_created_at,
        max(created_at) as max_created_at
    from mytable
)
select
    case when (select min_created_at from r) = created_at
    then created_at - created_at::date else null
    end as period_min,
    case when (select max_created_at from r) = created_at
    then created_at - created_at::date else null
    end as period_max
from mytable

答案 1 :(得分:1)

您可以在 CASE声明中使用window functions first_value() and last_value()

SELECT *
     , CASE WHEN ts IN ( first_value(created_at) OVER w
                       , last_value(created_at)  OVER w)
       THEN created_at::time::interval ELSE NULL END AS period
FROM   tbl
WINDOW w AS (ORDER BY created_at rows BETWEEN UNBOUNDED PRECEDING
                                          AND UNBOUNDED FOLLOWING);

此处有特殊要求:您需要调整last_value()来电的frame definition。默认情况下是:

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

但你需要:

ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

first_value()调用适用于默认框架,但也可以使用相同的框架。

我还简化了period的计算。您的定义与time的{​​{1}}组件相吻合,只需投放到timestamp.以“截断”日期部分:time
在此之后转换为created_at::time只是为了返回与原始查询相同的数据类型。

由于窗口函数的当前实现,结果将由interval自动排序。但不要依赖于此。如果您需要排序输出,请明确添加到结尾:

created_at
相关问题