我们希望我们的应用程序能够说 INSERT INTO measurement ...,并且数据能够被重定向到合适的子表。我们可以通过将合适的触发器函数附加到根表来实现。如果数据只添加到最新的子表中,我们可以使用非常简单的触发器函数:

CREATE OR REPLACE FUNCTION measurement_insert_trigger()

RETURNS TRIGGER AS $$

BEGIN

INSERT INTO measurement_y2008m01 VALUES (NEW.*);

RETURN NULL;

END;

$$

LANGUAGE plpgsql;

创建函数后,我们创建一个调用触发器函数的触发器:

CREATE TRIGGER insert_measurement_trigger

BEFORE INSERT ON measurement

FOR EACH ROW EXECUTE FUNCTION measurement_insert_trigger();

我们必须每月重新定义触发器函数,以便它始终插入到当前的子表中。但不需要更新触发器定义。

我们可能希望插入数据,并让服务器自动找到应将行添加到的子表。我们可以通过一个更复杂的触发器函数来实现,例如:

CREATE OR REPLACE FUNCTION measurement_insert_trigger()

RETURNS TRIGGER AS $$

BEGIN

IF ( NEW.logdate >= DATE '2006-02-01' AND

NEW.logdate < DATE '2006-03-01' ) THEN

INSERT INTO measurement_y2006m02 VALUES (NEW.*);

ELSIF ( NEW.logdate >= DATE '2006-03-01' AND

NEW.logdate < DATE '2006-04-01' ) THEN

INSERT INTO measurement_y2006m03 VALUES (NEW.*);

...

ELSIF ( NEW.logdate >= DATE '2008-01-01' AND

NEW.logdate < DATE '2008-02-01' ) THEN

INSERT INTO measurement_y2008m01 VALUES (NEW.*);

ELSE

RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';

END IF;

RETURN NULL;

END;

$$

LANGUAGE plpgsql;

触发器定义与之前相同。请注意,每个 IF 测试必须与子表的 CHECK 约束精确匹配。

虽然这个函数比单月情况更复杂,但它不需要经常更新,因为可以提前添加分支以备需要。

注意

实际上,如果大多数插入都进入最新的子表,最好先检查最新的子表。为了简单起见,我们在示例的其他部分中以相同的顺序显示了触发器的测试。

将插入重定向到合适子表的另一种方法是在根表上设置规则,而不是触发器。例如:

CREATE RULE measurement_insert_y2006m02 AS

ON INSERT TO measurement WHERE

( logdate >= DATE '2006-02-01' AND logdate < DATE '2006-03-01' )

DO INSTEAD

INSERT INTO measurement_y2006m02 VALUES (NEW.*);

...

CREATE RULE measurement_insert_y2008m01 AS

ON INSERT TO measurement WHERE

( logdate >= DATE '2008-01-01' AND logdate < DATE '2008-02-01' )

DO INSTEAD

INSERT INTO measurement_y2008m01 VALUES (NEW.*);

规则比触发器具有显著的额外开销,但开销是每个查询支付一次,而不是每行支付一次,因此此方法可能在批量插入情况下有利。但在大多数情况下,触发器方法将提供更好的性能。

请注意,COPY 会忽略规则。如果您想使用 COPY 插入数据,您需要将数据复制到正确的子表中,而不是直接复制到根表中。COPY 会触发触发器,因此如果您使用触发器方法,您可以正常使用它。

规则方法的另一个缺点是,没有简单的方法可以在规则集未涵盖插入日期时强制执行错误;数据将默默地进入根表。