如何从表中检索最新数据

时间:2019-02-14 09:15:17

标签: sql oracle oracle11g greatest-n-per-group

当前,我正在一个项目中,该项目需要从表中提取最新数据以用于报告。下面是示例表结构:-

enter image description here 每个学生都有几门课程,而program_id的编程语言为+ ve,非编程语言的课程ID为-ve。我想为每个学生提取最新的编程语言和非编程语言course_id。

我使用下面的SQL查询并能够提取数据。

CREATE TABLE COURSE
    ("STUDENT_ID" int, "COURSE_ID" int, "COURSE_NAME" varchar2(31), "COURSE_START_DATE" timestamp)
;

INSERT ALL 
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, -100, 'C Programming Language', '04-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, -200, 'Java Programming Language', '11-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, -300, 'C# Programming Language', '07-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, 100, 'Data Structure and algorithms', '05-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, 200, 'Computer Graphics', '13-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100001, 300, 'Networking', '02-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, -300, 'C# Programming Language', '12-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, -400, 'Python Programming Language', '07-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, -500, 'JavaScript Programming Language', '08-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, 100, 'Data Structure and algorithms', '17-Jan-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, 300, 'Computer Graphics', '26-Jan-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100002, 400, 'DataBase Management', '10-Jan-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, -500, 'JavaScript Programming Language', '07-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, -600, 'SQL', '13-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, -200, 'Java Programming Language', '17-Jan-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, 300, 'Networking', '04-Feb-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, 400, 'DataBase Management', '05-Jan-2019 12:00:00 AM')
    INTO COURSE ("STUDENT_ID", "COURSE_ID", "COURSE_NAME", "COURSE_START_DATE")
         VALUES (100003, 600, 'Cryptography', '18-Jan-2019 12:00:00 AM')
SELECT * FROM dual
;

SELECT STUDENT_ID
,COURSE_ID
,COURSE_NAME
,COURSE_START_DATE
  FROM (
SELECT 
ROW_NUMBER() OVER(PARTITION BY STUDENT_ID ORDER BY COURSE_START_DATE DESC) AS ROW_NUM
,STUDENT_ID
,COURSE_ID
,COURSE_NAME
,COURSE_START_DATE
  FROM
COURSE
WHERE COURSE_ID  0) TEMP1 WHERE TEMP1.ROW_NUM = 1;

enter image description here

但是问题是实际表非常大。几乎有85,000行,此查询需要花费一些时间。还有其他更好的方法吗?我正在使用Oracle 11g R2。请建议

这是SQLfiddle链接http://sqlfiddle.com/#!4/b3fe1/8

4 个答案:

答案 0 :(得分:3)

您可以尝试以下操作-您需要在{cluase中添加<HasData> false</HasData> (notice the space)

$args = ['item2' => 'item2',
        'item3' => 'value3'];

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }

答案 1 :(得分:0)

使用具有row_number的CTE,然后将其合并

with pro as 
(
select t1.*, row_number() over(partition by student_id order by course_start_date desc) rn
from course 
where course_id > 0 -- programming
)
, nonpro as 
(
select t1.*, row_number() over(partition by student_id order by course_start_date desc) rn
from course 
where course_id < 0 -- non-programming
)
select *
from pro
where rn = 1
union
select *
from nonpro
where rn = 1

答案 2 :(得分:0)

获得这些结果的另一种方法是使用NOT EXISTS

因为您想获取最近COURSE_START_DATE的记录 为学生。
那么对于该记录,将不存在日期更高的任何记录。
(除非有两个具有相同的最大日期,否则它将返回两个日期)

SELECT 
 STUDENT_ID, 
 COURSE_ID, 
 COURSE_NAME, 
 COURSE_START_DATE
FROM COURSE t
WHERE COURSE_ID != 0
AND NOT EXISTS
(
  SELECT 1
  FROM COURSE d
  WHERE d.STUDENT_ID = t.STUDENT_ID
    AND d.COURSE_START_DATE > t.COURSE_START_DATE
    AND SIGN(d.COURSE_ID) = SIGN(t.COURSE_ID)
    AND d.COURSE_ID != 0
)
ORDER BY SIGN(COURSE_ID), STUDENT_ID

这种查询可能会受益于STUDENT_ID上的非唯一索引。

db <>小提琴here

的测试

顺便说一句,在Oracle 12c中,您可以按ROW_NUMBER进行排序,然后仅获取具有并列关系的第一个。

SELECT 
 STUDENT_ID, 
 COURSE_ID, 
 COURSE_NAME, 
 COURSE_START_DATE
FROM COURSE t
WHERE COURSE_ID != 0
ORDER BY row_number() over(partition by student_id, SIGN(COURSE_ID) order by course_start_date desc)
FETCH FIRST ROW WITH TIES

答案 3 :(得分:0)

您可以使用查询并将SIGN( course_id )添加到分区:

查询

SELECT STUDENT_ID
     , COURSE_ID
     , COURSE_NAME
     , COURSE_START_DATE
FROM (
  SELECT ROW_NUMBER() OVER (
           PARTITION BY STUDENT_ID, SIGN( COURSE_ID )
           ORDER BY COURSE_START_DATE DESC
         ) AS ROW_NUM
       , STUDENT_ID
       , COURSE_ID
       , COURSE_NAME
       , COURSE_START_DATE
  FROM   COURSE
  WHERE COURSE_ID != 0
)
WHERE  ROW_NUM = 1;

输出

STUDENT_ID | COURSE_ID | COURSE_NAME               | COURSE_START_DATE           
---------: | --------: | :------------------------ | :---------------------------
    100001 |      -200 | Java Programming Language | 11-FEB-19 12.00.00.000000 AM
    100001 |       200 | Computer Graphics         | 13-FEB-19 12.00.00.000000 AM
    100002 |      -300 | C# Programming Language   | 12-FEB-19 12.00.00.000000 AM
    100002 |       300 | Computer Graphics         | 26-JAN-19 12.00.00.000000 AM
    100003 |      -600 | SQL                       | 13-FEB-19 12.00.00.000000 AM
    100003 |       300 | Networking                | 04-FEB-19 12.00.00.000000 AM

db <>提琴here