【问题标题】:Count number of events that happened in wrong order计算以错误顺序发生的事件数
【发布时间】:2017-10-26 18:42:06
【问题描述】:

如何在按时间顺序排列的组中进行搜索,并计算某个事件是否先于另一个事件发生?

我的数据显示为:

id   | flow_nme | prod | RowFilter |
'20' | A2       | 1    | 1         |
'20' | A3       | 1    | 2         |
'30' | A3       | 1    | 1         |
'30  | A2       | 1    | 2         |
'40' | C1       | 1    | 1         |
'40' | C2       | 1    | 2         |
'40' | A3       | 1    | 3         |
'40' | A2       | 1    | 4         |

RowFilter 包含每个 id 组的时间排序。名称 A2、A3、C1 和 C2 没有真正含义,是虚拟名称。 RowFilter 是根据指示事件发生顺序的时间戳创建的。唯一确定事件“应该”发生的顺序是正常流程。本质上,我想统计正常流程没有发生的次数。

所以我想计算 A3 在 A2 之前和 C2 在 A3 之前出现的每个 id 的实例。

我的预期输出应该是这样的:

type  | count |
A3-A2 | 2     |
C2-A3 | 1     |

我尝试过使用 OVER 和 PARTITION BY,但一定是做错了什么。

只要我有时间让这个问题易于重现,我就会着手编写代码来模拟数据。我对 R 比对 SQL 更熟悉,所以对我来说,这段代码的样子并不是很明显。

【问题讨论】:

  • 按时间排序是什么意思?你怎么知道正确的顺序应该是什么?
  • 大概正确的顺序是字典顺序(即自然)
  • 如果flow_nmes 对给定的id 出现多次怎么办?
  • 按时间排序我指的是RowFilter实际上代表了时间。正确的顺序由特定的过程决定。所以,在我编造的例子中,A2 应该在 A3 之前发生,C2 应该在 A3 之前发生。
  • 您的数据中没有任何内容表明 A3 在 A2 之前或之后,除非您可以使用 flow_nme 作为排序列。你怎么知道它没有跳过一个步骤,因为你没有主列表?为什么“第一”组步骤是准确的?

标签: sql sql-server tsql


【解决方案1】:

在 SQL Server 2012+ 中(对于 lead()concat())。

使用common table expression(派生表也可以)和lead() 来查找next_flow_nmeconcat() 以连接type 的两个flow_nme,过滤为where flow_nme > next_flow_nme。然后group bycount(*)

;with cte as (
select id, flow_nme, prod, rowfilter
  , next_flow_nme = lead(flow_nme) over (order by id, rowfilter)
from t
)
select 
    type = concat(flow_nme,'-',next_flow_nme)
  , [count]=count(*)
from cte
where flow_nme > next_flow_nme
group by concat(flow_nme,'-',next_flow_nme)

rextester 演示:http://rextester.com/NHW71132

返回:

+-------+-------+
| type  | count |
+-------+-------+
| A3-A2 |     2 |
| C2-A3 |     1 |
+-------+-------+

【讨论】:

    【解决方案2】:

    这是一种方法,它假设每个 flow_nmes 都有唯一的 id. 这会将值放在不同的列中:

    select sum(case when rf_a3 < rf_a2 then 1 else 0 end) as a3_a2,
           sum(case when rf_c2 < rf_a3 then 1 else 0 end) as c2_a3
    from (select id,
                 min(case when flow_nme = 'A3' then row_filter end) as rf_a3,
                 min(case when flow_nme = 'A2' then row_filter end) as rf_a2,
                 min(case when flow_nme = 'C2' then row_filter end) as rf_c2
          from t
          group by id
         ) t;
    

    如果你愿意,你可以取消旋转。我喜欢为此目的使用apply

    select v.*
    from (select sum(case when rf_a3 < rf_a2 then 1 else 0 end) as a3_a2,
                 sum(case when rf_c2 < rf_a3 then 1 else 0 end) as c2_a3
          from (select id,
                       min(case when flow_nme = 'A3' then row_filter end) as rf_a3,
                       min(case when flow_nme = 'A2' then row_filter end) as rf_a2,
                       min(case when flow_nme = 'C2' then row_filter end) as rf_c2
                from t
                group by id
               ) t
         ) t cross apply
         (values ('a3_a2', a3_a2), ('c2_a3', c2_a3)) v(type, count);
    

    【讨论】:

      猜你喜欢
      • 2014-08-03
      • 1970-01-01
      • 1970-01-01
      • 2014-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多