1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle SQL Plus The Definitive Guide- P16 potx

10 321 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 101,78 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The problem is that the command to turn TERMOUT off must precede the SELECT statement that generates the report, so terminal output is off by the time SQL*Plus reads the line containing

Trang 1

SQL> @c:\hours_dollars_b

Enter value for employee_id:111

As commands are executed, SQL*Plus constantly looks for the ampersand character, indicating a substitution variable When an ampersand is encountered, the next token in the command is treated as a variable SQL*Plus first looks to see if that variable has been previously defined In this example it hasn't, so SQL*Plus automatically prompts for the value

After prompting for a value and substituting it into the script in place of the corresponding variable, SQL*Plus will display both the old and the new versions of the particular line of script involved During development, this aids you in verifying that your script is executing correctly Here are the before and after versions of the line containing the &employee_id

variable from the current example:

old 13: AND E.EMPLOYEE_ID = &employee_id

new 13: AND E.EMPLOYEE_ID = 111

Next SQL*Plus goes on to tead the remining lines from the script, producing this hours and dollars report for Taras

Shevchenko:

The Fictional Company

I.S.Department Project Hours and Dollars Detail

==========================================================================

Employee: 111 Taras Shevchenko

Dollars

Proj ID Project Name Date Hours Charged

- - - - -

1001 Corporate Web Site 01-Jan-1998 1 $100.00

01_Mar-1998 3 $300.00

01_May-1998 5 $500.00

01-Jul-1988 7 $700.00

01-Sep-1998 1 $100.00

01-Nov-1998 3 $300.00

************************** - -

Project Totals 20 $2,000.00

In addition to being displayed on the screen, the report is also spooled to the file specified in the script

When TERMOUT is off

In the example just shown, the report was both displayed on the screen and spooled to a file In Chapter 3 you saw how the SET TERMOUT OFF command could be used to suppress output to the display while still allowing it to be

Trang 2

spooled, thus making a report run much faster Trying to do the same thing in this case presents a special problem The problem is that the command to turn TERMOUT off must precede the SELECT statement that generates the report, so terminal output is off by the time SQL*Plus reads the line containing the substitution variable SQL*Plus does not handle this situation too well You won't see a prompt for the substitution variable, because terminal output is off, but SQL*Plus will still be waiting for you to type in a value Your session will appear to be hung Here's what you will see:

SQL>@c:\hours_dollars_c

Strangely enough, even if you remember that SQL*Plus needs an employee number and you type one in, it won't be accepted Try running the script like this:

SQL> @c:\hours_dollars_c

111

Even though you entered a value of 111, SQL*Plus will proceed as if you had entered an empty string The end result will be the following error in the spool file:

Enter value for employee_id:

old 13: AND E.EMPLOYEE_ID =&employee_id

new 13: AND E.EMPLOYEE_ID =

ORDER BY E.EMPLOYEE_ID, P.PROJECT_ID, PH.TIME_LOG_DATE

*

ERROR at line 14:

ORA-00936: missing expression

Looking at the before and after versions of the line with the &employee_id variable, which are written to the spool file, you can see that the input of 111 was totally ignored The result was a syntactically incorrect SQL statement, so instead

of a report all you got was an error

There is a solution to this problem The solution is to use the ACCEPT command to explicitly prompt the user for the employee ID prior to issuing the SET TERMOUT OFF command You will see how to do this later in this chapter in the section titled Prompting for Values

Using Double-Ampersand Variables

Using a double ampersand in front of a substitution variable tells SQL*Plus to define that variable for the duration of the session This is useful when you need to reference a variable several times in one script, because you don't usually want to prompt the user separately for each occurrence

Trang 3

An example that prompts twice for the same value

Take a look at the following script, which displays information about a table followed by a list of all indexes defined on the table:

SET HEADING OFF

SET RECSEP OFF

SET NEWPAGE 1

COLUMN index_name FORMAT A30 NEW_VALUE index_name_var NOPRINT

COLUMN uniqueness FORMAT A6 NEW_VALUE uniqueness_var NOPRINT

COLUMN tablespace_name FORMAT A30 NEW_VALUE tablespace_name_var NOPRINT

COLUMN column_name FORMAT A30

BREAK ON index_name SKIP PAGE on column_header NODUPLICATES

TTITLE uniquenes _var INDEX index_name_var -

SKIP 1 TABLESPACE: tablespace_name_var -

SKIP 1

DESCRIBE &table_name

SELECT ui.index_name,

ui.tablespace_name,

DECODE(ui.uniqueness, UNIQUE,UNIQUE, ) uniqueness,

COLUMNS: column_header,

uic.column_name

FROM user_indexes ui,

user_ind_columns uic

WHERE ui.index_name = uic.index_name

AND ui.table_name = UPPER(&table_name)

ORDER BY ui.index_name,uic.column_position;

TTITLE OFF

SET HEADING ON

SET RECSEP WRAPPED

CLEAR BREAKS

CLEAR COLUMNS

This script uses &table_name twice, once in the DESCRIBE command that lists the columns for the table, and once in the SELECT statement that returns information about the tables's indexes When you run this script, SQL*Plus will issue separate prompts for each occurrence of &table_name The first prompt will occur when SQL*plus hits the

DESCRIBE command:

SQL>@c:\list_indexes_d

Enter value for table_name: project_hours

Name Null? Type

- -

PROJECT_ID NOT NULL NUMBER

EMPLOYEE_ID NOT NULL NUMBER

TIME_LOG_DATE NOT NULL DATE

HOURS_LOGGED NUMBER

DOLLARS_CHARGED NUMBER

Trang 4

Since only a single ampersand was used, the value entered by the user was used for that one specific instance It was not saved for future reference The result is that next time SQL*Plus encounters &table_name, it must prompt again This time it prompts for the table name to use in the SELECT statement:

Enter value for table_name: project_hours

old 9: AND ui.table_name = UPPER(&table_name)

new 9: AND ui.table_name = UPPER(project_hours)

Notice that SQL*Plus only displays before and after images of a line containing substitution variables when that line is part of a SQL query When the DESCRIBE command was read, the user was prompted for a table name, and the

substitution was made, but the old and new versions of the command were not shown

The remaining output from the script, showing the indexes defined on the project_ hours table, looks like this:

INDEX: PROJECT_HOURS_BY_DATE

TABLESPACE: USER_DATA

COLUMNS: TIME_LOG_DATE

INDEX: PROJECT_HOURS_EMP_DATE

TABLESPACE: USER_DATA

COLUMNS: EMPLOYEE_ID

TIME_LOG_DATE

UNIQUE INDEX: PROJECT_HOURS_PK

TABLESPACE: USER_DATA

COLUMNS: PROJECT_ID

EMPLOYEE_ID

TIME_LOG_DATE

6 rows selected

Commit complete

A modified example that prompts once

Obviously there's room for improvement here You don't want to type in the same value over and over just because it's used more than once in a script Aside from being inconvenient, doing so introduces the very real possibility that you won't get it the same each time One way to approach this problem is to use a doubleampersand the first time you

reference the table_name variable in the script Thus the DESCRIBE command becomes:

DESCRIBE &&table_name

The only difference between using a double ampersand rather than a single ampersand is that when a double ampersand

is used, SQL*Plus will save the value All subsequent references to the same variable use that same value It doesn't even

Trang 5

matter if subsequent references use a double ampersand or a single Once the table_name variable has been defined this way, any other reference to &table_ name or &&table_name will be replaced with the defined value

Now if you run the LIST_INDEXES script, you will only be prompted once for the table name, as the following output shows:

SQL> @c:\list_indexes_e

Enter value for table_name: project_hours

Name Null? Type

- -

PROJECT_ID NOT NULL NUMBER

EMPLOYEE_ID NOT NULL NUMBER

TIME_LOG_DATE NOT NULL DATE

HOURS_LOGGED NUMBER

DOLLARS_CHARGED NUMBER

old 9: AND ui.table_name = UPPER(&table_name)

new 9: AND ui.table_name = UPPER(project_hours)

INDEX: PROJECT_HOURS_BY_DATE

TABLESPACE: USER_DATA

COLUMNS: TIME_LOG_DATE

INDEX: PROJECT_HOURS_EMP_DATE

TABLESPACE: USER_DATA

COLUMNS: EMPLOYEE_ID

TIME_LOG_DATE

UNIQUE INDEX: PROJECT_HOURS_PK

TABLESPACE: USER_DATA

COLUMNS: PROJECT_ID

EMPLOYEE_ID

TIME_LOG_DATE

6 rows selected

Commit complete

A final caveat

If you run the LIST_INDEXES script again, you won't be prompted for a table name at all Instead, the value entered earlier will be reused, and you will again see information about the project_hours table and its indexes The reason for this is that once you define a variable, that definition sticks around until you either exit SQL*Plus or explicitly undefine the variable

Because variable definitions persist after a script has ended, it's usually best to explicitly prompt a user for input rather than depending on SQL*Plus to do it for you The ACCEPT command is used for this purpose and is described in the next

Trang 6

section At the very least, you should UNDEFINE variables at the end of a script so they won't inadvertently be reused later Prompting for Values

The most reliable and robust method for getting input from the user is to explicitly prompt for values using the ACCEPT and PROMPT commands The ACCEPT command takes input from the user and stores it in a user variable, and also allows you some level of control over what the user enters The PROMPT command may be used to display messages to the user, perhaps supplying a short summary of what your script is going to accomplish.

There are several potential problems that arise when you simply place substitution variables in your scripts and rely on

SQL*Plus's default prompting mechanisms All of these problems can be avoided through the use of the ACCEPT command Table 4-1 provides a list of these problems together with a description of how the ACCEPT and PROMPT commands can be used to overcome them.

Table 4-1 Potential Problems with SQL*Plus's Default Prompting

Using double ampersands to define a variable in a

script results in your not being prompted for a value

the second time you run the script.

Use the ACCEPT command to prompt for a value This works regardless of whether the variable has previously been defined.

Setting terminal output off, such as when spooling a

report to a file, prevents you from seeing the prompts

for substitution variables used in the query.

Use the ACCEPT command to prompt for these values earlier in the script, before the SET TERMOUT OFF command is executed.

The default prompt provided by SQL*Plus consists

of little more than the variable name.

Use the ACCEPT command to specify your own prompt

For longer explanations, the PROMPT command may be used.

This section shows how to enhance the LIST_INDEXES script with the PROMPT and ACCEPT commands The PROMPT command will be used to better explain what the script is doing, while the ACCEPT command will be used to reliably prompt the user for the table name.

The Accept Command

The ACCEPT command is used to obtain input from the user With it, you specify a user variable and text for a prompt The ACCEPT command displays the prompt for the user, waits for the user to respond, and assigns the user's response to the

variable.

Trang 7

Syntax for the ACCEPT command

Here is the syntax for the ACCEPT command:

ACC[EPT] user_variable [NUM[BER] ¦CHAR¦DATE]

[FOR[MAT] format_specification]

[DEF[AULT] default_value]

[PROMPT prompt_text¦NOPR[OMPT]]

[HIDE]

where:

ACC[EPT]

Tells SQL*Plus that you want to prompt the user for a value, and that you want the value stored in the specified user variable The command may be abbreviated to ACC

user_variable

Is the variable you want to define Do not include leading ampersands If your script uses a &table_name for a

substitution variable, you should used table_name here

NUMBER|CHAR \DATE

Is the type of data you are after The default is CHAR, which allows the user to type in anything as a response Use NUMBER to force the user to enter a number and DATE when you want a date

FOR[MAT] format_Specification

This is an optional format specification, which may optionally be enclosed in quotes If this is specified, ACCEPT will reject any input that does not conform to the specification An error message will be displayed, and the prompt reissued Specifying a format makes the most sense when dealing with numeric and date data, and SQL*Plus is actually

somewhat loose in enforcing the format Chapter 7, Advanced Scripting, delves into this aspect of the ACCEPT

command in detail

DEFAULT default_value

Specifies a default value to assign to the variable This is used if the user bypasses the prompt by pressing ENTER without actually entering a response The default value should usually be enclosed within single quotes

PROMPT prompt_text

This is the prompt text displayed to the user before waiting for input

NOPROMPT

Indicates that you do not want the user to see a visible prompt

HIDE

Causes SQL*Plus not to echo the user's response back to the display This is useful if you are prompting for a password

Trang 8

The syntax for the ACCEPT command has evolved significantly with the past few releases of

SQL*Plus The syntax shown here is valid for version 8.1 Not all of the clauses are available

when using prior versions Be sensitive to this, and check your documentation if you are

writing scripts that need to work under earlier versions of SQL*Plus

Using Accept to get the table name

You can make the LIST_INDEXES script more reliable by using ACCEPT to get the table name from the user This ensures that the user is prompted for a table name each time the script is run The following ACCEPT command should

do the trick:

ACCEPT table_name CHAR PROMPT Enter the table name >

A good place to add the command would be just prior to the COLUMN commands, so the resulting script would look like this:

SET HEADING OFF

SET RECSEP OFF

SET NEWPAGE 1

Get the table name from the user

ACCEPT table_name CHAR PROMPT Enter the table name >

COLUMN index_name FORMAT A30 NEW_VALUE index_name_var NOPRINT

COLUMN uniqueness FORMAT A6 NEW_VALUE uniqueness_var NOPRINT

COLUMN tablespace_name FORMAT A30 NEW_VALUE tablespace_name_var NOPRINT

COLUMN column_name FORMAT A30

BREAK ON index_name SKIP PAGE on column_header NODUPLICATES

TTITLE uniqueness_var INDEX: index_name_var -

SKIP 1 TABLESPACE: tablespace_name_var -

SKIP 1

DESCRIBE &&table_name

SELECT ui.index_name,

ui.tablespace_name,

DECODE(ui,uniqueness, UNIQUE,UNIQUE, ) uniqueness,

COLUMNS: column_header,

uic.column_name

FROM user_indexes ui,

user_ind_columns uic

WHERE ui.index_name = uic.index_name

AND ui.table_name = UPPER(&table_name)

ORDER BY ui.index_name, uic.column_position;

COMMIT;

TTITLE OFF

SET HEADING ON

SET RECSEP WRAPPED

CLEAR BREAKS

CLEAR COLUMNS

Trang 9

It doesn't really matter now whether the script uses &table_name or &&table_name for the substitution variable Either will work just as well, and the script just shown uses both When you run the script, here's how the prompt will look:

SQL> @C:\jonathan\sql_plus_book\xe_ch_5\list_indexes_f

Enter the table name >

Now you can run this script many times in succession, and you will be prompted for a different table name each time In addition, this prompt is a bit more userfriendly than the default prompt generated by SQL*Plus

The Prompt Command

The PROMPT command is used to print text on the display for the user to read It allows you to provide informative descriptions of what a script is about to do It can be used to provide very long and detailed prompts for information, and it can be used simply to add blank lines to the output in order to space things out a bit better

Syntax for the PROMPT command

PROMPT is a very simple command The syntax looks like this:

PRO[MPT] text_to_be_displayed

where:

PRO[MPT]

Is the command, which may be abbreviated to PRO

text_to_be_displayed

Is whatever text you want displayed for the user to see This should not be a quoted string If you include quotes, they will appear in the output

If you are spooling output to a file when a PROMPT command is executed, the prompt text will also be written to the file Any substitution variables in the prompt text will be replaced by their respective values before the text is displayed

Using prompt to summarize the script

It would be nice to add some messages to the LIST_INDEXES script to make it more self-explanatory to the user You can do that by adding the following PROMPT commands to the beginning of the script:

PROMPT

PROMPT This script will first DESCRIBE a table, then

PROMPT it will list the definitions for all indexes

PROMPT on that table

PROMPT

Trang 10

The first and last PROMPT commands simply space the output a bit better by adding a blank line above and below the description

Using prompt to explain the output

The PROMPT command can also be used to better explain the output of a script In the LIST_INDEXES example, messages could be added prior to the DESCRIBE command, and prior to the SELECT statement, in order to explain the output The resulting script would look like this:

PROMPT

PROMPT &table_name table definition:

PROMPT

DESCRIBE &&table_name

PROMPT

PROMPT Indexes defined on the &table_name table:

PROMPT

SELECT ui.index_name,

Here is the result of executing the script with all the PROMPT commands added The messages not only make the output more clear, but space it out better as well

SQL> @c:\jonathan\sql_plus_book\xe_ch_5\list_indexes_G

This script will first DESCRIBE a table, then

it will list the definitions for all indexes

on that table

Enter the table name >project_hours

project_hours table definition:

Name Null? Type

- -

PROJECT_ID NOT NULL NUMBER

EMPLOYEE_ID NOT NULL NUMBER

TIME_LOG_DATE NOT NULL DATE

HOURS_LOGGED NUMBER

DOLLARS_CHARGED NUMBER

Indexes defined on the project_hours table:

old 9: AND ui.table_name = UPPER(&table_name)

new 9: AND ui.table_name = UPPER(project_hours)

INDEX: PROJECT_HOURS_BY_DATE

TABLESPACE: USER_DATA

COLUMNS: TIME_LOG_DATE

Ngày đăng: 05/07/2014, 04:20

TỪ KHÓA LIÊN QUAN