As you may know, a lot of the code we write is repetitive. Yes, it is much better if you know exactly what most of the code is doing, but in general a lot of the code follows a similar pattern or template. Here are some pl sql templates I have used over the years.

Basic pl sql block

SET SERVEROUTPUT ON
 
DECLARE
BEGIN
	-- print
	dbms_output.put_line('hello world');
END;
/

Select into

SET SERVEROUTPUT ON
 
DECLARE
	-- declare variables
	v_name VARCHAR(20);
BEGIN
	-- get last name of one record
	SELECT col1
	  INTO v_name
	  FROM tbl1
	 WHERE ROWNUM < 2;
	 
	-- print
	dbms_output.put_line('last name is: ' || v_name);
END;
/

Select into exception

SET SERVEROUTPUT ON
 
DECLARE
	-- declare variables
	v_name VARCHAR(20);
BEGIN
	-- get last name of one record
	SELECT col1
	  INTO v_name
	  FROM tbl1
	 WHERE col2 = 5;
 
	EXCEPTION 
	WHEN NO_DATA_FOUND THEN
		v_name := NULL;
	 
	-- print
	dbms_output.put_line('last name is: ' || COALESCE(v_name, 'MISSING'));
END;
/

Simple for loop

SET SERVEROUTPUT ON
 
DECLARE
BEGIN
	-- loop through 9 records in tbl1
	FOR REC IN (SELECT col1
				  FROM tbl1
				 WHERE ROWNUM < 10)
		LOOP
			-- print
			dbms_output.put_line('last name is: ' || REC.col1);
		END LOOP;
END;
/

For loop with cursor

SET SERVEROUTPUT ON
 
DECLARE
	-- declare cursor
	CURSOR c1 IS
		SELECT col1
		  FROM tbl1
		 WHERE ROWNUM < 10;
BEGIN
	-- loop through 9 records in tbl1
	FOR REC IN c1
		LOOP
			-- print
			dbms_output.put_line('last name is: ' || REC.col1);
		END LOOP;
END;
/

Simple function

SET SERVEROUTPUT ON
 
DECLARE
	-- declare function
	FUNCTION get_num(p_par1 IN NUMBER) RETURN NUMBER
	IS
		v_num NUMBER := NULL;
	BEGIN
		SELECT col1
		  INTO v_num
		  FROM tbl1
		 WHERE col2 = p_par1;
	RETURN v_num;
	END get_num;
BEGIN
	-- call function and print
	dbms_output.put_line('number is: ' || get_num(10));
END;
/

Simple procedure

SET SERVEROUTPUT ON
 
DECLARE
	-- declare variables
	v_out NUMBER;
 
	-- declare function
	PROCEDURE get_num(p_par1 IN NUMBER, p_par2 OUT NUMBER)
	IS
	BEGIN
		SELECT col1
		  INTO p_par2
		  FROM tbl1
		 WHERE col2 = p_par1;
	END;
BEGIN
	-- call proc and print
	get_num(10, v_out);
	dbms_output.put_line('number is: ' || v_out);
END;
/

Commit every n rows

SET SERVEROUTPUT ON
 
DECLARE
	-- declare variables
	v_LIMIT_IN PLS_INTEGER DEFAULT 1000; -- commit every 1000 updates
 
	-- declare cursor
	CURSOR c1 IS
		SELECT col1
		  FROM tbl1
		 WHERE ROWNUM < 10;
 
	TYPE tt_tbl1 IS TABLE OF c1%ROWTYPE INDEX BY PLS_INTEGER;
	t_tbl1 tt_tbl1;
BEGIN
OPEN c1;
	LOOP
		FETCH c1
		BULK COLLECT INTO t_tbl1 LIMIT v_LIMIT_IN;
	
		FOR indx IN 1 .. t_tbl1.COUNT
		LOOP
			-- do stuff
			-- here is how you get your data: t_tbl1(indx).col1
		END LOOP;
 
		commit;
 
		EXIT WHEN c1%NOTFOUND;
	END LOOP;
CLOSE c1;
END;
/

record table

DECLARE
 
	-- declare variables
	v_id NUMBER :=0;
 
	-- declare cursor
	CURSOR c2 IS
		SELECT col1
		  FROM tbl1
		 WHERE ROWNUM < 10;
		 
	-- we delcare our table columns here
	TYPE rec is RECORD (
		a NUMBER;
		b NUMBER;
	);
	
	-- we declare our table type
	TYPE t_rec IS TABLE of rec INDEX BY BINARY_INTEGER;
 
	initrec rec;
	c_rec t_rec;
BEGIN
	FOR REC in c2
		LOOP
			-- initialize table
			IF NOT c_rec.exists(REC.col1) THEN
				c_rec(REC.col1) := initrec;
			END IF;
 
			-- add data to table
			c_rec(REC.col1) := REC.col2;
		END LOOP;
 
	-- loop through the table if it has data
	IF c_rec.FIRST IS NOT NULL THEN
		v_id := c_rec.FIRST;
 
		LOOP
			EXIT WHEN v_id IS NULL;
				DBMS_OUTPUT.PUT_LINE(c_rec(v_id).col1);
			v_id := c_rec.NEXT(v_id);
		END LOOP;
	END IF;
END;
/