使用分析函数选择具有 2 个日期列的记录的高性能查询

Posted

技术标签:

【中文标题】使用分析函数选择具有 2 个日期列的记录的高性能查询【英文标题】:performant query using analytic function to select records with 2 date columns 【发布时间】:2012-05-10 21:12:50 【问题描述】:

我正在寻找一种编写 SQL 查询的高性能方法。

我有一个包含列的表 (id,fname,lname,accountid,creation_date,update_date),我必须在该表中查找具有相同的fname,lname,accountid 并且具有基于greatest(max(creation_date),max(update_date)) 的最新日期(注意update_date 可以为空)

我希望我需要使用分析函数

我有这些情况:

(id,fname,lname,accountid,creation_date,update_date)
(1,'a','a','2','07/01/2010 10:59:43','07/01/2010 10:59:43')
(2,'a','a','2','07/01/2010 10:59:43','07/01/2010 10:59:43')
(3,'a','a','2','07/01/2010 10:59:43','07/01/2010 10:59:43')

我想选择最后插入的:这条记录 (3,'a','a','2','07/01/2010 10:59:43','07/01/2010 10:59 :43')

(id,fname,lname,accountid,creation_date,update_date)
(3,'b','a','2','07/01/2009 10:59:43','07/01/2010 10:59:43')
(4,'b','a','2','07/01/2011 10:59:43',null)
(5,'b','a','2','07/01/2009 10:59:43','07/01/2009 10:59:43')

我想在两列 (creation_date,update_date) 上选择最近的一个,即 (4,'b','a','2','07/01/201110:59:43',null)

(id,fname,lname,accountid,creation_date,update_date)
(6,'c','g','4','07/01/2010 10:59:43',null)
(7,'c','g','4','07/01/2011 10:59:43',null)
(8,'c','g','4','07/01/2009 10:59:43',null)

我想在两列 (creation_date,update_date) 上选择最近的一个,即 (7,'c','g','4','07/01/2011 10:59:43',null )

(id,fname,lname,accountid,creation_date,update_date)
(9,'k','t','2','07/01/2009 10:59:43','07/01/2012 10:59:43')
(10,'k','t','2','07/01/2011 10:59:43',null)
(11,'k','t','2','07/01/2009 10:59:43','07/01/2009 10:59:43')

我想在两列 (creation_date,update_date) 上选择最近的一个,即 (9,'k','t','2','07/01/2009 10:59:43','07/01/2012 10:59:43')

【问题讨论】:

我不确定我是否理解您的问题。发布一些示例数据、所需的输出以及如何从示例数据获得所需输出的说明会很有帮助。如果您可以以DDL 的形式发布它来创建表格,DML 以插入示例数据,这样我们就可以在我们的环境中运行您的代码。 在第一组行中,当所有 6 个日期值看起来都相同时,为什么要选择 id 为 3 的行? 【参考方案1】:

您应该使用分析函数rank()row_number()。我自己的特别偏好是rank(),但它只有在按唯一索引分区时才真正有效。如下所示,假设fname, lname, accountid, creation_date 上有一个唯一索引

select *
  from ( select a.*
              , rank() over ( partition by fname, lname, accountid 
                      order by creation_date desc
                              , update_date desc ) as rnk
           from my_table a )
 where rnk = 1

这会将fname, lname, accountid 的每个组合按creation_dateupdate_date 排序。使用where rnk = 1,您可以选择最大的creation_date, update_date

【讨论】:

我一直在为某事苦苦挣扎,您的排名建议非常有效!【参考方案2】:

听起来你想要类似的东西

SELECT *
  FROM (SELECT a.*,
               rank() over (partition by fname, lname, accountid
                                order by coalesce( update_date, creation_date ) desc,
                                         id desc) rnk
          FROM your_table)
 WHERE rnk = 1
我猜想为什么您希望返回 id 为 3 的行,而不是返回 id 为 1 或 2 的行,因为所有 3 行都具有相同的 update_date 和 @987654325 @。我的猜测是,您想通过选择具有最大 id 值的行来选择平局。如果您想实施不同的规则,您需要告诉我们这是什么规则。 我还假设update_date(如果存在)将始终大于或等于creation_date。如果行在创建之前被更新,那就太奇怪了。

【讨论】:

以上是关于使用分析函数选择具有 2 个日期列的记录的高性能查询的主要内容,如果未能解决你的问题,请参考以下文章

年份列与日期范围列的查询性能如何

选择日期和时间列的最后一条记录

如何使用 Sequelize.JS 选择具有 2 个唯一列的所有行?

多个表与一个具有更多列的表

单个查询从具有不同列的多个表中获取记录

如何在具有子句的聚合函数旁边选择相应的记录