Home > Software design >  Window function lag() in trigger uses default instead of previous value
Window function lag() in trigger uses default instead of previous value

Time:09-27

I'm trying to create an SQLite trigger to update balance for a particular account code.

accounts table :

CREATE TABLE accounts (
    year      INTEGER   NOT NULL,
    month     INTEGER   NOT NULL   CHECK(month BETWEEN 1 AND 12),
    amount    REAL      NOT NULL   CHECK(amount >= 0),
    balance   REAL,
    code      INTEGER   NOT NULL
);

When a new row is inserted I want the balance value of the new row to reflect OLD balance NEW amount. But this trigger does not recognize the lagging balance value and I cannot figure out why:

CREATE TRIGGER trg_accounts_balance
AFTER INSERT ON accounts
BEGIN
    UPDATE accounts
    SET balance = (
        SELECT
            lag(balance, 1, 0) OVER (
                PARTITION BY code
                ORDER BY month
            )   NEW.amount
        FROM accounts
    )
    WHERE rowid = NEW.ROWID;
END;

If I insert one row per month, I expect my data to look like:

year month amount balance code
2022 1 100.0 100.0 100
2022 2 9.99 109.99 100

But I get:

year month amount balance code
2022 1 100.0 100.0 100
2022 2 9.99 9.99 100

What am I doing wrong?

CodePudding user response:

The query:

SELECT
    lag(balance, 1, 0) OVER (
                PARTITION BY code
                ORDER BY month
            ) 
FROM accounts

returns as many rows as there are in the table and SQLite picks the first (whichever it is) to return it as the result so that it can use it to add NEW.amount.
There is nothing that links this value to the specific row that was inserted.

Instead, use this:

CREATE TRIGGER trg_accounts_balance
AFTER INSERT ON accounts
BEGIN
    UPDATE accounts
    SET balance = COALESCE(
       (
        SELECT balance
        FROM accounts
        WHERE code = NEW.code
        ORDER BY year DESC, month DESC
        LIMIT 1, 1
       ), 0)    NEW.amount
    WHERE rowid = NEW.ROWID;
END;

The subquery returns the previous inserted row by ordering the rows of the specific code descending and skipping the top row (which is the new row).

See the demo.

  • Related