【问题标题】:Best way to get Static data inside before trigger在触发之前获取静态数据的最佳方法
【发布时间】:2016-07-14 11:44:12
【问题描述】:

我定义了下面的 plpgsql 函数(触发前)来更新数据,如果提供了其中一列,我将从静态数据中获取另一列。但我想知道为给定的“columna”获取静态数据的最佳方法是什么,我需要从 static_tbl 获取“columnb”(更像是字典/地图数据结构)。目前我正在静态表上的 Trigger 函数内部进行查询。

我知道我也可以使用 case 语句来代替查询。请让我知道什么最适合这里。 添加测试数据 说 ColumnA 包含 'a' 它将作为 'Alphabet A' 传播到 ColumnB 否则 ColumnB 包含“字母 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();

【问题讨论】:

  • 这还不清楚。请添加触发器本身,而不仅仅是触发器功能。请添加触发器之前和之后的示例数据。
  • @SMW 添加了触发器定义本身和触发器定义的一些测试样本

标签: postgresql stored-procedures triggers plpgsql


【解决方案1】:

如果column_a 在功能上以稳定的方式依赖于column_b(反之亦然),最好的方法完全存储功能相关的值。即时查看。为了方便起见,可能创建一个视图(或物化视图)。可能使用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 用于多个选项,并且只有在它们几乎不会改变的情况下。实际上,我更喜欢带有 FK 约束的查找表。

【讨论】:

  • 感谢您的 cmets。 1)我不需要 column_a, column_b 声明,我从我的问题中删除了相同的声明 2)为什么我不能使用 Trigger ? (回答:是的,您是正确的,我们可以使用前面提到的视图,但将来,我将保留 column_b(这是新列)并弃用/删除 column_a(旧列)) 3)我真正的问题是还有其他方法可以存储查找数据(类似于python中的字典)。因为我只是想知道是否有更好的方法来存储查找数据。
【解决方案2】:

我认为您使用类似的表结构创建字典的方法会起作用,尽管 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。

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

【讨论】:

  • 感谢您提供的简化建议 :-) 您能给我提供有关如何在 Postgres 中创建类似 dict 的结构并在 PlPgsql 函数中使用相同结构的任何参考吗?
  • 在 postgres 中使用键/值对至少有几个选项。一个是通过hstore:postgresqltutorial.com/postgresql-hstore另一个是通过json:stormatics.com/howto-use-json-functionality-in-postgresql
  • @Shankar:由于(不必要的)命名冲突,此触发函数会产生错误column reference "column_a" is ambiguous。就像原来的一样。这个答案实际上不如原来的,无条件运行 SELECT,这是一种浪费。
猜你喜欢
  • 1970-01-01
  • 2018-09-08
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 2015-10-18
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多