We have already seen that the assignment operator is the colon equal (:=) syntax and we have seen how this is used to assign values to a variable both within the code and upon declaration. It is a good practice to initialize variables to a value when they are declared. This is especially important with number variables to avoid null math errors.
Many programming languages avoid NULLs by requiring that a variable be initialized before use. However, in a database, NULLs are commonly used and are not considered errors. Anytime a row is inserted into a table with only some of the column values defined, NULLs are used for the undefined columns. Thus NULLs are values in the database.
The value of NULL is 'undefined.' That means it is not zero, or one, or anything. It is undefined. Because the value of NULL is undefined it can be tricky to work with.
Null math is using any NULL value in a mathematical equation. Null math always returns a NULL. This is a simple concept, but NULL math is a very common PL/SQL bug.
SQL> declare 2 n_1 number; -- null 3 n_2 number := 0; 4 n_3 number := 1; 5 begin 6 dbms_output.put_line ('Addition: '|| n_1 + 5); 7 dbms_output.put_line ('Subtraction: '|| n_1 - 5); 8 dbms_output.put_line ('Multiplication: '|| n_1 * 5); 9 dbms_output.put_line ('Division: '|| n_1 + 5); 10 end; 11 / declare * ERROR at line 1: ORA-06502: PL/SQL: numeric or value error: character to number conversion error ORA-06512: at line 6
The example above fails when dbms_output.out_line attempts to convert n_1 + 5 from a number to a character because it has the value of NULL.
In the example below, the value of n_2 is shown. Notice that there is no value when n_1 is added because it is NULL.
SQL> declare 2 n_1 number; -- null 3 n_2 number := 0; 4 n_3 number := 1; 5 begin 6 n_2 := n_2 + n_3; 7 dbms_output.put_line ('Results: '|| n_2); 8 n_2 := n_1 + n_3; 9 dbms_output.put_line ('Results: '|| n_2); 10 end; 11 / Results: 1 Results:
This is a very common code bug and it can be hard to locate. So with PL/SQL, the developer must contend not only with division by zero, but also null math.
NULLs can also be problematic with comparisons. Since NULL is undefined the developer must insure that the correct comparison is used. In the example below, n_1 is a null while n_2 is a number.
n_1 number; -- null n_2 number := 4;
A comparison results in a true or a false. Here are some comparisons using the variables above.
(n_2 > 2) true; --4>2. (n_1 > 2) false; --null>2 undefined therefore false. (n_1 < n_2) false; --null < 4; undefined therefore false. (n_1 = n_2) false; --null = 4; undefined therefore false. (n_1 <> n_2) true; --null <> 4; undefined is not equal to 4.
No matter how n_1 is used in the comparison, it is still an undefined comparison and therefore false, except if the "not equal" comparison is used. The "not equal" comparison returns true because undefined can never be equal to a value. This is important in the if/then and loop flow control discussed in chapter two. If the developer selects the wrong comparison, it may return a "false" due to a variable not being initialized or return a "true" using the "not equal" comparison. If the variable n_x has not been initialized then the following will always branch to the ELSE clause.
if (n_x < 10) then v_line := 'Never get here'; else v_line := 'always end up here'; end if;
The variable v_line will always be 'always end up here' because n_x < 10 will always be false.
if (n_x <> 10) then v_line := 'this is true'; else v_line := 'this is false'; end if;
In the above example, v_line will always be 'this is true' because n_x <> 10 will always be true. If this is the behavior desired then the code will work. It will be very confusing to the code maintainer, who has to figure out what the initial coder was trying to accomplish. You should use PL/SQL's natural language structure to make code understandable and avoid "tricks" that accomplish a task but are confusing or difficult to understand. If the code is confusing to read, it's going to be hard to maintain. Good PL/SQL developers get in the habit of using comments to explain what actions are being performed and why you are making calculations. Next we will examine nested blocks and learn about the "scope" of PL/SQL variables.