0

这个问题和我之前的问题很像,但更复杂一些。 Rob van Wijk 的回答非常适合我的另一个问题,我一直以此为起点。我现在的问题是我正在为不同的字段旋转日期。之前我关心的是获取给定的所有值open_inopen_outid,现在我想要new_in, new_out, open_in, open_out, fixed_in, and fixed_outfor each id。我有以下内容:

SELECT id,
       state,
       state_time,
       MAX(new_row_num) OVER (PARTITION BY id ORDER BY state_time) AS new_row_group,
       MAX(open_row_num) OVER (PARTITION BY id ORDER BY state_time) AS open_row_group,
       MAX(fixed_row_num) OVER (PARTITION BY id ORDER BY state_time) AS fixed_row_group
FROM (
       SELECT id,
              state,
              state_time,
              CASE state
                   WHEN 'New'
                   THEN ROW_NUMBER() OVER (PARTITION BY id ORDER BY state_time)
              END AS new_row_num,
              CASE state
                   WHEN 'Open'
                   THEN ROW_NUMBER() OVER (PARTITION BY id ORDER BY state_time)
              END AS open_row_num,
              CASE state
                   WHEN 'Fixed'
                   THEN ROW_NUMBER() OVER (PARTITION BY id ORDER BY state_time)
              END AS fixed_row_num
       FROM ...
     )

这给了我如下数据:

id  state   state_time           new_row_group  open_row_group  fixed_row_group
1   New     2009-03-03 00:03:31  1
1   Closed  2009-03-04 04:15:27  1
2   New     2010-05-22 14:38:49  1
2   Open    2010-05-22 14:39:14  1              2
2   Fixed   2010-05-22 17:15:27  1              2               3

我想要如下数据:

id  new_in               new_out              open_in              open_out             fixed_in             fixed_out
1   2009-03-03 00:03:31  2009-03-04 04:15:27
2   2010-05-22 14:38:49  2010-05-22 14:39:14  2010-05-22 14:39:14  2010-05-22 17:15:27  2010-05-22 17:15:27

如何旋转数据以获取每个的日期配对id

编辑: 澄清一下,一个id可以多次进入和离开一个状态。例如,一个id可能从 New 到 Open 到 Fixed 到 Open 到 Fixed 到 Closed 。在这种情况下,需要有尽可能多的行来保存所有状态时间,例如:

id  new_in               new_out              open_in              open_out             fixed_in             fixed_out
4   2009-01-01 00:00:00  2009-01-02 00:00:00  2009-01-02 00:00:00  2009-01-03 00:00:00  2009-01-03 00:00:00  2009-01-04 00:00:00
4                                             2009-01-04 00:00:00  2009-01-05 00:00:00  2009-01-05 00:00:00  2009-01-06 00:00:00
4

3 回答 3

2

莎拉,

这是您的示例数据的示例:

SQL> create table yourtable (id,state,state_time)
  2  as
  3  select 1, 'New', to_date('2009-03-03 00:03:31','yyyy-mm-dd hh24:mi:ss') from dual union all
  4  select 1, 'Closed', to_date('2009-03-04 04:15:27','yyyy-mm-dd hh24:mi:ss') from dual union all
  5  select 2, 'New', to_date('2010-05-22 14:38:49','yyyy-mm-dd hh24:mi:ss') from dual union all
  6  select 2, 'Open', to_date('2010-05-22 14:39:14','yyyy-mm-dd hh24:mi:ss') from dual union all
  7  select 2, 'Fixed', to_date('2010-05-22 17:15:27','yyyy-mm-dd hh24:mi:ss') from dual union all
  8  select 3, 'New', date '2009-01-01' from dual union all
  9  select 3, 'Open', date '2009-01-02' from dual union all
 10  select 3, 'Fixed', date '2009-01-03' from dual union all
 11  select 3, 'Open', date '2009-01-04' from dual union all
 12  select 3, 'Fixed', date '2009-01-05' from dual union all
 13  select 3, 'Closed', date '2009-01-06' from dual
 14  /

Table created.

查询:

SQL> select id
  2       , max(decode(state,'New',state_time))   new_in
  3       , max(decode(state,'New',out_time))     new_out
  4       , max(decode(state,'Open',state_time))  open_in
  5       , max(decode(state,'Open',out_time))    open_out
  6       , max(decode(state,'Fixed',state_time)) fixed_in
  7       , max(decode(state,'Fixed',out_time))   fixed_out
  8    from ( select id
  9                , state
 10                , state_time
 11                , max(cnt) over (partition by id order by state_time) the_row
 12                , lead(state_time) over (partition by id order by state_time) out_time
 13             from ( select id
 14                         , state
 15                         , state_time
 16                         , count(*) over (partition by id,state order by state_time) cnt
 17                      from yourtable
 18                  )
 19         )
 20   group by id
 21       , the_row
 22   order by id
 23       , the_row
 24  /

        ID NEW_IN              NEW_OUT             OPEN_IN             OPEN_OUT            FIXED_IN            FIXED_OUT
---------- ------------------- ------------------- ------------------- ------------------- ------------------- -------------------
         1 03-03-2009 00:03:31 04-03-2009 04:15:27
         2 22-05-2010 14:38:49 22-05-2010 14:39:14 22-05-2010 14:39:14 22-05-2010 17:15:27 22-05-2010 17:15:27
         3 01-01-2009 00:00:00 02-01-2009 00:00:00 02-01-2009 00:00:00 03-01-2009 00:00:00 03-01-2009 00:00:00 04-01-2009 00:00:00
         3                                         04-01-2009 00:00:00 05-01-2009 00:00:00 05-01-2009 00:00:00 06-01-2009 00:00:00

4 rows selected.

要了解它是如何工作的,请从内到外执行查询并检查中间结果集。如果您需要一些额外的解释,请告诉我。

问候,罗布。

于 2010-06-24T09:42:53.230 回答
0
select news.id, news.state_time as new_in, min(not_news.state_time) as new_out
   , min(opens.state_time) as open_in
   , min(not_opens.state_time) as open_out
   , min(closes.state_time) as close_in
   , min(not_closed.state_time) as close_out
from
   (SELECT id,
          state,
          state_time
      from mytable
      where state = 'New' ) news
   left join
   (SELECT id,
          state,
          state_time
      from mytable
      where state <> 'New' ) not_news     on news.id = not_news.id and news.state_time <= not_news.state_time
   left join
   (SELECT id,
          state,
          state_time
      from mytable
      where state = 'Open' ) opens     on news.id = opens.id and news.state_time <= opens.state_time
   left join
   (SELECT id,
          state,
          state_time
      from mytable
      where state not in ('New', 'Open' )) not_opens     on news.id = opens.id and news.state_time <= opens.state_time    and opens.state_time <= not_opens.state_time
   left join
   (SELECT id,
          state,
          state_time
      from mytable
      where state = 'Closed' ) closes     on news.id = closes.id and news.state_time <= closes.state_time
   left join
   (SELECT id,
          state,
          state_time
      from mytable
      where state not in ('Closed' )) not_closed     on news.id = not_closed.id and news.state_time <= closes.state_time    and closes.state_time <= not_closed.state_time
group by news.id, news.state_time
order by id,  news.state_time

我的测试数据(从 Rob 借来的):

    创建表 mytable (id,state,state_time)
    作为
    select 1, 'New', to_date('2009-03-03 00:03:31','yyyy-mm-dd hh24:mi:ss') from dual union all
    select 1, 'Closed', to_date('2009-03-04 04:15:27','yyyy-mm-dd hh24:mi:ss') from dual union all
    select 2, 'New', to_date('2010-05-22 14:38:49','yyyy-mm-dd hh24:mi:ss') from dual union all
    select 2, 'Open', to_date('2010-05-22 14:39:14','yyyy-mm-dd hh24:mi:ss') from dual union all
    select 2, 'Fixed', to_date('2010-05-22 17:15:27','yyyy-mm-dd hh24:mi:ss') from dual union all
    select 3, 'New', date '2009-01-01' from dual union all
    选择 3, 'Open', date '2009-01-02' from dual union all
   选择 3, 'Fixed', date '2009-01-03' from dual union all
   选择 3, 'Open', date '2009-01-04' from dual union all
   选择 3, 'Fixed', date '2009-01-05' from dual union all
   选择 3, 'Closed', date '2009-01-06' from dual

查询结果:

ID NEW_IN NEW_OUT OPEN_IN OPEN_OUT CLOSE_IN CLOSE_OUT
1 2009 年 3 月 3 日 12:03:31 2009 年 3 月 4 日 4:15:27 2009 年 3 月 4 日 4:15:27   
2 2010 年 5 月 22 日 2:38:49 2010 年 5 月 22 日 2:39:14 2010 年 5 月 22 日 2:39:14 2010 年 5 月 22 日 5:15:27        
3 2009 年 1 月 1 日 2009 年 1 月 2 日 2009 年 1 月 2 日 2009 年 1 月 3 日 2009 年 1 月 6 日   

我希望你能阅读上面的内容,我在格式化时遇到了问题。

于 2010-06-23T20:27:45.303 回答
0

我不确定您希望如何处理同一状态对于 ID 重复多次的情况。以下答案采用简单的方法,假设您希望第一次设置状态和最后一次替换状态。

select id, 
       min(case state when 'New' then state_time else null end) as new_in,
       max(case state when 'New' then out_state_time else null end) as new_out,
       min(case state when 'Open' then state_time else null end) as open_in,
       max(case state when 'Open' then out_state_time else null end) as open_out,
       min(case state when 'Fixed' then state_time else null end) as fixed_in,
       max(case state when 'Fixed' then out_state_time else null end) as fixed_out
from
    (select id, 
            state, 
            state_time, 
            lead(state_time) over (partition by id 
                                   order by state_time) as out_state_time
     from ...
    )
group by id

分析函数获取分区/顺序语句描述的lead下一行,因此这是找出状态何时更改的最简单方法。中间查询是基本的透视查询(将列转换为行)。

于 2010-06-23T20:38:42.370 回答