簡體   English   中英

以 HH:MM:SS 表示的 Oracle SQL 時差

[英]Oracle SQL time difference in HH:MM:SS

我正在嘗試獲取 Oracle 數據庫中的時差。 除了一行之外,所有行的時間差都可以。 這是查詢

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_end: '2020-02-20 13:00:20'
call_start: '2020-02-20 12:56:03'

返回的結果是'11:55:43',這是錯誤的。 因為正確答案應該是'00:04:17'

看起來您的表已經將呼叫開始/結束時間存儲為日期,並且您正在進行從日期到字符串的隱式轉換,然后再轉換回日期。 如果在 NLS_DATE_FORMAT 設置中使用 HH 而不是 HH24,則可以看到該結果:

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')

並且HH和HH24之間的不匹配變得更加明顯。 因此,您實際上是將字符串 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 小時的呼叫,這將無法正常工作(過去常常看到調制解調器呼叫,但仍然可能發生); 但你的間隔也不會接近。 兩者都忽略任何一整天,只顯示剩余的天數。 當然有辦法處理這個問題,但是您需要決定如何顯示它 - 使用單獨的天數(就像間隔一樣),或者允許“小時”數超過 24 ......但是那么你可能會超過 99 小時...


您的問題顯示呼叫結束時間為 2020-02-20 13:00:20,這表明您的客戶在查詢表格時顯示它的方式。 一些客戶端(我認為是 PL/SQL Developer,但不確定,已經有一段時間了)使用他們自己的首選項/設置而不是遵守會話的 NLS 設置。 但這對 Oracle 在必須進行隱式轉換時的內部行為沒有影響。

我不確定您是否希望將結果作為間隔或時間戳,但這應該可以滿足您的需求:

select t.*, call_end - call_start,
       substr(to_char(call_end - call_start, 'HH24:MI:SS'), 12, 8) as str    from (select timestamp '2020-02-20 13:00:20.000' as call_end,
             timestamp '2020-02-20 12:56:03.000' as call_start
      from dual) t

是一個 db<>fiddle。

假設您的數據類型是字符串(您確實應該將它們存儲為DATE數據類型),您可以使用:

SELECT SUBSTR(
         MAX(
           ( TO_DATE( call_end,   'YYYY-MM-DD HH24:MI:SS' )
           - TO_DATE( call_start, 'YYYY-MM-DD HH24:MI:SS' )
           ) DAY(1) TO SECOND
         ),
         4,
         8
       ) AS call_time
FROM   calls

如果它們已經是DATE數據類型,那么在MAX聚合中,只需使用:

( call_end - call_start ) DAY(1) TO SECOND

所以對於你的數據:

CREATE TABLE calls ( call_end, call_start ) AS
SELECT '2020-02-20 13:00:20', '2020-02-20 12:56:03' FROM DUAL

這輸出:

\n |  CALL_TIME |\n |  :-------- |\n |  00:04:17 |\n

db<> 在這里擺弄

Gyl 先生,您也可以這樣做: db <> fiddle :此解決方案還將通過將這些小時加在一起來考慮呼叫何時失效:

WITH da AS (
SELECT
    NUMTODSINTERVAL(TO_DATE('2020-02-20 13:00:20', 'yyyy-mm-dd hh24:mi:ss') - TO_DATE('2020-02-20 12:56:03', 'yyyy-mm-dd hh24:mi:ss'), 'DAY') AS call_diff
FROM
    dual ) SELECT
    EXTRACT( DAY FROM call_diff )*24 + EXTRACT( HOUR FROM call_diff )|| ':' || EXTRACT( MINUTE FROM call_diff ) || ':' || EXTRACT( SECOND FROM call_diff ) DIFFERENCE
FROM
    da
 DIFFERENCE| ----------| 0:4:17 |

所以你可以實現為

WITH da AS (    
SELECT
    NUMTODSINTERVAL(TO_DATE(call_end, 'yyyy-mm-dd hh24:mi:ss') - TO_DATE(call_start, 'yyyy-mm-dd hh24:mi:ss'), 'DAY') AS call_diff
FROM
    calls
    ) SELECT
    EXTRACT( DAY FROM call_diff )*24 + EXTRACT( HOUR FROM call_diff )|| ':' || EXTRACT( MINUTE FROM call_diff ) || ':' || EXTRACT( SECOND FROM call_diff ) TIMESTAMP
FROM
    da

請參閱下面的回復,但這只會在 24 小時內起作用並返回“00”

WITH sample_lt AS(
                            SELECT '2020-02-20 12:56:03' START_TIME, '2020-02-20 13:00:20' END_TIME FROM dual
                                 )
                    SELECT start_time,
                            end_time,
                                TO_CHAR (TRUNC (SYSDATE) + (to_date(end_time, 'yyyy-mm-dd HH24:MI:SS') -
                                  to_date(start_time, 'yyyy-mm-dd HH24:MI:SS')
                                 ) , 'hh24:mi:ss' ) duration
                    FROM sample_lt ;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM