2010-01-27 4 views
4

У меня есть две таблицы:Select * Последнее * Оценка данных для каждого студента

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 

Любая помощь была бы принята с благодарностью, спасибо.

EDIT: ДОБАВЛЕНО РЕШЕНИЕ 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». С его помощью вы можете легко выполнить запрос без подзапросов и нескольких сканов одной таблицы.

В документах, пожалуйста, обратите внимание на ВКЛ. часть «DISTINCT ON».

+0

Это действительно отлично работает для меня. Я отправил запрос решения в конце вопроса. Некоторые из двух решений двойного запроса заняли около 20 секунд. Попробовав метод DISTINCT ON, я получил его до 3+ секунд. В таблице «Мои разряды» есть 50 000 строк. – PKKid

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 

Edit: Очевидно оконного функции не поддерживаются предложение 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

+0

К сожалению, это не работает для меня. «Функции окна не поддерживаются в предложении WHERE». – PKKid

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

Но другой способ выглядит лучше –

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 секунд, что может оказаться слишком большим для webapp. Теперь я просматриваю свои индексы, чтобы узнать, не хватает ли я чего-то. :) – PKKid

+0

@PKKid - Я вижу, что решение depintz DISTINCT ON работает для вас, и было намного быстрее. Я действительно удивляюсь, хотя даже 3-секундное исполнение может быть сделано еще быстрее с некоторой креативной индексацией. Возможно, мне придется попробовать Postgres в моем следующем личном проекте. DISTINCT ON - приятная функция. – ssakl

Смежные вопросы