每月选择最新的考试成绩

时间:2018-11-30 20:54:15

标签: sql oracle

我正在使用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

对于第一张表中的每一行(所有用户名| ActiveDate配对均不同),我想从Table2中选择最近的TestScore,其中有效日期早于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进行 JOINING 来使这项工作生效,其中,EffectiveDate

感谢您提前提出所有建议。这是我第一次在StackOverflow上发帖,所以希望我已经正确提出了这个问题!

编辑:谢谢大家的帮助,我想我现在拥有继续进行项目所需的一切。下次我在SO上问一个问题时,我一定会对我的发布做些改进。

3 个答案:

答案 0 :(得分:1)

如果只需要测试成绩,则相关子查询可能是最简单的方法:

$

答案 1 :(得分:1)

仅需要一个联接的两个解决方案:

Oracle设置

CREATE TABLE TABLE1 ( UserName, ActiveDate ) AS
  SELECT 'John Doe', DATE '2018-05-01' FROM DUAL UNION ALL
  SELECT 'John Doe', DATE '2018-04-01' FROM DUAL UNION ALL
  SELECT 'John Doe', DATE '2018-03-01' FROM DUAL UNION ALL
  SELECT 'Jane Doe', DATE '2018-04-01' FROM DUAL UNION ALL
  SELECT 'Jane Doe', DATE '2018-03-01' FROM DUAL UNION ALL
  SELECT 'Jim Doe',  DATE '2018-05-01' FROM DUAL;

CREATE TABLE TABLE2 ( UserName, TestScore, EffectiveDate ) AS
  SELECT 'John Doe', 87, DATE '2018-02-07' FROM DUAL UNION ALL
  SELECT 'John Doe', 85, DATE '2018-02-14' FROM DUAL UNION ALL
  SELECT 'John Doe', 90, DATE '2018-02-18' FROM DUAL UNION ALL
  SELECT 'John Doe', 92, DATE '2018-03-02' FROM DUAL UNION ALL
  SELECT 'John Doe', 91, DATE '2018-03-12' FROM DUAL UNION ALL
  SELECT 'Jane Doe', 70, DATE '2018-02-01' FROM DUAL UNION ALL
  SELECT 'Jane Doe', 72, DATE '2018-02-02' FROM DUAL UNION ALL
  SELECT 'Jane Doe', 78, DATE '2018-02-18' FROM DUAL UNION ALL
  SELECT 'Jane Doe', 77, DATE '2018-03-06' FROM DUAL UNION ALL
  SELECT 'Jane Doe', 81, DATE '2018-03-18' FROM DUAL UNION ALL
  SELECT 'Jim Doe',  50, DATE '2018-03-03' FROM DUAL UNION ALL
  SELECT 'Jim Doe',  48, DATE '2018-03-23' FROM DUAL UNION ALL
  SELECT 'Jim Doe',  58, DATE '2018-04-08' FROM DUAL;

查询1

SELECT *
FROM   (
  SELECT t2.*,
         t1.ActiveDate,
         ROW_NUMBER() OVER ( PARTITION BY t2.UserName, t1.ActiveDate ORDER BY EffectiveDate DESC ) AS rn
  FROM   table2 t2
         INNER JOIN
         table1 t1
         ON ( t1.UserName = t2.UserName
              AND t2.EffectiveDate < t1.ActiveDate )
) t2
WHERE rn = 1;

输出

USERNAME    TESTSCORE   EFFECTIVEDATE   ACTIVEDATE  RN
----------  ----------  --------------  ----------  ---
Jane Doe    78          18-FEB-18       01-MAR-18   1
Jane Doe    81          18-MAR-18       01-APR-18   1
Jim Doe     58          08-APR-18       01-MAY-18   1
John Doe    90          18-FEB-18       01-MAR-18   1
John Doe    91          12-MAR-18       01-APR-18   1
John Doe    91          12-MAR-18       01-MAY-18   1

查询2

SELECT t1.UserName,
       t1.ActiveDate,
       MAX( TestScore ) KEEP ( DENSE_RANK LAST ORDER BY EffectiveDate ) AS MostRecentTestScore
FROM   table2 t2
       INNER JOIN
       table1 t1
       ON ( t1.UserName = t2.UserName
            AND t2.EffectiveDate < t1.ActiveDate )
GROUP BY t1.UserName, t1.ActiveDate;

输出

USERNAME    ACTIVEDATE  MOSTRECENTTESTSCORE
----------  ----------  -------------------
Jim Doe     01-MAY-18   58
Jane Doe    01-MAR-18   78
Jane Doe    01-APR-18   81
John Doe    01-MAR-18   90
John Doe    01-APR-18   91
John Doe    01-MAY-18   91

答案 2 :(得分:0)

这是一个选项(您需要从第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>