如何找到连续零的平均值?

时间:2016-11-11 06:22:56

标签: sql tsql datetime sql-server-2012

这是我的桌子。

Site_name | date& Time              | PowerOutput         
----------+-------------------------+------------------
ACT0001   | 2013-07-21 01:00:00.000 | 196.852984494331  
ACT0001   | 2013-07-21 02:00:00.000 | 0   
xyz0001   | 2013-07-21 03:00:00.000 | 196.852984494331   
xyq0001   | 2013-07-21 04:00:00.000 | 196.958395639561 
xys0001   | 2013-07-21 05:00:00.000 | 0
xyd0001   | 2013-07-21 06:00:00.000 | 197.20098185022 
xye0001   | 2013-07-21 07:00:00.000 | 0 
xyg0001   | 2013-07-21 08:00:00.000 | 0     
cfg0001   | 2013-07-21 09:00:00.000 | 197.412144323522 
acb0001   | 2013-07-21 10:00:00.000 | 0 
bdf0001   | 2013-07-21 11:00:00.000 | 0 
olk0001   | 2013-07-21 12:00:00.000 | 196.886233049016 

我正在尝试更新零位的值。如果只有一个零,那么我可以更新表,但是如果有连续的零,我发现很难更新表。

逻辑是:

((Previous value-next value)/previous value)*100 <5

如果这是真的那么它应该插入先前的值

((Previous value-next value)/previous value)*100 >=5

如果这是真的那么它应该保持为零。

这是我到目前为止的代码:

;with cte as
(
    SELECT  
        *,
        lead(pr_output,1) OVER (ORDER BY (select null)) As PreviousValue,
        lag(pr_output,1) OVER (ORDER BY (select null)) As NextValue
    FROM
        [dbo].[My_table]
)
,ctee as
(
    select 
        *,
        abs((PreviousValue*100-NextValue*100)/(case when NextValue = 0 then 1 else NextValue end)) as CheckFlag
    from
        cte 
)
select
    Site_name,[DATE&Time],
    case 
        when pr_output <>0 then pr_output
        else
            case 
                when CheckFlag >= 5 then 0
                else PreviousValue
            end
    end as pr_output
from 
    ctee 

如果连续零,我无法更新记录。

预期产出:

Site_name | date& Time              | PowerOutput         
----------+-------------------------+------------------
ACT0001   | 2013-07-21 01:00:00.000 | 196.852984494331  
ACT0001   | 2013-07-21 02:00:00.000 | 196.852984494331   
xyz0001   | 2013-07-21 03:00:00.000 | 196.852984494331   
xyq0001   | 2013-07-21 04:00:00.000 | 196.958395639561 
xys0001   | 2013-07-21 05:00:00.000 | 196.958395639561
xyd0001   | 2013-07-21 06:00:00.000 | 197.20098185022 
xye0001   | 2013-07-21 07:00:00.000 | 197.20098185022 
xyg0001   | 2013-07-21 08:00:00.000 | 197.20098185022   
cfg0001   | 2013-07-21 09:00:00.000 | 197.412144323522 
acb0001   | 2013-07-21 10:00:00.000 | 197.412144323522
bdf0001   | 2013-07-21 11:00:00.000 | 197.412144323522
olk0001   | 2013-07-21 12:00:00.000 | 196.886233049016 

谢谢

2 个答案:

答案 0 :(得分:1)

如果你要做的是将PowerOutput中的任何零值替换为最新的先前非零PowerOutput值,仅在以下情况下:

((Previous value-next value)/previous value)*100 <5

然后我相信这就是诀窍:

SELECT  main.SiteName,
        main.[DateTime],
        CASE WHEN main.PowerOutput = 0 
            THEN CASE WHEN ((PreviousNonZero.PowerOutput - NextNonZero.PowerOutput) / PreviousNonZero.PowerOutput) * 100 < 5
                    THEN PreviousNonZero.PowerOutput
                    ELSE 0
                 END
            ELSE main.PowerOutput
        END AS PowerOutput
FROM [dbo].[My_table] main
OUTER APPLY
(
    SELECT TOP 1 PowerOutput 
    FROM [dbo].[My_table] prev 
    WHERE prev.[DateTime] < main.[DateTime]
    AND PowerOutput <> 0
    ORDER BY prev.[DateTime] DESC
) PreviousNonZero
OUTER APPLY
(
    SELECT TOP 1 PowerOutput 
    FROM [dbo].[My_table] future
    WHERE future.[DateTime] > main.[DateTime]
    AND PowerOutput <> 0
    ORDER BY future.[DateTime]
) NextNonZero
ORDER BY [DateTime]

我不确定是否:

((Previous value-next value)/previous value)*100 <5

实际上是你想要使用的逻辑。您似乎正在尝试确定该值是否从之前的非零值更改为或低于5%到下一个值,但这仅在更改始终在一个方向上发生时才起作用,否则您会得到一些否定值值也是(您的样本数据集具有此计算的值,范围从约-0.23到0.27)。

如果你想要的是识别PowerOutput值变化超过5%(在任一方向上)的实例,我会改变上面查询中的内部CASE语句:

CASE WHEN ((PreviousNonZero.PowerOutput - NextNonZero.PowerOutput) / PreviousNonZero.PowerOutput) * 100 < 5

为:

CASE WHEN (ABS(PreviousNonZero.PowerOutput - NextNonZero.PowerOutput) / PreviousNonZero.PowerOutput) * 100 < 5

答案 1 :(得分:1)

我使用标量函数做了不同的方法

                                CREATE FUNCTION [dbo].[fnGetAvgPower] 
                (
                        @site_name varchar(50), @date_time datetime
                )
                RETURNS decimal(24,12) --Check the number of decimal you need here
                AS
                BEGIN
                    --
                    DECLARE @AvgPower decimal(24,12), @PrevValue decimal(24,12),@NextValue decimal(24,12), @Value decimal(24,12)--Check the number of decimal you need here


                    set @PrevValue = (Select Top 1 PowerOutput from Table_3 where Site_name = @site_name and datestamp < @date_time  and PowerOutput <> 0
                     order by datestamp desc)
                     set @NextValue = (Select Top 1 PowerOutput from Table_3 where Site_name = @site_name and datestamp > @date_time  and PowerOutput <> 0
                     order by datestamp asc)

                     set @Value = @PrevValue / @NextValue * 100

                     if(@Value is null) 

                     begin

                    set @Value= 0 
                    end
                    else
                    begin
                     set @Value = (Select case  when @Value > 5 then @PrevValue when @Value <= 5 then 0 end)

                     end
                    RETURN  @Value
            -- Call funtion
            update Table_3 set PowerOutput = dbo.fnGetAvgPower(Site_name,datestamp)
            where PowerOutput  = 0