У меня есть запрос, по которому я хочу узнать текущий статус человека.
Настройка;
create table Person
(
personID int
,forename varchar2(50)
,surname varchar2(50)
);
insert all
into Person (personID, forename, surname) values (1,'AAA','BBB')
into Person (personID, forename, surname) values (2,'CCC','DDD')
select * from dual;
create table PersonStatus
(
personID int
,fromDate date
,status varchar2(5)
);
insert all
into PersonStatus (personID, fromDate, status) values (1,TO_DATE('2019-01-01','yyyy-mm-dd'),'Q')
into PersonStatus (personID, fromDate, status) values (1,TO_DATE('2019-02-01','yyyy-mm-dd'),'W')
into PersonStatus (personID, fromDate, status) values (1,TO_DATE('2019-03-01','yyyy-mm-dd'),'E')
into PersonStatus (personID, fromDate, status) values (2,TO_DATE('2019-01-01','yyyy-mm-dd'),'R')
into PersonStatus (personID, fromDate, status) values (2,TO_DATE('2019-02-01','yyyy-mm-dd'),'T')
into PersonStatus (personID, fromDate, status) values (2,TO_DATE('2019-03-01','yyyy-mm-dd'),'Y')
select * from dual;
Так что этот запрос работает нормально;
select * from
(
select
p.personID
,p.foreName
,p.surName
,ps.fromDate
,ps.status
,row_number() over (partition by p.personID order by ps.fromDate desc) as rn
from Person p
left outer join PersonStatus ps on p.personID = ps.personID and ps.fromDate <= SYSDATE
) where rn = 1;
PERSONID FORENAME SURNAME FROMDATE STATU RN
---------- -------------------------------------------------- -------------------------------------------------- --------- ----- ----------
1 AAA BBB 01-MAR-19 E 1
2 CCC DDD 01-MAR-19 Y 1
Итакпока все хорошо!
Проблема начинается с усложнения отчета. Итак, скажем, мне нужно знать список их проблем и их статус в том месте, где у них есть проблема.
Дополнительная настройка;
create table PersonIssue
(
issueID int
,personID int
,issueDate date
);
insert all
into PersonIssue (issueID, personID, issueDate) values (1,1,TO_DATE('2019-01-14','yyyy-mm-dd'))
into PersonIssue (issueID, personID, issueDate) values (2,1,TO_DATE('2019-02-14','yyyy-mm-dd'))
into PersonIssue (issueID, personID, issueDate) values (3,1,TO_DATE('2019-03-14','yyyy-mm-dd'))
into PersonIssue (issueID, personID, issueDate) values (4,2,TO_DATE('2019-01-14','yyyy-mm-dd'))
into PersonIssue (issueID, personID, issueDate) values (5,2,TO_DATE('2019-02-14','yyyy-mm-dd'))
into PersonIssue (issueID, personID, issueDate) values (6,2,TO_DATE('2019-03-14','yyyy-mm-dd'))
select * from dual;
Новый запрос и результаты;
select * from
(
select
pi.issueID
,pi.issueDate
,p.personID
,p.foreName
,p.surName
,ps.fromDate
,ps.status
,row_number() over (partition by pi.issueID, p.personID order by ps.fromDate desc) as rn
from Person p
left outer join PersonIssue pi on p.personID = pi.personID
left outer join PersonStatus ps on p.personID = ps.personID and ps.fromDate <= pi.issueDate
order by p.personID, pi.issueDate, ps.fromDate desc
) where rn = 1;
ISSUEID ISSUEDATE PERSONID FORENAME SURNAME FROMDATE STATU RN
---------- --------- ---------- -------------------------------------------------- -------------------------------------------------- --------- ----- ----------
1 14-JAN-19 1 AAA BBB 01-JAN-19 Q 1
2 14-FEB-19 1 AAA BBB 01-FEB-19 W 1
3 14-MAR-19 1 AAA BBB 01-MAR-19 E 1
4 14-JAN-19 2 CCC DDD 01-JAN-19 R 1
5 14-FEB-19 2 CCC DDD 01-FEB-19 T 1
6 14-MAR-19 2 CCC DDD 01-MAR-19 Y 1
Хотя это работает, у меня есть пара опасений по этому поводу, которые заставляют меня думать, что я делаю это неправильно.
Во-первых, это соединение неравенства во втором запросе PersonStatusпотенциально «возвращение» большого количества записей, которые меня не интересуют, только для последующего удаления? Есть ли более эффективный способ?
Во-вторых, мне пришлось изменить раздел во втором запросе, чтобы получить правильные результаты. Есть ли способ сделать это, что лучше инкапсулирует эту часть логики, чтобы не пришлось менять? Я хочу знать статус человека на определенную дату - такое чувство, что я должен каким-то образом сделать это более изолированным способом.
Заранее спасибо!