Official PostgreSQL 8.3 PL/pgSQL Documentation URL: http://www.postgresql.org/docs/8.3/static/plpgsql.
html
We cover only a subset of what we feel are the most useful constructs that we could squash in a single cheatsheet page
commonly used 1
New in this release.
FUNCTION CACHING RETURN constructs
IMMUTABLE RETURN somevariable
STABLE RETURN NEXT rowvariable
VOLATILE RETURN QUERY 1
CONTROL FLOW RAISE FAMILY
FOR i IN 1 ... numtimes LOOP RAISE DEBUG[1-5]
statements RAISE EXCEPTION
END LOOP; RAISE INFO
RAISE LOG
FOR i IN REVERSE numtimes ... 1 LOOP RAISE NOTICE
statements EXCEPTION Handling
END LOOP;
RAISE EXCEPTION 'Exception notice: %', var
FOR var_e IN EXECUTE('somedynamicsql') LOOP EXCEPTION
statements WHEN condition THEN
RETURN NEXT var_e; do something or
END LOOP; leave blank to ignore
END;
FOR var_e IN somesql LOOP
COMMON States and ERROR constants
statements
RETURN NEXT var_e; FOUND
END LOOP; ROW_COUNT
division_by_zero
IF condition THEN no_data_found
: too_many_rows
END IF; unique_violation
Variable Setting
IF condition THEN
: DECLARE
ELSE somevar sometype := somevalue;
: somevar sometype
END IF; curs1 refcursor;
curs2 CURSOR FOR SELECT * FROM sometable;
IF condition. THEN
: somevar := somevalue
ELSIF condition THEN
: SELECT field1, field2
ELSE INTO somevar1, somevar2
: FROM sometable WHERE .. LIMIT 1;
END IF;
Return types
WHILE condition LOOP RETURNS somedatatype
: RETURNS SETOF somedatatype
END LOOP; RETURNS refcursor
RETURNS trigger
LOOP RETURNS void
-- some computations
EXIT WHEN count > 100; QUALIFIERS
CONTINUE WHEN count < 50;
SECURITY DEFINER
-- some computations for count IN [50 .. 100]
STRICT
END LOOP;
COST cost_metric 1
ROWS est_num_rows 1
PLPGSQL FUNCTION SAMPLES
CREATE OR REPLACE FUNCTION fn_test(param_arg1 integer, param_arg2 text) --Perform action --
RETURNS text AS CREATE OR REPLACE FUNCTION cp_updatesometable(param_id bigint,
$$ param_lname varchar(50), param_fname varchar(50))
DECLARE RETURNS void AS
var_a integer := 0; $$
var_b text := 'test test test'; BEGIN
BEGIN UPDATE people SET first_name = param_fname, last_name = param_lname
RAISE NOTICE 'Pointless example to demonstrate a point'; WHERE name_key = param_id;
RETURN var_b || ' - ' || END;
CAST(param_arg1 As text) || ' - ' $$
|| param_arg2; LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
END
$$ --Sample logging trigger taken from docs
LANGUAGE 'plpgsql' STABLE; CREATE TABLE emp_audit(
operation char(1) NOT NULL,
SELECT fn_test(10, 'test'); stamp timestamp NOT NULL,
userid text NOT NULL,
--Example to RETURN QUERY -- empname text NOT NULL,
CREATE OR REPLACE FUNCTION fnpgsql_get_peoplebylname_key(param_lname text) salary integer
RETURNS SETOF int AS );
$$ CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $$
BEGIN BEGIN
RETURN QUERY SELECT name_key -- Create a row in emp_audit to reflect the operation performed on emp,
FROM people WHERE last_name LIKE param_lname; -- make use of the special variable TG_OP to work out the operation.
END IF (TG_OP = 'DELETE') THEN
$$ INSERT INTO emp_audit SELECT 'D', now(), current_user, OLD.*;
LANGUAGE 'plpgsql' STABLE; RETURN OLD;
--Example using dynamic query -- ELSIF (TG_OP = 'UPDATE') THEN
CREATE OR REPLACE FUNCTION cp_addtextfield(param_schema_name text, param_table_name text, INSERT INTO emp_audit SELECT 'U', now(), current_user, NEW.*;
param_column_name text) RETURN NEW;
RETURNS text AS ELSIF (TG_OP = 'INSERT') THEN
$$ INSERT INTO emp_audit SELECT 'I', now(), current_user, NEW.*;
BEGIN RETURN NEW;
EXECUTE 'ALTER TABLE ' || END IF;
quote_ident(param_schema_name) || '.' || quote_ident(param_table_name) RETURN NULL; -- result is ignored since this is an AFTER trigger
|| ' ADD COLUMN ' || quote_ident(param_column_name) || ' text '; END;
RETURN 'done'; $$ LANGUAGE plpgsql;
END;
$$ CREATE TRIGGER emp_audit
LANGUAGE 'plpgsql' VOLATILE; AFTER INSERT OR UPDATE OR DELETE ON emp
SELECT cp_addtextfield('public', 'employees', 'resume'); FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
http://www.postgresonline.com