根据一个不同的列值返回行信息

时间:2014-11-06 18:33:18

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

我想返回一个表,该表包含一个仅包含不同projectid的列,第二列显示给定日期范围内的max(date),第三列显示其他信息。我还是sql的新手。

查询:

select distinct (a.projectid), versiondate, newvalue 
from a 
   inner join b on a.projectid = b.projectid 
where b.contractor = 'SQA Contractor Company-1' 
  and a.attributename = 'Status' 
  and versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59' 
group by a.projectid, versiondate, newvalue 
order by versiondate

它返回的是什么:

projectid  |         versiondate    |  newvalue
-----------+------------------------+--------------------
p27641     |  2014 10 01 12:23:18   | In work         
p27641     |  2014 10 01 12:23:21   | In billing      
p27641     |  2014 10 01 12:23:45   | completed          
p19397     |  2014 10 01 12:25:03   | pending review       
p19397     |  2014 10 01 12:25:42   | pending assignment    
p10397     |  2014-10-01 12:26:18   | pending-acceptance

我希望它返回:

仅代表最新versiondate的独特项目。我需要查看每个不同newvalue的最近日期projectid的内容。

试图把它写成文字是有点艰难,所以希望我很好地解释了我的问题。任何帮助/批评都被接受。

2 个答案:

答案 0 :(得分:0)

这类问题需要分多步处理。

首先,找到每个项目的最合适的版本日期,然后找到相应的新值。

select a.projectid, a.max_versiondate, b.newvalue
from
    (select a.projectid, max(b.versiondate) max_versiondate
    from   a
    inner join b 
            on a.projectid = b.projectid
    where b.contractor = 'SQA Contractor Company-1'
      and a.attributename = 'Status'
      and b.versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59'
    group by
            a.project id) a 
inner join b
        on b.projectid = a.projectid
       and b.versiondate = a.max_versiondate

另一种选择是使用窗口聚合方法来查找内联的最大值,并根据该方法进行过滤。

select *
from
(
select a.projectid, versiondate, newvalue, ROW_NUMBER() OVER(PARTITION BY projectid ORDER BY versiondate DESC) rn
from a 
   inner join b on a.projectid = b.projectid 
where b.contractor = 'SQA Contractor Company-1' 
  and a.attributename = 'Status' 
  and versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59' 
group by a.projectid, versiondate, newvalue 
order by versiondate
)
where rn = 1

两者都应该给你相同的结果,这是你的索引和表格大小的问题,看看哪个是最有效的。

答案 1 :(得分:0)

使用Postgres特定的DISTINCT ON可以更简单。

SELECT DISTINCT ON (a.projectid)
       a.projectid, b.versiondate, b.newvalue 
FROM   a 
JOIN   b USING (projectid)
WHERE  a.attributename = 'Status' 
AND    b.contractor = 'SQA Contractor Company-1' 
AND    b.versiondate >= '2014-10-01 0:0'
AND    b.versiondate <  '2014-10-02 0:0' 
ORDER  BY a.projectid, b.versiondate DESC;

SQL标准DISTINCT在整行上折叠重复。作为此Postgres的扩展,已实施DISTINCT ON以折叠所选列上的重复项。对于SELECT列表中的其他列,将选择(一致)第一行中的值(由ORDER BY定义),如果定义不明确,则为任意值。

你对这两种结构都有误导性的错误。您的查询中的括号与DISTINCT ON结合使用会有意义,但几乎不会死DISTINCT。详细解释:

其他要点

  • 在这种情况下,您不需要GROUP BY
  • 时间戳的范围通常最好用包含下限和排除上限来表示。 BETWEEN .. AND包含两个边界并且对此不利:
  • 由于您选择了有意义的列名,因此您可以方便地加入USING construct