使用分析函数选择具有 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_date
、update_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 个日期列的记录的高性能查询的主要内容,如果未能解决你的问题,请参考以下文章