Похоже, ваша таблица уже хранит время начала / окончания звонка как даты, и вы выполняете неявное преобразование из даты в строку, а затем конвертируете обратно в дату. Вы можете увидеть этот результат, если у вас есть HH вместо HH24 в настройке NLS_DATE_FORMAT:
alter session set nls_date_format = 'YYYY-MM-DD HH:MI:SS';
with calls (call_end, call_start) as (
select cast(timestamp '2020-02-20 13:00:20' as date), cast(timestamp '2020-02-20 12:56:03' as date) from dual
)
SELECT MAX(REGEXP_SUBSTR (CAST(TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP) - CAST(TO_DATE(call_start, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP), '\d{2}:\d{2}:\d{2}')) AS call_time
FROM calls;
CALL_TIME
---------------------------
11:55:43
Когда вы делаете
TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS')
, потому что это уже дата, которую вы действительно делаете:
TO_DATE(TO_CHAR(call_end, <NLS_DATE_FORMAT>), 'YYYY/MM/DD HH24:MI:SS')
поэтому с моими настройками (и ваши должны быть похожими, возможно, с косыми чертами вместо черточек), то есть:
TO_DATE(TO_CHAR(call_end, 'YYYY-MM-DD HH:MI:SS'), 'YYYY/MM/DD HH24:MI:SS')
, и несоответствие между ЧЧ и ЧЧ24 становится более очевидным. Итак, вы на самом деле конвертируете строки 2020-02-20 01:00:20 и 2020-02-20 12:56:03 обратно в даты, а разницу во времени между 01:00:20 и 12:56:03 11:55:43. Ну, на самом деле, это минус 11 часов:
SELECT CAST(TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP) - CAST(TO_DATE(call_start, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP)
FROM calls;
CAST(TO_DATE(CALL_E
-------------------
-00 11:55:43.000000
, но ваше регулярное выражение не подхватывает это.
Поскольку они являются датами, пропустите эту часть преобразование полностью и просто приведение непосредственно к временным меткам, если вы хотите, чтобы интервалы работали с:
SELECT MAX(REGEXP_SUBSTR (CAST(call_end AS TIMESTAMP) - CAST(call_start AS TIMESTAMP), '\d{2}:\d{2}:\d{2}')) AS call_time
FROM calls;
CALL_TIME
---------------------------
00:04:17
или используйте подстроку вместо регулярного выражения, как показало @MTO.
Вы также можете оставить их как даты, получить разницу в виде доли дня, добавить ее обратно к любой номинальной дате в полночь, а затем преобразовать полученную дату в строку:
SELECT TO_CHAR(date '2000-01-01' + MAX(call_end - call_start), 'HH24:MI:SS') AS call_time
FROM calls;
CALL_TIM
--------
00:04:17
Это не будет работать должным образом для звонок, который длится более 24 часов (раньше видел это много с модемными звонками, но все же может происходить); но и ваш интервал не приблизится. Оба игнорируют любые полные дни и просто показывают остаток. Конечно, есть способы справиться с этим, но вам нужно решить, как вы хотите его отображать - с отдельным счетчиком дней (как в любом случае интервал) или с числом часов, разрешенным go выше 24 .. ... но тогда вы можете go превысить 99 часов ...
Ваш вопрос показывает время окончания вызова как 2020-02-20 13:00:20, что говорит о том, что ваш клиент отображает это когда вы запрашиваете таблицу. Некоторые клиенты (я думаю, PL / SQL Developer, но не уверен, что это было давно) используют свои собственные настройки / настройки вместо соблюдения настроек NLS сеанса. Но это никак не влияет на внутреннее поведение Oracle, когда приходится выполнять неявные преобразования.