2010-01-27 35 views
4

我有两个表:选择*最新*等级信息为每一个学生

STUDENT  GRADES 
----------  ---------- 
id    id 
name   person_id 
address  date 
city   test_name 
phone   grade 

每个学生都会有在成绩表中的几个条目。我想知道是否可以使用SQL(Postgres)来选择所有学生以及他们的最新成绩信息。我基本上需要一个如下所示的结果表,其中date,test_name和grade用于最新结果(按日期)。

LATEST_GRADES 
---------------- 
id 
name 
address 
city 
phone 
grade_id 
date 
test_name 
grade 

任何帮助将不胜感激,谢谢。

编辑:加入溶液QUERY

SELECT * FROM 
    students s 
    JOIN (SELECT DISTINCT ON (person_id) person_id, date, test_name, grade 
     FROM grades 
     ORDER BY person_id, date DESC) g 
    ON s.id = g.person_id; 

回答

1

是的,这是可能的。您正在寻找的条款是“DISTINCT ON”。使用它,您可以轻松地进行查询,而无需对同一张表进行子查询和多次扫描。

在文档中,请注意ON部分“DISTINCT ON”。

+0

这一个实际上对我很好。我在问题结尾处发布了解决方案查询。其他一些双查询解决方案花费了大约20多秒。尝试DISTINCT ON方法后,我把它降到3+秒以上。 我的'成绩表'实际上有50,000多行。 – PKKid 2010-01-28 21:27:46

2

我觉得Postgre支持窗口函数,所以你应该能够做到像

SELECT * 
    FROM person p 
    JOIN grades g ON grades.person_id = p.id 
WHERE row_number() OVER (PARTITION BY g.person_id ORDER BY g.date DESC) = 1 

编辑:显然窗功能不支持where子句(应该知道这是有道理的)。然而,这不是一个无法解决的问题:

SELECT * 
    FROM person p 
    JOIN (SELECT person_id, <other_fields>, row_number() OVER (PARTITION BY person_id ORDER BY date DESC) AS rn FROM grades) g 
WHERE g.rn = 1 

检查执行计划,但是,如果您的数据很大。

+0

是的,自v8.4开始支持窗口功能。 – bernie 2010-01-27 23:00:34

+0

不幸的是,这不适合我。 “WHERE子句中不支持窗口函数”。 – PKKid 2010-01-28 20:45:59

0
select 
S.id, 
S.name, 
S.address, 
S.city, 
S.phone, 
G.id as grade_id, 
G.date, 
G.test_name, 
G.grade 

from 
    Grades G, 
    Student S, 
    (select S.id as studentid, max(date) as latest_grade_date 
    from student S , grades G where s.id = g.person_id) Q 
WHERE 
    G.person_id = Q.studentid 
    AND S.id = Q.studentid 
    AND G.date = Q.latest_grade_date 
    AND S.id = G.person_id 
+0

但是,另一种方式看起来更好 – 2010-01-27 23:05:10

1

虽然我不熟悉Postgres,但我在与Oracle一起工作时做了很多这样的事情。也许下面的查询会有帮助。

select p.id, 
     p.name, 
     p.address, 
     p.city, 
     p.phone, 
     g.date, 
     g.test_name, 
     g.grade 
from person p, 
    grades g 
where p.id = g.person_id 
    and g.date = (select max(g2.date) 
        from grades g2 
        where g2.id = g.id 
       ) 
+0

这个工作,但需要20秒,这可能不是一个伟大的Web应用程序。我正在查看我的索引,看看我是否错过了一些东西。 :) – PKKid 2010-01-28 20:54:50

+0

@PKKid - 我看到depesz的DISTINCT ON解决方案为你工作,并且更快。不过,我很想知道,如果通过一些创造性索引甚至可以使3秒钟的执行速度更快。我可能不得不在下一个个人项目中给Postgres一个尝试。 DISTINCT ON是一个很好的功能。 – ssakl 2010-01-29 14:30:10

相关问题