Есть ли способ сделать этот запрос цикличным или более эффективным? - PullRequest
0 голосов
/ 24 января 2019

У меня есть таблица истории сотрудников, которая содержит дату статуса, статус и идентификатор сотрудника.Даты состояния не совпадают, и иногда они могут обновляться в течение нескольких месяцев.Мне нужно создать отчет, создающий ежемесячный снимок статусов сотрудника каждый месяц.

В настоящее время я выбираю максимальную дату статуса, предшествующую месяцу начала sysdate, и повторяю этот запрос, вычитая месяц за разиз запроса, а затем объединение, чтобы объединить все это.

SELECT id, 
       status_date, 
       status, 
       (trunc(sysdate, 'month')) AS Activity_Month
FROM empl_hist as e1 join
    (SELECT id, max(status_date) AS max_date, status_date FROM empl_hist 
     WHERE status_date <= (trunc(sysdate, 'month')) e2 
        on e1.id = e2.id and e1.status_date = e2.status_date

UNION ALL

SELECT id, 
    status_date, 
    status,
    (trunc(add_months(sysdate,-1), 'month')) AS Activity_Month,
FROM empl_hist as e1 join
    (SELECT id, max(status_date) AS max_date, status_date FROM empl_hist 
     WHERE status_date <= (trunc(add_months(sysdate,-1), 'month')) e2 
        on e1.id = e2.id and e1.status_date = e2.status_date

Мне нужен этот отчет за последние 24 месяца, и кажется, что должен быть гораздо лучший способ сделать это, чем 23 объединения.

Ответы [ 3 ]

0 голосов
/ 24 января 2019

Вы можете сделать это с помощью рекурсивного запроса, чтобы сгенерировать ваши отчетные месяцы, затем присоединить его к своей таблице empl_hist и использовать агрегатные функции для получения желаемых результатов:

WITH REPORT(ACTIVITY_MONTH) AS (
   SELECT CAST(ADD_MONTHS(TRUNC(SYSDATE,'month'),-24) AS DATE)
     FROM DUAL
  UNION ALL
   SELECT CAST(ADD_MONTHS(ACTIVITY_MONTH,1) AS DATE)
     FROM REPORT
    WHERE ADD_MONTHS(ACTIVITY_MONTH,1) < SYSDATE
)
SELECT eh.id
     , max(eh.status_date) status_Date
     , max(eh.status) keep (dense_rank first order by status_date desc) status
     , r.activity_month
  FROM REPORT r
  JOIN EMPL_HIST EH
    ON EH.STATUS_DATE <= r.ACTIVITY_MONTH
 group by eh.id, r.activity_month
0 голосов
/ 24 января 2019

Вы можете сделать объединение с таблицей calendar (таблица, содержащая 24 отчетных месяца) более эффективным, если на первом шаге рассчитывается интервал действия, т. Е. Последний день (включительно), в которыйстатус действителен - status_date_to.

Предлагаемый расчет действителен, если status_date обрезано, т. е. без времени.

Используйте status_date - interval '1' second вместо status_date - 1, еслиесть компонент времени .

Чем вы объединяете только те записи в EPML_HISTORY, которые соответствуют с reporing_month, то есть c.reporting_month between h.status_date and h.status_date_to

WITH calendar AS (
SELECT  trunc(add_months(sysdate, 1-level), 'MM') reporting_month
FROM    dual
CONNECT BY level <= 24
), hist as (
SELECT id, 
       status_date,
       nvl(lead(status_date-1) over (partition by id order by status_date),add_months(trunc(sysdate, 'MM'),1)) as status_date_to,
       status
from empl_hist)
select REPORTING_MONTH, ID, STATUS
from calendar c
join hist h on c.reporting_month between h.status_date and h.status_date_to
order by id, reporting_month;

REPORTING_MONTH             ID STATUS    
------------------- ---------- ----------
01.05.2018 00:00:00          1 active    
01.06.2018 00:00:00          1 active    
01.07.2018 00:00:00          1 active    
01.08.2018 00:00:00          1 active    
01.09.2018 00:00:00          1 deactive  
01.10.2018 00:00:00          1 deactive  
01.11.2018 00:00:00          1 deactive  
01.12.2018 00:00:00          1 deactive  
01.01.2019 00:00:00          1 active    
01.08.2018 00:00:00          2 active    
01.09.2018 00:00:00          2 active    
01.10.2018 00:00:00          2 active    
01.11.2018 00:00:00          2 deactive  
01.12.2018 00:00:00          2 deactive  
01.01.2019 00:00:00          2 deactive  
01.01.2019 00:00:00          4 active  

Обратите также внимание, что вы можете вернуться к своему логику назначения отчетного месяца с status_date <= (trunc(sysdate, 'month').В приведенных ниже примерах данные id=3 игнорируются, поскольку они были активированы 5-го числа текущего месяца, но сообщается id=4, поскольку они были активны 1-го числа текущего месяца.

ОбразецДанные

drop table empl_hist;
create table empl_hist(
id number,
status_date date,
status varchar2(10));

insert into empl_hist values(1,DATE'2018-05-01','active');
insert into empl_hist values(1,DATE'2018-08-05','deactive');
insert into empl_hist values(1,DATE'2018-12-05','active');
insert into empl_hist values(2,DATE'2018-07-05','active');
insert into empl_hist values(2,DATE'2018-10-05','deactive');
insert into empl_hist values(3,DATE'2019-01-05','active');
insert into empl_hist values(4,DATE'2019-01-01','active');
0 голосов
/ 24 января 2019

Вы можете создать список за 24 месяца с подзапросом и присоединиться к нему.Тогда я бы использовал row_number, чтобы определить, какая самая последняя запись в окне, чтобы избежать самостоятельного объединения:

SELECT   id, status_date, status, Activity_Month
FROM     (
            SELECT     e.*,
                       m.Activity_Month,
                       row_number() OVER (PARTITION BY m.Activity_Month 
                                          ORDER BY e.status_date DESC) rn
            FROM       (
                          SELECT  trunc(add_months(sysdate, 1-level), 'month') Activity_Month
                          FROM    dual
                          CONNECT BY level <= 24
                       ) m
            INNER JOIN empl_hist e
                    ON e.status_date <= m.Activity_Month
         ) base
WHERE    rn = 1
ORDER BY Activity_Month
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...