选择每人的最新记录

时间:2011-03-22 07:10:29

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

我只是想知道,如果以下两个sql语句有任何性能差异或它们基本相同:

spouse表(person_id,spouse_id,marriage_date)中选择一个人的最新配偶记录。

select *
from spouse 
where (person_id, marriage_date) in ( select person_id, max(marriage_date) 
                                      from spouse  
                                      group by person_id
                                     )

select *
from spouse s1
where marriage_date = ( select max(marriage_date) 
                        from spouse s2  
                        where s1.person_id = s2.person_id  
                      )

这是报告的常见要求,例如,员工的最新工作,最高教育等等。我想知道您是否更喜欢上述陈述,以及为什么,或者,如果还有其他更好的话方式(在性能/可读性方面)来获得这些最新/最高要求。

3 个答案:

答案 0 :(得分:3)

正如之前的回答中已经提到的那样,您可以使用SQL server windowing functions来很好地实现这一目标。

SELECT s1.person_id, s1.marriage_date
FROM spouse s1
JOIN ( 
    SELECT 
        person_id, 
        ROW_NUMBER() OVER (PARTITION BY person_id ORDER BY marriage_date DESC) AS Priority
        FROM spouse
    ) s2
ON s2.person_id = s1.person_id AND s2.Priority = 1

在联接查询中,我们按person_id对数据进行分区,然后应用排名函数(ROW_NUMBER()),按marriage_date的降序为每行分配一个数字。排名是针对每个person_id独立完成的,因此加入条件s2.Priority = 1表示我们只获得每个人的最大marriage_date记录。

您可能会发现以下内容:

答案 1 :(得分:1)

您可以使用分析函数来执行此操作:

SELECT *
  FROM (SELECT ROW_NUMBER() OVER (PARTITION BY person_id
                                   ORDER BY marriage_date DESC) AS r,
               t.*
          FROM spouse t) x
 WHERE x.r = 1

您可以通过查看执行计划来比较所有查询的效率。

答案 2 :(得分:0)

您的示例在语法上是相同的。根据经验,当子查询是最严格的(即从结果集中删除大量记录)时使用IN,并在外部查询最具限制时使用相关子查询(即子查询的记录多于总数结果集)。

根据表统计信息和估计成本,Oracle查询优化器可能会将IN子句重写为相关子查询,反之亦然。查看适合您情况的解释计划,并以最低的成本选择计划。