查找当前行是不是是要从数据库中选择的最后一行
Posted
技术标签:
【中文标题】查找当前行是不是是要从数据库中选择的最后一行【英文标题】:Finding if current row is last row to be selected from database查找当前行是否是要从数据库中选择的最后一行 【发布时间】:2014-03-24 13:08:47 【问题描述】:我正在从数据库中选择期间列表。如果当前行是第一行,则周期以日期开始,我可以像这样找到周期开始之间的间隔:
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
我怎样才能对 last 行执行相同的操作? 查找最后一行的 r.created_at 与其日期的午夜之间的时间。
我知道 PostgreSQL 中的 first
和 last
函数 (https://wiki.postgresql.org/wiki/First/last_(aggregate)),但它们是聚合函数,在这种情况下没有帮助。
编辑: 这个问题有2个很好的答案。在我的情况下,它们都没有帮助,因为我作为问题的一部分提出的这一行是更大查询的一部分,以编程方式放在一起并使用提供的解决方案会迫使我更改很多代码,我不愿意这样做这点。如果缩放问题出现 - 那么我一定会重新考虑。
【问题讨论】:
用DESC
而不是ASC
做同样的事情怎么样?
如果您按 (... DESC) 排序,最后一行将是第一行 ...
嗯,这可能真的有效。谢谢。我现在必须测试它:)
你需要created_at
排序的结果吗?
谢谢 - 使用 DESC 而不是 ASC 效果很好。
【参考方案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
【讨论】:
【参考方案2】:您可以在单个 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
的计算。您的定义与 timestamp.
的 time
组件一致,只需转换为 time
以“截断”日期部分:created_at::time
。
之后转换为 interval
只是为了返回与原始查询相同的数据类型。
由于当前窗口函数的实现,结果将自动按created_at
排序。但不要依赖于此。如果您需要排序输出,请显式添加到末尾:
ORDER BY created_at
【讨论】:
以上是关于查找当前行是不是是要从数据库中选择的最后一行的主要内容,如果未能解决你的问题,请参考以下文章