2017-05-29 52 views
1

我有一个相当长的查询,查看过去13周,并确定当天的表现与过去13周相比是否异常。它只是返回一个包含日期,当天表现以及标志表示是否异常的单行。让事情更复杂一点:表现不仅仅是一天,而是一个24小时运行的窗口。然后每隔一小时运行一次此查询以监视过去24小时内的KPI。即如果是星期二下午2点,它将从前一天(星期一)的下午2点开始到现在,并且在过去的13周内将其与下午2点到下午2点相比较。模拟一系列日期的查询

要测试此代码是否正常工作,我想模拟它在过去一个月内运行。

的代码去如下:

WITH performance AS(
    SELECT TRUNC(dateColumn - to_number(to_char(sysdate, 'hh24')/24) as startdate, 
      KPI_a, 
      KPI_b, 
      KPI_c 
    FROM table 
    WHERE someConditions 
    GROUP BY TRUNC(dateColumn - to_number(to_char(sysdate, 'hh24')/24)), 
compare_t AS(
    -- looks at relationships of the KPIs), 
variables AS(
    -- calculates the variables required for the anomaly detection), 

...好,我不知道需要多查询的多给予,但它基本上是我需要模拟“SYSDATE”。而不是输入当前日期,输入上个月的每个小时,以便此查询将运行约720次,并返回结果720次,每天每个小时。

我在想FOR循环,但我不确定。

+0

您认为什么是“异常”KPI值? –

+0

@ WernfriedDomscheit它是根据以前的表现计算的门限 –

+0

720小时给出30天 - 而不是13周。我没有得到关系。 –

回答

0

您可以使用一个递归子查询:

with times(time) as 
(
    select sysdate - interval '1' month as time from dual 
    union all 
    select time + interval '1' hour from times 
    where time < sysdate 
) 
, performance as() 
, compare_t as() 
, variables as() 
select * 
from times 
join ... 
order by time; 
+0

我得到一个表/视图不存在错误,如果我只是在括号内运行查询。 –

+0

递归的WITH CLAUSE语法仅在Oracle 11gR2或更高版本中受支持 – APC

+0

的确如此,但由于11.2是在多年前发布的,所以我通常假定它在没有另行声明时可用。 –

0

我不明白您的具体要求,但我不得不解决类似的问题。给你一个想法这里有两个建议:

计算过去13周到昨天KPI值的平均值和标准差。如果当前值低于“AVG - 10 * STDDEV”,则选择记录,即标记为异常。

WITH t AS 
    (SELECT dateColumn, KPI_A, 
     AVG(KPI_A) OVER (ORDER BY dateColumn RANGE BETWEEN 13 * INTERVAL '7' DAY PRECEDING AND INTERVAL '1' DAY PRECEDING) AS REF_AVG, 
     STDDEV(KPI_A) OVER (ORDER BY dateColumn RANGE BETWEEN 13 * INTERVAL '7' DAY PRECEDING AND INTERVAL '1' DAY PRECEDING) AS REF_STDDEV 
    FROM TABLE 
    WHERE someConditions) 
SELECT dateColumn, REF_AVG, KPI_A, REF_STDDEV 
FROM t 
WHERE TRUNC(dateColumn, 'HH') = TRUNC(LOCALTIMESTAMP, 'HH') 
    AND KPI_A < REF_AVG - 10 * REF_STDDEV; 

采取从上周的小时值(即相同平日昨日),并从昨日小时值的相关性。如果相关性小于某个值(我使用95%),则认为这一天是异常情况。

WITH t AS 
    (SELECT dateColumn, KPI_A,  
     FIRST_VALUE(KPI_A) OVER (ORDER BY dateColumn RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW) AS KPI_A_LAST_WEEK, 
     dateColumn - FIRST_VALUE(dateColumn) OVER (ORDER BY dateColumn RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW) AS RANGE_INT 
    FROM table 
    WHERE ...) 
SELECT 100*ROUND(CORR(KPI_A, KPI_A_LAST_WEEK), 2) AS CORR_VAL 
FROM t 
WHERE KPI_A_LAST_WEEK IS NOT NULL 
    AND RANGE_INT = INTERVAL '7' DAY 
    AND TRUNC(dateColumn) = TRUNC(LOCALTIMESTAMP - INTERVAL '1' DAY) 
GROUP BY TRUNC(dateColumn);