Разделение запроса на блоки, каждая из которых охватывает определенный c аспект отчета / query-logi c, как указано davidc2p , очень хорошая идея.
Но для этого нет необходимости во временных таблицах; для этого достаточно общих табличных выражений (CTE) aka «WITH CLAUSE».
Структура запроса
Очень важно понять, что EMPLOYEETABLE
является таблицей снимков с захватом STATUS
всех сотрудников каждую отдельную дату.
Для запроса существует общее условие - рассматривать только моментальные снимки за определенный период времени.
На основе этого «временного блока» В наборе данных запрос теперь имеет дело с сотрудниками (в отличие от снимков!) и их последним статусом (в «наборе данных с временными рамками»).
Это наблюдение позволяет легко определить MAX()
- STATUS
для каждый сотрудник. Поскольку для сотрудников "WIDTHDRAWN" существует специальное условие, что их соответствующие ENDDATE
должны быть включены или после начала отчетного периода времени, двум отдельным группам / группам / группам сотрудников требуется собственный подзапрос.
Эти два подзапроса возвращают для каждого сотрудника, запись которого (EMPLOYEEID
+ REPORTDATE
служит уникальным ключом для отчета-записи). ords) должны быть возвращены в результате запроса.
Для получения выходных данных две группы сотрудников объединяются (UNION ALL
) и затем используются в качестве окончательного фильтра / селектора для всех записей, которые должны быть возвращены из базовой таблицы.
переписанный запрос
with report_base as (
-- all records relevant to the reporting timeframe)
select
reportdate, EmployeeID
, startdate, enddate, status
from
employeetable
where
reportdate >= date'2019-04-01'
and reportdate <= date'2019-07-01')
, active_employees as (
-- all employees with most recent status in reporting timeframe = ACTIVE
-- should be DISJUNCT from WITHDRAWN_EMPLOYEES
select
employeeid
, max(reportdate) as reportdate
from
report_base
group by
employeeid
having
max(status)='Active')
, withdrawn_employees as (
-- all employees with most recent status in reporting timefrawm = WITHDRAWN
-- the ENDDATE should be on or after the start of the reporting timeframe
-- should be DISJUNCT from ACTIVE_EMPLOYEES)
select
employeeid
, min(reportdate) as reportdate
from
report_base
where
enddate >= date'2019-04-01'
group by
employeeid
having
max(status)='Withdrawn')
, report_records as(
-- all records that should be returned)
select
employeeid, reportdate
from
active_employees
union all
select
employeeid, reportdate
from
withdrawn_employees)
select
rb.reportdate, rb.EmployeeID
, rb.startdate, rb.enddate, rb.status
from
report_base rb
inner join report_records rr
on (rb.employeeid, rb.reportdate)
= (rr.employeeid, rr.reportdate);
почему он лучше?
Поскольку нет доступных данных объемного теста, я не смог проверить фактические различия производительности во время выполнения между запросом OP и реорганизованной версией.
Однако измененная версия приводит к одному меньшему объединению в EXPLAIN PLAN, что, вероятно, приводит к улучшению производительности и использования памяти.
В дополнение к этому, измененный план намного понятнее относительно того, как данные результата вычисляются и позволяют пошаговую разработку / отладку.