2014-01-13 4 views
7

мне нужно найти разницу между временем в формате чч: мм: сснайти время, прошедшее между двумя датами в Oracle SQL

select msglog.id,max(msglog.timestamp) enddate, 
    min(msglog.timestamp) startdate, 
    enddate - startdate 
    from MESSAGELOG msglog 
    group by id 

В abovequery msglog.timestamp имеет тип DATE.

Как получить прошедшее время или разницу между временем в правильном формате в oracle?

ответ

12

Арифметика даты в Oracle дает число, выраженное в днях. Таким образом, чтобы преобразовать часы, вы бы умножить на 24, а затем trunc, чтобы получить целое число:

trunc(24 * (enddate - startdate)) 

Чтобы получить минуты, преобразовать значение дней до нескольких минут и mod(), что с 60:

mod(trunc(24 * 60 * (enddate - startdate)), 60) 

для секунд, снова конвертировать дней до нескольких секунд и mod(), что с 60:

mod(trunc(24 * 60 * 60 * (enddate - startdate)), 60) 

Теперь вы можете положить их вместе, чтобы получить строковое значение në редактор

+0

Спасибо за upvote @GriffeyDog и +1 себя! Ваш ответ также будет хорошо работать. Это сводится к множеству математических вычислений и множеству вызовов функций, и я ожидаю, что некоторые люди могут быть более удобными с большим количеством математики. –

17

При вычитании двух значений DATE, таких как enddate - startdate, вы получаете разницу в днях с десятичной точностью, поэтому, например, 1,5 означает 1 1/2 дня или 36 часов. Вы можете конвертировать, что HH:MI:SS используя много математики, но более простой способ заключается в преобразовании значения десятичного к INTERVAL DAY TO SECOND значения с помощью функции NUMTODSINTERVAL:

NUMTODSINTERVAL(enddate - startdate, 'DAY') 

Можно подумать, что функция TO_CHAR сможет форматировать это как HH:MI:SS, но похоже, что это не так. Вы можете использовать EXTRACT вместо этого, и TO_CHAR, чтобы убедиться, что вы получаете ведущие нули:

TO_CHAR(EXTRACT(HOUR FROM NUMTODSINTERVAL(enddate-startdate, 'DAY')), 'FM00') 
    || ':' || 
TO_CHAR(EXTRACT(MINUTE FROM NUMTODSINTERVAL(enddate-startdate, 'DAY')), 'FM00') 
    || ':' || 
TO_CHAR(EXTRACT(SECOND FROM NUMTODSINTERVAL(enddate-startdate, 'DAY')), 'FM00') 

00 часть кода формата определяет две цифры с ведущим нулем, если это необходимо. Часть FM избавляет от ведущего места в форматированном результате, который зарезервирован для отрицательного знака, если это необходимо.

Также обратите внимание, что ваш запрос получает агрегированные значения и использует их в том же списке SELECT. Oracle не позволит вам это сделать. Попробуйте что-нибудь подобное вместо этого:

WITH StartEndByID AS (
    SELECT 
    msglog.id, 
    NUMTODSINTERVAL(max(msglog.timestamp) - min(msglog.timestamp), 'DAY') elapsed 
    FROM messagelog msglog 
    GROUP BY id 
) 
SELECT 
    id, 
    TO_CHAR(EXTRACT(HOUR FROM elapsed), 'FM00') || ':' || 
    TO_CHAR(EXTRACT(MINUTE FROM elapsed), 'FM00') || ':' || 
    TO_CHAR(EXTRACT(SECOND FROM elapsed), 'FM00') AS ElapsedHHMISS 
FROM StartEndByID 
+0

Мне нравится это лучше, чем мой ответ, +1. – GriffeyDog

+0

Привет, Эд, просто интересно узнать, работает ли NUMTODSINTERVAL для временных интервалов времени? – San

+0

@San - результат [timestamp арифметики] (http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements001.htm#SQLRF50990) в любом случае является «интервалом», поэтому вы не необходимо преобразовать его в один. –

1

Чтобы получить диф в секундах, вы можете использовать этот

select round(24 * 60 * 60* (TO_DATE('2017/02/17 9:32:25', 'YYYY/MM/DD HH:MI:SS') - TO_DATE('2017/02/17 8:30:30', 'YYYY/MM/DD HH:MI:SS'))) from dual; 
Смежные вопросы