Я использую Oracle SQL, и я пытаюсь выполнить исторический анализ результатов тестирования (чтобы визуализировать улучшения оценки за месяц для отдельных лиц). Во-первых, у меня есть таблица, которая представляет собой список пользователей и соответствующие месяцы, когда они активны; это выглядит примерно так:

    TABLE1
    ________________________
    UserName  |  ActiveDate
    ________________________
    John Doe,    01-MAY-18
    John Doe,    01-APR-18
    John Doe,    01-MAR-18
    Jane Doe,    01-APR-18
    Jane Doe,    01-MAR-18
    Jim Doe,     01-MAY-18

Кроме того, у меня есть еще одна таблица, в которой перечислены результаты тестов с отметками времени (вы можете повторить тест столько раз, сколько захотите). Это выглядит примерно так:

    TABLE2
    ________________________________________
    UserName  |  TestScore  |  EffectiveDate
    ________________________________________
    John Doe,    87,           07-FEB-18
    John Doe,    85,           14-FEB-18
    John Doe,    90,           18-FEB-18
    John Doe,    92,           02-MAR-18
    John Doe,    91,           12-MAR-18
    Jane Doe,    70,           01-FEB-18
    Jane Doe,    72,           02-FEB-18
    Jane Doe,    78,           18-FEB-18
    Jane Doe,    77,           06-MAR-18
    Jane Doe,    81,           18-MAR-18
    Jim Doe,     50,           03-MAR-18
    Jim Doe,     48,           23-MAR-18
    Jim Doe,     58,           08-APR-18

Для каждой строки в первой таблице (все пары UserName | ActiveDate различны) я хотел бы выбрать последнюю TestScore из таблицы 2, где EffectiveDate предшествует ActiveDate

Так что я надеюсь получить что-то подобное

    UserName  |  ActiveDate  |  Most recent TestScore prior to ActiveDate
    ______________________________________
    John Doe,    01-MAY-18,     91
    John Doe,    01-APR-18,     91
    John Doe,    01-MAR-18,     90
    Jane Doe,    01-APR-18,     81
    Jane Doe,    01-MAR-18,     78
    Jim Doe,     01-MAY-18,     58

Я пытался выполнить эту работу, ПРИСОЕДИНЯЯСЬ к таблице 1 к таблице 2 на UserName, где EffectiveDate

Спасибо за любой совет заранее. Это моя первая публикация в StackOverflow, поэтому я надеюсь, что я правильно задал этот вопрос!

Редактировать: Спасибо всем за помощь, я думаю, у меня есть все, что мне нужно, чтобы продолжить мой проект сейчас. Я обязательно внесу некоторые улучшения в мою публикацию в следующий раз, когда я задам вопрос здесь на SO.

2
Dave Parries 30 Ноя 2018 в 23:54

2 ответа

Вот один из вариантов (вам нужны строки 24 года; предыдущие строки просто тестируют CTE):

SQL> with table1 (username, activedate) as
  2    (select 'jod', date '2018-05-01' from dual union all
  3     select 'jod', date '2018-04-01' from dual union all
  4     select 'jod', date '2018-03-01' from dual union all
  5     select 'jad', date '2018-04-01' from dual union all
  6     select 'jad', date '2018-03-01' from dual union all
  7     select 'jid', date '2018-05-01' from dual
  8    ),
  9  table2 (username, testscore, effectivedate) as
 10    (select 'jod', 87, date '2018-02-07' from dual union all
 11     select 'jod', 85, date '2018-02-14' from dual union all
 12     select 'jod', 90, date '2018-02-18' from dual union all
 13     select 'jod', 92, date '2018-03-02' from dual union all
 14     select 'jod', 91, date '2018-03-12' from dual union all
 15     select 'jad', 70, date '2018-02-01' from dual union all
 16     select 'jad', 72, date '2018-02-02' from dual union all
 17     select 'jad', 78, date '2018-02-18' from dual union all
 18     select 'jad', 77, date '2018-03-06' from dual union all
 19     select 'jad', 81, date '2018-03-18' from dual union all
 20     select 'jid', 50, date '2018-03-03' from dual union all
 21     select 'jid', 48, date '2018-03-23' from dual union all
 22     select 'jid', 58, date '2018-04-08' from dual
 23    )
 24  select t1.username, t1.activedate, t2.testscore
 25  from table1 t1 join table2 t2 on t1.username = t2.username
 26  where t2.effectivedate = (select max(t2a.effectivedate)
 27                            from table2 t2a
 28                            where t2a.username = t2.username
 29                              and t2a.effectivedate < t1.activedate
 30                           )
 31  order by t1.username, t1.activedate desc;

USE ACTIVEDAT  TESTSCORE
--- --------- ----------
jad 01-apr-18         81
jad 01-mar-18         78
jid 01-may-18         58
jod 01-may-18         91
jod 01-apr-18         91
jod 01-mar-18         90

6 rows selected.

SQL>
0
Littlefoot 30 Ноя 2018 в 21:08

Если вы просто хотите получить оценку за тест, коррелированный подзапрос может быть самым простым подходом:

select t1.*,
       (select max(t2.score) keep (dense_rank first order by t2.effectivedate desc)
        from table2 t2
        where t2.effectivedate < t1.activedate
       ) as most_recent_score
from table1 t1;
1
Gordon Linoff 30 Ноя 2018 в 21:10