Tài liệu Teach Yourself PL/SQL in 21 Days- P10 docx

50 355 0
Tài liệu Teach Yourself PL/SQL in 21 Days- P10 docx

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Leveraging Large Object Types 427 The second part of the procedure selects the row where text will be added, locks the row for updating, assigns the starting position to the length of the contents + (so no data is overwritten), and calls the WRITE procedure This transaction is then committed Analyzing the Contents of an Internal LOB In this section, you can analyze the contents of an internal LOB by working with the functions INSTR and SUBSTR Execute the code in Listing 14.8, and make sure that you have entered SET SERVEROUTPUT ON at the SQL*Plus prompt so you can see output as the program executes INPUT 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: LISTING 14.8 Extracting and Matching Data Inside CLOBs DECLARE /* This PL/SQL block finds patterns in a CLOB It also extracts part of the data from a CLOB with SUBSTR */ Source_Lob CLOB; v_Pattern VARCHAR2(6) := ‘Oracle’; v_Starting_Location INTEGER := 1; v_Nth_Occurrence INTEGER := 1; v_Position INTEGER ; v_Extract_Amount INTEGER; v_Buffer VARCHAR2(100) ; BEGIN Search for 1st Occurrence of Oracle in Row SELECT CLOB_LOCATOR into Source_LOB FROM LOBS WHERE LOB_INDEX = 5; v_Position := DBMS_LOB.INSTR(Source_LOB,v_Pattern, v_Starting_Location,v_Nth_Occurrence); DBMS_OUTPUT.PUT_LINE(‘The first occurrence starts at position: ‘ || v_Position); Search for 2nd Occurrence of Oracle in Row v_Nth_Occurrence := 2; SELECT CLOB_LOCATOR into Source_LOB FROM LOBS WHERE LOB_INDEX = 5; v_Position := DBMS_LOB.INSTR(Source_LOB,v_Pattern, v_Starting_Location,v_Nth_Occurrence); DBMS_OUTPUT.PUT_LINE(‘The second occurrence starts at position: ‘ || v_Position); Extract part of the data from a CLOB continues 14 428 Day 14 LISTING 14.8 continued 35: SELECT CLOB_LOCATOR into Source_LOB 36: FROM LOBS 37: WHERE LOB_INDEX = 6; 38: v_Buffer := DBMS_LOB.SUBSTR(Source_LOB,11,v_Starting_Location); 39: DBMS_OUTPUT.PUT_LINE(‘The substring extracted is: ‘ || v_Buffer); 40: 41: END; 42: OUTPUT The first occurrence starts at position: 16 The second occurrence starts at position: 49 The substring extracted is: Oracle Data The procedure begins by selecting the data from Row 5, and reading the locator into the Source_Lob variable Using the INSTR function, the pattern ‘Oracle’, assigned to the v_Pattern variable, is searched for the first occurrence, specified by the v_Nth_Occurrence variable The Starting Location is defaulted to the first position in the CLOB, stored in the v_Starting_Location variable The process is repeated, except that you are now searching for the second occurrence of ‘Oracle’ in the CLOB ANALYSIS The last part of the procedure extracts 11 characters from Row 6, and stores them in v_Buffer, which is then displayed to the screen Using TRIM and ERASE to Edit CLOBs This sections demonstrates the use of the TRIM and ERASE procedures Execute the code in Listing 14.9 INPUT 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: LISTING 14.9 Reducing Data in CLOBs DECLARE /* This erases the data in Row 6, and trims the data in row to one occurrence of the book title */ Source_Lob CLOB; Erase_Amount INTEGER; Trim_Amount INTEGER; BEGIN Erase the data completely in Row SELECT CLOB_LOCATOR into Source_LOB FROM LOBS WHERE LOB_INDEX = FOR UPDATE; Locks Row for Update Erase_Amount :=DBMS_LOB.GETLENGTH(Source_LOB); Leveraging Large Object Types 429 16: DBMS_LOB.ERASE(Source_LOB,Erase_Amount,1); 17: 18: Reduce Data in Row to one instance of Book Title 19: SELECT CLOB_LOCATOR into Source_LOB 20: FROM LOBS 21: WHERE LOB_INDEX = FOR UPDATE; 22: 23: TRIM_AMOUNT := DBMS_LOB.GETLENGTH(Source_LOB) / 2; 24: DBMS_LOB.TRIM(Source_LOB, TRIM_AMOUNT); 25: COMMIT; 26: 27: END; To verify that the ERASE and TRIM procedures worked, at the SQL prompt type INPUT OUTPUT SELECT * FROM LOBS; LOB_INDEX CLOB_LOCATOR - Teach Yourself Oracle8 in 21 Days Oracle Data Warehousing Unleashed Teach Yourself Database Development With Oracle in 21 Days Oracle Unleashed 2E Teach Yourself Oracle8 in 21 Days ANALYSIS Three variables are declared: • Source_Lob • Erase_Amount • Trim_Amount holds the locator for the CLOBs you will alter holds the number of bytes to erase from Row stores the number of bytes that should remain in Row The procedure starts by reading the locator for the CLOB into the variable Source_Lob Erase_Amount is assigned the value of the length of the data in Row by using the GETLENGTH function The ERASE procedure is called and passes the CLOB locator, the total bytes to erase, and the starting position for erasing the data, which is hard-coded to the value in this example The second half of the block reduces the data in Row by half The locator for the CLOB in Row is read into the variable Source_Lob The Amount of data to remain is calculated by taking the total length of the data by using the GETLENGTH function, and dividing this value by The TRIM procedure is called, passing the locator and the amount of bytes to remain The transactions are then committed 14 430 Day 14 Temporary LOBs Oracle8i introduced temporary LOBs, which are synonymous with local variables and not exist permanently in the database The most common usage of temporary LOBs is for performing transformations on LOB data By default their life span is the duration of the session One of the biggest advantages of temporary LOBs is their ability to improve performance over the usage of persistent LOBs By default LOBs are persistent in nature unless otherwise defined This improved performance is gained because there are no redo records of logging occurring when temporary LOBs are used Likewise, you can explicitly remove a temporary LOB, thereby freeing up additional memory and tablespace PL/SQL operates on temporary LOBs through locators in the same way as for persistent LOBs Because temporary LOBs are never part of any table, you cannot use SQL Data Manipulation Language (DML) to operate on them You must manipulated them by using the DBMS_LOB package as you would with persistent LOBs Security is provided through the LOB locator Only the user who created the temporary LOB can access it Locators are not designed to be passed from one user’s session to another Note When you copy a persistent LOB into a temporary LOB locator, the temporary LOB locator points to the persistent LOB The persistent LOB is not copied into the temporary LOB—only the locators are affected Managing Temporary LOBs All temporary LOBs are recorded in the v$temporary_LOBS view A simple selection on this view will display all temporary LOBs currently valid for that session This is a great place to monitor for unwanted overhead of unnecessary temporary LOBs Creating Temporary LOBs To create temporary LOBs, you use the procedure CREATETEMPORARY, which resides in the DBMS_LOB package The Syntax for calling this procedure is as follows , SYNTAX Leveraging Large Object Types 431 DBMS_LOB.CREATETEMPORARY (lob_loc, cache, dur); In this syntax the parameters are as follows: • lob_loc • cache • dur is the location of the LOB specifies whether the LOB should be read into the database buffer , is one of two predefined duration values (SESSION or CALL), which specifies whether the temporary LOB is cleaned up at the end of the session or call The default value for this parameter is duration The following example illustrates the creation of a temporary LOB: INPUT begin DBMS_LOB.CREATETEMPORARY (Dest_Loc, TRUE, DBMS_LOB.SESSION); End; In this example a temporary LOB is created that will be loaded into the buffer and remain in existence for the duration of the current session After this session is completed, the temporary LOB will disappear, and all memory and tablespace allocated to it will be returned ANALYSIS Summary In this lesson you have learned how Oracle handles large objects, referred to as LOBs The two types of LOBs are internal and external LOBs Internal LOBs can be persistent or temporary External LOBs, called BFILEs, are files accessible to the operating system, rather than data stored in a table Internal LOBs can also be binary, character, multicharacter, and fixed width These have full transactional support and can be committed or rolled back LOBs can have a maximum size of 4GB, or the size of an unsigned LONG integer Q&A Q What is the difference between an external and an internal LOB? A Internal LOBs are stored within the Oracle database External LOBs are stored and maintained by the operating system Q What possible uses are there for LOBs? A You can use LOBs to easily store and track pictures, large text files, and sound files, which can then be used by front-end systems to display or play back the data 14 432 Day 14 Q How are paths accessed by Oracle? A A path is defined as a directory object, which you create by using the SQL statement CREATE DIRECTORY Workshop You can use this to test your comprehension of this lesson and put what you’ve learned into practice You’ll find the answers to the quiz and exercises in Appendix A, “Answers.” Quiz What are the two types of internal LOBs? What is the maximum size of a LOB? Can you write to external files? When copying LOBs from one row to another, is a new locator copied? Exercise Create a temporary LOB that is of BLOB datatype, that will not be stored in the buffer, and that will be limited to the current call WEEK In Review You have finished your second week of learning how to program in PL/SQL The week started with learning about SQL, creating and using tables, and working with stored procedures and packages You know all about encapsulation and grouping similar procedures and functions together in packages You have also learned how to plan for and react to certain runtime errors that can arise in PL/SQL code This includes how to write exception-handling routines to handle internal and userdefined PL/SQL processing errors 10 On Day you learned how to manipulate data with PL/SQL cursors Cursors are wonderful constructs in that they enable you to process a multiple-row query result set one row at a time You also learned how to pass arguments into cursors and how to use cursors as variables 11 You have also, on Day 10, learned about the various PL/SQL collection types On Day 11, you learned how to use triggers, which are automatically executed in response to certain SQL statements and database events On Day 12, you were introduced to Oracle8i’s object features 12 On Day 13, you learned how to prepare for errors and write error-handling routines to help prevent unwanted termination of your PL/SQL programs’ execution Finally, the week ended on Day 14 with you learning how to use the Oracle 8i large object datatypes 13 14 WEEK 15 At a Glance 16 At this point, you should have mastered the basics of Oracle’s PL/SQL language, from functions to procedures to cursors With this knowledge, you can now master the packages supplied by Oracle, which offer some additional advanced features Each chapter guides you through a package or concept and demonstrates its topic through an actual example you can try Where You Are Going Day 15 covers advanced topics such as managing transactions and locks You will then continue with the topics of dynamically creating SQL and writing to external files Next you are exposed to the Oracle-provided package DBMS_JOB Later in the week, you will see how sessions communicate using the DBMS_PIPE package and learn how to manage alerts by using the DBMS_ALERT package Toward the end of the week you will learn about the Java engine, which is a new feature of Oracle 8i You’ll see how Java classes can be loaded into the database, and you’ll learn how you can interface your PL/SQL code to Java methods Finally, the week ends with a discussion on how to use Oracle8i’s Advanced Queuing features 17 18 19 20 This is your last week reading this book It’s the week with the toughest and most challenging topics, but they are also the most interesting topics So forge ahead, and good luck! 21 Day 16 , 462 The header for the VARCHAR2 version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN VARCHAR2, column_size IN INTEGER); The header for the CHAR version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN CHAR, column_size IN INTEGER); The header for the DATE version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN DATE); The header for the RAW version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN RAW, column_size IN INTEGER); The header for the ROWID version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN ROWID); The header for the MLSLABEL version of DEFINE_COLUMN in Trusted Oracle is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN MLSLABEL); In this syntax the parameters are as follows: • c • position • column is the variable defined in the declaration that is associated with the column in the table • column_size is the cursor assigned by the OPEN_CURSOR statement identifies the position of the column in the output The first column listed after the SELECT keyword is column 1, the next is column 2, and so forth , is an optional parameter that allows you to specify the size of the column; otherwise, the size used is the size defined for the variable itself Not all datatypes allow a size to be specified Generating Dynamic SQL 463 Executing Queries , SYNTAX The procedure for executing a query is identical to that for DDL and DML statements After you have defined the columns, you are ready to execute the query by using the EXECUTE function The syntax for the EXECUTE function is shown earlier in this lesson in the section titled “Using the DBMS_SQL Package with Non-Query DDL and DML Statements.” Fetching the Rows into the Buffer with Queries After the query is executed, you need to retrieve the results You this by retrieving one row at a time, using the FETCH_ROWS function This function returns the number of rows stored into the buffer You can then error-check or process based upon %FOUND or %NOTFOUND The syntax header for the FETCH_ROWS function is as follows , FUNCTION FETCH_ROWS (c IN INTEGER) RETURN INTEGER; Using EXECUTE_AND_FETCH to Retrieve the First Set of Rows SYNTAX Instead of first running EXECUTE and then executing FETCH_ROWS, you can the initial execution and fetching in one step with the use of the EXECUTE_AND_FETCH function FUNCTION EXECUTE_AND_FETCH (c IN INTEGER, exact IN BOOLEAN DEFAULT FALSE) RETURN INTEGER; The only difference between EXECUTE_AND_FETCH and EXECUTE is the added parameter exact The value returns true if more than one row has been fetched Using COLUMN_VALUE to Read the Results into PL/SQL Variables , SYNTAX After fetching a row, you need to read the data from DBMS_SQL’s buffer into some PL/SQL variables You this by making calls to the COLUMN_VALUE procedure, which is overloaded, allowing it to handle various datatypes The syntax for the COLUMN_VALUE procedure is as follows There are two versions of COLUMN_VALUE used for NUMBER columns The headers for those two versions are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT NUMBER); , and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT NUMBER, column_error OUT NUMBER, actual_length OUT INTEGER); 16 Day 16 , 464 The headers for VARCHAR2 values are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT VARCHAR2); and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT VARCHAR2, column_error OUT NUMBER, actual_length OUT INTEGER); The headers for CHAR values are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT CHAR); and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT CHAR, column_error OUT NUMBER, actual_length OUT INTEGER); The formats for DATE values are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT DATE); and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT DATE, column_error OUT NUMBER, actual_length OUT INTEGER); The formats for RAW values are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT RAW); , and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT RAW, column_error OUT NUMBER, actual_length OUT INTEGER); , Generating Dynamic SQL 465 The formats for ROWID values are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT ROWID); and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT ROWID, column_error OUT NUMBER, actual_length OUT INTEGER) ; The formats for MLSLABEL values in Trusted Oracle are PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT MLSLABEL) ; and PROCEDURE COLUMN_VALUE (c IN INTEGER, position IN INTEGER, value OUT MLSLABEL, column_error OUT NUMBER, actual_length OUT INTEGER) ; In this syntax the parameters are as follows: • c • position • value • column_error • actual_length represents the cursor ID assigned by OPEN_CURSOR represents the order of the column in the SELECT list is the PL/SQL variable that you declared to hold the results returned for the column is an optional parameter that enables you to determine if a column caused an error When you retrieve the value for a column, the column_error parameter will normally be set to zero A non-zero value means that the column value couldn’t be retrieved , returns the length of the variable in the buffer before it is placed into the associated PL/SQL variable This parameter is useful when the column’s value in the table may be longer than the PL/SQL variable you have defined allows it to be By comparing the actual length with the size of the PL/SQL variable, you can tell if a column’s value has been truncated Closing the Cursor for Queries After you’ve fetched all the data returned by a SELECT statement, or at least all that you wanted to look at, you should close the cursor by making a call to CLOSE_CURSOR The 16 466 Day 16 CLOSE_CURSOR call is made the same way for queries as it is for any other type of statement Using Queries with the DBMS_SQL Package This section provides an example showing how to execute queries by using the DBMS_SQL package The code in Listing 16.3 uses dynamic SQL to query the table you created earlier and then retrieve the five rows that you inserted earlier These five rows are then displayed onscreen (if you are using SQL*Plus) You should execute the code in Listing 16.3, after making sure that you have entered SET SERVEROUTPUT ON at the SQL*Plus prompt INPUT 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: LISTING 16.3 Using SELECT to Verify Inserted Records DECLARE /* The purpose of this PL/SQL block is to demonstrate executing queries within PL/SQL through the use of the DBMS_SQL package We will simply display the output to screen with the DBMS_OUTPUT package */ v_CursorID NUMBER; v_SelectRecords VARCHAR2(500); SQL string v_NUMRows INTEGER; Number of rows processed - of no use v_MyNum INTEGER; v_MyText VARCHAR2(50); BEGIN v_CursorID := DBMS_SQL.OPEN_CURSOR; Get the Cursor ID v_SelectRecords := ‘SELECT * from MyTable’; SQL to view records DBMS_SQL.PARSE(v_CursorID,v_SelectRecords,DBMS_SQL.V7); /* Perform syntax error checking */ DBMS_SQL.DEFINE_COLUMN(v_CursorID,1,v_MyNum); DBMS_SQL.DEFINE_COLUMN(v_CursorID,2,v_MyText,50); v_NumRows := DBMS_SQL.EXECUTE(v_CursorID); /* Execute the SQL code */ LOOP IF DBMS_SQL.FETCH_ROWS(v_CursorID) = THEN EXIT; END IF; DBMS_SQL.COLUMN_VALUE(v_CursorId,1,v_MyNum); DBMS_SQL.COLUMN_VALUE(v_CursorId,2,v_MyText); DBMS_OUTPUT.PUT_LINE(v_MyNum || ‘ ‘ || v_MyText); Generating Dynamic SQL 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 467 END LOOP; EXCEPTION WHEN OTHERS THEN RAISE; raise if some other unknown error DBMS_SQL.CLOSE_CURSOR(v_CursorID); -END; -/ Close the cursor End PL/SQL block After you have executed the block, you should see OUTPUT 4 One Two Three Four Four You can see that it takes some work to execute a SELECT statement by using DBMS_SQL First, you have to open the cursor with OPEN_CURSOR in line 14 Then, v_SelectRecords is assigned the string for the SQL query to select all records from MyTable in line 15 That SQL statement is parsed in line 18 No input variables need to be bound in this example, but if your query has a WHERE clause, you could use binding In lines 21 and 22, the two output variables v_MyNum and v_MyText are defined These are used to hold values from the two columns returned by the query The query is then executed with DBMS_SQL.EXECUTE in line 24 In line 26, the code enters a loop that fetches each row, retrieves the values for the row by making calls to COLUMN_VALUES, and then passes those values to DBMS_OUTPUT The EXIT statement in line 28 is executed when no more rows are found, causing the loop to terminate Finally, the cursor is properly closed in line 42 ANALYSIS Using the DBMS_SQL Package with Anonymous PL/SQL Blocks This section demonstrates how to execute anonymous PL/SQL blocks by using the DBMS_SQL package The processing method is much the same as that used for processing queries and executing DDL or DML statements The following steps are required: Open the cursor Parse the statement Bind the input variables (if required) 16 468 Day 16 Execute the statement Retrieve the results into variables Close the cursor Step is the only place that you will see a difference between the processing required to execute a SQL statement dynamically and the process required to execute a PL/SQL statement dynamically To retrieve the results, you will use a function named VARIABLE_VALUE, which is described next Retrieving Values with Anonymous Blocks , SYNTAX The major difference between executing a PL/SQL block and executing a query or DML statement is that you might need to retrieve the values of bind variables that have been modified by the block For example, the dynamic PL/SQL block might call a procedure using several OUT parameters You need a way to get at the values of those parameters Using DBMS_SQL, you get those values by making calls to the VARIABLE_VALUE procedure, which is an overloaded procedure that has versions for several datatypes The Syntax for the VARIABLE_VALUE Procedures The header for NUMBER values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT NUMBER); The header for VARCHAR2 values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT VARCHAR2); The header for CHAR values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT CHAR); The header for DATE values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT DATE); , The header for RAW values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT RAW); , Generating Dynamic SQL 469 The header for ROWID values is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT ROWID); The syntax for MLSLABEL values in Trusted Oracle is PROCEDURE VARIABLE VALUE(c IN INTEGER name IN VARCHAR2, value OUT MLSLABEL); 16 In this syntax the parameters are as follows: c • name • , • value is the cursor ID returned from OPEN_CURSOR is the name of the placeholder Don’t forget to include the preceding colon when passing these to VARIABLE_VALUE For example, use :marker, not marker is the PL/SQL variable used to hold the output Executing an Anonymous PL/SQL Block Using DBMS_SQL This section demonstrates the process of executing an anonymous PL/SQL block by using the DBMS_SQL package The block to be executed in this example retrieves just one row from the table named mytable that you created earlier Make sure you have entered SET SERVEROUTPUT ON at the SQL*Plus prompt, and execute the code in Listing 16.4 INPUT LISTING 16.4 Using Anonymous Blocks 1: DECLARE 2: /* This procedure calls an anonymous block which performs a 3: query to lookup the description for the row id value = 4: This demonstrates the use of an anonymous PL/SQL block 5: within PL/SQL */ 6: 7: v_CursorID NUMBER; 8: v_MatchRecord VARCHAR2(500); SQL string 9: v_NUMRows INTEGER; Number of rows processed - of no use 10: v_MyNum INTEGER; 11: v_MyText VARCHAR2(50); 12: 13: BEGIN 14: v_CursorID := DBMS_SQL.OPEN_CURSOR; Get the Cursor ID 15: v_MatchRecord := ‘BEGIN Start of Anonymous PL/SQL Block 16: SELECT MyRow,MyDesc 17: INTO :MyRow, :MyText FROM MyTable 18: WHERE MyRow = 2; continues 470 Day 16 LISTING 16.4 continued 19: END;’; End of Anonymous PL/SQL Block 20: 21: DBMS_SQL.PARSE(v_CursorID,v_MatchRecord,DBMS_SQL.V7); 22: /* Perform syntax error checking */ 23: 24: DBMS_SQL.BIND_VARIABLE(v_CursorID, ‘:MyRow’,v_MyNum); 25: DBMS_SQL.BIND_VARIABLE(v_CursorID, ‘:MyText’,v_MyText,50); 26: 27: v_NumRows := DBMS_SQL.EXECUTE(v_CursorID); 28: /* Execute the SQL code */ 29: 30: 31: DBMS_SQL.VARIABLE_VALUE(v_CursorId,’:MyRow’,v_MyNum); 32: DBMS_SQL.VARIABLE_VALUE(v_CursorId,’:MyText’,v_MyText); 33: /* Defines variables to hold output */ 34: 35: DBMS_OUTPUT.PUT_LINE(v_MyNum || ‘ ‘ || v_MyText); 36: 37: 38: EXCEPTION 39: WHEN OTHERS THEN 40: RAISE; raise if some other unknown error 41: 42: DBMS_SQL.CLOSE_CURSOR(v_CursorID); Close the cursor 43: 44: END; End PL/SQL block 45: / After you have executed the block, you should see the following: OUTPUT Two The code first uses OPEN_CURSOR in line 14 to open a cursor It then assigns the anonymous PL/SQL block to the variable v_MatchRecord in line 15 This string codes the PL/SQL block with proper syntax Note that the block is terminated by a semicolon When using DBMS_SQL to execute a PL/SQL block, you must terminate that block with a semicolon because the semicolon is proper PL/SQL syntax The next step is to call DBMS_SQL.PARSE, as in line 21 After binding the appropriate variables in lines 24 and 25, the anonymous PL/SQL block is executed in line 27 The SQL statement executed by the block uses a SELECT INTO statement to retrieve one row from the table The values for that row are stored in the bind variables To retrieve those values, you call DBMS_SQL.VARIABLE_VALUE, which the code does in lines 31 and 32 The output is displayed in line 35, after making a call to DBMS_OUTPUT.PUT_LINE Finally, after the entire process has completed, line 42 makes a call to CLOSE_CURSOR to close the cursor ANALYSIS Generating Dynamic SQL 471 DBMS_SQL Error Handling The DBMS_SQL package provides many ways to avoid errors that would otherwise cause exceptions to be thrown You can check to see if the cursor is open by using IS_OPEN You can also check to see information provided by the DBMS_SQL package concerning the last set of rows retrieved by using the FETCH_ROWS function with the functions LAST_ROW_COUNT and LAST_ROW_ID Other functions that provide information on errors are LAST_ERROR_POSITION and LAST_SQL_FUNCTION_CODE Using IS_OPEN SYNTAX The IS_OPEN function enables you to see whether or not a cursor is open One possible use for this is to check for an open cursor, and if it is still open, close the cursor The Syntax for the IS_OPEN Function FUNCTION IS_OPEN(c IN INTEGER) RETURN BOOLEAN; In this syntax c is the cursor ID originally returned by the OPEN_CURSOR function If the cursor is open, it returns true; otherwise, if the cursor is closed, it returns false Using LAST_ROW_COUNT SYNTAX The Syntax for the LAST_ROW_COUNT Function SYNTAX The LAST_ROW_COUNT function passes the total number of rows fetched from the cursor to date This should be called immediately after FETCH_ROWS in order to receive accurate results Using LAST_ROW_ID FUNCTION LAST_ROW_COUNT RETURN INTEGER; If the call is made before FETCH_ROWS, you receive the value The LAST_ROW_ID function returns the ROWID of the last row processed Again, this should be called immediately after FETCH_ROWS in order for it to return correct results The syntax for the LAST_ROW_ID function is as follows: , FUNCTION LAST_ROW_ID RETURN ROWID; Note If you are executing a SELECT statement, the LAST_ROW_ID function returns correct results only when the FOR UPDATE clause is used 16 472 Day 16 Testing LAST_ROW_ID and LAST_ROW_COUNT Enter and execute the code in Listing 16.5 to test the LAST_ROW_ID and LAST_ROW_COUNT functions Make sure that you have entered SET SERVEROUTPUT ON at the SQL*Plus prompt Notice that the SELECT statement in line 18 includes the FOR UPDATE clause That’s done so that the LAST_ROW_ID function will return correct results INPUT 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: LISTING 16.5 Checking the Progress of Fetched Rows DECLARE /* The purpose of this PL/SQL block is to demonstrate executing queries within PL/SQL through the use of the DBMS_SQL package We will simply display the output to screen with the DBMS_OUTPUT package We also demonstrate the use of tracking the progress of fetching rows*/ v_CursorID NUMBER; v_SelectRecords VARCHAR2(500); SQL string v_NUMRows INTEGER; Number of rows processed - of no use v_MyNum INTEGER; v_MyText VARCHAR2(50); v_MyROWID ROWID; v_TotRow INTEGER; BEGIN v_CursorID := DBMS_SQL.OPEN_CURSOR; Get the Cursor ID v_SelectRecords := ‘SELECT * from MyTable FOR UPDATE’; DBMS_SQL.PARSE(v_CursorID,v_SelectRecords,DBMS_SQL.V7); /* Perform syntax error checking */ DBMS_SQL.DEFINE_COLUMN(v_CursorID,1,v_MyNum); DBMS_SQL.DEFINE_COLUMN(v_CursorID,2,v_MyText,50); v_NumRows := DBMS_SQL.EXECUTE(v_CursorID); /* Execute the SQL code */ LOOP IF DBMS_SQL.FETCH_ROWS(v_CursorID) = THEN EXIT; END IF; /* The next four rows are used for seeing the progress for fetching rows */ v_TOTROW := DBMS_SQL.LAST_ROW_COUNT; v_MyROWID := DBMS_SQL.LAST_ROW_ID; DBMS_OUTPUT.PUT_LINE(‘The last row count is: ‘ || Generating Dynamic SQL 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 473 v_TOTROW || ‘ The last ROWID is: ‘ || v_MyROWID); DBMS_SQL.COLUMN_VALUE(v_CursorId,1,v_MyNum); DBMS_SQL.COLUMN_VALUE(v_CursorId,2,v_MyText); DBMS_OUTPUT.PUT_LINE(v_MyNum || ‘ ‘ || v_MyText); END LOOP; EXCEPTION WHEN OTHERS THEN RAISE; 16 raise if some other unknown error DBMS_SQL.CLOSE_CURSOR(v_CursorID); -END; -/ OUTPUT Close the cursor End PL/SQL block The last One The last Two The last Three The last Four The last Four row count is: The last ROWID is: AAADZ4AAHAAACtSAAA row count is: The last ROWID is: AAADZ4AAHAAACtSAAB row count is: The last ROWID is: AAADZ4AAHAAACtSAAC row count is: The last ROWID is: AAADZ4AAHAAACtSAAD row count is: The last ROWID is: AAADZ4AAHAAACtSAAE As you can see, both functions worked as expected The row counter increased with each row fetched, and the ROWID was displayed for each row Had the SELECT statement not included the FOR UPDATE clause (line 18), the row count would still be correct, but the ROWIDs would not You must use FOR UPDATE in order for the LAST_ROW_ID function to work ANALYSIS Note Selecting FOR UPDATE entails some overhead, and interferes with concurrent access to the data by other users FOR UPDATE is used here to demonstrate the use of the LAST_ROW_ID function In real life, you are better off not using FOR UPDATE unless you really intend to update the rows that you are selecting 474 Day 16 SYNTAX Using LAST_ERROR_POSITION The LAST_ROW_POSITION function returns the location in an SQL statement where an error occurred This is useful only if the PARSE call was unsuccessful The syntax for the LAST_ROW_POSITION Function is as follows: , FUNCTION LAST_ROW_POSITION RETURN INTEGER; Using Native Dynamic SQL With the release of Oracle8i, Oracle extended the PL/SQL language to support dynamic SQL directly For most purposes, you no longer need to use DBMS_SQL to write dynamic SQL Instead, you can use the new features, which are referred to collectively as native dynamic SQL NEW TERM You will need Oracle8i in order to execute the examples pertaining to native dynamic SQL in the remaining part of this lesson Note Executing DML and DDL , SYNTAX Executing DML and DDL statements is quite easy using native dynamic SQL Instead of making all those calls to DBMS_SQL, you can simply issue a PL/SQL EXECUTE IMMEDIATE statement EXECUTE IMMEDIATE string [INTO {variable[, variable] | record}] [USING [IN | OUT | IN OUT] bind [, [IN | OUT | IN OUT] bind] ]; In this syntax the parameters are as follows: • string • variable • is a PL/SQL record Instead of supplying a list of variables for a statement, you can supply a record instead The results of the SELECT are placed in the record The fields of the record must match the columns being selected is a variable or literal that contains the SQL statement you want to execute is a PL/SQL variable If you are executing a SELECT INTO statement, you can supply a list of variables in which you want the results to be placed record SELECT INTO • , is a bind variable You use these to pass parameters to a dynamic SQL statement The parameter markers are numbered, and must be :1, :2, and so on The first bind variable becomes the value :1, the second bind variable becomes the value :2, and so forth bind Generating Dynamic SQL 475 Executing a DDL Statement Listing 16.6 demonstrates the use of EXECUTE INPUT LISTING 16.6 IMMEDIATE in creating a table Creating a Table by Using EXECUTE IMMEDIATE 1: BEGIN 2: EXECUTE IMMEDIATE ‘CREATE TABLE YOURTABLE (‘ 3: || ‘YOURROW NUMBER, ‘ 4: || ‘YOURDESC VARCHAR2(50))’; 5: END; 6: / 16 This is a very simple block of code The EXECUTE IMMEDIATE statement is in lines 2–4 The string to be executed is concatenated together from three smaller strings because the whole thing would be too long to fit on the page When you execute the block, the EXECUTE IMMEDIATE statement in turn executes the CREATE TABLE statement, and you have a new table named yourtable ANALYSIS Using Bind Variables Bind variables allow you to pass values to a SQL statement that you are executing They are much easier to use with native dynamic SQL than with the DBMS_SQL package Listing 16.7 shows a PL/SQL block that dynamically generates an INSERT statement, and then uses it to insert data into the table yourtable, created in Listing 16.6 INPUT LISTING 16.7 Using Bind Variables with Native Dynamic SQL 1: DECLARE 2: v_YourNum NUMBER; 3: v_YourDesc VARCHAR2(50); 4: v_INSERT_stmt VARCHAR2(100); 5: BEGIN 6: Generate an INSERT statement 7: v_INSERT_stmt := ‘INSERT INTO yourtable VALUES (:1, :2)’; 8: 9: Insert the first row 10: v_YourNum := 1; 11: v_YourDesc := ‘One’; 12: EXECUTE IMMEDIATE v_INSERT_stmt 13: USING v_YourNum, v_YourDesc; 14: 15: Insert the second row 16: v_YourNum := 2; continues 476 Day 16 LISTING 16.7 continued 17: v_YourDesc := ‘Two’; 18: EXECUTE IMMEDIATE v_INSERT_stmt 19: USING v_YourNum, v_YourDesc; 20: 21: Insert the third row 22: v_YourNum := 3; 23: v_YourDesc := ‘Three’; 24: EXECUTE IMMEDIATE v_INSERT_stmt 25: USING v_YourNum, v_YourDesc; 26: 27: Insert the fourth row 28: v_YourNum := 4; 29: v_YourDesc := ‘Four’; 30: EXECUTE IMMEDIATE v_INSERT_stmt 31: USING v_YourNum, v_YourDesc; 32: 33: Insert the fifth row 34: v_YourNum := 5; 35: v_YourDesc := ‘Five’; 36: EXECUTE IMMEDIATE v_INSERT_stmt 37: USING v_YourNum, v_YourDesc; 38: END; 39: / ANALYSIS The INSERT statement to be executed is built in line (In this case, it’s not really very dynamic, but it serves to illustrate how this all works.) The two variables v_YourNum and v_YourDesc, declared in lines 2–4, are used as bind variables They hold the values that we want to insert In preparation for the first insert, these are set to and ‘One’, respectively (lines 10 and 11) The EXECUTE statement in line 12–13 lists these variables in the USING clause The order in which they are listed in the USING clause controls how they are bound to the numeric parameter markers in the SQL statement The variable v_YourNum is listed first, so it becomes :1 The variable v_YourDesc is listed next, so it is used in place of :2 The INSERT statement is executed five times, with different values in the bind variables each time, in order to insert five rows in the table Executing SQL Queries To execute a SELECT statement by using native dynamic SQL, you need to three things: Open a cursor by using a new form of the OPEN statement Fetch values from the cursor by using the FETCH statement Close the cursor ... DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN VARCHAR2, column_size IN INTEGER); The header for the CHAR version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER,... DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN ROWID); The header for the MLSLABEL version of DEFINE_COLUMN in Trusted Oracle is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER,... of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN (c IN INTEGER, position IN INTEGER, column IN RAW, column_size IN INTEGER); The header for the ROWID version of DEFINE_COLUMN is PROCEDURE DEFINE_COLUMN

Ngày đăng: 15/12/2013, 05:15

Tài liệu cùng người dùng

Tài liệu liên quan