繁体   English   中英

锯齿模式局部最大值的每日总计

[英]Daily totals for sawtooth pattern local maxima

我有多个可以临时重置的单调计数器。 这些计数器在绘制图形时表现出锯齿状行为(但它们并未严格增加)。 我想要一份月度报告,显示每个计数器的最大值的每日总和。

到目前为止,我的策略是在计数器小于计数器的前一个采样(也小于或等于下一个)的行上放置一个“1”。 然后计算该列的运行总计以识别没有重置的系列。

然后我将每天的时间间隔分组以计算当天每个系列的最大最小值,然后将这些部分相加以获得当天的总计。

我有什么作品,但它需要〜10秒才能运行。 执行计划显示了两大类:一种在 cteData 中,我认为另一种在 cteSeries 中。 我觉得我应该能够消除其中一个,但我不知道该怎么做。

这段代码的结果是(我现在可以看到实际上是在间隔边界上跳过一个样本):

 interval tagname total 2020-01-01 alpha 3 2020-01-01 bravo 4 2020-01-02 alpha 3 2020-01-02 bravo 4
IF OBJECT_ID('tempdb..#counter_data') IS NOT NULL
    DROP TABLE #counter_data;

CREATE TABLE #counter_data(
    t_stamp DATETIME NOT NULL
    ,tagname VARCHAR(32) NOT NULL
    ,val REAL NULL
    PRIMARY KEY(t_stamp, tagname)
);

INSERT INTO #counter_data(t_stamp, tagname, val)
VALUES
     ('2020-01-01 04:00', 'alpha', 0)
    ,('2020-01-01 04:00', 'bravo', 0)
    ,('2020-01-01 08:00', 'alpha', 1)
    ,('2020-01-01 08:00', 'bravo', 1)
    ,('2020-01-01 12:00', 'alpha', 2)
    ,('2020-01-01 12:00', 'bravo', 2)
    ,('2020-01-01 16:00', 'alpha', 0)
    ,('2020-01-01 16:00', 'bravo', 3)
    ,('2020-01-01 20:00', 'alpha', 1)
    ,('2020-01-01 20:00', 'bravo', 4)
    ,('2020-01-02 04:00', 'alpha', 2)
    ,('2020-01-02 04:00', 'bravo', 5)
    ,('2020-01-02 08:00', 'alpha', 3)
    ,('2020-01-02 08:00', 'bravo', 6)
    ,('2020-01-02 12:00', 'alpha', 0)
    ,('2020-01-02 12:00', 'bravo', 7)
    ,('2020-01-02 16:00', 'alpha', 1)
    ,('2020-01-02 16:00', 'bravo', 8)
    ,('2020-01-02 20:00', 'alpha', 2)
    ,('2020-01-02 20:00', 'bravo', 9)
;

DECLARE @dateStart AS DATETIME = '2020-01-01';
DECLARE @dateEnd AS DATETIME = DATEADD(month, 2, @dateStart);

WITH cteData AS(
    SELECT
        t_stamp
        ,tagname
        ,val
        ,CASE 
            WHEN val < LAG(val) OVER(PARTITION BY tagname ORDER BY t_stamp)
                AND val <= LEAD(val) OVER(PARTITION BY tagname ORDER BY t_stamp)
                THEN 1 
            ELSE 0
            END AS rn
    FROM #counter_data
    WHERE 
        t_stamp >= @dateStart AND t_stamp < @dateEnd
        AND tagname IN(
            'alpha'
            ,'bravo'
        )
)
,cteSeries AS(
    SELECT
        CAST(t_stamp AS DATE) AS interval
        ,tagname
        ,val
        ,SUM(rn) OVER(PARTITION BY tagname ORDER BY t_stamp) AS series
    FROM cteData
)
,cteSubtotal AS(
    SELECT 
        interval
        ,tagname
        ,MAX(val) - MIN(val) AS subtotal
    FROM cteSeries
    GROUP BY interval, tagname, series
)
,cteGrandTotal AS(
    SELECT
        interval
        ,tagname
        ,SUM(subtotal) AS total
    FROM cteSubtotal
    GROUP BY interval, tagname
)
SELECT *
FROM cteGrandTotal
ORDER BY interval, tagname

我将通过将其与前一行进行比较来计算每行中计数器的增加:

with cte
as
(
    SELECT *,isnull(lag(val) over (partition by tagname order by t_stamp),0) as previousVal
    FROM counter_data
)
SELECT cast(t_stamp as date),tagname, sum(case when val>previousVal then val-previousval else val end )
FROM cte
GROUP BY cast(t_stamp as date),tagname;

这看起来像是一个差距和孤岛问题。 我认为您希望lag()获得“先前”值和条件总和来计算每日计数。

select 
    tag_name,
    cast(t_stamp as date) t_date,
    sum(case when val = lag_val + 1 the 1 else 0 end) total
from (
    select 
        c.*,
        lag(val) over(
            partition by tagname, cast(t_stamp as date) 
            order by t_stamp
        ) lag_val
    from #counter_data c
) c
group by tagname, cast(t_stamp as date)
order by t_date, tagname

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM