Postgresql:从两个连接表中选择MAX值

时间:2014-11-19 13:09:58

标签: sql postgresql greatest-n-per-group

我有两张桌子:

tbl_status:
  id
  status_code
  month_digest_id
  project_id

tbl_project
  id
  name

tbl_month_digest:
  id
  month_ts

我有一个项目。每个项目的状态为零个或多个月(存储在tbl_month_digest中)。给定一个项目ID列表,我需要获取最新的状态对象。

我在做这件事时遇到了麻烦。在MySQL中,我可以从tbl_month_digesttbl_status的联接中选择并添加having tbl_month_digest.month_ts = max(tbl_month_digest.month_ts)。 Postgres坚持认为我将tbl_month_digest.month_ts添加到一个组中,但没有达到预期的效果。

是否可以在postgresql中的单个SQL查询中获取项目列表的最新状态?

示例数据和预期结果:

tbl_month_digest:
id   month_ts
1    2014-05-01
2    2014-06-01
3    2014-07-01

tbl_project:
id    name
90    'Foundation'
91    'Testing'
92    'Examination'

tbl_status:
id  project_id  month_digest_id  status_code
1   90          1                'on_track'
2   90          2                'on_track'
3   90          3                'late'
4   91          1                'late'
5   91          2                'unknown'
6   91          3                'unknown'
7   92          1                'late'
8   92          2                'late'
9   92          3                'on_track'

鉴于项目ID 90和91,我想得到

project_id  latest_status
90          'late'
92          'on_track'

1 个答案:

答案 0 :(得分:1)

我不确定为什么91的最新状态为on_track。但是,你可以使用窗口函数做你想做的事。

我的猜测是你甚至不需要month_digest表,因为id通常是按时间顺序排列的。

select s.project_id, s.status as latest_status
from (select s.*,
             row_number() over (partition by project_id order by month_digest_id desc) as seqnum
      from tbl_status s
      where project_id in (90, 91)
     ) 
where seqnnum = 1;

您可以使用join基本相同的事情:

select s.project_id, s.status as latest_status
from (select s.*,
             row_number() over (partition by project_id order by md.month_ts desc) as seqnum
      from tbl_status s join
           tbl_month_digest md
           on s.month_digest_id = md.id
      where project_id in (90, 91)
     ) 
where seqnnum = 1;

编辑:

实际上,在Postgres中,您可以使用distinct on

      select distinct on(s.project_id) s.project_id, s.status as latest_status
      from tbl_status s join
           tbl_month_digest md
           on s.month_digest_id = md.id
      where s.project_id in (90, 91) and s.status <> 'unknown'
      order by s.project_id, md.month_ts desc;

我不确定你想用未知状态做什么。这只是过滤掉它们。