📄 ch18.htm
字号:
using the <TT>START</TT> command or the character <TT>@</TT>. PL/SQL script files can also be called within other PL/SQL files, shell scripts, or other programs. <HR></BLOCKQUOTE><H3><FONT COLOR="#000077">Displaying Output to the User</FONT></H3><P>Particularly when handling exceptions, you may want to display output to keepusers informed about what is taking place. You can display output to convey information,and you can display your own customized error messages, which will probably makemore sense to the user than an error number. Perhaps you want the user to contactthe database administrator if an error occurs during processing, rather than to seethe exact message.</P><P>PL/SQL does not provide a direct method for displaying output as a part of itssyntax, but it does allow you to call a package that serves this function from withinthe block. The package is called <TT>DBMS_OUTPUT</TT>.</P><PRE><FONT COLOR="#0066FF">EXCEPTION WHEN zero_divide THEN DBMS_OUTPUT.put_line('ERROR: DIVISOR IS ZERO. SEE YOUR DBA.');</FONT></PRE><H5>ANALYSIS:<TT></TT></H5><P><TT>ZERO_DIVIDE</TT> is an Oracle predefined exception. Most of the common errorsthat occur during program processing will be predefined as exceptions and are raisedimplicitly (which means that you don't have to raise the error in the PROCEDURE sectionof the block).</P><P>If this exception is encountered during block processing, the user will see:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL><B> @block1</B>ERROR: DIVISOR IS ZERO. SEE YOUR DBA.PL/SQL procedure successfully completed.</FONT></PRE><P>Doesn't that message look friendly than:</P><H5>INPUT/OUTPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>@block1begin*</B>ERROR at line 1:ORA-01476: divisor is equal to zeroORA-06512: at line 20</FONT></PRE><H2><FONT COLOR="#000077">Transactional Control in PL/SQL</FONT></H2><P>On Day 11, "Controlling Transactions," we discussed the transactionalcontrol commands <TT>COMMIT</TT>, <TT>ROLLBACK</TT>, and <TT>SAVEPOINT</TT>. Thesecommands allow the programmer to control when transactions are actually written tothe database, how often, and when they should be undone.</P><H5>SYNTAX:</H5><PRE><FONT COLOR="#0066FF">BEGIN DECLARE ... BEGIN statements... IF condition THEN COMMIT; ELSE ROLLBACK; END IF; ... EXCEPTION ... END;END;</FONT></PRE><P>The good thing about PL/SQL is that you can automate the use of transactionalcontrol commands instead of constantly monitoring large transactions, which can bevery tedious.<H2><FONT COLOR="#000077">Putting Everything Together</FONT></H2><P>So far, you have been introduced to PL/SQL, have become familiar with the supporteddata types, and are familiar with the major features of a PL/SQL block. You knowhow to declare local variables, constants, and cursors. You have also seen how toembed SQL in the <TT>PROCEDURE</TT> section, manipulate cursors, and raise exceptions.When a cursor has been raised, you should have a basic understanding of how to handleit in the <TT>EXCEPTION</TT> section of the block. Now you are ready to work withsome practical examples and create blocks from <TT>BEGIN</TT> to <TT>END</TT>. Bythe end of this section, you should fully understand how the parts of a PL/SQL blockinteract with each other.<H3><FONT COLOR="#000077">Sample Tables and Data</FONT></H3><P>We will be using two tables to create PL/SQL blocks. <TT>PAYMENT_TABLE</TT> identifiesa customer, how much he or she has paid, and the total amount due. <TT>PAY_STATUS_TABLE</TT>does not yet contain any data. Data will be inserted into <TT>PAY_STATUS_TABLE</TT>according to certain conditions in the <TT>PAYMENT_TABLE</TT>.</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>select *</B> 2 <B>from payment_table;</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF">CUSTOMER PAYMENT TOTAL_DUE-------- -------- ---------ABC 90.50 150.99AAA 79.00 79.00BBB 950.00 1000.00CCC 27.50 27.50DDD 350.00 500.95EEE 67.89 67.89FFF 555.55 455.55GGG 122.36 122.36HHH 26.75 0.009 rows selected.</FONT></PRE><H5><FONT COLOR="#000000">INPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF">SQL> <B>describe pay_status_table</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF"> Name Null? Type ------------------------------ --------- ---- CUST_ID NOT NULL CHAR(3) STATUS NOT NULL VARCHAR2(15) AMT_OWED NUMBER(8,2) AMT_CREDIT NUMBER(8,2)</FONT></PRE><H5>ANALYSIS:<TT></TT></H5><P><TT>DESCRIBE</TT> is an Oracle SQL command that displays the structure of a tablewithout having to query the data dictionary. <TT>DESCRIBE</TT> and other Oracle SQL*Pluscommands are covered on Day 20, "SQL*Plus."<H3><FONT COLOR="#000077">A Simple PL/SQL Block</FONT></H3><P>This is how the PL/SQL script (<TT>block1.sql</TT>) file looks:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF"><B>set serveroutput onBEGIN DECLARE AmtZero EXCEPTION; cCustId payment_table.cust_id%TYPE; fPayment payment_table.payment%TYPE; fTotalDue payment_table.total_due%TYPE; cursor payment_cursor is select cust_id, payment, total_due from payment_table; fOverPaid number(8,2); fUnderPaid number(8,2); BEGIN open payment_cursor; loop fetch payment_cursor into cCustId, fPayment, fTotalDue; exit when payment_cursor%NOTFOUND; if ( fTotalDue = 0 ) then raise AmtZero; end if; if ( fPayment > fTotalDue ) then fOverPaid := fPayment - fTotalDue; insert into pay_status_table (cust_id, status, amt_credit) values (cCustId, 'Over Paid', fOverPaid); elsif ( fPayment < fTotalDue ) then fUnderPaid := fTotalDue - fPayment; insert into pay_status_table (cust_id, status, amt_owed) values (cCustId, 'Still Owes', fUnderPaid); else insert into pay_status_table values (cCustId, 'Paid in Full', null, null); end if; end loop; close payment_cursor; EXCEPTION when AmtZero then DBMS_OUTPUT.put_line('ERROR: amount is Zero. See your supervisor.'); when OTHERS then DBMS_OUTPUT.put_line('ERROR: unknown error. See the DBA'); END;END;/</B></FONT></PRE><H5>ANALYSIS:</H5><P>The <TT>DECLARE</TT> section defines six local variables, as well as a cursorcalled <TT>payment_cursor</TT>. The <TT>PROCEDURE</TT> section starts with the second<TT>BEGIN</TT> statement in which the first step is to open the cursor and starta loop. The <TT>FETCH</TT> command passes the current values in the cursor into thevariables that were defined in the <TT>DECLARE</TT> section. As long as the loopfinds records in the cursor, the statement compares the amount paid by a customerto the total amount due. Overpayments and underpayments are calculated accordingto the amount paid, and we use those calculated amounts to insert values into the<TT>PAY_STATUS_TABLE</TT>. The loop terminates, and the cursor closes. The <TT>EXCEPTION</TT>section handles errors that may occur during processing.</P><P>Now start the PL/SQL script file and see what happens.</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL><B> @block1</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF">Input truncated to 1 charactersERROR: amount is Zero. See your supervisor.PL/SQL procedure successfully completed.</FONT></PRE><P>Now that you know that an incorrect amount appears in the total due column, youcan fix the amount and run the script again.</P><H5>INPUT/OUTPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>update payment_table</B> 2 <B>set total_due = 26.75</B> 3 <B>where cust_id = 'HHH';</B>1 row updated.SQL> <B>commit;</B>Commit complete.SQL> <B>truncate table pay_status_table;</B>Table truncated.</FONT></PRE><BLOCKQUOTE> <P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>This example truncates the <TT>PAY_STATUS_TABLE</TT> to clear the table's contents; the next run of the statement will repopulate the table. You may want to add the <TT>TRUNCATE TABLE</TT> statement to your PL/SQL block. <HR></P></BLOCKQUOTE><H5>INPUT/OUTPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>@block1</B>Input truncated to 1 charactersPL/SQL procedure successfully completed.</FONT></PRE><P>Now you can select from the <TT>PAY_STATUS_TABLE</TT> and see the payment statusof each customer.</P><H5>INPUT/OUTPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>select *</B> 2 <B>from pay_status_table</B> 3 <B>order by status;</B></FONT></PRE><PRE><FONT COLOR="#0066FF">CUSTOMER STATUS AMT_OWED AMT_CREDIT-------- -------------- --------- -----------FFF Over Paid 100.00AAA Paid in FullCCC Paid in FullEEE Paid in FullGGG Paid in FullHHH Paid in FullABC Still Owes 60.49DDD Still Owes 150.95BBB Still Owes 50.009 rows selected.</FONT></PRE><H5>ANALYSIS:</H5><P>A row was inserted into <TT>PAY_STATUS_TABLE</TT> for every row of data that iscontained in the <TT>PAYMENT_TABLE</TT>. If the customer paid more than the amountdue, then the difference was input into the <TT>amt_credit</TT> column. If the customerpaid less than the amount owed, then an entry was made in the <TT>amt_owed</TT> column.If the customer paid in full, then no dollar amount was inserted in either of thetwo columns.<H3><FONT COLOR="#000077">Another Program</FONT></H3><P>This example uses a table called <TT>PAY_TABLE</TT>:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>desc pay_table</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF"> Name Null? Type ------------------------------ -------- ---- NAME NOT NULL VARCHAR2(20) PAY_TYPE NOT NULL VARCHAR2(8) PAY_RATE NOT NULL NUMBER(8,2) EFF_DATE NOT NULL DATE PREV_PAY NUMBER(8,2)</FONT></PRE><P>First take a look at the data:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>select *</B> 2 <B>from pay_table</B> 3 <B>order by pay_type, pay_rate desc;</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF">NAME PAY_TYPE PAY_RATE EFF_DATE PREV_PAY-------------------- -------- --------- --------- ---------SANDRA SAMUELS HOURLY 12.50 01-JAN-97ROBERT BOBAY HOURLY 11.50 15-MAY-96KEITH JONES HOURLY 10.00 31-OCT-96SUSAN WILLIAMS HOURLY 9.75 01-MAY-97CHRISSY ZOES SALARY 50000.00 01-JAN-97CLODE EVANS SALARY 42150.00 01-MAR-97JOHN SMITH SALARY 35000.00 15-JUN-96KEVIN TROLLBERG SALARY 27500.00 15-JUN-968 rows selected.</FONT></PRE><P>Situation: Sales are up. Any individual who has not had a pay increase for sixmonths (180 days) will receive a raise effective today. All eligible hourly employeeswill receive a 4 percent increase, and eligible salary employees will receive a 5percent increase.</P><P>Today is:</P><H5>INPUT/OUTPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>select sysdate</B> 2 <B>from dual;</B>SYSDATE--------20-MAY-97</FONT></PRE><P>Before examining the next PL/SQL block, we will perform a manual select from the<TT>PAY_TABLE</TT> that flags individuals who should receive a raise.</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF">SQL> <B>select name, pay_type, pay_rate, eff_date,</B> 2 <B>'YES' due</B> 3 <B> from pay_table</B> 4 <B>where eff_date < sysdate - 180</B> 5 <B>UNION ALL</B> 6 <B>select name, pay_type, pay_rate, eff_date,</B> 7 <B> 'No' due</B> 8 <B>from pay_table</B> 9 <B>where eff_date >= sysdate - 180</B> 10 <B>order by 2, 3 desc;</B></FONT></PRE><H5><FONT COLOR="#000000">OUTPUT:</FONT><FONT COLOR="#0066FF"></FONT></H5><PRE><FONT COLOR="#0066FF">NAME PAY_TYPE PAY_RATE EFF_DATE DUE-------------------- --------- -------- --------- ---SANDRA SAMUELS HOURLY 12.50 01-JAN-97 NoROBERT BOBAY HOURLY 11.50 15-MAY-96 YESKEITH JONES HOURLY 10.00 31-OCT-96 YESSUSAN WILLIAMS HOURLY 9.75 01-MAY-97 NoCHRISSY ZOES SALARY 50000.00 01-JAN-97 NoCLODE EVANS SALARY 42150.00 01-MAR-97 NoJOHN SMITH SALARY 35000.00 15-JUN-96 YESKEVIN TROLLBERG SALARY 27500.00 15-JUN-96 YES8 rows selected.</FONT></PRE><P>The <TT>DUE</TT> column identifies individuals who should be eligible for a raise.Here's the PL/SQL script:</P><H5>INPUT:</H5><PRE><FONT COLOR="#0066FF"><B>set serveroutput onBEGIN DECLARE UnknownPayType exception;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -