SQL манипулирование - PullRequest
       3

SQL манипулирование

0 голосов
/ 08 декабря 2018

Ниже приведены структура таблицы и данные

ВХОД:

 S_ID   PREV_STD    NEXT_STD    CHG_DT
 ------------------------------------------
 1      3           4           23-NOV-16
 1      4           5           20-NOV-17
 1      5           6           17-NOV-18
 2      3           4           20-NOV-17
 3      3           4           23-NOV-16

Я хочу преобразовать приведенное ниже: 09-DEC-18 - это системная дата, 01-JAN-00дата начала первого стандартного экзамена для каждого студента.

Желаемый результат:

 S_ID   PREV_STD    NEXT_STD    START_DT    END_DT
 --------------------------------------------------
 1      3           4           01-JAN-00   22-NOV-16
 1      4           5           23-NOV-16   19-NOV-17
 1      5           6           20-NOV-17   16-NOV-18
 1      6           6           17-NOV-18   09-DEC-18
 2      3           4           01-JAN-00   19-NOV-17
 2      4           4           20-NOV-17   09-DEC-18
 3      3           4           01-JAN-00   22-NOV-16
 3      4           4           23-NOV-16   09-DEC-18

Моя попытка (в процессе):

with input as
(
     select 1 s_id, 3 prev_std, 4 next_std, to_date('20161123', 'YYYYMMDD') chg_dt 
     from dual
     union all
     select 1 s_id, 4, 5, to_date('20171120', 'YYYYMMDD') 
     from dual
     union all
     select 1 s_id, 5, 6, to_date('20181117', 'YYYYMMDD') 
     from dual
     union all 
     select 2 s_id, 3, 4, to_date('20171120', 'YYYYMMDD') 
     from dual
     union all
     select 3 s_id, 3, 4, to_date('20161123', 'YYYYMMDD') 
     from dual
)
select 
    S_ID, PREV_STD, NEXT_STD,   
    NVL(lag(CHG_DT) over(partition by s_id order by chg_dt),   
    to_date('20000101','YYYYMMDD')) start_dt,
    CHG_DT - 1 stop_dt,
    CHG_DT,
    NVL(lead(CHG_DT) over(partition by s_id order by chg_dt), sysdate) next_start_dt,
    count(1) over(partition by s_id order by chg_dt) rec_num,
    count(1) over(partition by s_id) rec_to_process
from 
    input;

Ответы [ 3 ]

0 голосов
/ 09 декабря 2018

Вот запрос

select data.S_ID, data.PREV_STD, data.NEXT_STD,
replace(convert(varchar,lag(data.CHG_DT,1,'01-JAN-2000') over(partition by data.S_ID order by data.S_ID, data.PREV_STD),6),' ','-') START_DT,
replace(convert(varchar,dateadd(D,-1,isnull(data.CHG_DT,getdate()+1)),6),' ','-') END_DT
from
(
select * from #test_data union 
(select S_ID, max(NEXT_STD) PREV_STD , max(NEXT_STD) NEXT_STD, NULL CHG_DT
 from #test_data
group by S_ID) 
) data

Вывод

S_ID    PREV_STD    NEXT_STD    START_DT    END_DT
1   3   4   01-Jan-00   22-Nov-16
1   4   5   23-Nov-16   19-Nov-17
1   5   6   20-Nov-17   16-Nov-18
1   6   6   17-Nov-18   09-Dec-18
2   3   4   01-Jan-00   19-Nov-17
2   4   4   20-Nov-17   09-Dec-18
3   3   4   01-Jan-00   22-Nov-16
3   4   4   23-Nov-16   09-Dec-18
0 голосов
/ 09 декабря 2018

Завершено мое решение.

with input as(
  select 
    1 s_id, 
    3 prev_std, 
    4 next_std, 
    to_date('20161123', 'YYYYMMDD') chg_dt 
  from 
    dual 
  UNION ALL 
  select 
    1 s_id, 
    4, 
    5, 
    to_date('20171120', 'YYYYMMDD') 
  from 
    dual 
  UNION ALL 
  select 
    1 s_id, 
    5, 
    6, 
    to_date('20181117', 'YYYYMMDD') 
  from 
    dual 
  UNION ALL 
  select 
    2 s_id, 
    3, 
    4, 
    to_date('20171120', 'YYYYMMDD') 
  from 
    dual 
  UNION ALL 
  select 
    3 s_id, 
    3, 
    4, 
    to_date('20161123', 'YYYYMMDD') 
  from 
    dual
) 
select 
  * 
from 
  (
    select 
      S_ID, 
      PREV_STD, 
      NEXT_STD, 
      NVL(
        lag(CHG_DT) over(
          partition by s_id 
          order by 
            chg_dt
        ), 
        to_date('20000101', 'YYYYMMDD')
      ) start_dt, 
      CHG_DT - 1 stop_dt 
    from 
      input 
    UNION ALL 
    select 
      S_ID, 
      NEXT_STD, 
      NEXT_STD, 
      CHG_DT, 
      sysdate 
    from 
      (
        select 
          S_ID, 
          NEXT_STD, 
          CHG_DT, 
          count(1) over(
            partition by s_id 
            order by 
              chg_dt
          ) rec_num, 
          count(1) over(partition by s_id) rec_to_process 
        from 
          input
      ) 
    where 
      rec_num = rec_to_process
  ) 
order by 
  S_ID, 
  start_dt;
0 голосов
/ 08 декабря 2018

Вы можете попробовать что-то вроде следующего:

Изменить в соответствии с разновидностью SQL вы используете.

with input as
(
     select 1 s_id, 3 prev_std, 4 next_std, to_date('20161123', 'YYYYMMDD') chg_dt 
     union all
     select 1 s_id, 4, 5, to_date('20171120', 'YYYYMMDD') 
     union all
     select 1 s_id, 5, 6, to_date('20181117', 'YYYYMMDD') 
     union all 
     select 2 s_id, 3, 4, to_date('20171120', 'YYYYMMDD') 
     union all
     select 3 s_id, 3, 4, to_date('20161123', 'YYYYMMDD') 

),


intermediate AS (
    SELECT s_id
    , prev_std
    , next_std
    , start_date
    , end_date
    FROM
        (
            SELECT *
            , COALESCE(LAG(chg_dt, 1) OVER(PARTITION BY s_id ORDER BY chg_dt), to_date('20000101', 'YYYYMMDD')) start_date
            , (chg_dt - INTERVAL '1 Day')::DATE end_date
            FROM input
        ) a
)


SELECT s_id
    , prev_std
    , next_std
    , TO_CHAR(start_date, 'DD-MON-YY') start_dt
    , TO_CHAR(end_date, 'DD-MON-YY') end_dt
FROM(
    SELECT *
    FROM intermediate

    UNION ALL

    SELECT s_id, MAX(prev_std)+1, MAX(next_std), (MAX(end_date) + INTERVAL '1 Day')::DATE, Current_date
    FROM intermediate
    GROUP BY s_id
) a
ORDER BY 1, 2, 3;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...