Home Explore Blog CI



postgresql

58th chunk of `doc/src/sgml/plpgsql.sgml`
ca147687a8c308a1ec0b244de29729d5ba3430aa8ef78ba60000000100000fa0
 RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            UPDATE emp SET salary = NEW.salary WHERE empname = OLD.empname;
            IF NOT FOUND THEN RETURN NULL; END IF;

            NEW.last_updated = now();
            INSERT INTO emp_audit VALUES('U', current_user, NEW.*);
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO emp VALUES(NEW.empname, NEW.salary);

            NEW.last_updated = now();
            INSERT INTO emp_audit VALUES('I', current_user, NEW.*);
            RETURN NEW;
        END IF;
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER emp_audit
INSTEAD OF INSERT OR UPDATE OR DELETE ON emp_view
    FOR EACH ROW EXECUTE FUNCTION update_emp_view();
</programlisting>
   </example>

   <para>
    One use of triggers is to maintain a summary table
    of another table. The resulting summary can be used in place of the
    original table for certain queries &mdash; often with vastly reduced run
    times.
    This technique is commonly used in Data Warehousing, where the tables
    of measured or observed data (called fact tables) might be extremely large.
    <xref linkend="plpgsql-trigger-summary-example"/> shows an example of a
    trigger function in <application>PL/pgSQL</application> that maintains
    a summary table for a fact table in a data warehouse.
   </para>


   <example id="plpgsql-trigger-summary-example">
    <title>A <application>PL/pgSQL</application> Trigger Function for Maintaining a Summary Table</title>

    <para>
     The schema detailed here is partly based on the <emphasis>Grocery Store
     </emphasis> example from <emphasis>The Data Warehouse Toolkit</emphasis>
     by Ralph Kimball.
    </para>

<programlisting>
--
-- Main tables - time dimension and sales fact.
--
CREATE TABLE time_dimension (
    time_key                    integer NOT NULL,
    day_of_week                 integer NOT NULL,
    day_of_month                integer NOT NULL,
    month                       integer NOT NULL,
    quarter                     integer NOT NULL,
    year                        integer NOT NULL
);
CREATE UNIQUE INDEX time_dimension_key ON time_dimension(time_key);

CREATE TABLE sales_fact (
    time_key                    integer NOT NULL,
    product_key                 integer NOT NULL,
    store_key                   integer NOT NULL,
    amount_sold                 numeric(12,2) NOT NULL,
    units_sold                  integer NOT NULL,
    amount_cost                 numeric(12,2) NOT NULL
);
CREATE INDEX sales_fact_time ON sales_fact(time_key);

--
-- Summary table - sales by time.
--
CREATE TABLE sales_summary_bytime (
    time_key                    integer NOT NULL,
    amount_sold                 numeric(15,2) NOT NULL,
    units_sold                  numeric(12) NOT NULL,
    amount_cost                 numeric(15,2) NOT NULL
);
CREATE UNIQUE INDEX sales_summary_bytime_key ON sales_summary_bytime(time_key);

--
-- Function and trigger to amend summarized column(s) on UPDATE, INSERT, DELETE.
--
CREATE OR REPLACE FUNCTION maint_sales_summary_bytime() RETURNS TRIGGER
AS $maint_sales_summary_bytime$
    DECLARE
        delta_time_key          integer;
        delta_amount_sold       numeric(15,2);
        delta_units_sold        numeric(12);
        delta_amount_cost       numeric(15,2);
    BEGIN

        -- Work out the increment/decrement amount(s).
        IF (TG_OP = 'DELETE') THEN

            delta_time_key = OLD.time_key;
            delta_amount_sold = -1 * OLD.amount_sold;
            delta_units_sold = -1 * OLD.units_sold;
            delta_amount_cost = -1 * OLD.amount_cost;

        ELSIF (TG_OP = 'UPDATE') THEN

            -- forbid updates that change the time_key -
            -- (probably not too onerous, as DELETE + INSERT is how most
            -- changes will be made).
            IF ( OLD.time_key != NEW.time_key) THEN
                RAISE EXCEPTION 'Update of time_key : % -&gt; % not allowed',
                         

Title: PL/pgSQL Trigger Example: Maintaining a Summary Table for Data Warehousing
Summary
This section introduces another practical use of triggers: maintaining a summary table of another table, commonly used in data warehousing. The resulting summary table can significantly reduce query run times compared to querying the original table. The example details the schema for a sales fact table and a summary table (sales by time), along with a trigger function that automatically updates the summary table when changes (inserts, updates, or deletes) occur in the fact table. It aims to demonstrate how triggers can be employed to efficiently maintain summarized data for reporting and analytical purposes.