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

时间:2016-07-14 11:44:13

标签: postgresql stored-procedures triggers plpgsql

我定义了下面的plpgsql函数(Before trigger)来更新数据,如果提供了一个列,我将从静态数据中获取另一个。但我想知道在给定的" columna"中获取静态数据的最佳方法是什么,我需要得到" columnb"来自static_tbl(更像是字典/地图datastrcuture)。目前我正在查询静态表上的Trigger函数。

我知道我也可以使用case语句而不是查询。请告诉我这里最适合的是什么。 添加测试数据 Say ColumnA包含' a'它将作为'字母A'传播到ColumnB。 否则ColumnB包含'字母A'它将被传播到ColumnA作为' a' 将用于转换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();

2 个答案:

答案 0 :(得分:2)

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

如果您确实需要列和触发器,请修复偷偷摸摸的错误:您声明变量 column_acolumn_b,这些是可见的在功能体到处都是。如果您使用相同的名称column_acolumn_b而没有表格资格,则会产生命名冲突。相关:

您的案例中的解决方案很简单:不要声明变量开头,您没有用它们。一般解决方案是,如果可能存在冲突,始终表限定列名。我实施了两个:

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

存储查找值的另一种方法是enum data type。但我不会将enum用于更多选项,只有在它们几乎没有改变时才会使用Maven>Download Sources。实际上,我更喜欢具有FK约束的查找表。

答案 1 :(得分:0)

我认为使用像这样的表结构创建字典的方法可行,尽管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函数返回其列表中的第一个非null参数。如果所有参数都为NULL,则返回NULL。

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