Oracle 选择多条记录的最大日期

Posted

技术标签:

【中文标题】Oracle 选择多条记录的最大日期【英文标题】:Oracle Select Max Date on Multiple records 【发布时间】:2012-05-25 21:37:09 【问题描述】:

我有以下 SELECT 语句,基于我在这里看到的:SQL Select Max Date with Multiple records 我的示例设置方式相同。我在 Oracle 11g 上。它不是为每个asset_tag 返回一条记录,而是返回多个记录。没有源表中的记录那么多,但(我认为)应该多。如果我运行内部 SELECT 语句,它还会返回正确的记录集(每个asset_tag 1 个),这真的让我很难过。

SELECT 
outside.asset_tag,
outside.description, 
outside.asset_type, 
outside.asset_group, 
outside.status_code, 
outside.license_no, 
outside.rentable_yn, 
outside.manufacture_code, 
outside.model, 
outside.manufacture_vin, 
outside.vehicle_yr, 
outside.meter_id, 
outside.mtr_uom, 
outside.mtr_reading, 
outside.last_read_date
FROM mp_vehicle_asset_profile outside
RIGHT OUTER JOIN
  (
  SELECT asset_tag, max(last_read_date) as last_read_date
  FROM mp_vehicle_asset_profile
  group by asset_tag
  ) inside
ON outside.last_read_date=inside.last_read_date

有什么建议吗?

【问题讨论】:

【参考方案1】:

我认为您需要添加...

AND outside.asset_tag=inside.asset_tag

...符合ON 列表中的条件。

也不需要RIGHT OUTER JOININNER JOIN 将给出相同的结果(并且可能更有效),因为在mp_vehicle_asset_profile 中不存在的子查询中不可能有asset_taglast_read_date 的组合。

即便如此,如果存在“关系”,查询可能会为每个资产标签返回多于一行——即具有相同last_read_date 的多行。相比之下,@Lamak 的基于分析的答案会在这种情况下任意选择一行。

您的评论表明您希望通过为last_read_date 选择具有最高mtr_reading 的行来打破平局。

您可以通过将OVER 子句中的ORDER BY 更改为:

ORDER BY last_read_date DESC, mtr_reading DESC

如果仍然存在平局(即多行具有相同的asset_taglast_read_datemtr_reading),则查询将再次随意选择一行。

您可以修改我的基于聚合的答案以使用最高 mtr_reading 打破平局,如下所示:

SELECT  
    outside.asset_tag, 
    outside.description,
    outside.asset_type,
    outside.asset_group,
    outside.status_code,
    outside.license_no,
    outside.rentable_yn,
    outside.manufacture_code,
    outside.model,
    outside.manufacture_vin,
    outside.vehicle_yr,
    outside.meter_id,
    outside.mtr_uom,
    outside.mtr_reading,
    outside.last_read_date 
FROM 
    mp_vehicle_asset_profile outside 
    INNER JOIN 
    ( 
        SELECT
            asset_tag, 
            MAX(last_read_date) AS last_read_date,
            MAX(mtr_reading) KEEP (DENSE_RANK FIRST ORDER BY last_read_date DESC) AS mtr_reading
        FROM
            mp_vehicle_asset_profile 
        GROUP BY
            asset_tag 
    ) inside 
    ON 
        outside.asset_tag = inside.asset_tag
        AND
        outside.last_read_date = inside.last_read_date
        AND
        outside.mtr_reading = inside.mtr_reading

如果仍然存在关联(即多行具有相同的asset_taglast_read_datemtr_reading),则查询可能会再次返回多行。

基于分析和聚合的答案的另一个不同之处在于它们对空值的处理。如果 asset_taglast_read_datemtr_reading 中的任何一个为 null,则基于分析的答案将返回相关行,但基于聚合的答案不会(因为连接中的相等条件不会评估为 @987654345 @ 当涉及到 null 时。

【讨论】:

这是我需要的。在一次修复中解决了它。我没有考虑其他汽车的最后阅读日期相同的多条记录,所以我没有想到要添加它。我认为 last_read_date 是一个 DATETIME 字段,但我错了。谢谢! 只是为了(希望)清楚...即使您将条件添加到ON 列表并按照我的建议使用和INNER JOIN,查询仍可能返回不止一行如果last_read_date 上有“关系”,则为资产标签。如果这不是你想要的,如何打破关系? @Lamak 基于分析的答案将任意选择一个,或者可以修改(通过将表达式添加到 ORDER BY 列表)以其他方式打破联系。还有一些方法可以修改我的基于聚合的答案来做同样的事情。有兴趣可以回帖。 在这个数据集中,我并不太担心平局的情况,但让我们来探索一下。如果在日期出现平局,我想选择该日期存在的任何mtr_reading 中的最高值。推理是,正在驾驶的汽车可能在早上驾驶,然后在报告运行前的晚上再次驾驶。我们会在外部查询中添加一个order by ... mtr_reading,从而对那些进行排序吗?还是我们需要调整内部查询?【参考方案2】:

尝试分析函数:

SELECT  outside.asset_tag,
        outside.description, 
        outside.asset_type, 
        outside.asset_group, 
        outside.status_code, 
        outside.license_no, 
        outside.rentable_yn, 
        outside.manufacture_code, 
        outside.model, 
        outside.manufacture_vin, 
        outside.vehicle_yr, 
        outside.meter_id, 
        outside.mtr_uom, 
        outside.mtr_reading, 
        outside.last_read_date
FROM (  SELECT *, ROW_NUMBER() OVER(PARTITION BY asset_tag ORDER BY last_read_date DESC) Corr
        FROM mp_vehicle_asset_profile) outside
WHERE Corr = 1

【讨论】:

出于好奇,“Corr”代表什么? Corr 是行中项目的别名,所以行号返回一个数字,Lamak 给它起了一个别名,并用它来检索第 1 行。

以上是关于Oracle 选择多条记录的最大日期的主要内容,如果未能解决你的问题,请参考以下文章

从多条记录中获取最大日期

在Oracle中选择具有最近日期和时间的记录[重复]

如何在 Rails 中选择通过连接到另一个具有多条记录的表的最新记录

为啥不能为具有 date=max(date) 的最大日期的每个代码选择记录?

从 Oracle 中选择最新的两条不同记录

oracle 如何返回多条记录