| PostgreSQL 8.3.3¹®¼ | ||||
|---|---|---|---|---|
| Prev | Fast Backward | Chapter 37. PL/pgSQL - SQL¼ö¼Ó ¾ð¾î | Fast Forward | Next |
PL/pgSQL´Â Æ®¸®°Å ÇÁ·Î½ÃÀúÀÇ Á¤ÀÇ¿¡ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù. Æ®¸®°Å ÇÁ·Î½ÃÀú´Â, CREATE FUNCTION¸í·ÉÀ» »ç¿ëÇØ, trigger¶ó´Â ¹Ýȯ°ªÀÇ ÇüŸ¦ °¡Áø ÀÎÀÚ°¡ ¾ø´Â ÇÔ¼ö·Î¼ ÀÛ¼ºµË´Ï´Ù. ±× ÇÔ¼ö´Â, ºñ·Ï, CREATE TRIGGER¿¡¼ ÀÎÀÚ¸¦ ÃëÇϰí ÀÖ¾ú¾îµµ, ÀÎÀÚ¸¦ °¡ÁöÁö ¾Ê´Â °ÍÀÌ ¼±¾ðµÇ¾î¾ß ÇÕ´Ï´Ù. Æ®¸®°ÅÀÇ ÀÎÀÚ´Â, Èļú ÇÏ´Â ´ë·Î, TG_ARGV¸¦ ÅëÇØ °Ç³×¹Þ½À´Ï´Ù.
PL/pgSQLÇÔ¼ö°¡ Æ®¸®°Å·Î¼ ºÒ·Á °¬À» °æ¿ì, ¸î°³ÀÇ Æ¯¼öÇÑ º¯¼ö°¡ ÀÚµ¿ÀûÀ¸·Î ÃÖ»ó ·¹º§ÀÇ ºí·ÏÀ¸·Î ÀÛ¼ºµË´Ï´Ù. ±×°ÍµéÀ» ÀÌÇÏ¿¡ ³ªÅ¸³À´Ï´Ù.
RECORDµ¥ÀÌÅÍÇü. ÀÌ º¯¼ö´Â Çà ·¹º§ÀÇ Æ®¸®°Å¿¡¼ÀÇ INSERT/UPDATEÁ¶ÀÛ¿¡ ÀÇÇØ °»½ÅµÈ, »õ·Î¿î µ¥ÀÌÅͺ£À̽ºÀÇ ÇàÀ» º¸°ü À¯ÁöÇÕ´Ï´Ù. ÀÌ º¯¼ö´Â ¸í·É¹® ·¹º§ÀÇ Æ®¸®°Å¿¡¼´Â NULLÀÔ´Ï´Ù.
RECORDµ¥ÀÌÅÍÇü. ÀÌ º¯¼ö´Â, Çà ·¹º§ÀÇ Æ®¸®°Å¿¡¼ÀÇ UPDATE/DELETEÁ¶ÀÛ¿¡ ÀÇÇØ °»½ÅµÇ±â ÀüÀÇ µ¥ÀÌÅͺ£À̽ºÀÇ ÇàÀ» º¸°ü À¯ÁöÇÕ´Ï´Ù. ÀÌ º¯¼ö´Â ¸í·É¹® ·¹º§ÀÇ Æ®¸®°Å¿¡¼´Â NULLÀÔ´Ï´Ù.
nameµ¥ÀÌÅÍÇü. ½ÇÁ¦·Î ¹ßÇàµÈ Æ®¸®°ÅÀÇ À̸§À» °¡Áö´Â º¯¼ö.
textµ¥ÀÌÅÍÇü. Æ®¸®°ÅÀÇ Á¤ÀÇ¿¡ ÀÇÁ¸ÇÑ BEFORE ¶Ç´Â AFTER¶ó´Â ¹®ÀÚ¿.
textµ¥ÀÌÅÍÇü. Æ®¸®°ÅÀÇ Á¤ÀÇ¿¡ ÀÇÁ¸ÇÑ ROW ¶Ç´Â STATEMENT¶ó´Â ¹®ÀÚ¿.
textµ¥ÀÌÅÍÇü. Æ®¸®°Å¸¦ ¹ßÇàÇÑ Á¶ÀÛÀ» ³ªÅ¸³»´Â, INSERT, UPDATE ¶Ç´Â DELETE¶ó´Â ¹®ÀÚ¿.
oidµ¥ÀÌÅÍÇü. ÀÌ Æ®¸®°Å È£ÃâÀÇ ±â¿øÀÌ µÇ´Â Å×À̺íÀÇ °´Ã¼ ID.
nameµ¥ÀÌÅÍÇü. ÀÌ Æ®¸®°Å È£ÃâÀÇ ±â¿øÀÌ µÇ´Â Å×À̺íÀÇ À̸§. ÇâÈÄ, À̰ÍÀº ÆóÁöµÉ °Í °°½À´Ï´Ù. ´ë½Å¿¡ TG_TABLE_NAME¸¦ »ç¿ëÇØ ÁÖ¼¼¿ä.
nameµ¥ÀÌÅÍÇü. ÀÌ Æ®¸®°Å È£ÃâÀÇ ±â¿øÀÌ µÇ´Â Å×À̺íÀÇ À̸§.
nameµ¥ÀÌÅÍÇü. ÀÌ Æ®¸®°Å È£ÃâÀÇ ±â¿øÀÌ µÇ´Â Å×À̺íÀÇ ½ºÅ°¸¶¸í.
integerÇü. CREATE TRIGGER¹®¿¡¼ÀÇ Æ®¸®°Å ÇÁ·Î½ÃÀú¿¡°Ô ÁÙ ¼ö ÀÖ´Â ÀÎÀÚÀÇ ¼ö.
textÇüÀÇ ¹è¿Çü. CREATE TRIGGER¹®¿¡¼ÀÇ ÀÎÀÚ. ÀÌ À妽º´Â 0À¸·ÎºÎÅÍ ½ÃÀ۵˴ϴÙ. ¹«È¿ÀÎ À妽º(0 ¹Ì¸¸À̳ª tg_nargsÀÌ»ó)´Â, NULL°ªÀ̶ó´Â °á°ú°¡ µË´Ï´Ù.
Æ®¸®°Å ÇÔ¼ö´Â NULL ¶Ç´Â, Æ®¸®°ÅÀÇ ±Ù¿øÀÌ µÈ Å×À̺íÀÇ ±¸Á¶¸¦ Á¤È®ÇÏ°Ô °¡Áø ·¹ÄÚµå/ÇàÀ» µ¹·ÁÁÖ¾î¾ß ÇÕ´Ï´Ù.
BEFORE·Î¼ ¹ßÇàµÈ Çà level trigger°¡ NULL¸¦ µ¹·ÁÁÖ´Â °æ¿ì¿¡´Â, Æ®¸®°Å °ü¸®ÀÚ¿¡ ½ÇÁ¦ÀÇ Çà¿¡ÀÇ Á¶ÀÛÀ» Ãë¼ÒÇϵµ·Ï ÅëÁöÇÕ´Ï´Ù (Áï, ±× ÈÄ¿¡ Æ®¸®°Å°¡ ¹ßÇàµÇÁö ¾Ê°í, ±× INSERT/UPDATE/DELETE´Â ±× Çà¿¡ ´ëÇØ¼ ½ÇÇàµÇÁö ¾Ê½À´Ï´Ù). ºñNULL°ªÀ» µ¹·ÁÁÖ´Â °æ¿ì¿¡´Â, ±× Á¶ÀÛÀº ±× Çà°ªÀ¸·Î 󸮵˴ϴÙ. ¿ø·¡ÀÇ NEWÀÇ °ª°ú ´Ù¸¥ Çà°ªÀ» µ¹·ÁÁÖ´Â °ÍÀº, »ðÀÔ, °»½ÅµÇ´Â °ªÀ» º¯°æÇÏ´Â °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä (±×·¯³ª, DELETEÀÇ °æ¿ì´Â Á÷Á¢ ¿µÇâÀ» ÁÖÁö ¾Ê½À´Ï´Ù). ÀúÀåÇØ¾ß ÇÒ ÇàÀ» º¯°æÇϱâ À§Çؼ, NEWÀÇ °³°³ÀÇ °ªÀ» Á÷Á¢ ¿Å°Ü³õ°í NEW¸¦ µ¹·ÁÁÖ´Â Àϵµ, »õ·Î¿î ·¹ÄÚµå/ÇàÀ» ¿ÏÀüÇÏ°Ô ÀÛ¼ºÇØ µ¹·ÁÁÖ´Â Àϵµ °¡´ÉÇÕ´Ï´Ù.
¸í·É¹® ·¹º§ÀÇ BEFORE ¶Ç´Â AFTERÆ®¸®°Å, Çà ·¹º§ÀÇ AFTERÆ®¸®°ÅÀÇ ¹Ýȯ°ªÀº Ç×»ó ¹«½ÃµË´Ï´Ù. NULL¶ó°í ÇØµµ »ó°üÇÏÁö ¾Ê½À´Ï´Ù. ±×·¯³ª, ÀÌ·¯ÇÑ Á¾·ùÀÇ Æ®¸®°Å·Î, ¿¡·¯¸¦ ¹ß»ý½ÃÄÑ Á¶ÀÛ Àüü¸¦ ÁߴܽÃŰ´Â °ÍÀÌ °¡´ÉÇÕ´Ï´Ù.
Example 37-2¿¡ PL/pgSQLÀÇ Æ®¸®°Å ÇÔ¼öÀÇ ¿¹¸¦ ³ªÅ¸³À´Ï´Ù.
Example 37-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();
Å×ÀÌºí¿¡ ÀÖ¾î¼ÀÇ º¯°æÀÇ ·Î±×¸¦ ÃëÇÏ´Â ´Ù¸¥ ¹æ¹ýÀº, »ðÀÔ, °»½Å ¶Ç´Â »èÁ¦ÀÇ °¢°¢¿¡ ´ëÇÑ ÇàÀ» º¸À¯ÇÏ´Â »õ Å×À̺íÀ» ÀÛ¼ºÇÏ´Â °ÍÀÔ´Ï´Ù. ÀÌ ¹æ¹ýÀº Å×ÀÌºí¿¡¼ÀÇ º¯°æÀÇ °¨»ç¶ó°í »ý°¢ÇÒ ¼ö ÀÖ½À´Ï´Ù. Example 37-3´Â PL/pgSQL¿¡ ÀÇÇÑ °¨»ç Æ®¸®°Å ÇÁ·Î½ÃÀúÀÇ ÀϷʸ¦ ³ªÅ¸³À´Ï´Ù.
Example 37-3. A 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();
Æ®¸®°ÅÀÇ »ç¿ë ¸ñÀûÀÇ Çϳª´Â, ¾î´À Å×À̺íÀÇ ¿ä¾à Å×À̺í(µ¥ÀÌÅ͸¦ ¹ßÃéÇÑ Å×À̺í)À» À¯ÁöÇÏ´Â °ÍÀÔ´Ï´Ù. ¿ä¾à Å×À̺íÀº, ¿ø·¡ÀÇ Å×ÀÌºí¿¡ ´ë½ÅÇØ, ƯÁ¤ Á¾·ùÀÇ Äõ¸®¿¡ ´ëÇØ¼ »ç¿ëÇÒ ¼ö ÀÖ¾î Á¾Á¾ ½ÇÇà ½Ã°£À» Å«ÆøÀ¸·Î Ãà¼ÒÇÕ´Ï´Ù. Åë»ó ÀÌ ¹æ¹ýÀº µ¥ÀÌÅÍ µµ¸Å»ó¿¡ »ç¿ëµÇ¾î ÃøÁ¤ ¶Ç´Â °üÃø µ¥ÀÌÅÍ(ÆÑÆ® Å×À̺íÀ̶ó°í ¸»ÇÕ´Ï´Ù)¸¦ ¸Å¿ì Å©°Ô ÇÒ ¼ö ÀÖ½À´Ï´Ù. µ¥ÀÌÅÍ ¿þ¾îÇϿ콺 ³»ÀÇ ÆÑÆ® Å×ÀÌºí¿¡ ´ëÇØ¼ ¿ä¾à Å×À̺íÀ» À¯ÁöÇÏ´Â PL/pgSQLÀÇ Æ®¸®°Å ÇÁ·Î½ÃÀúÀÇ ¿¹¸¦ Example 37-4¿¡ ³ªÅ¸³À´Ï´Ù.
Example 37-4. A ¿ä¾à Å×À̺íÀ» À¯ÁöÇϱâ À§ÇÑ 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;