-2

I need help to write query do the following: subtract between two columns (start date and end date), and please note that the type for the columns are char not date, this is the exact format: 10-MAR-12 11.11.40.288389000 AM), then get the average for the result.

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
Rona
  • 21
  • 9
  • 3
    First off, the standard disclaimer. Storing dates and timestamps in `VARCHAR2` columns is a horrible, horrible idea. Eventually, someone is going to store a date in a different format and your queries are going to blow up. Second, what data type and units do you want the result to be? Do you want an `INTERVAL DAY TO SECOND`? Do you want the number of days between the dates? The number of seconds? The number of nanoseconds? – Justin Cave Mar 20 '12 at 19:34
  • ..I know its horrible but this is what i found in DB ( its related to my work I am not who design this DB)..thanks for both of you and I will back with my tries tomorrow. – Rona Mar 20 '12 at 21:00
  • possible duplicate of [Oracle date "Between" Query](http://stackoverflow.com/questions/2369222/oracle-date-between-query) – APC Mar 20 '12 at 23:01

2 Answers2

1

I assume this is homework, so some hints...

First don't ever store dates as varchar, it will cause you and the optimiser all sorts of problems.

Second, Oracle's date datatype can only store to second precision, and your string has fractions of a second, so you are looking at timestamp rather than date. You can convert your string to a timestamp with the to_timestamp() function, passing a suitable format mask. Oh OK, I'm feeling generous:

select to_timestamp(start_date, 'DD-Mon-RR HH.MI.SS.FF9 AM') from your_table;

Third, subtracting two timestamps will give you an interval data type, from which you will need to extract the information you want in a readable format. Search this site or elsewhere for timestamp subtraction, but I'll point you at this recent one as a sample.

The average is a bit trickier, so you may want to convert your intervals to numbers for that; again search for previous questions, such as this one. The size of the intervals, the precision you actually care about, and the way you want the output formatted, etc. will have some bearing on the approach you want to take.


If you need an approximate result then @Joachim Isaksson's answer will give you that - 'approximate' because of rounding; a duration of less than a second will show up as zero, for example. The same effect can be seen with timestamps cast to dates, which also loses the fractional seconds:

select 24*60*60*avg(
    cast(to_timestamp(step_ending_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as date)
        - cast(to_timestamp(step_starting_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as date)
    ) as avg_duration
from process_audit;

A more accurate answer can be found by extracting the various components of the timestamps, as in a question I linked to earlier. You may not need them all if you know that your durations are always less then an hour, say, but if you need more than one (i.e. if a duration could be more than a minute) then using an intermediate common table expression simplifies things a bit:

with cte as (
    select to_timestamp(step_ending_time, 'DD-Mon-RR HH.MI.SS.FF9 AM')
        - to_timestamp(step_starting_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as duration
    from process_audit
)
select avg(extract(second from duration)
    + extract(minute from duration) * 60
    + extract(hour from duration) * 60 * 60
    + extract(day from duration) * 60 * 60 * 24) as avg_duration
from cte;

With two sample rows, one with a gap of exactly a second and one with exactly 1.5 seconds, this gives the result 1.25.

Community
  • 1
  • 1
Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • No, its not a homework. Its related to my work, I want to prepare a performance report for the services in our system, so I need to calculate the avarage time for the interval between the start date and the end date for the step. I will back to show you my tries.thanks – Rona Mar 20 '12 at 20:55
0

Comments about storing times in VARCHAR aside; Oracle's to_date to the rescue; this should work for you to show the average number of seconds between the times. Since you're a bit low on details on precision, I didn't bother about the "sub seconds";

SELECT 24*3600*AVG(
  to_date(enddate,   'DD-Mon-YY HH.Mi.SS.????????? AM') -
  to_date(startdate, 'DD-Mon-YY HH.Mi.SS.????????? AM')) avg_seconds
FROM TableA;

Demo here.

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
  • Many thanks, its seems exactly what I need , Can't wait to test it tomorrow, I will back with a feedback. – Rona Mar 20 '12 at 21:06
  • Dear, I try your code, but there is error appear for the string format, could you please check whats wrong? ![error][1] [1]: http://i.stack.imgur.com/mnE4C.png – Rona Mar 21 '12 at 06:15
  • @Rona You have a 9 digit precision on the seconds (11.11.40.288389000) but in your query you're only putting 3 question marks. You need to put in all 9 question marks since to_date requires an exact match. – Joachim Isaksson Mar 21 '12 at 07:54
  • @Rona - you've also used `MM` instead of `Mon` for the month part. Also be aware of the effect of rounding - any durations of less than a second will show as zero, for example. If you have a wide range of durations this may be OK, but if they're all sub-second then you won't get a very useful result. – Alex Poole Mar 21 '12 at 09:53