【问题标题】: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 - 是的,您是对的,给您带来的不便,我们深表歉意。

标签: sql postgresql gaps-and-islands


【解决方案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。

    【讨论】:

      猜你喜欢
      • 2014-02-05
      • 1970-01-01
      • 2014-02-05
      • 2020-01-15
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多