今天遇到一个问题,需要在Postgresql里面写做一个trigger,是在insert的时候,如果这条数据的某个字段满足一定条件,就修改数据或者做相应的处理。在pg里面写触发器,分为两个步骤。第一,需要先建触发器函数。第二,需要创建触发器,然后指定相应的触发条件以及选择触发函数。
1,写触发器函数。
因为pg可以用Python来扩展,而我又是写Python的,所以很自然想到的就是用Python来写触发器函数。以下是一段示例代码:
CREATE OR REPLACE FUNCTION p() RETURNS trigger AS
$BODY$
if TD['new']['type'] == 'S':
TD['new']['remark'] = 'by python'
return 'MODIFY'
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
Python的代码夹在两个$BODY$中间,是正常不过的Python代码了。同样也是分行,缩进,懂Python的代码一看就知道,并不复杂。只是这里需要留意的是这里有一个特殊的变量叫TD。这个TD变量,是plpython自带的变量,它包含了很多对编写Python函数有用的参数。而TD['new']代表的就是引起触发器工作的那一条新增的记录,同样TD['old']就代表被update的原始旧的记录。而每一条记录可以通过以column_name为key,去存取记录里面对应的值。例如TD['new']['type']就是这一行记录里面type这一列的数据。上面的例子的意思就是说,如果新插入的这条记录的 type 这列值为 'S'的话,就修改这一列的 remark 为'by python'。最后还有注意一点的就是那个返回值。官方的文档是这样说的:
If TD["when"] is BEFORE or INSTEAD OF and TD["level"] is ROW, you can return None or "OK" from the Python function to indicate the row is unmodified, "SKIP" to abort the event, or if TD["event"] is INSERT or UPDATE you can return "MODIFY" to indicate you've modified the new row. Otherwise the return value is ignored.
意思就是说,如果TD['when']是 BEFORE 或者 INSTEAD OF,并且TD['level']是 ROW的时候,你可以返回None或者OK来表示你未对这条记录做任何修改,如果返回的是SKIP,那么pg就是忽略这个操作,也就是不会插入或者修改了。如果TD['event']是INSERT或者是UPDATE的话,你需要返回MODIFY来告诉pg,你修改了记录,让pg用你修改过的记录来更新数据库。如果你返回其它的值,pg都会忽略你对该记录的操作,还是用原来的新增或修改的记录来更新数据库。
2.创建触发器
使用pgAdmin很直观很容易就可以创建一个触发器,下图是例子:
这里主要是注意“行触发器”,和“约束触发”。“约束触发”是指当插入或者修改的记录在不满足某一个约束的时候触发的,这种情况要结合到当前该表的约束设定,会稍为复杂一些。我们这里选择的是“行触发器”。下面的触发器函数就是之前我们用Python写的那个函数,它是在public下面的,所以全部的数据库都可以使用。当然你也可以把你的触发器函数定义一个使用范围,不设成是public的,那么其它数据库也就不能使用到,从而不同数据库就不会搞混,或者冲突。事件,就是指这个触发器启动的情况,也就是上面提到的TD['event']。可以是INSERT,UPDATE,DELETE中的一个或多个。以下是上面配置对应的SQL:
CREATE TRIGGER "A"
BEFORE INSERT
ON system_log
FOR EACH ROW
EXECUTE PROCEDURE p();
然后触发器就创建好了,就安静地等着它工作吧。
关于触发器的内容,今天就先写到这里,以后有更深入探究,再跟大家分享。
http://www.postgresql.org/docs/9.1/static/plpython-trigger.html
谢谢