我正在使用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上问一个问题时,我一定会对我的发布做些改进。
答案 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>