Tải bản đầy đủ
Lab 17.2: OPEN-FOR, FETCH, and CLOSE Statements

Lab 17.2: OPEN-FOR, FETCH, and CLOSE Statements

Tải bản đầy đủ

TheOPEN-FOR,FETCH,andCLOSEstatementsareusedformultirowqueriesorcursors.
ThisconceptisverysimilartothestaticcursorprocessingthatyouencounteredinChapter
11.Justasinthecaseofstaticcursors,firstyouassociateacursorvariablewithaquery.
Next,youopenthecursorvariablesothatitpointstothefirstrowoftheresultset.Next,
youfetchonerowatatimefromtheresultset.Finally,whenallrowshavebeen
processed,youclosethecursor(cursorvariable).

OpeningCursor
InthecaseofadynamicSQL,theOPEN-FORstatementhasanoptionalUSINGclause
thatallowsyoutopassvaluestothebindargumentsatruntime.Thegeneralsyntaxforan
OPEN-FORstatementisasfollows(thereservedwordsandphrasessurroundedby
bracketsareoptional):
Clickheretoviewcodeimage
OPENcursor_variableFORdynamic_SQL_string
[USINGbind_argument1,bind_argument2,…]

Thecursor_variableisavariableofaweakREFCURSORtype,andthe
dynamic_SQL_stringisastringthatcontainsamultirowquery.
ForExample
Clickheretoviewcodeimage
DECLARE
TYPEstudent_cur_typeISREFCURSOR;
student_curstudent_cur_type;
v_zipVARCHAR2(5):=‘&sv_zip’;
v_first_nameVARCHAR2(25);
v_last_nameVARCHAR2(25);
BEGIN
OPENstudent_curFOR
‘SELECTfirst_name,last_nameFROMstudent‘||‘WHEREzip=:1’
USINGv_zip;


Thiscodefragmentfirstdefinesaweakcursortype,student_cur_type.Next,it
definesacursorvariable,student_cur,basedontheREFCURSORtypespecifiedin
thepreviousstep.Atruntime,thestudent_curvariableisassociatedwiththe
SELECTstatementthatreturnsthefirstandlastnamesofstudentsforagivenvalueof
zip.

FetchingfromaCursor
Asmentionedearlier,theFETCHstatementreturnsasinglerowfromtheresultsetintoa
listofvariablesdefinedinaPL/SQLblockandmovesthecursortothenextrow.Ifaloop
isbeingprocessedandtherearenomorerowstofetch,theEXITWHENstatement
evaluatestoTRUE,andcontroloftheexecutionpassesoutsidethecursorloop.The
generalsyntaxforaFETCHstatementisasfollows:
Clickheretoviewcodeimage
FETCHcursor_variable

INTOdefined_variable1,defined_variable2,…
EXITWHENcursor_variable%NOTFOUND;

Continuingthepreviousexample,youfetchthestudent’sfirstandlastnamesinto
variablesspecifiedinthedeclarationsectionofthePL/SQLblock.Next,youevaluateif
therearemorerecordstoprocessviaanEXITWHENstatement.Aslongasthereare
morerecordstoprocess,thestudent’sfirstandlastnamesaredisplayedonthescreen.
Oncethelastrowisfetched,thecursorloopterminates.Thechangesnecessaryforthese
stepsareshowninbold.
ForExample
Clickheretoviewcodeimage
DECLARE
TYPEstudent_cur_typeISREFCURSOR;
student_curstudent_cur_type;
v_zipVARCHAR2(5):=‘&sv_zip’;
v_first_nameVARCHAR2(25);
v_last_nameVARCHAR2(25);
BEGIN
OPENstudent_curFOR
‘SELECTfirst_name,last_nameFROMstudent‘||‘WHEREzip=:1’
USINGv_zip;
LOOP
FETCHstudent_curINTOv_first_name,v_last_name;
EXITWHENstudent_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(‘FirstName:‘||v_first_name);
DBMS_OUTPUT.PUT_LINE(‘LastName:’||v_last_name);
ENDLOOP;


ThenumberofvariableslistedintheINTOclausemustcorrespondtothenumberof
columnsreturnedbythecursor.Furthermore,thevariablesintheINTOclausemustbe
typecompatiblewiththecursorcolumns.

ClosingaCursor
TheCLOSEstatementdisassociatesthecursorvariablewiththemultirowquery.Asa
result,aftertheCLOSEstatementexecutes,theresultsetbecomesundefined.Thegeneral
syntaxforaCLOSEstatementisasfollows:
CLOSEcursor_variable;

Nowconsiderthecompleteversionoftheexampleshownpreviously.Changesare
showninbold.
ForExample
Clickheretoviewcodeimage
DECLARE
TYPEstudent_cur_typeISREFCURSOR;
student_curstudent_cur_type;
v_zipVARCHAR2(5):=‘&sv_zip’;
v_first_nameVARCHAR2(25);
v_last_nameVARCHAR2(25);

BEGIN
OPENstudent_curFOR
‘SELECTfirst_name,last_nameFROMstudent‘||‘WHEREzip=:1’
USINGv_zip;
LOOP
FETCHstudent_curINTOv_first_name,v_last_name;
EXITWHENstudent_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(‘FirstName:‘||v_first_name);
DBMS_OUTPUT.PUT_LINE(‘LastName:’||v_last_name);
ENDLOOP;
CLOSEstudent_cur;
EXCEPTION
WHENOTHERSTHEN
IFstudent_cur%ISOPENTHEN
CLOSEstudent_cur;
ENDIF;
DBMS_OUTPUT.PUT_LINE(‘ERROR:‘||SUBSTR(SQLERRM,1,200));
END;

TheIFstatementintheexception-handlingsectionevaluatestoTRUEifanexception
isencounteredbeforethecursorprocessingiscompleted.Insuchacase,itisconsidered
goodpracticetocheckwhetheracursorisstillopenandcloseit,ifnecessary,sothatall
resourcesassociatedwiththecursorwillbefreedbeforetheprogramterminates.
Whenrun,thisexampleproducesthefollowingoutput:
Clickheretoviewcodeimage
Entervalueforsv_zip:11236
old5:v_zipVARCHAR2(5):=‘&sv_zip’;
new5:v_zipVARCHAR2(5):=‘11236’;
FirstName:Derrick
LastName:Baltazar
FirstName:Michael
LastName:Lefbowitz
FirstName:Bridget
LastName:Hagel
PL/SQLproceduresuccessfullycompleted.

Inthefollowingexample,paycloseattentiontotheuseofspaces.
ForExamplech17_2.sql,version1.0
Clickheretoviewcodeimage
SETSERVEROUTPUTON
DECLARE
TYPEzip_cur_typeISREFCURSOR;
zip_curzip_cur_type;
sql_stmtVARCHAR2(500);
v_zipVARCHAR2(5);
v_totalNUMBER;
v_countNUMBER;
BEGIN
sql_stmt:=‘SELECTzip,COUNT(*)total’||
’FROMstudent‘||
‘GROUPBYzip’;
v_count:=0;
OPENzip_curFORsql_stmt;
LOOP

FETCHzip_curINTOv_zip,v_total;
EXITWHENzip_cur%NOTFOUND;
—Limitthenumberoflinesprintedonthe
—screento10
v_count:=v_count+1;
IFv_count<=10THEN
DBMS_OUTPUT.PUT_LINE(‘Zipcode:‘||v_zip||
’Total:‘||v_total);
ENDIF;
ENDLOOP;
CLOSEzip_cur;
EXCEPTION
WHENOTHERSTHEN
IFzip_cur%ISOPENTHEN
CLOSEzip_cur;
ENDIF;
DBMS_OUTPUT.PUT_LINE(‘ERROR:‘||SUBSTR(SQLERRM,1,200));
END;

ConsidertheuseofspacesintheSQLstatementsgenerateddynamically.Inthe
precedingscript,thestringthatholdsthedynamicSQLstatementconsistsofthreestrings
concatenatedtogether,whereeachstringiswrittenonaseparateline.
Clickheretoviewcodeimage
sql_stmt:=‘SELECTzip,COUNT(*)total’||
’FROMstudent‘||
‘GROUPBYzip’;

ThisformatofthedynamicSELECTstatementisverysimilartotheformatofany
staticSELECTstatementthatyouhaveseenthroughoutthisbook.However,thereisa
subtledifference.Inoneinstance,extraspaceshavebeenaddedforformattingreasons.
Forexample,theFROMkeywordisprefixedbytwospacessothatitisalignedwiththe
SELECTkeyword.Yet,inanotherinstance,aspacehasbeenaddedtoseparateouta
reservedphrase.Inthiscase,aspacehasbeenaddedaftertheSTUDENTtabletoseparate
outtheGROUPBYclause.Thisstepisnecessarybecauseoncethestringsare
concatenated,theresultingSELECTstatementlooksasfollows:
Clickheretoviewcodeimage
SELECTzip,COUNT(*)totalFROMstudentGROUPBYzip

IfnospaceisaddedaftertheSTUDENTtable,theresultingSELECTstatement
Clickheretoviewcodeimage
SELECTzip,COUNT(*)totalFROMstudentGROUPBYzip

causesthefollowingerror:
Clickheretoviewcodeimage
ERROR:ORA-00933:SQLcommandnotproperlyended
PL/SQLproceduresuccessfullycompleted.

Inthedeclarationportionoftheexamplescript,aweakcursortypeisdefinedas
zip_cur_type,andacursorvariablezip_curofthezip_cur_typetypeisalso
defined.Next,astringvariabletoholdadynamicSQLstatementisdefinedaswellastwo
variablesv_zipandv_total,whichholddatareturnedbythecursor.Finally,a

countervariableisdefinedsothatonlythefirst10rowsreturnedbythecursorare
displayedonthescreen.
Intheexecutableportionofthescript,adynamicSQLstatementisgenerated,whichis
thenassociatedwiththecursorvariable,zip_cur.Thecursorisopened.Then,foreach
rowreturnedbythecursor,thevaluesofaZIPcodeandthetotalnumberofstudents
livinginthatZIPcodeareaarepopulatedintothevariablesv_zipandv_total,
respectively.Next,thescriptcheckswhethertherearemorerowstofetchfromthecursor.
Iftherearemorerowstoprocess,thevalueofthecountervariableisincrementedby1.As
longasthevalueofthecounterislessthanorequalto10,therowreturnedbythecursor
isdisplayedonthescreen.Iftherearenomorerowstofetch,thecursorisclosed.
Theexception-handlingsectionofthescriptcheckswhetherthecursorisopen.Ifitis,
thescriptclosesthecursoranddisplaysanerrormessageonthescreenbeforeterminating.
Whenrun,thescriptshouldproduceoutputsimilartothatshownhere:
Clickheretoviewcodeimage
Zipcode:01247Total:1
Zipcode:02124Total:1
Zipcode:02155Total:1
Zipcode:02189Total:1
Zipcode:02563Total:1
Zipcode:06483Total:1
Zipcode:06605Total:1
Zipcode:06798Total:1
Zipcode:06820Total:3
Zipcode:06830Total:3
PL/SQLproceduresuccessfullycompleted.

Thescriptch17_2.sql,version1.0,fromthepreviousexampleisnowmodifiedsothat
theSELECTstatementcanberunagainsteithertheSTUDENTorINSTRUCTORtable.In
otherwords,theusercanspecifythetablenameusedintheSELECTstatementatrun
time.
ForExamplech17_2.sql,version2.0
Clickheretoviewcodeimage
SETSERVEROUTPUTON
DECLARE
TYPEzip_cur_typeISREFCURSOR;
zip_curzip_cur_type;
v_table_nameVARCHAR2(20):=‘&sv_table_name’;
sql_stmtVARCHAR2(500);
v_zipVARCHAR2(5);
v_totalNUMBER;
v_countNUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE(‘Totalsfrom‘||v_table_name||
‘table’);
sql_stmt:=‘SELECTzip,COUNT(*)total’||
‘FROM‘||v_table_name||’‘||
‘GROUPBYzip’;
v_count:=0;

OPENzip_curFORsql_stmt;
LOOP
FETCHzip_curINTOv_zip,v_total;
EXITWHENzip_cur%NOTFOUND;
—Limitthenumberoflinesprintedonthe
—screento10
v_count:=v_count+1;
IFv_count<=10THEN
DBMS_OUTPUT.PUT_LINE(‘Zipcode:‘||v_zip||
‘Total:‘||v_total);
ENDIF;
ENDLOOP;
CLOSEzip_cur;
EXCEPTION
WHENOTHERSTHEN
IFzip_cur%ISOPENTHEN
CLOSEzip_cur;
ENDIF;
DBMS_OUTPUT.PUT_LINE(‘ERROR:‘||SUBSTR(SQLERRM,1,200));
END;

Inthisversionofthescript,thevariablev_table_namehasbeenaddedtoholdthe
nameofatableprovidedattheruntime.ADBMS_OUTPUT.PUT_LINEhasbeenadded
todisplayamessageindicatingthetablefromwhichthetotalnumbersarecoming.The
dynamicSQLstatementwasalsomodifiedasfollows:
Clickheretoviewcodeimage
sql_stmt:=‘SELECTzip,COUNT(*)total’||
’FROM‘||v_table_name||’‘||
‘GROUPBYzip’;

Thevariablev_table_namehasbeeninsertedinplaceoftheactualtablename
(STUDENT).Notethataspaceisconcatenatedtothevariablev_table_name,sothat
theSELECTstatementdoesnotcauseanyerrors.
Whenrun,thisscriptproducesthefollowingoutput.Thefirstrunisbasedonthe
STUDENTtable.
Clickheretoviewcodeimage
Entervalueforsv_table_name:student
old5:v_table_nameVARCHAR2(20):=‘&sv_table_name’;
new5:v_table_nameVARCHAR2(20):=‘student’;
Totalsfromstudenttable
Zipcode:01247Total:1
Zipcode:02124Total:1
Zipcode:02155Total:1
Zipcode:02189Total:1
Zipcode:02563Total:1
Zipcode:06483Total:1
Zipcode:06605Total:1
Zipcode:06798Total:1
Zipcode:06820Total:3
Zipcode:06830Total:3
PL/SQLproceduresuccessfullycompleted.

ThesecondrunisbasedontheINSTRUCTORtable.

Clickheretoviewcodeimage
Entervalueforsv_table_name:instructor
old5:v_table_nameVARCHAR2(20):=‘&sv_table_name’;
new5:v_table_nameVARCHAR2(20):=‘instructor’;
Totalsfrominstructortable
Zipcode:10005Total:1
Zipcode:10015Total:3
Zipcode:10025Total:4
Zipcode:10035Total:1
PL/SQLproceduresuccessfullycompleted.

Sofar,youhaveseenthatvaluesreturnedbythedynamicSQLstatementsarestoredin
individualvariablessuchasv_last_nameorv_first_name.Insuchcases,youlist
variablesintheorderofthecorrespondingcolumnsreturnedbytheSELECTstatement.
ThisapproachbecomessomewhatcumbersomewhenadynamicSQLstatementreturns
morethanafewcolumns.Asaresult,PL/SQLallowsyoutostorevaluesreturnedbythe
dynamicSELECTstatementsinthevariablesoftherecordtype.
Considerthemodifiedversionofthescriptusedinthislab.Inthisversion,insteadof
creatingseparatevariables,auser-definedrecordiscreated.Thisrecordisthenusedto
fetchdatafromthecursoranddisplayitonthescreen.Changesareshowninbold.
ForExamplech17_2.sql,version3.0
Clickheretoviewcodeimage
SETSERVEROUTPUTON
DECLARE
TYPEzip_cur_typeISREFCURSOR;
zip_curzip_cur_type;
TYPEzip_rec_typeISRECORD
(zipVARCHAR2(5),
totalNUMBER);
zip_reczip_rec_type;
v_table_nameVARCHAR2(20):=‘&sv_table_name’;
sql_stmtVARCHAR2(500);
v_countNUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE(‘Totalsfrom‘||v_table_name||
’table’);
sql_stmt:=‘SELECTzip,COUNT(*)total’||
‘FROM‘||v_table_name||’‘||
‘GROUPBYzip’;
v_count:=0;
OPENzip_curFORsql_stmt;
LOOP
FETCHzip_curINTOzip_rec;
EXITWHENzip_cur%NOTFOUND;
—Limitthenumberoflinesprintedonthe
—screento10
v_count:=v_count+1;
IFv_count<=10THEN
DBMS_OUTPUT.PUT_LINE(‘Zipcode:‘||zip_rec.zip||
‘Total:‘||zip_rec.total);

ENDIF;
ENDLOOP;
CLOSEzip_cur;
EXCEPTION
WHENOTHERSTHEN
IFzip_cur%ISOPENTHEN
CLOSEzip_cur;
ENDIF;
DBMS_OUTPUT.PUT_LINE(‘ERROR:‘||SUBSTR(SQLERRM,1,200));
END;

Whenversion3ofthisscriptisrun,itproducesthefollowingresultsfortheSTUDENT
table:
Clickheretoviewcodeimage
Entervalueforsv_table_name:student
old10:v_table_nameVARCHAR2(20):=‘&sv_table_name’;
new10:v_table_nameVARCHAR2(20):=‘student’;
Totalsfromstudenttable
Zipcode:01247Total:1
Zipcode:02124Total:1
Zipcode:02155Total:1
Zipcode:02189Total:1
Zipcode:02563Total:1
Zipcode:06483Total:1
Zipcode:06605Total:1
Zipcode:06798Total:1
Zipcode:06820Total:3
Zipcode:06830Total:3
PL/SQLproceduresuccessfullycompleted.

ThesamescriptproducesthefollowingresultsfortheINSTRUCTORtable:
Clickheretoviewcodeimage
Entervalueforsv_table_name:instructor
old10:v_table_nameVARCHAR2(20):=‘&sv_table_name’;
new10:v_table_nameVARCHAR2(20):=‘instructor’;
Totalsfrominstructortable
Zipcode:10005Total:1
Zipcode:10015Total:3
Zipcode:10025Total:4
Zipcode:10035Total:1
PL/SQLproceduresuccessfullycompleted.

Summary
Inthischapter,youlearnedhowtobuildnativedynamicSQLstatementsinPL/SQL;such
statementsareusedwhenyouneedtobuildflexibilityintoyourcode.DynamicSQL
allowsforvaryingtheSQLstatementsthatareexecutedatruntime,therebyallowingfor
variouselementsoftheSQLtochange,suchasthetableandthecolumns.Thefirst
methodcoveredinthischapterwastheEXECUTEIMMEDIATEstatement;youalsosaw
howtoavoidvariousOracleerrorswhenusingthismethod.TheOPEN-FOR,FETCH,and
CLOSEstatementswerethenexplainedindetail;theseapproachesallowformultirow
queries.

BytheWay
Thecompanionwebsiteprovidesadditionalexercisesandsuggestedanswers
forthischapter,withdiscussionrelatedtohowthoseanswersresulted.The
mainpurposeoftheseexercisesistohelpyoutestthedepthofyour
understandingbyutilizingalloftheskillsthatyouhaveacquiredthroughout
thischapter.

18.BulkSQL
Inthischapter,youwilllearnabout
FORALLStatements
TheBULKCOLLECTClause
BindingCollectionsinSQLStatements
InChapter1,youlearnedthatthePL/SQLenginesendsSQLstatementstotheSQL
engine,whichthenreturnsresultsbacktothePL/SQLengine.Thecommunication
betweenthePL/SQLandSQLenginesisalsoknownasacontextswitch.Acertain
performanceoverheadisassociatedwiththesecontextswitches.However,thePL/SQL
languagehasanumberoffeaturesthatcanminimizetheperformanceoverhead,whichare
collectivelyknownasbulkSQL.Generally,ifaSQLstatementaffectsfourormorerows,
bulkSQLmayimproveperformancesignificantly.BulkSQLsupportsbatchprocessingof
SQLstatementsandtheirresults,anditconsistsoftwofeatures,theFORALLstatement
andtheBULKCOLLECTclause.
StartingwithOracle12c,supportforcollectiondatatypesandbulkSQLhasbeen
extendedtodynamicSQL.Asaconsequence,youareabletobindcollectionvariables
whenusinganEXECUTEIMMEDIATEstatementorOPEN-FOR,FETCH,andCLOSE
statements.ThisabilityiscoveredindetailinLab18.3.

Lab18.1:FORALLStatements
AfterthisLab,youwillbeableto
UseFORALLStatements
UsetheSAVEEXCEPTIONSOption
UsetheINDICESOFOption
UsetheVALUESOFOption
ConsideranINSERTstatementenclosedbyanumericFORloopthatiterates10times,as
showninListing18.1.
Listing18.1INSERTStatementEnclosedbyaNumericFORLoop
FORiIN1..10
LOOP
INSERTINTOtable_name
VALUES(…);
ENDLOOP;

ThisINSERTstatementwillbesentfromthePL/SQLenginetotheSQLengine10
times.Inotherwords,10contextswitchestakeplace.IfthenumericFORloopisreplaced
withaFORALLstatement,however,theINSERTstatementissentonlyoncefrom

PL/SQLenginetotheSQLengine,yetitisstillexecuted10times.Inthiscase,thereis
onlyonecontextswitchbetweenPL/SQLandSQL.

UsingFORALLStatements
TheFORALLstatementsendsINSERT,UPDATE,orDELETEstatementsinbatchesfrom
thePL/SQLenginetotheSQLengineinsteadofonestatementatatime.Ithasthe
structureshowninListing18.2(thereservedwordsandphrasessurroundedbybrackets
areoptional).
Listing18.2FORALLStatementSyntax
Clickheretoviewcodeimage
FORALLloop_counterINbounds_clause
SQL_STATEMENT[SAVEEXCEPTIONS];

whereBOUNDS_CLAUSEisoneofthefollowing:
Clickheretoviewcodeimage
lower_limit..upper_limit
INDICESOFcollection_nameBETWEENlower_limit..upper_limit
VALUESOFcollection_name

TheFORALLstatementhasanimplicitlydefinedloopcountervariableassociatedwith
it.Thevaluesofthisloopcountervariableandthenumberofloopiterationsarecontrolled
bytheBOUNDS_CLAUSE,whichhasthreeforms.Thefirstformspecifieslowerand
upperlimitsfortheloopcounter;thissyntaxisverysimilartothenumericFORloop.The
secondform,INDICESOF…referencessubscriptsoftheindividualelementsofa
particularcollection.Thiscollectionmaybeanestedtableoranassociativearraythathas
numericsubscripts.ThethirdformoftheBOUNDS_CLAUSE,VALUESOF…references
valuesoftheindividualelementsofaparticularcollectionthatiseitheranestedtableor
anassociativearray.
BytheWay
AcollectionreferencedbytheINDICESOFclausemaybesparse.Inother
words,someofitselementshavebeendeleted.