CREATE OR REPLACE FUNCTION add(a int, b int) RETURNS intLANGUAGE sql IMMUTABLE AS $ SELECT a + b;$;
2. Using Function Parameters
Mode
Direction
IN (default)
Input
OUT
Output (defines return)
INOUT
Both
VARIADIC
Variable-length last param
3. Returning Single Value
CREATE FUNCTION square(n int) RETURNS int LANGUAGE sql AS $ SELECT n*n $;
4. Returning Table
CREATE FUNCTION top_customers(lim int)RETURNS TABLE(id bigint, name text, total numeric)LANGUAGE sql AS $ SELECT c.id, c.full_name, sum(o.total_cents) FROM customers c JOIN orders o ON o.customer_id = c.id GROUP BY c.id, c.full_name ORDER BY 3 DESC LIMIT lim;$;SELECT * FROM top_customers(10);
5. Returning Set of Rows
CREATE FUNCTION primes_up_to(n int) RETURNS SETOF intLANGUAGE sql AS $ SELECT g FROM generate_series(2,n) g WHERE NOT EXISTS ( SELECT 1 FROM generate_series(2, floor(sqrt(g))::int) d WHERE g % d = 0);$;
6. Writing SQL Functions
Property
Detail
Inlined
Often into calling query
No control flow
Pure SQL only
Fast
No PL overhead
7. Writing PL/pgSQL Functions
CREATE OR REPLACE FUNCTION transfer(from_id int, to_id int, amt numeric)RETURNS void LANGUAGE plpgsql AS $BEGIN UPDATE accounts SET bal = bal - amt WHERE id = from_id; UPDATE accounts SET bal = bal + amt WHERE id = to_id; IF NOT FOUND THEN RAISE EXCEPTION 'Account % not found', to_id; END IF;END $;
8. Declaring Variables
DECLARE count_var int := 0; row_var customers%ROWTYPE; email_var customers.email%TYPE;
9. Assigning Values
x := 5;SELECT count(*) INTO count_var FROM orders;GET DIAGNOSTICS row_count = ROW_COUNT;
10. Using IF Statements
IF x > 0 THEN RAISE NOTICE 'positive';ELSIF x = 0 THEN RAISE NOTICE 'zero';ELSE RAISE NOTICE 'negative';END IF;
11. Using CASE Statements
CASE x WHEN 1 THEN RAISE NOTICE 'one'; WHEN 2,3 THEN RAISE NOTICE 'two or three'; ELSE RAISE NOTICE 'other';END CASE;
12. Using LOOP Statements
LOOP i := i + 1; EXIT WHEN i > 10;END LOOP;
13. Using FOR Loops
FOR i IN 1..10 LOOP RAISE NOTICE '%', i; END LOOP;FOR r IN SELECT * FROM customers LOOP PERFORM process(r);END LOOP;