2014-01-29 32 views
0

我今天遇到了一个奇怪的问题:我有一个被job调用的函数。我想找到从函数开始到结束的差别,然后记录到某个表。Oracle作业和查找时间戳差异

所以,让我们说我有功能

procedure p is 
    starttime timestamp := systimestamp; 

    procedure writeTime 
    is 
     diff   interval day to second := systimestamp - starttime; 
    begin 
    -- here insert diff to some table 
    end; 
begin 
    -- doing some long stuff 

    writeTime(); 
exception 
    when others then 
    writeTime(); 
end; 

问题中的函数是:

  1. 当我手动运行此,它工作得很好,差别是显而易见的。例如。我用提取解析间隔:extract(hour from diff)*60*60 + extract(minute from diff)*60 + extract(second from diff)

  2. 当我设置了作业和作业运行这个功能我有一个很大的问题:它返回负的结果,这是我,一些测试后,了解产生这里systimestamp - starttime。似乎这个计算中的systimestamp取自格林威治时区,而我的大小是一个小时,所以这个计算diff interval day to second := systimestamp - starttime;返回的值是(-1小时+差)。

通过愚蠢的暴力破解我已经找到了解决办法:

procedure p is 
    starttime timestamp := systimestamp; 

    procedure writeTime 
    is 
     diff   interval day to second; 
     endtime  timestamp := systimestamp; 
    begin 
    diff := endtime - starttime; 

    -- here insert diff to some table 
    end; 
begin 
    -- doing some long stuff 

    writeTime(); 
exception 
    when others then 
    writeTime(); 
end; 

它只是在变量首先写入SYSTIMESTAMP,然后才计算差异。

我的数据库参数:

  • 甲骨文11.2.0.2.0
  • 时区+1柏林

所以,现在的问题是:我真的想知道是不是我的RDBMS的错误或者我可能没有看到一些明显的解释,为什么它是这样的?具体问题是:为什么这个操作

starttime timestamp := systimestamp; 

它需要一个时区,并在此

diff   interval day to second := systimestamp - starttime; 

另需一个在使用相同的设置同一个会话的同一过程中?

回答

2

是数据库时区DBTIMEZONE同样喜欢你的会话时区SESSIONTIMEZONE

函数SYSTIMESTAMP返回datatye TIMESTAMP WITH TIME ZONE,所以你做一个隐式转换为TIMESTAMP数据类型。

数据类型LOCALTIMESTAMPTIMESTAMP

尝试

starttime timestamp WITH TIME ZONE := systimestamp; 

starttime timestamp := LOCALTIMESTAMP; 

您可以使用此查询中时区的计划作业运行的检查:

SELECT * FROM ALL_SCHEDULER_GLOBAL_ATTRIBUTE where attribute_name = 'DEFAULT_TIMEZONE' 
+0

和无论如何,我认为这是错误的,以允许从另一个数据类型减去,至少在这种情况下。它只能混淆... – smnbbrv

+0

那么,这取决于编程语言的设计。在PL/SQL中允许隐式转换。例如,在C#中,它是不允许的,在VB.NET中,您可以在编译器设置中启用或禁用它。像往常一样,有没有它的优点和缺点。对于PL/SQL你只需要把它。 –

0

我用这种方法

declare 
time_start number; 
begin 
time_start := dbms_utility.get_time(); 

-- some heavy lifting 

dbms_output.put_line(dbms_utility.get_time() - time_start); 
end; 
/
+0

是的,谢谢,好方法,但它不回答这个问题... – smnbbrv

+1

GET_TIME的精确度是10ms,如果您需要它,TIMESTAMP更准确。 –