Избегайте цикла while для проверки строки «изменение состояния» - PullRequest
0 голосов
/ 24 января 2019

У меня есть таблица, в которой хранятся Id, datetime и значение int crescent.Это значение увеличивается, пока не «сломается» и не вернется к значению, близкому к 0.Пример: ... 1000, 1200, 1350, 8, 10, 25 ... Мне нужно посчитать, сколько раз происходит это "переполнение", НО ... Я говорю о таблице, которая хранит 200 тыс. Строк в день!Я уже решил это!Но используя процедуру с курсором, который перебирает ее с помощью цикла while.Но я ЗНАЮ, что это не быстрый способ сделать это.

Может ли кто-нибудь помочь мне найти какой-то другой способ?Спасибо!

->

Структура таблицы: Id Bigint Первичный ключ, CreatedAt DateTime, значение не нулевое Int.

Проблема: если Delta-Value между двумя последовательными строками равно <0, увеличить счетчик.Таблица содержит 200 тысяч новых строк каждый день.Запрещен триггер. </p>


[ПЕРВОЕ РЕДАКТИРОВАНИЕ]

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 даст мне ложный положительный результат.

Итак, как на самом деле выглядит моя таблица: Многие строки фактической таблицы

(На изображении выше выбираются 3 или 4 машины. Но, В ЭТОМ ПРИМЕРЕ, машины не перепутались. Но может произойти! И в этомВ этом случае LEAD / LAG не заботится, если строка выше - машина-1 или машина-2)

Что я хочу: В этой строке 85 [значение] разрывается и перезапускается.Я бы хотел посчитать каждый случай, когда это произойдет, выбранные машины.Итак: «Машина-1 перезапущена 6 раз ... Машина-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 голосов
/ 24 января 2019

Решено с использованием предложенного @ 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, ​​и этот вопрос сводит меня с ума на целый день.

0 голосов
/ 24 января 2019

Используйте LEAD (). Если следующая строка <текущая строка, посчитайте это вхождение. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...