避免while循环检查行“状态更改”

时间:2019-01-24 11:46:06

标签: sql-server database

我有一个存储Id,日期时间和整数新月值的表。该值增加,直到它“破坏”并返回到0附近的值。例如:... 1000、1200、1350、8、10、25 ... 我需要计算一下这种“溢出”发生了多少次,但是……我说的是每天存储20万行的表! 我已经解决了!但是使用带有游标的过程,并使用while循环对其进行迭代。但是我知道这不是更快的方法。

有人可以帮助我找到其他方式吗? 谢谢!

->

表结构: ID Bigint主键,CreatedAt DateTime,值不为Null Int。

问题: 如果两个连续行之间的Delta值<0,则增加一个计数器。 表格每天有20万新行。 不允许触发。


[第一次编辑]

Table has the actual structure:
    CREATE TABLE ValuesLog (
    Id BIGINT PRIMARY KEY, 
    Machine BIGINT, 
    CreatedAt DATETIME,
    Value INT
)

我需要: 检查某些[机器]的[值]何时突然降低。

据说有些用户使用过LEAD / LAG。但这有一个问题...如果我选择了很多机器,那么LEAD / LAG功能就不会在乎“它是什么机器”。因此,如果我发现机器1和机器2,如果机器1增加但机器2减少,则LEAD / LAG会给我一个误报。

因此,我的表实际上是什么样的: Many rows of the actual table

(上面的图像是为3台或4台机器选择的。但是,在此示例中,机器并没有弄乱。但是可能会发生!在这种情况下,LEAD / LAG不在乎上面的行是否是机器-1或machine-2)

我想要什么: 在第85行中,[value]中断并重新启动。我想统计一下每次发生的情况,即所选择的机器。 所以: “ Machine-1重新启动了6次... Machine-9重新启动了10次...”

我做了一些类似的事情:

CREATE PROCEDURE CountProduction @Machine INT_ARRAY READONLY, @Start DATETIME, @End DATETIME AS
    SET NOCOUNT ON

    -- Declare counter and insert start values
    DECLARE @Counter TABLE(
        machine INT PRIMARY KEY, 
        lastValue BIGINT DEFAULT 0, 
        count BIGINT DEFAULT 0
    )
    INSERT INTO @Counter(machine) SELECT n FROM @Machine

    -- Declare cursor to iteract over results of values log
    DECLARE valueCursor CURSOR LOCAL FOR 
        SELECT
            Value,
            Aux.LastValue,
            Aux.count
        FROM
            ValueLog,
            @Machine AS Machine,
            @Counter AS Counter
        WHERE
            ValueLog.Machine = Machine.n
            AND Counter.machine = ValueLog.Machine
            AND ValueLog.DateCreate BETWEEN @Start AND @End;

    -- Start iteration
    OPEN valueCursor
    DECLARE @RowMachine INT
    DECLARE @RowValue BIGINT
    DECLARE @RowLastValue BIGINT
    DECLARE @RowCount BIGINT
    FETCH NEXT FROM valueCursor INTO @RowMachine, @RowValue, @RowLastValue, @RowCount

    -- Iteration
    DECLARE @increment INT
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @RowValue < @RowLastValue
            SET @increment = 1
        ELSE
            SET @increment = 0

        -- Update counters
        UPDATE 
            @Counter
        SET
            lastValue = @RowValue,
            count = count + @increment
        WHERE
            inj = @RowMachine

        -- Proceed to iteration
        FETCH NEXT FROM valueCursor INTO @RowMachine, @RowValue, @RowLastValue, @RowCount
    END

    -- Closing iteration
    CLOSE valueCursor
    DEALLOCATE valueCursor

    SELECT machine, count FROM @Counter

2 个答案:

答案 0 :(得分:0)

使用LEAD()。如果下一行<当前行,则计算该次出现。

答案 1 :(得分:0)

使用建议的@ jeroen-mostert解决

DECLARE @Start DATETIME
DECLARE @End DATETIME

SET @Start = '2019-01-01'
SET @End = GETDATE()

SELECT 
    Machine, 
    COUNT(DeltaValue) AS Prod
FROM
    (SELECT
        Log.Machine,
        Log.Value - LAG(Log.Value) OVER (PARTITION BY Log.Machine ORDER BY Log.Id) AS DeltaValue
    FROM
        ValueLog AS Log,
        (SELECT
            Id,
            Machine,
            Value
        FROM
            ValueLog
        ) AS AuxLog
    WHERE
        AuxLog.Id = Log.Id
        AND Proto.DateCreate BETWEEN @Start AND @End
        AND Proto.Machine IN (1, 9, 10)
        ) as TB1
WHERE
    DeltaValue < 0
GROUP BY
    Machine
ORDER BY
    Machine

在这种情况下,内部的LAG / LEAD函数不会弄乱内容(创建视图时由于某种原因发生的事情……我将在以后尝试理解)。

谢谢大家!我是DB的新手,这个问题使我整整疯狂了。