计算表中最大的负数系列

Posted

技术标签:

【中文标题】计算表中最大的负数系列【英文标题】:Count largest negative series in table 【发布时间】:2020-07-22 06:28:23 【问题描述】:

我正在寻找一系列负数/正数。假设我有一个包含两列的表:order_time 和 win,其中 order_time 是日期,win 是 +1 或 -1。我想在“win”列中找到最大的负值系列。我知道如何在 Python 中做到这一点,但我想在 postgres 中做到这一点,而不是去其他环境。

例子

      order_time     wins
2020-01-02 17:12:19    0
2020-01-02 17:12:19    0
2020-01-02 21:02:15    1
2020-01-03 02:40:56    1
2020-01-03 10:38:39    0
2020-01-03 10:38:44    0
2020-01-03 10:38:44    1
2020-01-03 10:38:44    0
2020-01-03 10:58:32    1
2020-01-03 11:18:13    1
2020-01-03 11:18:35    1

输出

      order_time     wins   s
2020-01-02 17:12:19    0    1
2020-01-02 17:12:19    0    2
2020-01-02 21:02:15    1    1
2020-01-03 02:40:56    1    2
2020-01-03 10:38:39    0    1
2020-01-03 10:38:44    0    2
2020-01-03 10:38:44    1    1
2020-01-03 10:38:44    0    1
2020-01-03 10:58:32    1    1
2020-01-03 11:18:13    1    2
2020-01-03 11:18:35    1    3

然后我会找到 s 列的最大值

【问题讨论】:

用你想要的输出提供样本数据 你的意思是连续的正数还是负数?日期重要不重要? 您的示例没有负数。您的意思是 0 而不是 -1 尝试使用LAG- 函数写一些东西。 a_horse_with_no_name - 是的,您是对的,给您带来的不便,我们深表歉意。 【参考方案1】:

检测胜利何时更改,然后使用更改标志创建组。每组的行数,取最大行数。

with t (order_time,     wins) as (values
(timestamp '2020-01-02 17:12:19',    0),
(timestamp '2020-01-02 17:12:19',    0),
(timestamp '2020-01-02 21:02:15',    1),
(timestamp '2020-01-03 02:40:56',    1),
(timestamp '2020-01-03 10:38:39',    0),
(timestamp '2020-01-03 10:38:44',    0),
(timestamp '2020-01-03 10:38:44',    1),
(timestamp '2020-01-03 10:38:44',    0),
(timestamp '2020-01-03 10:58:32',    1),
(timestamp '2020-01-03 11:18:13',    1),
(timestamp '2020-01-03 11:18:35',    1)
), ch as (
  select t.*
       , case coalesce(wins != lag(wins) over (order by order_time), true) 
           when true then 1
           else 0
         end as wins_changed
  from t
), groups as (
  select ch.*
       , sum(wins_changed) over (order by order_time) as grp
  from ch
), counts as (
  select order_time
       , wins
       , row_number() over (partition by grp order by order_time) rn
  from groups
)
select max(rn) from counts;

请注意,您的示例在第三行 2020-01-03 10:38:44 处不清楚。查询如何识别win=1 值是中间的值?出于这个原因,我的查询也为此行三元组返回 3。您可以通过更精确的order_time(到毫秒)或添加另一个order by 标准来避免它。

Db 小提琴here.

【讨论】:

【参考方案2】:

这是一个孤岛问题。识别相邻值的“孤岛”的最简单方法可能是行数差异法:

select t.*,
       row_number() over (partition by wins, seqnum - seqnum_1 order by order_time) as s
from (select t.*,
             row_number() over (order by order_time) as seqnum,
             row_number() over (partition by wins order by order_time) as seqnum_1
      from t
     ) t;

您实际上可以在没有子查询的情况下获得最长的连胜:

select count(*) over (partition by wins, seqnum - seqnum_1 order by order_time) as s
from (select t.*,
             row_number() over (order by order_time) as seqnum,
             row_number() over (partition by wins order by order_time) as seqnum_1
      from t
     ) t
order by s desc
limit 1;

如果您想要最长的输(或赢)系列,只需将where wins = <whatever> 添加到外部查询。

Here 是一个 dbfiddle。

【讨论】:

以上是关于计算表中最大的负数系列的主要内容,如果未能解决你的问题,请参考以下文章

输入一系列正整数后 以负数结尾 求出输出数的最大值和最小值

尝试根据 ID 计算一系列数据的平均值、最小值和最大值

数组求最大值

剑指offer系列56---连续子数组的最大和

正数最大值的绝对值比负数最大值的绝对值小一个

剑指Offer对答如流系列 - 连续子数组的最大和