在触发之前获取内部静态数据的最佳方法

Best way to get Static data inside before trigger

我定义了下面的 plpgsql 函数(触发前)来更新数据,如果提供的列之一,我将从静态数据中获取另一列。但我想知道获取给定 "columna" 静态数据的最佳方法是什么,我需要从 static_tbl 获取 "columnb"(更像是字典/地图数据结构)。目前我正在静态 table .

上的 Trigger 函数中查询

我知道我也可以使用 case 语句而不是查询。请让我知道什么最适合这里。 添加测试数据 假设 ColumnA 包含 'a' 它将作为 'Alphabet A' 传播到 ColumnB 否则 ColumnB 包含 'Alphabet A' 它将作为 'a' 传播到 ColumnA。 存储用于将 columnA 值转换为 columnB 值的静态数据的最佳方法是什么?

CREATE FUNCTION update_tblname_column_b () RETURNS TRIGGER AS $$
        BEGIN                                                                        
        IF NEW IS NULL THEN                                                               
            RAISE EXCEPTION 'this function cannot be installed with a DELETE trigger';
    END IF;
    IF NEW.column_b IS NOT NULL AND NEW.column_a IS NULL THEN
        NEW.column_a = (select column_a from static_tbl where column_b = NEW.column_b);
    ELSIF NEW.column_a IS NOT NULL AND NEW.column_b IS NULL THEN
        NEW.column_b = (select column_b from static_tbl where column_b = NEW.column_a);
    END IF;
    RETURN NEW;
    END;

$$ LANGUAGE PLPGSQL;

CREATE TRIGGER populate_column
                            BEFORE INSERT OR UPDATE ON creatives FOR each ROW
                            EXECUTE PROCEDURE update_tblname_column_b();

我认为您使用像这样的 table 结构创建字典的方法可行,尽管 else 子句对我来说不太有意义。您是说 "WHERE column_a = NEW.column_a" 吗?无论如何,这可能会稍微简单一些:

CREATE FUNCTION update_tblname_column_b () RETURNS TRIGGER AS $$
    DECLARE 
        column_a tblname.column_a%TYPE;
        column_b tblname.column_b%TYPE;
    BEGIN                                                                        
        IF NEW IS NULL THEN                                                               
            RAISE EXCEPTION 'this function cannot be installed with a DELETE trigger';
    END IF;

    NEW.column_a = COALESCE(NEW.column_a, (SELECT column_a FROM static_tbl WHERE column_b = NEW.column_b));
    NEW.column_b = COALESCE(NEW.column_b, (SELECT column_b FROM static_tbl WHERE column_a = NEW.column_a));

    RETURN NEW;
END;

$$ LANGUAGE PLPGSQL;

CREATE TRIGGER populate_column
    BEFORE INSERT OR UPDATE ON creatives FOR each ROW
        EXECUTE PROCEDURE update_tblname_column_b();

COALESCE 函数returns 其列表中的第一个非空参数。如果所有参数都是 NULL,那么它 returns NULL。

根据您打算如何使用它,您最好使用 postgres 9.3 及更高版本中的一些新 JSON 功能。这将为您提供另一种创建 key/value 对的方法。

如果 column_a 以 stable 的方式在功能上依赖于 column_b(反之亦然),最佳方式not 来存储功能相关的值。即时查找。也许为了方便起见创建一个视图(或物化视图)。可能通过 FOREIGN KEY 约束确保参照完整性。将查找合并到您的输入逻辑中。那你就不需要触发器了。

如果您确实需要列和触发器,请修复 偷偷摸摸的错误:您声明 变量 column_acolumn_b, 那些在函数体中随处可见。当您使用相同的 名称 column_acolumn_b 而没有 table 限定时,您会产生 命名冲突 .相关:

针对您的情况,解决方案很简单:不要一开始就声明变量,它们对您没有用处。如果可能发生冲突,一般的解决方案是 always table 限定列名。我同时实现了:

CREATE OR REPLACE FUNCTION update_tblname_column_b()
  RETURNS TRIGGER AS $$
BEGIN                                                                        
   IF TG_OP = 'DELETE' THEN
      RAISE EXCEPTION 'This function cannot be used for  DELETE trigger.';
   END IF;

IF NEW.column_b IS NOT NULL AND NEW.column_a IS NULL THEN
   SELECT INTO NEW.column_a  s.column_a
   FROM   static_tbl s
   WHERE  s.column_b = NEW.column_b;

ELSIF NEW.column_a IS NOT NULL AND NEW.column_b IS NULL THEN
   SELECT INTO NEW.column_b  s.column_b
   FROM   static_tbl s
   WHERE  s.column_a = NEW.column_a;
END IF;

RETURN NEW;

END
$$ LANGUAGE plpgsql;

另外,不要检查 NULL 来识别触发器类型,这可能是不正确的极端情况。检查特殊变量 TG_OP 代替:

  • Can a function detect the trigger event type?

另一种存储查找值的方法是 enum data type。但是我不会将 enum 用于多个选项,并且仅当它们几乎不会改变时才使用。实际上,我更喜欢使用 FK 约束的查找 tables。