postgresql 在某些条件下,当前日期和前一天日期在天数上不同

but5z9lq  于 2023-01-30  发布在  PostgreSQL
关注(0)|答案(2)|浏览(213)

我有下表的前三个字段。我想计算金额连续大于0的天数(“days”字段)。
| 键|日期|数量|天|
| - ------|- ------|- ------|- ------|
| 1个|二〇二三年一月二十三日|无|无|
| 1个|2023年1月22日|十个|第二章|
| 1个|2023年1月21日|二十个|1个|
| 1个|2023年1月20日|无|无|
| 1个|2023年1月19日|无|无|
| 1个|2023年1月18日|无|无|
| 1个|2023年1月17日|三个|1个|
| 1个|2023年1月16日|无|无|
我已经尝试了一些windows功能使用this link。没有添加和重置为1,如果以前的数额是0。
我的代码:

case when f.amount > 0 
     then SUM ( DATE_PART('day',  
                          date::text::timestamp - previou_bus_date::text::timestamp )  
              ) OVER (partition by f.key 
                      ORDER BY f.date  
                      ROWS BETWEEN 1 PRECEDING AND CURRENT ROW )
     else 0 
end as days
4ioopgfo

4ioopgfo1#

另一种选择,你可以使用两个row_number之间的差异的方法如下:

select key, date, amount,
  sum(case when amount > 0 then 1 else 0 end) over 
  (partition by key, grp, case when amount > 0 then 1 else 0 end order by date) days
from
(
  select *,
    row_number() over (partition by key order by date) -
    row_number() over (partition by key, case when amount > 0 then 1 else 0 end order by date) grp
  from table_name
) T
order by date desc

See demo

eimct9ow

eimct9ow2#

只要您需要计算非空金额的 * 连续 * 值,这个问题就属于间隙和岛类问题。
您可以通过3个步骤可靠地解决此问题:

  • 当分区发生变化时进行标记,当前数量〉0且先前数量= 0时使用1
  • 计算步骤1中生成的标志的运行总和(使用SUM),以创建分区,并观察其上连续值的数量
  • 计算排名(使用ROW_NUMBER),对步骤2中生成的每个分区中的非空连续金额进行排名
WITH cte AS (
    SELECT *, 
           CASE WHEN amount > 0 
                 AND LAG(amount) OVER(PARTITION BY key_ ORDER BY date_) = 0
                THEN 1
           END AS change_part
    FROM tab
), cte2 AS (
    SELECT *, 
           SUM(change_part) OVER(PARTITION BY key_ ORDER BY date_) AS parts
    FROM cte
)
SELECT key_, date_, amount,
       CASE WHEN amount > 0 
            THEN ROW_NUMBER() OVER(PARTITION BY key_, parts ORDER BY date_)
            ELSE 0
       END AS days
FROM cte2
ORDER BY date_ DESC

检查here演示。

    • 注意**:这不是最好的解决方案,尽管我将它留到下一部分参考(缺少连续日期)。@Ahmed的答案在这种情况下更有可能工作得更好。

如果您的数据在日期上有漏洞(一些缺失的记录,使得金额的连续性不再有效),您应该在步骤1中添加进一步的条件,在步骤1中创建更改分区的标志。
分区应更改:

  • 当前金额〉0且先前金额= 0时
  • 或者如果当前日期大于前一日期+1天(连续日期在时间上不连续)
WITH cte AS (
    SELECT *, 
           CASE WHEN (amount > 0 
                 AND LAG(amount) OVER(PARTITION BY key_ ORDER BY date_) = 0)
                  OR date_ > LAG(date_) OVER(PARTITION BY key_ ORDER BY date_)
                           + INTERVAL '1 day'
                THEN 1
           END AS change_part
    FROM tab
), cte2 AS (
...

查看here演示。

相关问题