Introduction to PL/SQL

PL/SQL is a procedural language that can use a step through records approach to handle processing. It implements IF statements and loops, variables and types, procedures and functions while still allowing for traditional query and maintenance type processing through SQL. The procedural constructions available in PL/SQL add tremendous power to the processing capabilities available with the Oracle relational database.

PL/SQL is written in a block structure where each block performs a logical task. Blocks can be nested within each other. The structure of a block is:

DECLARE (optional)
Declarative section - allows for variables, types, cursors, user defined-exceptions etc
BEGIN (required)
Executable section - PL/SQL procedural statements and SQL statements
EXCEPTION (optional)
Exception section - error and exception handling
END; (required)

Example:

In this example, I declared a message called v_msg in the declarative section. Then I assigned a literal to v_msg. The assign is done using the assignment code :=. This means that the data to the right of the assignment sign will be assigned to the dataname on the left of the assignment sign.This ended the PL/SQL block.

Looking at the code below, the edit afst_intro takes me into the editor where I coded the PL/SQL code. When I had completed the code and saved it, I exited the editor and ran the code. This can be done with START followed by the name of the code or @ followed by the name of the code. In this case it would be START afst_intro or @ afst_intro.

SQL CODE:

SQL> EDIT afst_intro

PL/SQL CODE:

DECLARE
  v_msg VARCHAR2(25);
BEGIN
  v_msg :='This PL/SQL block works!';
END;
/

SQL CODE:

SQL> @ afst_intro

PL/SQL procedure successfully completed.
If I want to be able to see the message and assure myself that it works, I can use the following code to show the output. If you set serveroutput on in SQL*PLUS (notice you also set it off) then you can display output on the screen using dbms_output.put_line and enclosing the information you want to see within quotes. In the example below, I have a literal message followed by the contents of a PL/SQL defined variable.

SQL CODE:

SQL> edit afst1_intro

PL/SQL CODE:

SET SERVEROUTPUT ON
DECLARE
  v_msg1 VARCHAR2(25);
BEGIN
  v_msg1 :='This PL/SQL block works!';
  DBMS_OUTPUT.PUT_LINE('The output is: '|| v_msg1);
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> edit afst1_intro
SQL> @ afst1_intro
The output is: This PL/SQL block works!

PL/SQL procedure successfully completed.
This example could also have been done by declaring the variable within SQL*Plus instead of within PL/SQL. When you declare the variable within SQL*Plus, you can use the PRINT followed by the field you want to see to display information on the screen.

I wanted to see the results and make sure the message was in v_msg so I added the PRINT line telling it to display the contents of v_msg so you could see how it worked. This command works after a declaration in SQL*Plus and assignment in PL/SQL. It cannot be done if v_msg is declared within the PL/SQL block. This line can be executed at the SQL> prompt or it can be added after the / in the code in the editor. Throughout this session, I can access the variable and give the command PRINT v_msg and see the results.

The :v_msg inside the begin is necessary because v_msg was declared externally rather then within the PL/SQL block. To reference a bind variable which is a variable that is declared outside the PL/SQL block, you need to have a colon in front of the name when you refer to it within the PL/SQL block.

SQL CODE:

SQL> VARIABLE v_msg VARCHAR2(25);
SQL> edit bfst_intro

PL/SQL CODE:

BEGIN
  :v_msg :='This PL/SQL still works!';
END;
/
SQL CODE:
SQL> START bfst_intro;

PL/SQL procedure successfully completed.

SQL> print v_msg

V_MSG
--------------------------------
This PL/SQL still works!
Or the variable assignment and/or the print can be included in the editor code, although it is still not inside the block. Notice the :v_msg inside the block, this is necessary because v_msg is declared externally.

SQL CODE:

SQL> EDIT fst_intro

PL/SQL CODE:

VARIABLE v_msg VARCHAR2(25)
BEGIN
  :v_msg :='This PL/SQL works again!';
END;
/
PRINT v_msg

SQL CODE:

SQL> START fst_intro

PL/SQL procedure successfully completed.

Input truncated to 11 characters
 
V_MSG
--------------------------------
This PL/SQL works again!
You can add comments to your PL/SQL code in two ways. If it is a single line comment you can use --Comment. If you are commenting several lines, you would use /* at the beginning of the comment area and */ to end the comment.

SQL CODE:

SQL> edit afst2_intro

PL/SQL CODE:

SET SERVEROUTPUT ON
DECLARE
  v_msg1 VARCHAR2(25);
BEGIN
  v_msg1 :='This PL/SQL block works!'; --This assigns the message to v_msg1
  /* The dbms_output.put_line allows the programmer to put information on the
     screen as they process.  It is an excellent tool for debugging.  Notice that
     you need to have the set serveroutput on and the set serveroutput off when you 
     are using this command */
  DBMS_OUTPUT.PUT_LINE('The output is: '|| v_msg1);
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> @ afst2_intro
The output is: This PL/SQL block works!

PL/SQL procedure successfully completed.
In this example, I am again using serveroutput to show the results of the processing. I have declared three variables. Notice that instead of giving them a type and a length, I am telling them to use the type and length of the fields that I show. For example, with v_idno, I am establishing the type and length as the type and length of the idno field in the table donornew. The format is table name.column name %TYPE. The processing in the executable part does a select of the idno, name and yrgoal for a particular record and puts the information into the variables listed in the INTO clause. The SELECT can only select one record. Later we will deal with the concepts to handle multiple records. Notice that order is critical here. The dbms_output.put_line(...) is used to show the information in the variables.

SQL CODE:

SQL> edit snd_intro

PL/SQL CODE:

SET SERVEROUTPUT ON
DECLARE
  v_idno donornew.idno%TYPE;
  v_name donornew.name%TYPE;
  v_yrgoal donornew.yrgoal%TYPE;
BEGIN
  SELECT idno, name, yrgoal
  INTO v_idno, v_name, v_yrgoal
  FROM donornew
  WHERE idno = '12121';
  dbms_output.put_line (v_idno||'  '||v_name||'  '||v_yrgoal);
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> @ snd_intro
12121  Jennifer Ames  440

PL/SQL procedure successfully completed.
In the example below, instead of having the identification number a constant in the code, I want the user to enter the identificaiton number and then I want to retrieve the matching record. I will illustrate two ways to do this below. The first way takes in the input within the BEGIN and the second takes it in from SQL*Plus ACCEPT statement.

SQL CODE:

SQL> edit snd1_intro

PL/SQL CODE:

SET SERVEROUTPUT ON
DECLARE
  v_idno donornew.idno%TYPE;
  v_name donornew.name%TYPE;
  v_yrgoal donornew.yrgoal%TYPE;
  v_in_idno donornew.idno%TYPE;
BEGIN
  v_in_idno := &input_idno;
  SELECT idno, name, yrgoal
  INTO v_idno, v_name, v_yrgoal
  FROM donornew
  WHERE idno = v_in_idno;
  dbms_output.put_line (v_idno||'  '||v_name||'  '||v_yrgoal);
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> START snd1_intro
Enter value for input_idno: 11111
old   7:   v_in_idno := &input_idno;
new   7:   v_in_idno := 11111;
11111  Stephen Daniels  650

PL/SQL procedure successfully completed.

SQL CODE:

SQL> edit snd2_intro

PL/SQL CODE:

SET SERVEROUTPUT ON
ACCEPT input_idno PROMPT 'Enter the identification number: '
DECLARE
  v_idno donornew.idno%TYPE;
  v_name donornew.name%TYPE;
  v_yrgoal donornew.yrgoal%TYPE;
 BEGIN
  SELECT idno, name, yrgoal
  INTO v_idno, v_name, v_yrgoal
  FROM donornew
  WHERE idno = &input_idno;
  dbms_output.put_line (v_idno||'  '||v_name||'  '||v_yrgoal);
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> @ snd2_intro
Enter the identification number: 11111
old   9:   WHERE idno = &input_idno;
new   9:   WHERE idno = 11111;
11111  Stephen Daniels  650

PL/SQL procedure successfully completed.

Nesting blocks:

The next topic will deal with a brief introduction to nesting blocks within each other and the scope of the variables defined in the blocks.

SQL CODE:

SQL> edit nest1_intro
I defined v_first and v_msg in the outer block and in the inner block. I gave them initial values in both places. In the outer block v_first has an initial value of 212 and v_msg has an initial value of * Outer define *. In the inner block v_msg has an initial value of 555 and v_msg has an initial value of * Inner define *. The things defined in the outer loop and the processing that takes place in the BEGIN are show first. Then I go to the inner loop and v_first number is no longer 212, it now picks up the value of 555 because the definitions in the inner loop takes precedence over the definitions in the outer loop. The same applies to the message. In the inner loop I print the information and see those things uniquely defined in the outer, those things uniquely defined in the inner and where the definitions are the same, I see the results of the inner. When I leave the inner loop, I no longer have access to the things uniquely defined in the inner loop. The things defined in both the inner and the outer revert to their outer defined values.

PL/SQL CODE:

SET SERVEROUTPUT ON
DECLARE
  v_first NUMBER :=212;
  v_msg   VARCHAR2(20) :='* Outer define *';
  out_msg VARCHAR2(20);
  out_ans   NUMBER;
BEGIN
    out_msg := v_msg;
    out_ans := v_first *2;
    dbms_output.put_line('BEFORE INNER DEFINE');
    dbms_output.put_line(v_first||v_msg||out_msg||out_ans);
    DECLARE
      v_first NUMBER := 555;
      v_msg VARCHAR2(20) := '* Inner define *';
      in_msg VARCHAR2(20);
      in_ans NUMBER;
    BEGIN
      in_msg := v_msg;
      in_ans := v_first * 2;
      dbms_output.put_line('INNER LOOP SHOWING INNER');
      dbms_output.put_line(v_first||v_msg||in_msg||in_ans);
      dbms_output.put_line('INNER LOOP SHOWING OUTER');
      dbms_output.put_line(out_msg||out_ans);
    END;
    dbms_output.put_line('AFTER INNER/BACK TO OUTER'||v_first||v_msg);
    dbms_output.put_line('OUTER LOOP SHOWING OUTER'||out_msg||out_ans);
    /* Note that when I try to show inner definitions here, in_msg and
       in_ans it crashes */
END;
/
SET SERVEROUTPUT OFF

SQL CODE:

SQL> @ nest1_intro

BEFORE INNER DEFINE
212* Outer define ** Outer define *424
INNER LOOP SHOWING INNER
555* Inner define ** Inner define *1110
INNER LOOP SHOWING OUTER
* Outer define *424
AFTER INNER/BACK TO OUTER212* Outer define *
OUTER LOOP SHOWING OUTER* Outer define *424

PL/SQL procedure successfully completed.