【问题标题】:Window function lag() in trigger uses default instead of previous value触发器中的窗口函数 lag() 使用默认值而不是以前的值
【发布时间】:2022-12-07 13:41:50
【问题描述】:

我正在尝试创建一个 SQLite 触发器来更新特定帐户 codebalance

accounts表:

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
);

插入新行时,我希望新行的 balance 值反映 OLD balance + NEW amount。但是这个触发器无法识别滞后的 balance 值,我不明白为什么:

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;

如果我每月插入一行,我希望我的数据如下所示:

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

但我得到:

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

我究竟做错了什么?

【问题讨论】:

    标签: sqlite triggers sql-update sql-insert window-functions


    【解决方案1】:

    查询:

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

    返回与表中一样多的行,SQLite 选择第一个(无论是哪个)将其作为结果返回,以便它可以使用它来添加 NEW.amount
    没有任何内容将此值链接到插入的特定行。

    相反,使用这个:

    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;
    

    子查询通过对特定 code 的行进行降序排序并跳过顶行(即新行)来返回先前插入的行。

    请参阅demo

    【讨论】:

    • 作为后续,RETURNING * 子句返回 NULL balancedbfiddle.uk/ENx3-bEz。有没有办法强制提交或确保返回的 INSERT 始终包含余额?
    • 来自sqlite.org/lang_returning.html#limitations_and_caveats的@kemri@:“RETURNING 子句发出的值是顶级 DELETE、INSERT 或 UPDATE 语句所见的值,不反映触发器所做的任何后续值更改。因此,如果数据库包含修改某些插入或更新的每一行的值,RETURNING 子句发出在这些触发器运行之前计算的原始值。”
    猜你喜欢
    • 2023-03-16
    • 2021-06-08
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 2012-04-06
    • 2015-09-28
    • 2011-05-14
    相关资源
    最近更新 更多