PostgreSQL - 如何获得前一个(滞后)计算值

Posted

技术标签:

【中文标题】PostgreSQL - 如何获得前一个(滞后)计算值【英文标题】:PostgreSQL - How to get the previous(lag) calculated value 【发布时间】:2016-11-24 18:36:44 【问题描述】:

我想得到之前(滞后)的计算值?

   id  | value
-------|-------
    1  |   1
    2  |   3
    3  |   5
    4  |   7
    5  |   9

我想要实现的是:

   id  | value | new value
-------|-------|-----------
   1   |   1   |   10      <-- 1 * lag(new_value)
   2   |   3   |   30      <-- 3 * lag(new_value)
   3   |   5   |  150      <-- 5 * lag(new_value)
   4   |   7   | 1050      <-- 7 * lag(new_value)
   5   |   9   | 9450      <-- 9 * lag(new_value)

我尝试过的:

SELECT value,
       COALESCE(lag(new_value) OVER () * value, 10) AS new_value
FROM table

错误:

错误:列“new_value”不存在

【问题讨论】:

貌似是递归计算吧? @JuanCarlosOropeza 是的,伙计。我应该在这里使用什么?递归 CTE 还是横向连接? 递归 CTE。应该很容易。如果需要更多帮助,请告诉我postgresql.org/docs/9.4/static/queries-with.html 你的价值观是1,2,3,4,5,然后变成1,3,5,7,9 不相关,但是:你不需要 coalesce() 有滞后。您可以将默认值直接传递给lag() 函数:lag(some_col, 1, 0) 【参考方案1】:

类似于胡安的回答,但我想我还是会发布它。它至少避免了对 ID 列的需要,并且末尾没有空行:

with recursive all_data as (
  select value, value * 10 as new_value
  from data
  where value = 1

  union all

  select c.value, 
         c.value * p.new_value
  from data c
    join all_data p on p.value < c.value
  where c.value = (select min(d.value) 
                   from data d 
                   where d.value > p.value)
)
select *
from all_data
order by value;

这个想法是将递归部分中的一行恰好连接到一个“父”行。虽然可以使用派生表和横向连接(令人惊讶地确实允许limit)来完成“完全一个父级”。不幸的是,递归部分中“子”的“恰好一行”只能使用带有min() 的子选择来完成。

如果在递归部分也可以使用order bylimit,则不需要where c.value= (...),但不幸的是,当前的Postgres 版本不支持。

在线示例:http://rextester.com/WFBVM53545

【讨论】:

不错。我会给你的例子。我仍在努力让胡安工作。我所做的是限制和抵消。只需将每个语句括在括号中即可。 (SELECT ..... LIMIT 1) UNION ALL (SELECT .... OFFSET 1). 我会用 MIN(value) 更改基本情况,因为 OP 解释数据是随机的。 是的,order by - limit 的限制让我的生活变得悲惨:( 将横向连接更改为 join all_data p on p.value &lt; c.value 速度提高了 50%... @Willem:你说得对,select min() 并不真正需要【参考方案2】:

我的错,这并不像我想象的那么容易。得到了非常接近的结果,但仍需要一些调整。

DEMO

WITH RECURSIVE t(n, v) AS (
    SELECT MIN(value), 10 
    FROM Table1

    UNION ALL
    SELECT (SELECT min(value) from Table1 WHERE value > n), 
           (SELECT min(value) from Table1 WHERE value > n) * v
    FROM t
    JOIN Table1 on t.n = Table1.value    
)    
SELECT n, v 
FROM t;

【讨论】:

至少你得到了结果。 +1 如果你在你的桌子上添加一个 id 会更容易;) 我有身份证。因此,您可以将其更改为 id 的工作。我会更新问题 你不应该接受,也许别人找到了正确的答案。除非你在那种情况下找到它,否则请张贴它。

以上是关于PostgreSQL - 如何获得前一个(滞后)计算值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用滞后功能跳过一行? PostgreSQL 9.3

使用 PostgreSQL 更新前 N 个值

使用滞后访问mysql中的前一行值

如何防止这种奇怪的 jQuery .animate() 滞后?

Storm/Kafka - 无法获得 kafka 的偏移滞后

使用滞后函数(TSQL)返回0获得销售差异