【问题标题】:How to get update statement in trigger function or when condition如何在触发函数或条件下获取更新语句
【发布时间】:2016-02-03 03:19:37
【问题描述】:
CREATE TABLE accounts (
 id SERIAL PRIMARY KEY,
 email TEXT,
 verified BOOLEAN DEFAULT FALSE,
 ...
);

CREATE OR REPLACE FUNCTION fn_reset_verified() RETURNS TRIGGER AS $$
BEGIN 
IF (
    OLD.email != NEW.email -- do nothing if no change
) THEN
    RAISE NOTICE 'UPDATE';
    UPDATE users SET verified=FALSE WHERE id=NEW.id;
END IF;
RETURN NEW;
END; $$ language 'plpgsql';

CREATE TRIGGER reset_verified AFTER UPDATE OF email ON accounts
FOR EACH ROW
WHEN (OLD.email != NEW.email) -- only when email changed
EXECUTE PROCEDURE fn_reset_verified();

基于上述架构,如果用户更改电子邮件,我希望创建自动更新验证为 false 的触发器。 它适用于以下语句:

UPDATE accounts SET email='newemail@email.com' WHERE id=1;

当我打算更新电子邮件并同时将验证设置为 TRUE 时,我的问题出现了,如下所示:

UPDATE accounts SET email='verified@email.com', verified=TRUE WHERE id=1;

如果在更新语句中设置了验证,我应该跳过该功能。也许条件如下:

WHEN (OLD.email != NEW.email AND STATEMENT.verified IS NULL)

那么有什么方法可以获得更新声明或涉及的列吗?

【问题讨论】:

    标签: postgresql triggers


    【解决方案1】:

    首先,您不应该在该表的更新触发器内对该表调用UPDATE。您可能会无限循环(在这种特殊情况下,但无论如何),通常有更好的方法来实现相同的目标。

    在您的情况下,您将创建一个BEFORE UPDATE 触发器,该触发器在电子邮件地址更改时触发并检查/修改该触发器中的verified 列:

    CREATE OR REPLACE FUNCTION fn_reset_verified() RETURNS TRIGGER AS $$
    BEGIN 
        -- Below condition does not have to be checked because of WHEN clause in trigger
    IF (
        OLD.email != NEW.email -- do nothing if no change
    ) THEN
        RAISE NOTICE 'UPDATE';
        NEW.verified := ...;
    END IF;
        RETURN NEW;
    END; $$ language 'plpgsql';
    
    CREATE TRIGGER reset_verified BEFORE UPDATE OF email ON accounts
    FOR EACH ROW
    WHEN (OLD.email != NEW.email) -- only when email changed
    EXECUTE PROCEDURE fn_reset_verified();

    但是,没有逻辑可以确定在触发器内部将NEW.verified 设置为什么。问题是,NEW 变量保存了新行的所有列的值, 设置了具有新值的列,而不仅仅是那些被命令修改的值。所以如果NEW.verified = true 没有办法知道调用触发器的命令是否是:

    UPDATE accounts SET email = 'newemail@email.com', verified = true WHERE id = 1;
    

    UPDATE accounts SET email = 'newemail@email.com' WHERE id = 1;
    

    所以NEW.verified 可以引用旧的电子邮件地址或新的电子邮件地址,在UPDATE 命令中专门标记为已验证。

    你唯一的选择是改变你的逻辑:如果电子邮件地址改变了,之后总是需要验证,所以NEW.verified = false

    【讨论】:

    • 感谢您使用 'NEW.verified := ' 而不是再次调用更新。仅当验证不在 sql 语句中时才需要触发 fn_reset_verified 的原因是因为允许某些管理员用户跳过电子邮件验证。我可以考虑其他解决方法来使其正常工作。创建这个问题是因为我是 pgsql 的新手(以前使用 mysql),因此我想确认 pgsql 中是否存在像“Statement”这样的对象。无论如何感谢您的回答。
    猜你喜欢
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2014-10-10
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    相关资源
    最近更新 更多