我们希望我们的应用程序能够说 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 会触发触发器,因此如果您使用触发器方法,您可以正常使用它。
规则方法的另一个缺点是,没有简单的方法可以在规则集未涵盖插入日期时强制执行错误;数据将默默地进入根表。