计算并求和多行之间的时间差

发布于 2024-12-14 12:59:43 字数 451 浏览 1 评论 0原文

我有一个子表,其中包含特定父记录的状态历史记录。

该表为:

Parent_id NUMBER(38)
Date_Created  DATE
Status VARCHAR2(15)

示例数据:

1, sysdate-20, REQ
1, sysdate-10, INPRG
1, sysdate-5, WAIT
1, sysdate-2, INPRG
1, sysdate, COMP

对于任何特定的parent_id,如何计算parent_id 处于特定状态的总时间?鉴于计算是创建下一个状态的日期减去创建记录的日期。请记住,该状态可能会出现多次。

对于示例数据,如何计算记录处于“INPRG”状态的总时间?

它必须完全在 Oracle SQL 中完成。没有函数、过程、包等。

提前致谢。

I have a child table that contains the history of statuses for the particular parent record.

The table would be:

Parent_id NUMBER(38)
Date_Created  DATE
Status VARCHAR2(15)

Sample Data:

1, sysdate-20, REQ
1, sysdate-10, INPRG
1, sysdate-5, WAIT
1, sysdate-2, INPRG
1, sysdate, COMP

For any particular parent_id, how can I calculate the total time a parent_id stayed in a particular status? Given that the calculation is the date next status was created minus the teh date record was created. Keeping in mind that the status can occur multiple times.

For the sample data, how could you calculate the total time the record was in "INPRG" status?

It has to be done entirely in Oracle SQL. No functions, procedures, packages, etc.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

菩提树下叶撕阳。 2024-12-21 12:59:43

您可以使用分析函数 LEADLAG 访问结果集中下一行或上一行的数据。这样的东西会给你每个状态的总时间

SQL> ed
Wrote file afiedt.buf

  1  with t as (
  2    select 1 parent_id, sysdate-20 date_created, 'REQ' status from dual
  3    union all
  4    select 1, sysdate-10, 'INPRG' from dual
  5    union all
  6    select 1, sysdate-5, 'WAIT' from dual
  7    union all
  8    select 1, sysdate-2, 'INPRG' from dual
  9    union all
 10    select 1, sysdate, 'COMP' from dual
 11  )
 12  select parent_id,
 13         status,
 14         sum(time_in_status)
 15    from (
 16      select parent_id,
 17             date_created,
 18             nvl(lead(date_created) over
 19                          (partition by parent_id
 20                               order by date_created),
 21                 sysdate) next_status_date,
 22             nvl(lead(date_created) over
 23                          (partition by parent_id
 24                               order by date_created),
 25                 sysdate) -
 26               date_created time_in_status,
 27             status
 28        from t)
 29*  group by parent_id, status
SQL> /

 PARENT_ID STATU SUM(TIME_IN_STATUS)
---------- ----- -------------------
         1 REQ                    10
         1 COMP                    0
         1 WAIT                    3
         1 INPRG                   7

You can use the analytic function LEAD and LAG to access data from the next or prior row in the result set. Something like this will give you the total time in each status

SQL> ed
Wrote file afiedt.buf

  1  with t as (
  2    select 1 parent_id, sysdate-20 date_created, 'REQ' status from dual
  3    union all
  4    select 1, sysdate-10, 'INPRG' from dual
  5    union all
  6    select 1, sysdate-5, 'WAIT' from dual
  7    union all
  8    select 1, sysdate-2, 'INPRG' from dual
  9    union all
 10    select 1, sysdate, 'COMP' from dual
 11  )
 12  select parent_id,
 13         status,
 14         sum(time_in_status)
 15    from (
 16      select parent_id,
 17             date_created,
 18             nvl(lead(date_created) over
 19                          (partition by parent_id
 20                               order by date_created),
 21                 sysdate) next_status_date,
 22             nvl(lead(date_created) over
 23                          (partition by parent_id
 24                               order by date_created),
 25                 sysdate) -
 26               date_created time_in_status,
 27             status
 28        from t)
 29*  group by parent_id, status
SQL> /

 PARENT_ID STATU SUM(TIME_IN_STATUS)
---------- ----- -------------------
         1 REQ                    10
         1 COMP                    0
         1 WAIT                    3
         1 INPRG                   7
总攻大人 2024-12-21 12:59:43

我主要使用 SQL Server,而不是 Oracle,所以如果我的语法有点偏差,请原谅我...

with base as (
  select Parent_id, Date_Created, Status,
    row_number() over(partition by Parent_id order by Date_Created) as 'row'
  from Table
)
select Parent_id, Status, sum(timeInStatus)
from (
  select this.Parent_id, this.Status,
    next.Date_Created-this.Date_Created as 'timeInStatus'
  from base this
    join base next on this.Parent_id=next.Parent_id
                  and this.row=next.row-1
  ) t
where Status = 'INPRG'
group by Parent_id, Status

基本概念是利用 row_number 将每一行自连接到下一行并计算之间的时间他们。然后只需对这些数据进行简单的聚合即可获得您想要的答案。

I primarily use SQL Server, not Oracle, so forgive me if my syntax is a little off...

with base as (
  select Parent_id, Date_Created, Status,
    row_number() over(partition by Parent_id order by Date_Created) as 'row'
  from Table
)
select Parent_id, Status, sum(timeInStatus)
from (
  select this.Parent_id, this.Status,
    next.Date_Created-this.Date_Created as 'timeInStatus'
  from base this
    join base next on this.Parent_id=next.Parent_id
                  and this.row=next.row-1
  ) t
where Status = 'INPRG'
group by Parent_id, Status

The basic concept is to utilize row_number to self join each row to it's next row and compute the time between them. Then it's just a simple aggregation of that data to get the answer you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文