【问题标题】:SQLite trigger after update更新后的 SQLite 触发器
【发布时间】:2017-09-24 10:34:40
【问题描述】:

我的表有时间戳列。我想要一个触发器,当更新行且更新语句中未指定时间戳时,将受影响行上的时间戳设置为 0。

如果我使用这个触发器:

CREATE TRIGGER AFTER UPDATE ON mytable FOR EACH ROW
WHEN (NEW.timestamp IS NULL)
BEGIN
UPDATE mytable SET timestamp = 0 WHERE id = NEW.id;
END;

那么触发器不会为此更新语句触发:

UPDATE mytable SET comecolumn='some'

即受影响行的时间戳不会更改为 0。

你能帮我定义触发器吗?

【问题讨论】:

  • 如果你的时间戳不是NULL,你的触发器不会因为WHEN语句而被触发,你希望它什么时候被触发?
  • 我想为此语句触发:UPDATE mytable SET comecolumn='some'(即,如果更新语句中未提及,则在触发器中将时间戳设置为零)我不想触发此语句 UPDATE mytable SET comecolumn='some', timestamp=12345 (即,如果更新语句已将时间戳设置为某个值,则不要在触发器中将时间戳设置为零)
  • WHEN NEW.timestamp = OLD.timestamp 呢?
  • 恐怕这不会像我描述的那样......
  • 实际上NEW 定义了整个新行及其所有内容,因此只有当您在@ 中为timestamp 设置不同 值时,NEW.timestamp = OLD.timestamp 才会为假987654329@声明

标签: sqlite


【解决方案1】:

对 UPDATE 触发器中的行进行额外更改的唯一方法是之后在同一个表上执行另一个 UPDATE。

检测列值是否改变的唯一方法是比较新旧行值;触发器不知道在原始 UPDATE 语句中实际提到了哪些列。

为了防止触发器递归地触发自身,你应该限制它被除时间戳之外的所有列的变化触发:

CREATE TRIGGER clear_timestamp
AFTER UPDATE OF all_the, other, columns ON MyTable
FOR EACH ROW
WHEN OLD.timestamp = NEW.timestamp
BEGIN
    UPDATE MyTable
    SET timestamp = 0
    WHERE id = NEW.id;
END;

【讨论】:

    【解决方案2】:

    我认为问题在于SET 语句扩展到每一列,每一列都设置为数据库中的当前值。因此,如果当前的 timestamp 列是 NULL,则原始唯一触发器有效。

    一种解决方案可能是创建另一个触发器,在 UPDATE 之前将时间戳列重置为 NULL

    CREATE TRIGGER "set_null"
    BEFORE UPDATE ON "mytable" FOR EACH ROW 
    BEGIN
    UPDATE mytable set timestamp = NULL where rowid = NEW.rowid;
    END
    

    这样NEW.timestamp 就是NULL,如果UPDATE SET 中没有指定的话。

    显然现在不能在时间戳上设置NOT NULL 约束。

    另一个问题是执行更新查询时必须关闭触发递归:

    PRAGMA recursive_triggers = OFF;
    

    【讨论】:

    • 现在你有了一个递归触发器。
    • PRAGMA recursive_triggers = false 怎么样?
    • 是的,这确实是个问题。我对其进行了测试并且它有效,可能是因为触发器递归已关闭。但我没想到。
    【解决方案3】:

    这是另一种方式:

    import sqlite3
    conn = sqlite3.connect(':memory:')
    c = conn.cursor()
    name = {'name':'jack'}
    
    c.execute("""CREATE TABLE Programs (
        id INTEGER PRIMARY KEY,
        name VARCHAR(64) NOT NULL,
        time_added INTEGER
    );""")
    
    c.execute("""CREATE TRIGGER program_time_added AFTER INSERT ON Programs
        FOR EACH ROW
        BEGIN
            UPDATE Programs SET time_added =datetime('now', 'localtime') WHERE id = NEW.id;
        END;""")
    
    c.execute('INSERT INTO Programs (name) VALUES (?)', [name['name']])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      • 2021-10-13
      • 2016-11-03
      • 2021-03-27
      • 1970-01-01
      相关资源
      最近更新 更多