2

I am trying to get the closest date to a given date in Oracle. I have been working form How to get the closest dates in Oracle sql, but the example in that question uses two different tables. I'm no PL SQL guru and I'm struggling to get this to work. I have a single table that contains an ID field and a Date field. I need the ID that it closest to the date passed into the query.

select *
  from ( select SEQ_ID, ENTERED_DATE, rank() over ( partition by ENTERED_DATE order by difference asc ) as rnk
         from ( select SEQ_ID, ENTERED_DATE, abs(ENTERED_DATE - 2/9/1999) from DOWNTIME_DETAILS)) as difference             
 where rnk = 1

This gives me an error: "SQL command not properly ended"

How can I fix the query? What am I doing wrong?

Community
  • 1
  • 1
mack
  • 2,715
  • 8
  • 40
  • 68

1 Answers1

2

The as difference is assigning a table alias. You can't use as for table aliases, only for column aliases (so as rnk is OK). Just remove the second as. As you are refering to difference in the outer query, it looks like you meant it to be a column alias and just had it in the wrong place:

select *
from (
  select SEQ_ID, ENTERED_DATE,
    rank() over ( order by difference ) as rnk
  from (
    select SEQ_ID, ENTERED_DATE,
      abs(ENTERED_DATE - to_date('2/9/1999', 'MM/DD/YYYY')) as difference
    from DOWNTIME_DETAILS
  )
)
where rnk = 1

You also had a date without any quote marks, so that would have been interpreted as numbers in this case, and wouldn't have had the effect you were looking for. You should always use explicit conversion; I've guessed your date format. And you should not be partitioning by the original entered_date as that will make everything rank as 1. If you have two records that have the same difference they will still both rank as 1 so you'll see both. You could add a way to break ties by modifying the order by, e.g.

    rank() over ( order by difference , entered_date, seq_id ) as rnk

... but you'll need to specify the criteria so it makes sense for your data and situation.

You could also do this:

select max(SEQ_ID) keep (dense_rank first
    order by abs(ENTERED_DATE - to_date('2/9/1999', 'MM/DD/YYYY')))
    as seq_id,
  max(ENTERED_DATE) keep (dense_rank first
    order by abs(ENTERED_DATE - to_date('2/9/1999', 'MM/DD/YYYY')))
    as entered_date
from DOWNTIME_DETAILS;

... but then you have to supply the date twice.

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • Thanks @Alex Poole. When I run this query I get ORA-00904: "DIFFERENCE": invalid identifier. I tried to execute the query a piece at a time, and to get the inner select to run I had to do ` select SEQ_ID, ENTERED_DATE, abs(ENTERED_DATE - TO_DATE('09-APR-99')) from DOWNTIME_DETAILS`, but I still get the ORA-00904 when I run the whole query. Any suggestions? :) – mack Aug 01 '14 at 12:37
  • @mack - updated answer; you need it as a column alias, not a table alias. – Alex Poole Aug 01 '14 at 12:50
  • Thanks @Alex Poole, the query runs now, it just doesn't rank things the way I expected. Everything is ranked as 1. – mack Aug 01 '14 at 14:02
  • @mack - even after the `partition by` was taken out? – Alex Poole Aug 01 '14 at 14:03
  • Thank you! Both suggestions worked perfectly! Thank you very much for your help with this. Thanks also for explaining what I wasn't doing right. – mack Aug 01 '14 at 14:55