¾�ΥС�������ʸ�� �� 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

38.9. �ȥꥬ�ץ���������

PL/pgSQL�ϥȥꥬ�ץ��������������˻��ѤǤ��ޤ��� �ȥꥬ�ץ���������ϡ�CREATE FUNCTION���ޥ�ɤ�Ȥäơ�trigger�Ȥ�������ͤη�����ä������Τʤ��ؿ��Ȥ��ƺ�������ޤ��� ���δؿ��ϡ����Ȥ���CREATE TRIGGER�ˤư��������ΤȤ��Ƥ����Ȥ��Ƥ⡢����������ʤ���Τ�������ʤ���Фʤ�ޤ��� �ȥꥬ�ΰ����ϡ���Ҥ����̤ꡢTG_ARGV��ͳ���Ϥ���ޤ���

PL/pgSQL�ؿ����ȥꥬ�Ȥ��ƸƤӽФ��줿��硢�����Ĥ����ü���ѿ�����ưŪ�˺Ǿ�̥�٥�Υ֥��å��Ǻ�������ޤ��� ������ʲ��˼����ޤ���

NEW

RECORD�ǡ������� �����ѿ��Ϲԥ�٥�Υȥꥬ�Ǥ�INSERT/UPDATE���ˤ�äƹ������줿���������ǡ����١����ιԤ��ݻ����ޤ��� �����ѿ���ʸ��٥�Υȥꥬ�Ǥ�NULL�Ǥ���

OLD

RECORD�ǡ������� �����ѿ��ϡ��ԥ�٥�Υȥꥬ�Ǥ�UPDATE/DELETE���ˤ�äƹ�����������Υǡ����١����ιԤ��ݻ����ޤ��� �����ѿ���ʸ��٥�Υȥꥬ�Ǥ�NULL�Ǥ���

TG_NAME

name�ǡ������� �ºݤ�ȯ�Ԥ��줿�ȥꥬ��̾��������ѿ���

TG_WHEN

text�ǡ������� �ȥꥬ������˰�¸����BEFORE�ޤ���AFTER�Ȥ���ʸ����

TG_LEVEL

text�ǡ������� �ȥꥬ������˰�¸����ROW�ޤ���STATEMENT�Ȥ���ʸ����

TG_OP

text�ǡ������� �ȥꥬ��ȯ�Ԥ������򼨤���INSERT��UPDATE�ޤ���DELETE�Ȥ���ʸ����

TG_RELID

oid�ǡ������� ���Υȥꥬ�θƤӽФ����ˤʤ�ơ��֥�Υ��֥�������ID��

TG_RELNAME

name�ǡ������� ���Υȥꥬ�θƤӽФ����ˤʤ�ơ��֥��̾���� ���褳����ѻߤ��줽���Ǥ��� �����TG_TABLE_NAME����Ѥ��Ƥ���������

TG_TABLE_NAME

name�ǡ������� ���Υȥꥬ�θƤӽФ����ˤʤ�ơ��֥��̾����

TG_TABLE_SCHEMA

name�ǡ������� ���Υȥꥬ�θƤӽФ����ˤʤ�ơ��֥�Υ�������̾��

TG_NARGS

integer���� CREATE TRIGGERʸ�ˤ�����ȥꥬ�ץ����������Ϳ����������ο���

TG_ARGV[]

text�������󷿡� CREATE TRIGGERʸ�Ǥΰ����� ���Υ���ǥå�����0����Ϥޤ�ޤ��� ̵���ʥ���ǥå�����0̤����tg_nargs�ʾ�ˤϡ�NULL�ͤȤ�����̤ˤʤ�ޤ���

�ȥꥬ�ؿ���NULL�ޤ��ϡ��ȥꥬ��ȯ�Ը��ˤʤä��ơ��֥�ι�¤�����Τ˻��ä��쥳����/�Ԥ��֤��ʤ���Фʤ�ޤ���

BEFORE�Ȥ���ȯ�Ԥ��줿�ԥ�٥�ȥꥬ��NULL���֤����ˤϡ��ȥꥬ�ޥ͡�����˼ºݤιԤؤ����������褦�����Τ��ޤ��ʤĤޤꡢ���θ�˥ȥꥬ��ȯ�Ԥ��줺������INSERT/UPDATE/DELETE�Ϥ��ιԤ��Ф��Ƽ¹Ԥ���ޤ���ˡ� ��NULL�ͤ��֤����ˤϡ��������Ϥ��ι��ͤǽ�������ޤ��� ����NEW���ͤȰۤʤ���ͤ��֤����Ȥϡ�����������������ͤ��ѹ����뤳�Ȥ����դ��Ƥ������� �ʤ�������DELETE�ξ���ľ�ܱƶ����ޤ���ˡ� ��Ǽ���٤��Ԥ��ѹ����뤿��ˡ�NEW�θġ����ͤ�ľ���֤�����������NEW���֤����Ȥ⡢�������쥳����/�Ԥ����˺��������֤����Ȥ��ǽ�Ǥ���

ʸ��٥��BEFORE�ޤ���AFTER�ȥꥬ���ԥ�٥��AFTER�ȥꥬ������ͤϾ��̵�뤵��ޤ��� NULL�Ȥ��Ƥ⹽���ޤ��� �������������μ���Υȥꥬ�Ǥ⡢���顼��ȯ�������뤳�Ȥ�������Τ����Ǥ����뤳�Ȥ���ǽ�Ǥ���

例38-2��PL/pgSQL�Υȥꥬ�ؿ�����򼨤��ޤ���

例 38-2. PL/pgSQL�ȥꥬ�ץ���������

���Υȥꥬ����Ǥϡ��ơ��֥�ιԤ������ޤ��Ϲ������줿���ˤ�ɬ�������ߤΥ桼��̾�Ȼ��郎���ιԤ����äƤ��뤳�Ȥ�μ¤ˤ��ޤ��� �����ơ����Ȱ�̾��Ϳ�����Ƥ��뤳�ȤȤ��ε����������ͤǤ��뤳�Ȥ��ǧ���ޤ���

CREATE TABLE emp (
    empname text,
    salary integer,
    last_date timestamp,
    last_user text
);

CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
    BEGIN
        -- empname��salary��Ϳ�����Ƥ��뤳�Ȥ�����å�
        IF NEW.empname IS NULL THEN
            RAISE EXCEPTION 'empname cannot be null';
        END IF;
        IF NEW.salary IS NULL THEN
            RAISE EXCEPTION '% cannot have null salary', NEW.empname;
        END IF;

        -- ��ʧ�������꤬������ʤ��褦��
        IF NEW.salary < 0 THEN
            RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
        END IF;

        -- ï�������ѹ���������Ͽ
        NEW.last_date := current_timestamp;
        NEW.last_user := current_user;
        RETURN NEW;
    END;
$emp_stamp$ LANGUAGE plpgsql;

CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
    FOR EACH ROW EXECUTE PROCEDURE emp_stamp();

�ơ��֥�ˤ������ѹ��Υ�������¾����ˡ�ϡ������������ޤ��Ϻ���γơ����Ф���Ԥ���ͭ���뿷�ơ��֥��������뤳�ȤǤ��� ������ˡ�ϥơ��֥�ˤ������ѹ��δƺ��ȹͤ��뤳�Ȥ��Ǥ��ޤ���

例38-3��PL/pgSQL�ˤ��ƺ��ѥȥꥬ�ץ���������ΰ���򼨤��ޤ���

例 38-3. PL/pgSQL�ˤ�� �ƺ��ѤΥȥꥬ�ץ���������

���Υȥꥬ����Ǥϡ�emp�ơ��֥�ˤ�����Ԥ������������ޤ��Ϻ���Τɤ�⤬emp_audit�ơ��֥����سμ¤˵�Ͽ�ʤ��ʤ���ƺ��ˤ���ޤ��� ���߻���ȥ桼��̾�ϡ��Ԥä����μ���ȤȤ��emp_audit�ιԤ�����ǹ蘆��ޤ���

CREATE TABLE emp (
    empname           text NOT NULL,
    salary            integer
);

CREATE TABLE emp_audit( 
    operation         char(1)   NOT NULL,
    stamp             timestamp NOT NULL,
    userid            text      NOT NULL,
    empname           text      NOT NULL,
    salary integer
);

CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
    BEGIN
        --
		-- emp�ǹԤä�����ȿ�Ǥ���Ԥ�emp_audit�˺���
		-- ���μ������ꤹ�뤿��ˡ��ü���ѿ�TG_OP�����
        --
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO emp_audit SELECT 'D', now(), user, OLD.*;
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO emp_audit SELECT 'U', now(), user, NEW.*;
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*;
            RETURN NEW;
        END IF;
        RETURN NULL; -- AFTER�ȥꥬ�Ǥ��Τǡ���̤�̵�뤵��ޤ�
    END;
$emp_audit$ LANGUAGE plpgsql;

CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
    FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();

�ȥꥬ�λ�����Ū��1�Ĥϡ�����ơ��֥�Υ��ޥ�ơ��֥�ʥǡ�����ȴ�褷���ơ��֥�ˤ�ݻ����뤳�ȤǤ��� ���ޥ�ơ��֥�ϡ����Υơ��֥�����äơ��������䤤��碌���Ф��ƻ��ѤǤ������Ф��м¹Ի��֤������˽̾����ޤ��� �̾盧�μ�ˡ�ϥǡ����������ϥ����˻��Ѥ��졢��¬�ޤ��ϴ�¬�ǡ����ʥե����ȥơ��֥�ȸ����ޤ��ˤ������礭�����뤳�Ȥ��Ǥ��ޤ��� �ǡ����������ϥ�����Υե����ȥơ��֥���Ф��ƥ��ޥ�ơ��֥��ݻ�����PL/pgSQL�Υȥꥬ�ץ�������������例38-4�˼����ޤ���

例 38-4. ���ޥ�ơ��֥��ݻ����뤿���PL/pgSQL�ȥꥬ�ץ���������

�����˽Ҥ٤륹�����ޤΰ�����Ralph Kimball�ˤ��The Data Warehouse Toolkit��Grocery Store����˴�Ť��Ƥ��ޤ���

--
-- time dimension��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);

--
-- 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);

--
-- ��������������Ӻ���ˤ�ꥵ�ޥ�ơ��֥�����������ؿ��ȥȥꥬ
--
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

        -- ���äޤ��ϸ����̤򻻽�
        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

            -- time_key���ѹ����빹����ػߤ��ޤ�
            -- �ʺ�� + ��������ˡ�ˤ������ʬ���ѹ���Ԥ�����
            -- ����ۤ����ǤϤ���ޤ���ˡ�
            IF ( OLD.time_key != NEW.time_key) THEN
                RAISE EXCEPTION 'Update of time_key : % -> % not allowed', OLD.time_key, NEW.time_key;
            END IF;

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

        ELSIF (TG_OP = 'INSERT') THEN

            delta_time_key = NEW.time_key;
            delta_amount_sold = NEW.amount_sold;
            delta_units_sold = NEW.units_sold;
            delta_amount_cost = NEW.amount_cost;

        END IF;


        -- ���ޥ�ơ��֥�ιԤ������ޤ��Ͽ������ͤǹ������ޤ���
        <<insert_update>>
        LOOP
            UPDATE sales_summary_bytime
                SET amount_sold = amount_sold + delta_amount_sold,
                    units_sold = units_sold + delta_units_sold,
                    amount_cost = amount_cost + delta_amount_cost
                WHERE time_key = delta_time_key;

            EXIT insert_update WHEN found;

            BEGIN
                INSERT INTO sales_summary_bytime (
                            time_key, 
                            amount_sold, 
                            units_sold, 
                            amount_cost)
                    VALUES ( 
                            delta_time_key,
                            delta_amount_sold,
                            delta_units_sold,
                            delta_amount_cost
                           );

                EXIT insert_update;

            EXCEPTION

                WHEN UNIQUE_VIOLATION THEN
                    -- ���⤷�ޤ���
            END;
        END LOOP insert_update;

        RETURN NULL;

    END;
$maint_sales_summary_bytime$ LANGUAGE plpgsql;

CREATE TRIGGER maint_sales_summary_bytime
AFTER INSERT OR UPDATE OR DELETE ON sales_fact
    FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();

INSERT INTO sales_fact VALUES(1,1,1,10,3,15);
INSERT INTO sales_fact VALUES(1,2,1,20,5,35);
INSERT INTO sales_fact VALUES(2,2,1,40,15,135);
INSERT INTO sales_fact VALUES(2,3,1,10,1,13);
SELECT * FROM sales_summary_bytime;
DELETE FROM sales_fact WHERE product_key = 1;
SELECT * FROM sales_summary_bytime;
UPDATE sales_fact SET units_sold = units_sold * 2;
SELECT * FROM sales_summary_bytime;