could do this with a more complex trigger function, for example:
<programlisting>
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;
</programlisting>
The trigger definition is the same as before.
Note that each <literal>IF</literal> test must exactly match the
<literal>CHECK</literal> constraint for its child table.
</para>
<para>
While this function is more complex than the single-month case,
it doesn't need to be updated as often, since branches can be
added in advance of being needed.
</para>
<note>
<para>
In practice, it might be best to check the newest child first,
if most inserts go into that child. For simplicity, we have
shown the trigger's tests in the same order as in other parts
of this example.
</para>
</note>
<para>
A different approach to redirecting inserts into the appropriate
child table is to set up rules, instead of a trigger, on the
root table. For example:
<programlisting>
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.*);
</programlisting>
A rule has significantly more overhead than a trigger, but the
overhead is paid once per query rather than once per row, so this
method might be advantageous for bulk-insert situations. In most
cases, however, the trigger method will offer better performance.
</para>
<para>
Be aware that <command>COPY</command> ignores rules. If you want to
use <command>COPY</command> to insert data, you'll need to copy into the
correct child table rather than directly into the root. <command>COPY</command>
does fire triggers, so you can use it normally if you use the trigger
approach.
</para>
<para>
Another disadvantage of the rule approach is that there is no simple
way to force an error if the set of rules doesn't cover the insertion
date; the data will silently go into the root table instead.
</para>
</listitem>
<listitem>
<para>
Ensure that the <xref linkend="guc-constraint-exclusion"/>
configuration parameter is not disabled in
<filename>postgresql.conf</filename>; otherwise
child tables may be accessed unnecessarily.
</para>
</listitem>
</orderedlist>
</para>
<para>
As we can see, a complex table hierarchy could require a
substantial amount of DDL. In the above example we would be creating
a new child table each month, so it might be wise to write a script that
generates the required DDL automatically.
</para>
</sect3>
<sect3 id="ddl-partitioning-inheritance-maintenance">
<title>Maintenance for Inheritance Partitioning</title>
<para>
To remove old data