代码之家  ›  专栏  ›  技术社区  ›  Sarah Vessels

Oracle SELECT查询:在为不同字段配对日期时折叠空值

  •  0
  • Sarah Vessels  · 技术社区  · 14 年前

    这个问题很像 my previous question ,但有点复杂。 Rob van Wijk's answer 这对我的另一个问题很有效,我一直以此为出发点。我现在的问题是,我正在为不同的领域旋转日期。而在我关心得到所有 open_in open_out 给定值 id ,现在我想 new_in , new_out , 在中打开 打开\u , fixed_in ,和 fixed_out 对于每个 身份证件 . 我有以下几点:

    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  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
    
    3 回复  |  直到 8 年前
        1
  •  2
  •   Rob van Wijk    14 年前

    莎拉,

    以下是示例数据:

    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.
    

    要了解它的工作原理,请从内到外执行查询并检查中间结果集。如果你需要更多的解释,请告诉我。

    罗伯。

        2
  •  0
  •   Allan    14 年前

    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

        3
  •  0
  •   redcayuga    14 年前
    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):

        create table mytable (id,state,state_time) 
        as 
        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 
        select 3, 'Open', date '2009-01-02' from dual union all 
       select 3, 'Fixed', date '2009-01-03' from dual union all 
       select 3, 'Open', date '2009-01-04' from dual union all 
       select 3, 'Fixed', date '2009-01-05' from dual union all 
       select 3, 'Closed', date '2009-01-06' from dual 
    

    查询结果:

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