Oracle Select Max Date on Multiple records

2019-08-30 13:18发布

I've got the following SELECT statement, and based on what I've seen here: SQL Select Max Date with Multiple records I've got my example set up the same way. I'm on Oracle 11g. Instead of returning one record for each asset_tag, it's returning multiples. Not as many records as in the source table, but more than (I think) it should be. If I run the inner SELECT statement, it also returns the correct set of records (1 per asset_tag), which really has me stumped.

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

Any suggestions?

2条回答
甜甜的少女心
2楼-- · 2019-08-30 13:53

Try with analytical functions:

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
查看更多
姐就是有狂的资本
3楼-- · 2019-08-30 13:56

I think you need to add...

AND outside.asset_tag=inside.asset_tag

...to the criteria in your ON list.

Also a RIGHT OUTER JOIN is not needed. An INNER JOIN will give the same results (and may be more efficicient), since there will be cannot be be combinations of asset_tag and last_read_date in the subquery that do not exist in mp_vehicle_asset_profile.

Even then, the query may return more than one row per asset tag if there are "ties" -- that is, multiple rows with the same last_read_date. In contrast, @Lamak's analytic-based answer will arbitrarily pick exactly one row this situation.

Your comment suggests that you want to break ties by picking the row with highest mtr_reading for the last_read_date.

You could modify @Lamak's analyic-based answer to do this by changing the ORDER BY in the OVER clause to:

ORDER BY last_read_date DESC, mtr_reading DESC

If there are still ties (that is, multiple rows with the same asset_tag, last_read_date, and mtr_reading), the query will again abritrarily pick exactly one row.

You could modify my aggregate-based answer to break ties using highest mtr_reading as follows:

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

If there are still ties (that is, multiple rows with the same asset_tag, last_read_date, and mtr_reading), the query may again return more than one row.

One other way that the analytic- and aggregate-based answers differ is in their treatment of nulls. If any of asset_tag, last_read_date, or mtr_reading are null, the analytic-based answer will return related rows, but the aggregate-based one will not (because the equality conditions in the join do not evaluate to TRUE when a null is involved.

查看更多
登录 后发表回答