Oracle 日期函数面临的问题
我试图从dba\u调度程序\u作业\u运行\u详细信息视图中获取该值。 其中log_date>(SYSDATE-5/(24*60))(即过去5分钟的数据) 但它并没有为我提供正确的值 有关示例,请查看以下数据: SQL查询:Oracle 日期函数面临的问题,oracle,date,Oracle,Date,我试图从dba\u调度程序\u作业\u运行\u详细信息视图中获取该值。 其中log_date>(SYSDATE-5/(24*60))(即过去5分钟的数据) 但它并没有为我提供正确的值 有关示例,请查看以下数据: SQL查询: SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS') FROM dba_scheduler_job_run_details
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE LOG_DATE > (SYSDATE - 5/(24*60))
ORDER BY LOG_DATE DESC;
o/p:
附加图像这是因为
log_date
是带有时区的时间戳
数据类型,当您将其与日期数据类型连接时,Oracle进行隐式转换以进行比较时,将导致两个不同的时间:
SQL> SELECT SYSTIMESTAMP, CAST(SYSDATE AS TIMESTAMP WITH TIME ZONE) time_with_tz FROM dual;
SYSTIMESTAMP TIME_WITH_TZ
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
19-MAR-18 09.57.07.654161 AM -04:00 19-MAR-18 09.57.07.000000 AM +05:30
因此,如果我在偏移量为-4:00的服务器上从偏移量为+5:30的时区执行查询,Oracle将把SYSDATE-5/(24*60)
转换为SYSDATE-(9:30+0:05)
告诉Oracle显式地将日志日期转换为日期,然后应用>(SYSDATE-5/(24*60)
的文件管理器,如下所示,您就可以了:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE cast(LOG_DATE AS DATE) > (SYSDATE - 5/(24*60))
ORDER BY LOG_DATE DESC;
更新:由于以下原因,此查询可能存在性能问题
1) Oracle将转换LOG\u DATE from列的每一行的数据类型
带有截止日期时区的时间戳
2) 列LOG_DATE上的内置索引(如果有)将由于以下原因而不使用
到CAST函数
更好的解决方案是将sysdate-5/(24*60)转换为带时区的时间戳,您必须知道Oracle服务器的时区,假设服务器位于UTC-4:00,下面的查询应该可以正常工作:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE LOG_DATE > TO_TIMESTAMP_TZ (to_char(SYSDATE - 5/(24*60), 'YYYY-MM-DD HH24:MI:SS') || ' -4:00', 'YYYY-MM-DD HH24:MI:SS TZH:TZM')
ORDER BY LOG_DATE DESC;
@mathguy建议的另一种更简单的方法是使用区间函数:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE LOG_DATE > SYSTIMESTAMP - INTERVAL '5' MINUTE
ORDER BY LOG_DATE DESC;
这是因为
log\u date
是带有时区的时间戳
数据类型,当您将其与日期数据类型合并时,Oracle将在两个不同的时间进行隐式转换以进行比较:
SQL> SELECT SYSTIMESTAMP, CAST(SYSDATE AS TIMESTAMP WITH TIME ZONE) time_with_tz FROM dual;
SYSTIMESTAMP TIME_WITH_TZ
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
19-MAR-18 09.57.07.654161 AM -04:00 19-MAR-18 09.57.07.000000 AM +05:30
因此,如果我在偏移量为-4:00的服务器上从偏移量为+5:30的时区执行查询,Oracle将把SYSDATE-5/(24*60)
转换为SYSDATE-(9:30+0:05)
告诉Oracle显式地将日志日期转换为日期,然后应用>(SYSDATE-5/(24*60)
的文件管理器,如下所示,您就可以了:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE cast(LOG_DATE AS DATE) > (SYSDATE - 5/(24*60))
ORDER BY LOG_DATE DESC;
更新:由于以下原因,此查询可能存在性能问题
1) Oracle将转换LOG\u DATE from列的每一行的数据类型
带有截止日期时区的时间戳
2) 列LOG_DATE上的内置索引(如果有)将由于以下原因而不使用
到CAST函数
更好的解决方案是将sysdate-5/(24*60)转换为带时区的时间戳,您必须知道Oracle服务器的时区,假设服务器位于UTC-4:00,下面的查询应该可以正常工作:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE LOG_DATE > TO_TIMESTAMP_TZ (to_char(SYSDATE - 5/(24*60), 'YYYY-MM-DD HH24:MI:SS') || ' -4:00', 'YYYY-MM-DD HH24:MI:SS TZH:TZM')
ORDER BY LOG_DATE DESC;
@mathguy建议的另一种更简单的方法是使用区间函数:
SELECT SYSDATE, SYSDATE - 5/(24*60),LOG_DATE,TRUNC(LOG_DATE),TO_CHAR(LOG_DATE,'YYYY/MM/DD HH:MI:SS')
FROM dba_scheduler_job_run_details
WHERE LOG_DATE > SYSTIMESTAMP - INTERVAL '5' MINUTE
ORDER BY LOG_DATE DESC;
HH:MM:SS
-您正在显示小时和秒之间的月数。您应该在问题输入错误时删除它。HH:MM:SS
-您正在小时和秒之间显示月数。您应该在问题输入错误时删除它。更好(假设使用的“时区”相同)-将日志日期与SYSTIMESTAMP而不是SYSDATE进行比较。@mathguy谢谢您的建议,我已更新了答案。只是想知道是否还有更好的解决方案。可能有。我假设LOG\u DATE
是服务器时区中的时间戳。(很抱歉,我不在该行业工作;我没有机会与调度器一起工作。)如果是这样,那么测试LOG\u DATE>SYSTIMESTAMP-间隔“5”分钟就简单多了。更一般地说,LOG\u DATE
应该与返回当前时间戳的函数进行比较,该函数的时区与LOG\u DATE
的时区相同。更好(假设使用的“时区”相同)-将LOG\u DATE与SYSTIMESTAMP而不是SYSDATE进行比较。@mathguy感谢您的建议,我已经更新了答案。只是想知道是否还有更好的解决方案。可能有。我假设LOG\u DATE
是服务器时区中的时间戳。(很抱歉,我不在该行业工作;我没有机会与调度器一起工作。)如果是这样,那么测试LOG\u DATE>SYSTIMESTAMP-间隔“5”分钟就简单多了。更一般地说,LOG\u DATE
应该与返回当前时间戳的函数进行比较,该时间戳的时区与LOG\u DATE
的时区相同。