Chapter 7. Advanced Scripting

SQL*Plus was not designed to be a tool used for writing complex scripts. Its capabilities cannot compare to those of your typical Unix shell, such as the Korn shell or the Bourne shell. Nor does it have anywhere near the capabilities of an advanced scripting tool such as Perl. Most noticeably, SQL*Plus suffers from the following limitations:

  • It lacks an IF statement.

  • There are no looping constructs.

  • It has very limited error handling.

  • There is only marginal support for validating user input.

Because of these limitations, SQL*Plus is best suited to executing top-down scripts that don’t require any branching, looping, or error handling. Most of the scripts you have seen so far in this book fall into this category. Many are reports that simply set up some column and page formatting, then execute a query. If something goes wrong, you either don’t see any data in the report or may see some SQL or SQL*Plus error messages.

This limited scripting support is fine when it comes to producing a report. After all, if a report fails, you can simply fix the problem and rerun the report. But what if you are performing a more complex and critical task? What if you are summarizing some data, posting the summary results to a summary table, and then deleting the underlying detail? In that case, you certainly wouldn’t want to delete the data if the summarization failed. You would need some sort of error-handling mechanism.

Tip

If you need to write scripts of any significant complexity, I strongly encourage you to investigate the use of PL/SQL in your script. PL/SQL is a powerful programming language in its own right, and includes support for error handling, branching, and looping — the very items that SQL*Plus lacks. Steven Feuerstein’s and Bill Pribyl’s book, Oracle PL/SQL Programming, 2nd edition (O’Reilly, 1997), is an excellent resource.

This chapter will show you some specific ways to work around these limitations of SQL*Plus. Believe it or not, it is possible, using just SQL*Plus, to implement branching and to validate user input. There are even ways to deal with repetitive tasks without resorting to a loop. You will learn about bind variables and see how they better enable you to mix PL/SQL code into your SQL*Plus scripts. You will also see how bind variables can make the job of developing queries for application programs a little bit easier.

Bind Variables

Back in Chapter 4, you learned about substitution variables. In addition to substitution variables, SQL*Plus supports another type of variable called a bind variable. Unlike substitution variables, bind variables are real variables, having both a datatype and a size.

Bind variables were created to support the use of PL/SQL in a SQL*Plus script. They provide a mechanism for returning data from a PL/SQL block back to SQL*Plus, where it can be used in subsequent queries or by other PL/SQL blocks. Here’s a simple example showing how a bind variable can be used:

--Bind variables can be declared in your SQL*Plus script.
VARIABLE  s_table_name  varchar2(30)

--Preface a bind variable with a colon to reference it
--in a PL/SQL block.
BEGIN
  :s_table_name := 'EMPLOYEE';
END;
/

--Bind variables can even be referenced by SQL queries.
SELECT index_name
  FROM user_indexes
 WHERE table_name = :s_table_name;

--Bind variables persist until you exit SQL*Plus, so
--they can be referenced by more than one PL/SQL block.
SET SERVEROUTPUT ON
BEGIN
  DBMS_OUTPUT.PUT_LINE(:s_table_name);
END;
/

The scope of a bind variable is the SQL*Plus session in which it was defined. Variables defined within a PL/SQL block, on the other hand, cease to exist once that block has finished executing. Bind variables are defined one level higher (at the SQL*Plus level), so they can be referenced by many PL/SQL blocks and queries.

Declaring Bind Variables

The SQL*Plus VARIABLE command is used to declare bind variables. The syntax looks like this:

VAR[IABLE] var_name 
               data_type

where:

VAR[IABLE]

Is the command, which can be abbreviated to VAR.

var_name

Is whatever name you want to give the variable. A variable name must start with a letter, but after that, the name may contain any combination of letters, digits, underscores, pound signs, and dollar signs. 30 characters is the maximum length for a variable name.

data_type

Is the datatype of the variable. The following datatypes are allowed:

NUMBER

Results in a floating-point number, and is the same as a NUMBER variable in PL/SQL or a NUMBER column in a table. Unlike PL/SQL, SQL*Plus does not let you specify a length or a precision, so a declaration like NUMBER (9,2) would not be allowed.

CHAR [(length)]

Results in a fixed-length character string. Length is optional. If it’s omitted, you get a one-character string.

NCHAR [(length)]

Results in a fixed-length character string in the national character set. Length is optional. If it’s omitted, you get a one-character string.

VARCHAR2 (length)

Results in a variable-length character string.

NVARCHAR2 (length)

Results in a variable-length character string using the national language character set.

CLOB

Results in a character large object variable.

NCLOB

Results in a character large object variable using the national language character set.

REFCURSOR

Gives you a cursor variable that you can use to return the results of a SQL query from PL/SQL to SQL*Plus.

In addition to declaring variables, you can also use the VARIABLE command to list all the variables you have defined. To do that, simply issue the command VARIABLE, with no arguments, as shown in the following example:

SQL> VARIABLE
variable   jenny
datatype   NUMBER

variable   jeff
datatype   CHAR

variable   sharon
datatype   VARCHAR2(30)

If you are interested in one specific variable, you can specify that variable’s name as an argument to the VARIABLE command, for example:

SQL> VARIABLE SHARON
variable   sharon
datatype   VARCHAR2(30)

There is no way to get rid of a variable once you’ve defined it.

Using Bind Variables and Substitution Variables Together

Bind variables and substitution variables don’t mesh together too well in SQL*Plus. Each was created for a different purpose, and the two types cannot be used interchangeably. For example, bind variables cannot be used with the ACCEPT command, while substitution variables can. Substitution variables can be used with the TTITLE and BTITLE commands that set up page headers and footers, while bind variables cannot. Bind variables are true variables, and can be passed as arguments to PL/SQL functions and procedures, while substitution variables cannot. Table 7.1 summarizes the best uses and capabilities of each type of variable.

Table 7-1. Bind Variables versus Substitution Variables

Task

Bind Variable

Substitution Variable

Comments

Display information to the user — the PROMPT command.

 

X

 

Accept input from the user — the ACCEPT command.

 

X

 

Place information from a query into page headers and footers — the TTITLE and BTITLE commands.

 

X

 

Run a query with user-specified criteria in the WHERE clause.

X

X

User input must come through a substitution variable, but you can store the resulting value in a bind variable.

Pass values to a PL/SQL function or procedure.

X

X

Substitution variables may be used to pass input arguments as literals.

Return information back from a PL/SQL function or procedure.

X

 

Bind variables must be used for OUT and IN OUT arguments.

As you can see, each variable type pretty much exists in its own world, completely separate from the other. In fact, you cannot even directly assign values from a bind variable to a substitution variable, or vice versa. The following lines of script, though appearing perfectly reasonable on the surface, simply will not work:

DEFINE my_sub_var = ' '
VARIABLE my_bind_var VARCHAR2(30)
EXECUTE :my_bind_var := 'Donna Gennick'
my_sub_var = my_bind_var

This lack of interoperability between variable types can be a real frustration when writing scripts. As Table 7.1 shows, there are some tasks for which you can only use a bind variable, and others for which you can only use a substitution variable. Yet SQL*Plus does not let you easily move values back and forth between the two types. Fortunately, there are some relatively straightforward incantations that let you work around this problem.

From substitution to bind

Putting the value of a substitution variable into a bind variable is actually the easier of the two tasks. Remember that as SQL*Plus executes your script, any substitution variables are simply replaced by their contents as each line of code is executed. You can easily take advantage of this in order to place a value into a bind variable. Take a look at the following short script:

DEFINE my_sub_var = 'Raymond'
VARIABLE my_bind_var VARCHAR2(30)
EXECUTE :my_bind_var := '&my_sub_var';

EXECUTE is a command that executes one line of PL/SQL code. When SQL*Plus encounters the EXECUTE command, it replaces the reference to the substitution variable with the value of that variable. The command after substitution, the one that is actually executed, looks like this:

EXECUTE :my_bind_var := 'Raymond';

Since the assignment involves a character string, the substitution variable must be contained in quotes; otherwise, you would not have a valid string. If you are working with numeric values, you shouldn’t quote them. The following example declares a variable of type NUMBER and assigns a value to it:

DEFINE my_sub_num = 9
VARIABLE my_bind_num NUMBER
EXECUTE :my_bind_num := &&my_sub_num;

So quote your strings, don’t quote your numbers, and remember that substitution is occurring.

From bind to substitution

Taking a value from a bind variable and placing it into a substitution variable is a more difficult task. What you need to do is take advantage of SQL*Plus’s ability to store the results of a SELECT statement into a substitution variable. Let’s say you have the following in your script:

DEFINE my_sub_var = ' '
VARIABLE my_bind_var VARCHAR2(30)
EXECUTE :my_bind_var := 'This is a test.';

In order to get the value of the bind variable into the substitution variable, you need to go through the following steps:

  1. Think up a column name.

  2. Execute a COLUMN command for the column name you thought up. Use the NEW_VALUE clause and specify the substitution variable as the target.

  3. Turn off terminal output by executing a SET TERMOUT OFF command. This is optional.

  4. Issue a SELECT statement that selects the bind variable from Oracle’s DUAL table. Use the column name you thought up in step 1 as the column alias.

  5. Turn terminal output back on.

The SELECT statement will, of course, only return one value, but that value will be a new value for the column in question. The COLUMN command, with its NEW_VALUE clause, causes this value to be stored in the specified substitution variable. It’s a roundabout solution to the problem, but when it’s all over the substitution variable will contain the value from the bind variable. The important thing is to be sure that the column alias matches the column name used in the COLUMN command. Here’s a code sample that demonstrates this technique:

--Declare one bind variable and one substitution variable.
--Initialize the bind variable to a value.
DEFINE my_sub_var = ' '
VARIABLE my_bind_var VARCHAR2(30)
EXECUTE :my_bind_var := 'This is a test.';

--Store the new value of the my_alias column in my_sub_var.
COLUMN my_alias NEW_VALUE my_sub_var

--SELECT the value of the bind variable. SQL*Plus
--will store that value in my_sub_var because of the
--previous COLUMN command.
SET TERMOUT OFF
SELECT :my_bind_var my_alias
  FROM dual;
SET TERMOUT ON

Notice that a column alias is used in the SELECT statement to give the column a name. This same name must be used in the COLUMN command issued prior to the SELECT. If these two don’t match, then the assignment won’t be made, and my_sub_var will still be blank.

Strictly speaking, it’s not necessary to turn the terminal output off for the SELECT statement. The variable assignment will still be made, even with the output on. However, if you are writing a script, you probably won’t want the results of this SELECT to clutter up the display.

Displaying the Contents of a Bind Variable

There are two ways to display the contents of a bind variable to a user. You can use the PRINT command, or you can list the variable in a SELECT statement.

The PRINT command

The format for the PRINT command looks like this:

PRI[NT] [bind_variable_name]

where:

PRI[NT]

Is the command, which can be abbreviated to PRI.

bind_variable_name

Is the name of the bind variable you want to print. If you omit a name, the values of all bind variables are printed.

The results from the PRINT command look very much like the results you get from a SELECT. Here’s an example:

SQL> PRINT my_string

MY_STRING
------------------------------------------------
Brighten the corner where you are

The bind variable is treated like a database column, with the variable name being the default column heading. If you have page titles defined, they will print as well. You can even use the COLUMN commands to format the output. The following example shows how this works:

SQL> COLUMN my_string FORMAT A40 HEADING 'My Motto'
SQL> PRINT my_string

My Motto
----------------------------------------
Brighten the corner where you are

SQL> 
SQL> TTITLE LEFT 'This is a Page Title' SKIP 2
SQL> COLUMN my_number FORMAT 99.99 HEADING 'My Age'
SQL> PRINT my_number

This is a Page Title

My Age
------
 36.00

All other formatting options, such as PAGESIZE and LINESIZE, apply when printing bind variables. You can even use the COLUMN command’s NEW_VALUE clause to store the value of a bind variable in a substitution variable, as the following example demonstrates:

SQL> DEFINE s_my_string = ' '
SQL> COLUMN my_string NOPRINT NEW_VALUE s_my_string
SQL> PRINT my_string
SQL> PROMPT &&s_my_string
Brighten the corner where you are

Issuing the PRINT command by itself causes the contents of all bind variables to be displayed. Here’s an example:

SQL> PRINT

My Motto
----------------------------------------
Brighten the corner where you are


My Age
------
 36.00

Some special considerations apply when printing bind variables of type CLOB and of type REFCURSOR. These are described in the following sections.

Printing CLOB variables

The CLOB datatype is new with Oracle8. CLOB stands for character large object, and variables of this type can hold up to 2 gigabytes of text data. When printing variables of type CLOB or NCLOB, there are three SQL*Plus settings you can use to control what you see and how that works. See Table 7.2.

Table 7-2. Settings That Affect the Printing of CLOBs

Setting

Default

Description

SET LONG

80

Controls the number of characters that are actually displayed from a CLOB variable. By default, only the first 80 characters will print. The rest are ignored.

SET LONGCHUNKSIZE

80

CLOB variables are retrieved from the database a piece at a time. This setting controls the size of that piece.

SET LOBOFFSET

1

An offset you can use to start printing with the nth character in the CLOB variable. By default, SQL*Plus will begin printing with the first character. A LOB-OFFSET of 80, for example, skips the first 79 characters of the string.

By default, SQL*Plus will only display the first 80 characters of a CLOB value. This is rarely enough. After all, if you only needed 80 characters, you wouldn’t have used a CLOB datatype in the first place. On the other hand, you may not want to risk printing 2 gigabytes of data either.

The following example shows the result of printing a CLOB value using the default settings for the values in Table 7.2:

SQL> SELECT clob_value FROM clob_example;

CLOB_VALUE
-----------------------------------------------------------------------------
By default, SQL*Plus will only display the first 80 characters of a CLOB value.

1 row selected.

As you can see, only 80 characters of the value were displayed. You can change the LONG setting to see more of the value, as the next example shows:

SQL> SET LONG 500
SQL> SELECT clob_value from clob_example;

CLOB_VALUE
-----------------------------------------------------------------------------
By default, SQL*Plus will only display the first 80 characters of a CLOB 
value. This is rarely enough. After all, if you only needed 80 characters,
you wouldn't have used a CLOB datatype in the first place.
On the other hand, you may not want to risk printing 2 gigabytes of data 
either.

1 row selected.

By combining the LOBOFFSET and LONG settings, you can print any arbitrary substring of a CLOB variable. The following example prints the characters 81 through 102, which make up the second sentence in the example:

SQL> SET LONG 22
SQL> SET LOBOFFSET 81
SQL> SELECT clob_value FROM clob_example;

CLOB_VALUE
----------------------
This is rarely enough.

1 row selected.

Finally, the LONGCHUNKSIZE setting controls the amount of the CLOB that is fetched from the database at one time. If you have the memory available, you may want to set this to match the LONG setting. That way SQL*Plus will retrieve the value with one fetch from the database, possibly improving performance.

Printing REFCURSOR variables

Beginning with Oracle8, SQL*Plus allows you to create bind variables of the type REFCURSOR. A REFCURSOR variable is a pointer to a cursor that returns a result set. Using PL/SQL, you can assign any SELECT query to a variable of this type, and then you can use the SQL*Plus PRINT command to format and display the results of that query. The following script makes use of this capability. It asks the user for a pattern match string and prints the list tables with names that match the pattern supplied by the user. A PL/SQL block is used to interpret the user’s response, and to open a cursor that will return the desired results.

--Find out what tables the user wants to see.
--A null response results in seeing all the tables.
ACCEPT s_table_like PROMPT 'List tables LIKE > '

VARIABLE l_table_list REFCURSOR

--This PL/SQL block sets the l_table_list variable
--to the correct query, depending on whether or
--not the user specified all or part of a table_name.
BEGIN
  IF '&&s_table_like' IS NULL THEN
    OPEN :l_table_list FOR 
      SELECT table_name 
        FROM user_tables;
  ELSE
    OPEN :l_table_list FOR
      SELECT table_name
        FROM user_tables
       WHERE table_name LIKE UPPER('&&s_table_like'),
  END IF;
END;
/

--Print the list of tables the user wants to see.
PRINT l_table_list

As you can see, this script defines a SQL*Plus REFCURSOR variable. The cursor is opened and a query assigned by code within a PL/SQL block. Then the SQL*Plus PRINT command is used to display the results of that query.

SQL> @ref_cursor
List tables LIKE > 

TABLE_NAME
------------------------------
EMPLOYEE
PROJECT
PROJECT_HOURS
SQL> 
SQL> 
SQL> @ref_cursor
List tables LIKE > p%

TABLE_NAME
------------------------------
PROJECT
PROJECT_HOURS

The output you get when PRINTing a REFCURSOR variable is identical to the output you would get if you executed the same query directly from SQL*Plus.

SELECTing a bind variable

The SQL*Plus manual, at least the one for versions 8.0.3 and before, will tell you that bind variables cannot be used in SQL statements. Don’t believe it. Bind variables can be used in SELECT statements, both in the column list and in the WHERE clause. You will frequently see this done in scripts where there is a need to get the contents of a bind variable into a substitution variable. See the section titled Section 7.1.2.2 earlier in this chapter. Here’s an example of a SELECT statement being used to display the contents of a bind variable:

SQL> VARIABLE l_user VARCHAR2(30)
SQL> EXECUTE :l_user := user;
SQL> SELECT :l_user FROM dual;

:L_USER
--------------------------------
NATHAN

Using SELECT like this offers no real advantage over the use of the PRINT command. If you just need to display one variable, you might as well PRINT it. Being able to use bind variables in a SELECT statement becomes more of an advantage when you need to display information from more than one column, when you want to use the bind variable in an expression for a computed column, or when you want to use it in the WHERE clause. Here’s an example that combines all three of these:

SQL> SET HEADING OFF
SQL> SELECT 'User ' || :l_user || ' has ' 
  2         || TO_CHAR(COUNT(*)) || ' tables.'
  3    FROM all_tables
  4   WHERE owner = :l_user;
NATHAN
User SQLPLUS has 3 tables.

Two types of bind variables cannot be used in a SQL statement. These are the REFCURSOR and CLOB types. You must use the PRINT command with these.

When and How to Use Bind Variables

There are three primary reasons to use bind variables in SQL*Plus:

  • You need to call PL/SQL procedures or functions that return a value or that use IN OUT parameters.

  • You need to conditionally execute one of several possible SELECT statements depending on user input or other circumstances.

  • You want to test a query for use in an application, and that query uses colons to mark parameters.

The next few sections briefly describe each of these uses.

Calling PL/SQL procedures and functions from SQL*Plus

Oracle provides a number of built-in PL/SQL packages that allow you to do such things as create and execute dynamic SQL queries (the DBMS_SQL package), submit and manage PL/SQL batch jobs (the DBMS_JOBS package), and many other very useful things. In many cases, the procedures and functions in these packages use OUT parameters to return information to the caller. To call these routines from within a SQL*Plus script and display the results to the person running the script, you need to use bind variables.

Consider the problem of writing a SQL*Plus script to submit a PL/SQL job for periodic execution by Oracle. To do this, you would use a procedure in Oracle’s DBMS_JOBS package named SUBMIT. SUBMIT takes several arguments, one of which is an OUT argument. The declaration for SUBMIT looks like this:

DBMS_JOB.SUBMIT(  job             OUT    BINARY_INTEGER,
                  what            IN     VARCHAR2,
                  next_date       IN     DATE DEFAULT SYSDATE,
                  interval        IN     VARCHAR2 DEFAULT 'null',
                  no_parse        IN     BOOLEAN DEFAULT FALSE)

The job parameter is the job number, and is an output from the procedure. This job number uniquely identifies a job within Oracle, and is important to know because all the procedures to modify, delete, or otherwise manage database jobs require the job number as an input. Here is one approach you could use to write a script that submits a PL/SQL job for a user. In particular, note the use of a bind variable in the EXECUTE command. Also note the subsequent PRINT command that displays the job number to the user.

SET ECHO OFF
SET FEEDBACK OFF
SET VERIFY ON
SET HEADING ON
SET TERMOUT ON

--
--This script submits a job to the queue after first
--prompting the user for the required information.

--Get the neccessary information from the user.
PROMPT
prompt Submit a PL/SQL job.
PROMPT
ACCEPT what CHAR PROMPT 'Enter the PL/SQL statement to execute >'
PROMPT
ACCEPT when CHAR PROMPT 'When (e.g. 15-Nov-1961 18:30)?'
ACCEPT interval CHAR PROMPT 'Interval (e.g. sysdate+1)?'

--Submit the job
VARIABLE job_number NUMBER
EXECUTE DBMS_JOB.SUBMIT(:job_number, '&what', &when, '&interval'),

--Tell the user the job's ID number.
PRINT job_number

SET FEEDBACK ON
SET VERIFY ON

Running the above script looks like this:

SQL> @submit_job

Submit a PL/SQL job.

Enter the PL/SQL statement to execute >NULL;

When (e.g. 15-Nov-1961 18:30)?sysdate
Interval (e.g. sysdate+1)?sysdate+1

JOB_NUMBER
----------
         4

NULL is a valid PL/SQL statement that does nothing, and is often used as a placeholder for code to be written later. In this example, Oracle will do nothing once each day.

Using REFCURSOR variables

As mentioned earlier, the REFCURSOR datatype holds a pointer to a cursor, and is a new feature introduced with Oracle8. Using REFCURSOR variables, you can open a cursor for a SELECT statement in PL/SQL and print the results from SQL*Plus. One practical use for this is to write PL/SQL code that selects one query from many possibilities, based on user input or some other factor.

Earlier, in the section on printing, you saw a REFCURSOR example that printed a list of tables owned by the current user. Here is an enhanced version of that script that allows the user to optionally enter a pattern match string to narrow the list of table names to be displayed. The script executes one of two possible queries depending on whether or not a string was supplied.

--Find out what tables the user wants to see.
--A null response results in seeing all the tables.
ACCEPT s_table_like PROMPT 'List tables LIKE > '

VARIABLE l_table_list REFCURSOR

--This PL/SQL block sets the l_table_list variable
--to the correct query, depending on whether or
--not the user specified all or part of a table_name.
BEGIN
  IF '&&s_table_like' IS NULL THEN
    OPEN :l_table_list FOR 
      SELECT table_name 
        FROM user_tables;
  ELSE
    OPEN :l_table_list FOR
      SELECT table_name
        FROM user_tables
       WHERE table_name LIKE UPPER('&&s_table_like'),
  END IF;
END;
/

--Print the list of tables the user wants to see.
PRINT l_table_list

This script first asks the user for a search string to be used with the LIKE operator. Entering this is optional. If a pattern match string is specified, then only table names that match that string are displayed; otherwise, all table names are listed. This conditional logic is implemented by the PL/SQL block, which checks the value of the substitution variable and then opens the REFCURSOR variable using the appropriate SELECT statement. Here’s how it looks to run the script:

SQL> @ref_cursor
List tables LIKE > 

TABLE_NAME
------------------------------
EMPLOYEE
PROJECT
PROJECT_HOURS
SQL> 
SQL> 
SQL> @ref_cursor
List tables LIKE > p%

TABLE_NAME
------------------------------
PROJECT
PROJECT_HOURS

You can see that when no search string was specified, all the tables were listed, whereas entering a search string of “p%” caused only tables starting with the letter “P” to be listed. The output is just like that from a standard SELECT statement, and all the column and page formatting options of SQL*Plus apply.

Tip

You might be thinking now about using REFCURSOR variables with the DBMS_SQL package to return the results of dynamically generated SQL queries back to SQL*Plus. Unfortunately, that can’t be done. DBMS_SQL returns integer values that reference cursors held internally, but there is no way to get a REFCURSOR value pointing to one of those cursors.

Using REFCURSOR variables is one way to add conditional logic to your SQL*Plus scripts. You’ll see another example of this later in the section titled Section 7.2.

Testing application queries

Bind variables can make it more convenient to take a query from an application development environment such as PowerBuilder and debug it using SQL*Plus. PowerBuilder queries often contain parameters to be supplied at runtime. PowerBuilder parameters are preceded by colons, the same syntax SQL*Plus uses for bind variables. If you had a PowerBuilder datawindow that allowed you to edit just one employee record, here is how the query behind that datawindow might look:

SELECT employee.employee_id,
       employee.employee_name,
       employee.employee_hire_date,
       employee.employee_termination_date,
       employee.employee_billing_rate
 FROM employee
 WHERE employee.employee_id = :emp_id

Now if you want to test this query, and you just paste it into SQL*Plus as it is, you will get the following results:

SQL> SELECT employee.employee_id,
  2         employee.employee_name,
  3         employee.employee_hire_date,
  4         employee.employee_termination_date,
  5         employee.employee_billing_rate
  6   FROM employee
  7   WHERE employee.employee_id = :emp_id
  8  /
Bind variable "EMP_ID" not declared.

At this point, you have two choices. You can change the query and simply replace the parameter :emp_id with an employee number that you know exists. Then you can test the query, and when you are satisfied the query works, you can replace the hardcoded value with the parameter reference. Woe be unto you, however, if there are several parameters and you forget to change one back. A safer approach would be simply to declare bind variables to match the parameters in the query. In this case there’s just one to declare:

SQL> VARIABLE emp_id NUMBER

Once the variable has been declared, it is a simple matter to initialize it to a known good value:

SQL> EXECUTE :emp_id := 101;

PL/SQL procedure successfully completed.

Having declared and initialized the variable, it’s now a simple matter to copy the query directly from PowerBuilder, or wherever, and paste it unchanged into SQL*Plus:

SQL> SELECT employee.employee_id,
  2         employee.employee_name,
  3         employee.employee_hire_date,
  4         employee.employee_termination_date,
  5         employee.employee_billing_rate
  6   FROM employee
  7   WHERE employee.employee_id = :emp_id
  8  /

EMPLOYEE_ID EMPLOYEE_NAME        EMPLOYEE_ EMPLOYEE_ EMPLOYEE_BILLING_RATE
----------- -------------------- --------- --------- ---------------------
        101 Jonathan Gennick     15-NOV-61                             169

Once you are satisfied that everything is correct, you can paste the query directly back into your application without the risk that you might forget to manually change a hardcoded value back into a parameter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.248.37