2015-05-07 2 views
3

У меня есть три таблицы:запрос, чтобы найти второй по величине значение из каждой группы

  1. project: project_id, project_name
  2. milestone: milestone_id, milestone_name
  3. project_milestone: id, project_id, milestone_id, completed_date

Я хочу, чтобы получить вторую высшую completed_date и milestone_id от project_milestone сгруппированы по project_id. То есть я хочу получить milestone_id второй самой высокой завершенной_даты для каждого проекта. Каким будет правильный запрос?

ответ

6

Я думаю, что вы можете делать то, что вы хотите с project_milestone стол и row_number():

select pm.* 
from (select pm.*, 
      row_number() over (partition by project_id order by completed_date desc) as seqnum 
     from project_milestone pm 
     where pm.completed_date is not null 
    ) pm 
where seqnum = 2; 

Если вам необходимо включить все проекты, даже те, без двух этапов, вы можете использовать left join:

select p.project_id, pm.milestone_id, pm.completed_date 
from projects p left join 
    (select pm.*, 
      row_number() over (partition by project_id order by completed_date desc) as seqnum 
     from project_milestone pm 
     where pm.completed_date is not null 
    ) pm 
    on p.project_id = pm.project_id and pm.seqnum = 2; 
+0

Thanks.It работает, но когда в завершенном_дате есть значение null, оно приближается к значениям даты и порядок изменяется. Можно ли избежать нулевых значений – user1690835

+0

ok. Я решил это, добавив условие «где pm.completed_date не является нулевым» в подзапросе – user1690835

0

Использование LATERAL (PG 9.3+) может обеспечить лучшую производительность, чем версия оконной функции.

SELECT * FROM project; 
project_id | project_name 
------------+-------------- 
      1 | Project A 
      2 | Project B 

SELECT * FROM project_milestone; 
id | project_id | milestone_id |  completed_date  
----+------------+--------------+------------------------ 
    1 |   1 |   1 | 2000-01-01 00:00:00+01 
    2 |   1 |   2 | 2000-01-02 00:00:00+01 
    3 |   1 |   5 | 2000-01-03 00:00:00+01 
    4 |   1 |   6 | 2000-01-04 00:00:00+01 
    5 |   2 |   3 | 2000-02-01 00:00:00+01 
    6 |   2 |   4 | 2000-02-02 00:00:00+01 
    7 |   2 |   7 | 2000-02-03 00:00:00+01 
    8 |   2 |   8 | 2000-02-04 00:00:00+01 


SELECT * 
FROM project p 
CROSS JOIN LATERAL (
    SELECT milestone_id, completed_date 
    FROM project_milestone pm 
    WHERE pm.project_id = p.project_id 
    ORDER BY completed_date ASC 
    LIMIT 1 
    OFFSET 1 
) second_highest; 
project_id | project_name | milestone_id |  completed_date  
------------+--------------+--------------+------------------------ 
      1 | Project A |   2 | 2000-01-02 00:00:00+01 
      2 | Project B |   4 | 2000-02-02 00:00:00+01 
Смежные вопросы