Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
按块分组并获取每个-SQL的开始和结束时间_Sql_Oracle_Oracle Sqldeveloper - Fatal编程技术网

按块分组并获取每个-SQL的开始和结束时间

按块分组并获取每个-SQL的开始和结束时间,sql,oracle,oracle-sqldeveloper,Sql,Oracle,Oracle Sqldeveloper,我在为可视化准备数据库输出时遇到问题 我有一个表(在Oracle SQL中),用于监视我网络上的每台计算机(第1列)所做的事情以及启动操作的时间(第2列)。见下文: # comps ~ 20 # actions - 10 # rows ~ 10_000 comp | time | action -------+--------+---------- comp_1 | t_0 | A comp_1 | t_1 | A comp_2 | t_2 |

我在为可视化准备数据库输出时遇到问题

我有一个表(在Oracle SQL中),用于监视我网络上的每台计算机(第1列)所做的事情以及启动操作的时间(第2列)。见下文:

# comps   ~ 20
# actions - 10
# rows    ~ 10_000

comp   |  time  |  action
-------+--------+----------
comp_1 | t_0    |    A
comp_1 | t_1    |    A
comp_2 | t_2    |    B
comp_1 | t_3    |    B
comp_1 | t_4    |    A
comp_2 | t_5    |    B
comp_2 | t_6    |    B
comp_1 | t_7    |    A
comp_1 | t_8    |    A
comp_2 | t_9    |    C
comp_2 | t_10   |    C
comp_1 | t_11   |    C
 ...     ...        ...
  .       .          . 
一个动作的结束就是另一个动作的开始。B从A开始到A结束。然后,在B结束后,A可能再次作为新的“块”出现。计算机一次只能做一个动作

时间值实际上是Oracle
datetime
列(为了简化,它只写为t_x)

我需要帮助按计算机操作块对表进行分组,每个操作块都有开头和结尾
t_start
是查询的开始时间(从),而
t_end
是结束时间(到)

这是我想要的输出:

comp   | action  | start   | end
-------+---------+---------+----------
comp_1 |   A     |  t_start|  t_3
comp_2 |   B     |  t_2    |  t_9
comp_1 |   B     |  t_3    |  t_4
comp_1 |   A     |  t_4    |  t_11
comp_2 |   C     |  t_9    |  t_end
comp_1 |   C     |  t_11   |  t_end
如果仔细观察,您会发现,源表中的记录可能是重叠的,因为每台计算机都是独立报告的,但都是按时间顺序排列的

我尝试了不同的版本,但没有成功。我怀疑,它的实现可能更聪明,或者通过使用“按拥有分组”或“结束”来实现,但我对SQL没有那么熟练


非常感谢您的光临。

您可以通过模式匹配来实现这一点:

create table t (
  comp varchar2(10),
  time varchar2(10),
  action varchar2(1)
);

insert into t values ( 'comp_1', 't_00', 'A' );
insert into t values ( 'comp_1', 't_01', 'A' );
insert into t values ( 'comp_2', 't_02', 'B' );
insert into t values ( 'comp_1', 't_03', 'B' );
insert into t values ( 'comp_1', 't_04', 'A' );
insert into t values ( 'comp_2', 't_05', 'B' );
insert into t values ( 'comp_2', 't_06', 'B' );
insert into t values ( 'comp_1', 't_07', 'A' );
insert into t values ( 'comp_1', 't_08', 'A' );
insert into t values ( 'comp_2', 't_09', 'C' );
insert into t values ( 'comp_2', 't_10', 'C' );
insert into t values ( 'comp_1', 't_11', 'C' );
commit;

select comp, st, 
       lead ( st ) over (
         partition by comp
         order by st
       ) en
from   t
  match_recognize (
    partition by comp
    order by time
    measures
      first ( time ) st
    pattern ( init same* )
    define
      same as action = prev ( action )
  );

COMP      ST      EN       
comp_1    t_00    t_03      
comp_1    t_03    t_04      
comp_1    t_04    t_11      
comp_1    t_11    <null>    
comp_2    t_02    t_09      
comp_2    t_09    <null>  
创建表t(
comp varchar2(10),
时间varchar2(10),
行动2(1)
);
插入t值('comp_1','t_00','A');
插入t值('comp_1','t_01','A');
插入t值('comp_2','t_02','B');
插入t值('comp_1','t_03','B');
插入t值('comp_1','t_04','A');
插入t值('comp_2','t_05','B');
插入t值('comp_2','t_06','B');
插入t值('comp_1','t_07','A');
插入t值('comp_1','t_08','A');
插入t值('comp_2','t_09','C');
插入t值('comp_2','t_10','C');
插入t值('comp_1','t_11','C');
犯罪
选择comp,st,
领先(st)超过(
按comp划分
圣彼得堡
)嗯
从t
相配(
按comp划分
按时间订购
措施
第一次(时间)圣
模式(初始相同*)
定义
与action=prev(action)相同
);
公司
comp_1 t_00 t_03
组件1 t\u 03 t\u 04
comp_1 t_04 t_11
comp_1 t_11
comp_2 t_02 t_09
comp_2 t_09
  • 与action=prev(action)
    在当前行的操作与前一行的操作相同(由分区和排序依据定义)时为true
  • 模式是一个正则表达式,因此
    init same*
    init
    的一个实例,后跟零个或多个
    same
  • init
    是未定义的,所以“始终为真”,匹配第一行,然后匹配操作与前一行不同的任何行
  • 选择中的
    lead
    返回下一次开始的值

    • 好的,我没想到我会有时间写这篇文章,因此发表了评论,但是:

      让我们获取数据,根据每台计算机上前一行的操作是相同的还是不同的,将一列设置为0或1:

      SELECT
        t.*,
        CASE WHEN action = LAG(action) OVER(PARTITION BY computer ORDER BY time) THEN 0 ELSE 1 END as differs
      FROM
        t
      
      现在,让我们将0和1的流转换为递增计数器:

      WITH cte AS(
        SELECT
          t.*,
          CASE WHEN action = LAG(action) OVER(PARTITION BY comp ORDER BY time) THEN 0 ELSE 1 END as differs
        FROM
          t
      )
      
      SELECT cte.*, SUM(differs) OVER(PARTITION BY comp ORDER BY time ROWS UNBOUNDED PRECEDING) as run_tot_dif
      
      现在让我们按每台计算机的计数器分组,并计算最小/最大时间。我注意到你的时间不是当前行动的结束,而是下一个行动的开始。为此,我们将在中添加一个函数,用于在第一个cte中为每台计算机拾取每行的下一次时间,以便我们以后可以拾取它,并且我们还将合并它,以便它在时间段结束时导致的空值变为:

      WITH cte_diff AS(
        SELECT
          t.*,
          COALESCE(LEAD(time) OVER(PARTITION BY comp ORDER BY time), :endtime) next_start_time,
          CASE WHEN action = LAG(action) OVER(PARTITION BY comp ORDER BY time) THEN 0 ELSE 1 END as differs
        FROM
          t
        WHERE time BETWEEN :starttime and :endtime --parameterize it
      ), 
      cte_runtot AS(
       SELECT 
         cte_diff.*, 
         SUM(differs) OVER(PARTITION BY comp ORDER BY time ROWS UNBOUNDED PRECEDING) as run_tot_dif
       FROM
         cte_diff
      )
      
      SELECT 
        comp, 
        action, 
        MIN(time) as start_time, 
        MAX(next_start_time) as end_time
      FROM
        cte_runtot
      GROUP BY
        comp, action, run_tot_dif
      ORDER BY
        start_time
      
      我要指出的是,我认为您在期望的输出中犯了一个错误—comp2的操作B一直运行到comp2在t=9时启动操作C,而不是直到comp1在t=7时启动操作A。。除非我误解了你的要求

      聚苯乙烯;您可以通过不使用CTE将其折叠起来,但这可能并不意味着它更具可读性:

      SELECT 
        comp, 
        action, 
        MIN(time) as start_time, 
        MAX(next_start) as end_time
      FROM
      (
        SELECT 
          x.*, 
          SUM(diff) OVER(PARTITION BY comp ORDER BY time ROWS UNBOUNDED PRECEDING) as run_tot_diff 
        FROM
          (
            SELECT 
              t.*, 
              COALESCE(LEAD(time) OVER(PARTITION BY comp ORDER BY time), 9999) next_start,
              CASE WHEN action = LAG(action) OVER(PARTITION BY comp ORDER BY time) THEN 0 ELSE 1 END diff 
              FROM t
              WHERE time BETWEEN 0 and 11
          ) x
        )y
      GROUP BY
        comp, action, run_tot_diff
      ORDER BY
        start_time
      

      因为Oracle不允许在GROUP BY、其他窗口函数内部或聚合内部使用窗口函数(SQL Server对此问题较少)

      您如何知道comp 1在t3而不是t9(或8)完成了操作A?是因为它在3处做了一个B,然后又做了另一个a吗?有一种技术,你可以使用LAG来查看前一行的动作,按时间排序(但如果它确实是一个以t_为前缀的int,则需要将其转换为数字),并使用一个案例来查看它是否与当前行的动作不同,是放1,还是放0。然后,您可以使用带有行无界前置限定符的SUM OVER,将交替为1和0的这列转换为递增计数器,您可以按它分组。很高兴知道您的时间列是否真的是这样的,或者它是否是一些模糊的数据,而时间列实际上排序很像日期或时间谢谢你的回复。正如你所说,我要补充这些重要的细节(我的错)。查找其更新。感谢您的回复。我一定会调查这件事并报告我的发现。另外,我想,添加动作名称就像将其添加到select一样简单,对吗?哦,非常感谢。我马上就去试试。此外,您对comp2 t_7/t_9的看法是正确的。。应该是在9号。我会在OP中更正它。