243 56 28MB
English Pages 911 Year 2009
SQL The Complete Reference, Third Edition
This page intentionally left blank
SQL The Complete Reference, Third Edition PaulWeinberg JamesGroff AndrewOppel
NewYorkChicagoSanFrancisco LisbonLondonMadridMexicoCity MilanNewDelhiSanJuan SeoulSingaporeSydneyToronto
Copyright © 2010 by The McGraw-Hill Companies. All rights reserved. Except as permitted under the United States Copyright Act of 1976, no part of this publication may be reproduced or distributed in any form or by any means, or stored in a database or retrieval system, without the prior written permission of the publisher. ISBN: 978-0-07-159256-7 MHID: 0-07-159256-3 The material in this eBook also appears in the print version of this title: ISBN: 978-0-07-159255-0, MHID: 0-07-159255-5. All trademarks are trademarks of their respective owners. Rather than put a trademark symbol after every occurrence of a trademarked name, we use names in an editorial fashion only, and to the benefit of the trademark owner, with no intention of infringement of the trademark. Where such designations appear in this book, they have been printed with initial caps. McGraw-Hill eBooks are available at special quantity discounts to use as premiums and sales promotions, or for use in corporate training programs. To contact a representative please e-mail us at [email protected]. Information has been obtained by McGraw-Hill from sources believed to be reliable. However, because of the possibility of human or mechanical error by our sources, McGraw-Hill, or others, McGraw-Hill does not guarantee the accuracy, adequacy, or completeness of any information and is not responsible for any errors or omissions or the results obtained from the use of such information. TERMS OF USE This is a copyrighted work and The McGraw-Hill Companies, Inc. (“McGraw-Hill”) and its licensors reserve all rights in and to the work. Use of this work is subject to these terms. Except as permitted under the Copyright Act of 1976 and the right to store and retrieve one copy of the work, you may not decompile, disassemble, reverse engineer, reproduce, modify, create derivative works based upon, transmit, distribute, disseminate, sell, publish or sublicense the work or any part of it without McGraw-Hill’s prior consent. You may use the work for your own noncommercial and personal use; any other use of the work is strictly prohibited. Your right to use the work may be terminated if you fail to comply with these terms. THE WORK IS PROVIDED “AS IS.” McGRAW-HILL AND ITS LICENSORS MAKE NO GUARANTEES OR WARRANTIES AS TO THE ACCURACY, ADEQUACY OR COMPLETENESS OF OR RESULTS TO BE OBTAINED FROM USING THE WORK, INCLUDING ANY INFORMATION THAT CAN BE ACCESSED THROUGH THE WORK VIA HYPERLINK OR OTHERWISE, AND EXPRESSLY DISCLAIM ANY WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. McGraw-Hill and its licensors do not warrant or guarantee that the functions contained in the work will meet your requirements or that its operation will be uninterrupted or error free. Neither McGraw-Hill nor its licensors shall be liable to you or anyone else for any inaccuracy, error or omission, regardless of cause, in the work or for any damages resulting therefrom. McGraw-Hill has no responsibility for the content of any information accessed through the work. Under no circumstances shall McGraw-Hill and/or its licensors be liable for any indirect, incidental, special, punitive, consequential or similar damages that result from the use of or inability to use the work, even if any of them has been advised of the possibility of such damages. This limitation of liability shall apply to any claim or cause whatsoever whether such claim or cause arises in contract, tort or otherwise.
About the Authors
JamesR.GroffisCEOofPBworks,whosehostedcollaborationsoftwarehelpsteamsofpeople worktogethermoreeffectivelyandefficiently.Earlier,GroffwasCEOofTimesTen,theleading providerofin-memorySQLdatabases.HeledTimesTenfromitsearlydaysthrougheightyearsof growthandasuccessfulacquisitionbyOraclein2005,whereheservedasaseniorvicepresident, andOracleTimesTenbecameOracle’sflagshipreal-timedatabaseproduct.Groffwasthe cofounder,withPaulWeinberg,ofNetworkInnovationsCorporation,adeveloperofSQL-based networkingsoftware,andcoauthorwithhimofUnderstandingUNIX:AConceptualGuideaswell asthisbook.GroffhasalsoheldseniordivisionmanagementandmarketingpositionsatApple ComputerandHewlett-Packard.HeholdsaBSinMathematicsfromtheMassachusettsInstitute ofTechnologyandanMBAfromHarvardUniversity. PaulN.WeinbergisaseniorvicepresidentatSAP,whereherunscoreMDM(MasterData Management)development.PriortoworkingatSAP,WeinbergwaspresidentofA2i,Inc.,which wasacquiredbySAPin2004foritsenterprisewideplatformforproductcontentmanagementand catalogpublishing.Weinbergwasthecofounder,withJamesGroff,ofNetworkInnovations Corporation,apioneerinclient/serverdatabaseaccessthatwasacquiredbyAppleComputerin 1988,andcoauthorwithhimofUnderstandingUNIX: AConceptualGuideaswellasthisbook.Hehasalsoheldsoftwaredevelopmentandmarketing positionsatBellLaboratories,Hewlett-Packard,andPlexusComputers.In1981,hecollaborated onTheSimpleSolutiontoRubik’sCube,thenumber-onebest-sellingbookofthatyear,withover6 millioncopiessold.HeholdsaBSfromtheUniversityofMichiganandanMSfromStanford University,bothinComputerScience. AndrewJ.(Andy)OppelisleaddatamodeleratBlueShieldofCalifornia.Inaddition,hehas servedasapart-timeinstructorindatabasetechnologywiththeUniversityofCaliforniaat Berkeley,Extensionformorethan20years.Andyhasdesignedandimplementedhundredsof databasesforawiderangeofapplications,includingheathcare,banking,insurance,apparel manufacturing,telecommunications,wirelesscommunications,andhumanresources.Heisthe authorofDatabasesDemystified,SQLDemystified,andDatabases:ABeginner’sGuideandiscoauthor ofSQL:ABeginner’sGuide.HeholdsaBAinComputerSciencefromTransylvaniaUniversity (Lexington,KY).
About the Technical Editor AaronDavenporthasbeenworkingwithSQL-basedRDBMStechnologiesforovertenyears.He iscurrentlyaprincipalatLCSTechnologies,Inc.,aSacramentoandSanFranciscoBayArea databaseconsultingfirmspecializinginperformancetuning,applicationdevelopment,and databasearchitecture.PriortojoiningLCS,AaronhadtenuresatYahoo!,GapInc.,andBlueShield ofCalifornia.
This page intentionally left blank
Contents at a Glance Part I An Overview of SQL
1 Introduction .....................................................
3
2 AQuickTourofSQL .............................................
13
3 SQLinPerspective ...............................................
21
4 RelationalDatabases .............................................
45
Part II Retrieving Data
5 SQLBasics ......................................................
63
6 SimpleQueries ..................................................
85
7 MultitableQueries(Joins) ......................................... 119
8 SummaryQueries ................................................ 163
9 SubqueriesandQueryExpressions ................................. 187
Part III Updating Data
10 DatabaseUpdates ................................................ 231
11 DataIntegrity .................................................... 247
12 TransactionProcessing ............................................ 281
Part IV Database Structure
13 CreatingaDatabase .............................................. 315
14 Views ........................................................... 355
15 SQLSecurity ..................................................... 375
16 TheSystemCatalog .............................................. 399
vii
viii
SQL: The Complete Reference
Part V Programming with SQL
17 EmbeddedSQL .................................................. 429
18 DynamicSQL* ................................................... 477
19 SQLAPIs ........................................................ 521
Part VI SQL Today and Tomorrow
20 DatabaseProcessingandStoredProceduralSQL ..................... 617
21 SQLandDataWarehousing ....................................... 667
22 SQLandApplicationServers ...................................... 681
23 SQLNetworkingandDistributedDatabases ........................ 699
24 SQLandObjects ................................................. 735
25 SQLandXML .................................................... 769
26 SpecialtyDatabases .............................................. 805
27 TheFutureofSQL ................................................ 819
Part VII Appendixes
A TheSampleDatabase ............................................. 835
B DBMSVendorProfiles ............................................ 841
C SQLSyntaxReference ............................................ 857
Index ........................................................... 865
Contents
Contents Acknowledgments ................................................ xxiii Introduction ...................................................... xxv
Part I An Overview of SQL
1 Introduction ..................................................... TheSQLLanguage ................................................ TheRoleofSQL .................................................. SQLSuccessFactors ............................................... VendorIndependence ....................................... PortabilityAcrossComputerSystems .......................... OfficialSQLStandards ....................................... EarlyIBMCommitment ..................................... MicrosoftSupport ........................................... RelationalFoundation ....................................... High-Level,English-LikeStructure ............................ Interactive,AdHocQueries .................................. ProgrammaticDatabaseAccess ............................... MultipleViewsofData ...................................... CompleteDatabaseLanguage ................................ DynamicDataDefinition .................................... Client/ServerArchitecture ................................... EnterpriseApplicationSupport ............................... ExtensibilityandObjectTechnology ........................... InternetDatabaseAccess ..................................... JavaIntegration(JDBC) ...................................... OpenSourceSupport ........................................ IndustryInfrastructure ......................................
3 4 6 7 8 8 9 9 9 9 10 10 10 10 10 10 11 11 11 11 12 12 12
2 AQuickTourofSQL ............................................. ASimpleDatabase ................................................ RetrievingData ................................................... SummarizingData ................................................ AddingDatatotheDatabase ....................................... DeletingData .................................................... UpdatingtheDatabase ............................................ ProtectingData ................................................... CreatingaDatabase ............................................... Summary ........................................................
13 13 14 16 17 18 18 18 19 20
ix
ix
x
SQL: The Complete Reference
3 SQLinPerspective ............................................... SQLandtheEvolutionofDatabaseManagement ...................... ABriefHistoryofSQL ............................................. TheEarlyYears ............................................. EarlyRelationalProducts .................................... IBMProducts ............................................... CommercialAcceptance ..................................... SQLStandards .................................................... TheANSI/ISOStandards .................................... OtherEarlySQLStandards ................................... ODBCandtheSQLAccessGroup ............................. JDBCandApplicationServers ................................ SQLandPortability ......................................... SQLandNetworking .............................................. CentralizedArchitecture ..................................... FileServerArchitecture ...................................... Client/ServerArchitecture ................................... MultitierArchitecture ....................................... TheProliferationofSQL ........................................... SQLonMainframes ......................................... SQLonMinicomputers ...................................... SQLonUNIX-BasedSystems ................................. SQLonPersonalComputers .................................. SQLandTransactionProcessing .............................. SQLandWorkgroupDatabases ............................... SQL,DataWarehousing,andBusinessIntelligence .............. SQLandInternetApplications ................................ Summary ........................................................
21 21 22 22 22 24 25 26 26 29 29 30 30 32 32 33 34 35 36 36 36 37 37 38 39 40 42 43
4 RelationalDatabases ............................................. EarlyDataModels ................................................ FileManagementSystems .................................... HierarchicalDatabases ...................................... NetworkDatabases ......................................... TheRelationalDataModel ......................................... TheSampleDatabase ........................................ Tables ..................................................... PrimaryKeys ............................................... Relationships ............................................... ForeignKeys ............................................... Codd’s12RulesforRelationalDatabases* ............................ Summary ........................................................
45 45 45 47 48 50 51 52 53 55 56 57 59
Contents
Part II Retrieving Data
5 SQLBasics ...................................................... Statements ....................................................... Names .......................................................... TableNames ............................................... ColumnNames ............................................. DataTypes ....................................................... Constants ........................................................ NumericConstants .......................................... StringConstants ............................................ DateandTimeConstants .................................... SymbolicConstants ......................................... Expressions ...................................................... Built-InFunctions ................................................. MissingData(NULLValues) ....................................... Summary ........................................................
63 63 70 70 71 72 77 77 78 78 79 80 80 82 83
6 SimpleQueries .................................................. TheSELECTStatement ............................................ TheSELECTClause ......................................... TheFROMClause .......................................... QueryResults .................................................... SimpleQueries ................................................... CalculatedColumns ......................................... SelectingAllColumns(SELECT*) ................................... DuplicateRows(DISTINCT) ....................................... RowSelection(WHEREClause) .................................... SearchConditions ................................................. TheComparisonTest(=,,=) ............................ TheRangeTest(BETWEEN) .................................. TheSetMembershipTest(IN) ................................ ThePatternMatchingTest(LIKE) ............................. TheNullValueTest(ISNULL) ................................ CompoundSearchConditions(AND,OR,andNOT) ............ SortingQueryResults(ORDERBYClause) ........................... RulesforSingle-TableQueryProcessing ............................. CombiningQueryResults(UNION)* .......................... UnionsandDuplicateRows* ................................. UnionsandSorting* ......................................... MultipleUNIONs* .......................................... Summary ........................................................
85 85 87 88 88 90 91 93 94 95 97 97 100 102 104 106 107 110 112 113 115 116 117 118
xi
xii
SQL: The Complete Reference
7 MultitableQueries(Joins) ......................................... ATwo-TableQueryExample ....................................... SimpleJoins(Equi-Joins) ........................................... Parent/ChildQueries ....................................... AnAlternativeWaytoSpecifyJoins ........................... JoinswithRowSelectionCriteria ............................. MultipleMatchingColumns .................................. NaturalJoins ............................................... QuerieswithThreeorMoreTables ............................ OtherEqui-Joins ............................................ Non-Equi-Joins ................................................... SQLConsiderationsforMultitableQueries ........................... QualifiedColumnNames .................................... All-ColumnSelections ....................................... Self-Joins .................................................. TableAliases ............................................... MultitableQueryPerformance ...................................... TheStructureofaJoin ............................................. TableMultiplication ......................................... RulesforMultitableQueryProcessing ......................... OuterJoins ....................................................... LeftandRightOuterJoins ................................... OlderOuterJoinNotation* ................................... JoinsandtheSQLStandard ........................................ InnerJoinsinStandardSQL .................................. OuterJoinsinStandardSQL* ................................. CrossJoinsinStandardSQL* ................................. MultitableJoinsinStandardSQL .............................. Summary ........................................................
119 119 121 123 125 126 127 128 129 131 134 134 135 136 137 139 141 142 142 143 144 148 151 153 153 154 155 157 162
8 SummaryQueries ................................................ ColumnFunctions ................................................ ComputingaColumnTotal(SUM) ............................ ComputingaColumnAverage(AVG) ......................... FindingExtremeValues(MINandMAX) ...................... CountingDataValues(COUNT) .............................. ColumnFunctionsintheSelectList ........................... NULLValuesandColumnFunctions .......................... DuplicateRowElimination(DISTINCT) ....................... GroupedQueries(GROUPBYClause) ............................... MultipleGroupingColumns ................................. RestrictionsonGroupedQueries .............................. NULLValuesinGroupingColumns ...........................
163 163 165 166 166 168 169 171 173 173 176 179 181
Contents
GroupSearchConditions(HAVINGClause) .......................... RestrictionsonGroupSearchConditions ....................... NULLValuesandGroupSearchConditions .................... HAVINGWithoutGROUPBY ................................ Summary ........................................................
182 185 186 186 186
9 SubqueriesandQueryExpressions ................................. UsingSubqueries ................................................. WhatIsaSubquery? ........................................ SubqueriesintheWHEREClause ............................. OuterReferences ............................................ SubquerySearchConditions ........................................ TheSubqueryComparisonTest(=,,=) ............. TheSetMembershipTest(IN) ................................ TheExistenceTest(EXISTS) .................................. QuantifiedTests(ANYandALL)* ............................. SubqueriesandJoins .............................................. NestedSubqueries ................................................ CorrelatedSubqueries* ............................................ SubqueriesintheHAVINGClause* ................................. SubquerySummary ............................................... AdvancedQueries* ............................................... Scalar-ValuedExpressions ................................... Row-ValuedExpressions ..................................... Table-ValuedExpressions .................................... QueryExpressions .......................................... SQLQueries:AFinalSummary .....................................
187 187 188 189 191 192 192 194 196 198 203 204 205 208 209 211 213 218 221 224 227
Part III Updating Data
10 DatabaseUpdates ................................................ AddingDatatotheDatabase ....................................... TheSingle-RowINSERTStatement ............................ TheMultirowINSERTStatement ............................. BulkLoadUtilities .......................................... DeletingDatafromtheDatabase .................................... TheDELETEStatement ...................................... DeletingAllRows ........................................... DELETEwithSubquery* ..................................... ModifyingDataintheDatabase .................................... TheUPDATEStatement ..................................... UpdatingAllRows .......................................... UPDATEwithSubquery* .................................... Summary ........................................................
231 231 232 235 238 238 239 240 241 242 243 245 245 246
xiii
xiv
SQL: The Complete Reference
11 DataIntegrity .................................................... WhatIsDataIntegrity? ............................................ RequiredData .................................................... SimpleValidityChecking .......................................... ColumnCheckConstraints ................................... Domains ................................................... EntityIntegrity ................................................... OtherUniquenessConstraints ................................ UniquenessandNULLValues ................................ ReferentialIntegrity ............................................... ReferentialIntegrityProblems ................................ DeleteandUpdateRules* .................................... CascadedDeletesandUpdates* ............................... ReferentialCycles* .......................................... ForeignKeysandNULLValues* .............................. AdvancedConstraintCapabilities ................................... Assertions ................................................. SQLConstraintTypes ....................................... DeferredConstraintChecking ................................ BusinessRules .................................................... WhatIsaTrigger? ........................................... TriggersandReferentialIntegrity ............................. TriggerAdvantagesandDisadvantages ........................ TriggersandtheSQLStandard ............................... Summary ........................................................
247 248 249 250 251 251 253 253 254 255 256 258 262 262 267 269 270 270 271 274 275 277 277 278 279
12 TransactionProcessing ............................................ WhatIsaTransaction? ............................................. TheANSI/ISOSQLTransactionModel .............................. TheSTARTTRANSACTIONandSETTRANSACTIONStatements ... TheSAVEPOINTandRELEASESAVEPOINTStatements ........ TheCOMMITandROLLBACKStatements ..................... Transactions:BehindtheScenes* .................................... TransactionsandMultiuserProcessing ............................... TheLostUpdateProblem .................................... TheUncommittedDataProblem .............................. TheInconsistentDataProblem ................................ ThePhantomInsertProblem ................................. ConcurrentTransactions ..................................... Locking* ......................................................... LockingLevels ............................................. SharedandExclusiveLocks .................................. Deadlocks* ................................................. AdvancedLockingTechniques* ...............................
281 282 284 284 286 286 289 290 291 292 293 294 296 297 298 300 300 303
Contents
Versioning* ...................................................... VersioninginOperation* ..................................... VersioningAdvantagesandDisadvantages* .................... Summary ........................................................
307 308 311 311
Part IV Database Structure
13 CreatingaDatabase .............................................. TheDataDefinitionLanguage ...................................... CreatingaDatabase ............................................... TableDefinitions .................................................. CreatingaTable(CREATETABLE) ............................ RemovingaTable(DROPTABLE) ............................. ChangingaTableDefinition(ALTERTABLE) ................... ConstraintDefinitions ............................................. Assertions ................................................. Domains ................................................... AliasesandSynonyms(CREATE/DROPALIAS) ...................... Indexes(CREATE/DROPINDEX) .................................. ManagingOtherDatabaseObjects .................................. DatabaseStructure ................................................ Single-DatabaseArchitecture ................................. MultidatabaseArchitecture ................................... MultilocationArchitecture ................................... DatabasesonMultipleServers ................................ DatabaseStructureandtheANSI/ISOStandard ...................... Catalogs ................................................... Schemas ................................................... Summary ........................................................
315 315 317 318 318 327 328 332 332 333 333 335 339 342 343 344 346 348 348 350 351 354
14 View ............................................................ WhatIsaView? ............................................ HowtheDBMSHandlesViews ............................... AdvantagesofViews ........................................ DisadvantagesofViews ..................................... CreatingaView(CREATEVIEW) ................................... HorizontalViews ........................................... VerticalViews .............................................. Row/ColumnSubsetViews .................................. GroupedViews ............................................. JoinedViews ............................................... UpdatingaView .................................................. ViewUpdatesandtheANSI/ISOStandard ..................... ViewUpdatesinCommercialSQLProducts .................... CheckingViewUpdates(CHECKOPTION) ....................
355 355 357 357 358 358 359 361 361 363 364 366 367 368 368
xv
xvi
SQL: The Complete Reference
DroppingaView(DROPVIEW) .................................... 371 MaterializedViews* ............................................... 372 Summary ........................................................ 374
15 SQLSecurity ..................................................... SQLSecurityConcepts ............................................ User-Ids ................................................... SecurityObjects ............................................ Privileges .................................................. ViewsandSQLSecurity ........................................... GrantingPrivileges(GRANT) ...................................... ColumnPrivileges .......................................... PassingPrivileges(GRANTOPTION) ......................... RevokingPrivileges(REVOKE) ..................................... REVOKEandtheGRANTOPTION ........................... REVOKEandtheANSI/ISOStandard ......................... Role-BasedSecurity ............................................... Summary ........................................................
375 376 376 381 381 384 386 388 389 391 393 394 396 398
16 TheSystemCatalog .............................................. WhatIstheSystemCatalog? ....................................... TheCatalogandQueryTools ................................. TheCatalogandtheANSI/ISOStandard ...................... CatalogContents ........................................... TableInformation ................................................. ColumnInformation .............................................. ViewInformation ................................................. Remarks ......................................................... RelationshipInformation .......................................... UserInformation ................................................. PrivilegesInformation ............................................. TheSQLInformationSchema ....................................... OtherCatalogInformation ......................................... Summary ........................................................
399 399 400 401 401 403 407 410 412 413 415 417 418 425 426
Part V Programming with SQL
17 EmbeddedSQL .................................................. ProgrammaticSQLTechniques ..................................... DBMSStatementProcessing .................................. EmbeddedSQLConcepts .................................... DevelopinganEmbeddedSQLProgram ....................... RunninganEmbeddedSQLProgram ..........................
429 429 431 433 434 437
Contents
SimpleEmbeddedSQLStatements .................................. DeclaringTables ............................................ ErrorHandling ............................................. UsingHostVariables ........................................ DataRetrievalinEmbeddedSQL ................................... Single-RowQueries ......................................... MultirowQueries ........................................... Cursor-BasedDeletesandUpdates .................................. CursorsandTransactionProcessing ................................. Summary ........................................................
439 441 443 451 457 457 464 470 475 476
18 DynamicSQL* ................................................... LimitationsofStaticSQL ........................................... DynamicSQLConcepts ............................................ DynamicStatementExecution(EXECUTEIMMEDIATE) ............... Two-StepDynamicExecution ....................................... ThePREPAREStatement ..................................... TheEXECUTEStatement .................................... DynamicQueries ................................................. TheDESCRIBEStatement .................................... TheDECLARECURSORStatement ........................... TheDynamicOPENStatement ............................... TheDynamicFETCHStatement .............................. TheDynamicCLOSEStatement .............................. DynamicSQLDialects ............................................. DynamicSQLinOracle* ..................................... DynamicSQLandtheSQLStandard ................................ BasicDynamicSQLStatements ............................... TheStandardSQLDA ....................................... TheSQLStandardandDynamicSQLQueries .................. Summary ........................................................
477 477 479 480 483 485 486 493 495 500 500 503 504 504 504 508 508 510 515 518
19 SQLAPIs ........................................................ APIConcepts ..................................................... ThedblibAPI(SQLServer) ......................................... BasicSQLServerTechniques ................................. SQLServerQueries ......................................... PositionedUpdates ......................................... DynamicQueries ........................................... ODBCandtheSQL/CLIStandard .................................. TheCall-LevelInterfaceStandardization ....................... CLIStructures .............................................. CLIStatementProcessing .................................... CLIErrorsandDiagnosticInformation ........................ CLIAttributes .............................................. CLIInformationCalls .......................................
521 522 523 524 532 539 540 549 549 552 557 575 577 577
xvii
xviii
SQL: The Complete Reference
TheODBCAPI ................................................... TheStructureofODBC ...................................... ODBCandDBMSIndependence .............................. ODBCCatalogFunctions .................................... ExtendedODBCCapabilities ................................. TheOracleCallInterface(OCI) ..................................... OCIHandles ............................................... OracleServerConnection .................................... StatementExecution ......................................... QueryResultsProcessing .................................... DescriptorHandling ........................................ TransactionManagement .................................... JavaDatabaseConnectivity(JDBC) .................................. JDBCHistoryandVersions ................................... JDBCImplementationsandDriverTypes ...................... TheJDBCAPI .............................................. Summary ........................................................
579 580 581 581 582 586 586 588 589 590 590 590 592 592 593 598 614
Part VI SQL Today and Tomorrow
20 DatabaseProcessingandStoredProceduralSQL ..................... ProceduralSQLConcepts .......................................... ABasicExample .................................................. UsingStoredProcedures ........................................... CreatingaStoredProcedure .................................. CallingaStoredProcedure ................................... StoredProcedureVariables ................................... StatementBlocks ............................................ Functions .................................................. ReturningValuesviaParameters .............................. ConditionalExecution ....................................... RepeatedExecution ......................................... OtherFlow-of-ControlConstructs ............................. Cursor-BasedRepetition ..................................... HandlingErrorConditions ................................... AdvantagesofStoredProcedures ................................... StoredProcedurePerformance ...................................... System-DefinedStoredProcedures .................................. ExternalStoredProcedures ......................................... Triggers ......................................................... AdvantagesandDisadvantagesofTriggers ..................... TriggersinTransact-SQL ..................................... TriggersinInformixSPL ..................................... TriggersinOraclePL/SQL ................................... OtherTriggerConsiderations .................................
617 618 620 621 622 624 625 627 630 631 634 636 638 639 643 645 646 647 647 648 649 649 651 653 655
Contents
StoredProcedures,Functions,Triggers,andtheSQLStandard .......... TheSQL/PSMStoredProceduresStandard .................... TheSQL/PSMTriggersStandard ............................. Summary ........................................................
655 656 664 666
21 SQLandDataWarehousing ....................................... DataWarehousingConcepts ........................................ ComponentsofaDataWarehouse ............................. TheEvolutionofDataWarehousing ........................... DatabaseArchitectureforWarehousing .............................. FactCubes ................................................. StarSchemas ............................................... MultilevelDimensions ....................................... SQLExtensionsforDataWarehousing ......................... WarehousePerformance ........................................... LoadPerformance .......................................... QueryPerformance ......................................... Summary ........................................................
667 668 669 670 671 672 673 675 676 678 678 679 680
22 SQLandApplicationServers ...................................... SQLandWebSites:EarlyImplementations ........................... ApplicationServersandThree-TierWebSiteArchitectures ............. DatabaseAccessfromApplicationServers ........................... EJBTypes .................................................. SessionBeanDatabaseAccess ................................ EntityBeanDatabaseAccess ................................. EJB2.0Enhancements ....................................... EJB3.0Enhancements ....................................... OpenSourceApplicationDevelopment ........................ ApplicationServerCaching ........................................ Summary ........................................................
681 681 682 684 685 686 689 692 693 695 695 698
23 SQLNetworkingandDistributedDatabases ........................ TheChallengeofDistributedDataManagement ...................... DistributingData:PracticalApproaches ............................. RemoteDatabaseAccess ..................................... RemoteDataTransparency ................................... TableExtracts .............................................. TableReplication ........................................... UpdateableReplicas ......................................... ReplicationTrade-Offs ....................................... TypicalReplicationArchitectures ............................. DistributedDatabaseAccess ........................................ RemoteRequests ............................................ RemoteTransactions ........................................ DistributedTransactions ..................................... DistributedRequests ........................................
699 700 704 705 708 709 711 713 715 715 719 720 721 722 722
xix
xx
SQL: The Complete Reference
TheTwo-PhaseCommitProtocol* ................................... NetworkApplicationsandDatabaseArchitecture ..................... Client/ServerApplicationsandDatabaseArchitecture ........... Client/ServerApplicationswithStoredProcedures ............. EnterpriseApplicationsandDataCaching ..................... High-VolumeInternetDataManagement ...................... Summary ........................................................
724 727 728 729 730 731 733
24 SQLandObjects ................................................. Object-OrientedDatabases ......................................... Object-OrientedDatabaseCharacteristics ...................... ProsandConsofObject-OrientedDatabases ................... ObjectsandtheDatabaseMarket .............................. Object-RelationalDatabases ........................................ LargeObjectSupport ........................................ LOBsintheRelationalModel ................................. SpecializedLOBProcessing .................................. Abstract(Structured)DataTypes .................................... DefiningAbstractDataTypes ................................. ManipulatingAbstractDataTypes ............................ Inheritance ....................................................... TableInheritance:ImplementingObjectClasses ................. Sets,Arrays,andCollections ....................................... DefiningCollections ......................................... QueryingCollectionData .................................... ManipulatingCollectionData ................................ CollectionsandStoredProcedures ............................ User-DefinedDataTypes .......................................... MethodsandStoredProcedures .................................... ObjectSupportintheSQLStandard ................................. Summary ........................................................
735 735 736 737 738 739 740 740 742 744 746 748 749 751 754 755 758 759 760 762 763 766 767
25 SQLandXML .................................................... WhatIsXML? .................................................... XMLBasics ...................................................... XMLforData ..................................................... XMLandSQL .............................................. Elementsvs.Attributes ...................................... UsingXMLwithDatabases ......................................... XMLOutput ............................................... XMLInput ................................................. XMLDataExchange ......................................... XMLStorageandIntegration .................................
769 769 771 773 774 775 777 778 782 784 784
Contents
XMLandMetadata ................................................ DocumentTypeDefinitions(DTDs) ........................... XMLSchema ............................................... XMLandQueries ................................................. XQueryConcepts ........................................... QueryProcessinginXQuery ................................. XMLDatabases ................................................... Summary ........................................................
788 790 791 797 798 800 802 803
26 SpecialtyDatabases .............................................. VeryLowLatencyandIn-MemoryDatabases ......................... AnatomyofanIn-MemoryDatabase .......................... In-MemoryDatabaseImplementations .............................. CachingwithIn-MemoryDatabases ........................... ComplexEvent-ProcessingandStreamDatabases ..................... ContinuousQueriesinStreamDatabases ...................... StreamDatabaseImplementations ............................ StreamDatabaseComponents ................................ EmbeddedDatabases .............................................. EmbeddedDatabaseCharacteristics ........................... EmbeddedDatabaseImplementations ......................... MobileDatabases ................................................. MobileDatabaseRoles ....................................... MobileDatabaseImplementations ............................ Summary ........................................................
805 805 806 808 808 810 811 812 813 814 815 815 816 816 817 818
27 TheFutureofSQL ................................................ DatabaseMarketTrends ........................................... EnterpriseDatabaseMarketMaturity .......................... MarketDiversityandSegmentation ........................... PackagedEnterpriseApplications ............................. Software-as-a-Service(SaaS) .................................. HardwarePerformanceGains ................................ DatabaseServerAppliances .................................. SQLStandardization ........................................ SQLintheNextDecade ............................................ DistributedDatabases ....................................... MassiveDataWarehousingforBusinessOptimization ........... Ultrahigh-PerformanceDatabases ............................. InternetandNetworkServicesIntegration ..................... EmbeddedDatabases ........................................ ObjectIntegration ........................................... Cloud-BasedandHorizontallyScalableDatabases .............. Summary ........................................................
819 820 820 821 822 823 823 824 825 826 826 826 827 828 829 829 830 832
xxi
xxii
SQL: The Complete Reference
Part VII Appendixes
A TheSampleDatabase ............................................. 835
B DBMSVendorProfiles ............................................ 841
C SQLSyntaxReference ............................................ DataDefinitionStatements ......................................... AccessControlStatements ......................................... BasicDataManipulationStatements ................................. Transaction-ProcessingStatements .................................. Cursor-BasedStatements .......................................... QueryExpressions ................................................ SearchConditions ................................................. Expressions ...................................................... StatementElements ............................................... SimpleElements ..................................................
857 858 859 859 860 860 860 862 863 863 864
Index ........................................................... 865
Introduction
Acknowledgments
S
pecialthankstoAndyOppel,ournewcoauthorforthisthirdeditionofSQL:The CompleteReference.Hisimpressivehigh-levelmasteryofthesubjectmattercoupled withhismeticulousattentiontodetailmadethisabetterbook,andwearefortunate tohavehadhisinvolvement. —JimandPaul
It’sanhonortojoinsuchanaccomplishedteamofauthorsforthiseditionofSQL:The CompleteReference.MythanksfortheexcellentsupportoftheentireMcGraw-Hillteamfor theirtirelesssupportinthiseffort.InparticularIwishtothanktechnicaleditorAaron DavenportandcopyeditorJanJuefortheirpersistenceandattentiontodetail,which contributedsomuchtotheoverallqualityofthisbook. —Andy
xxiii
xxiii
This page intentionally left blank
Introduction
S
QL:TheCompleteReference,ThirdEditionprovidesacomprehensive,in-depth treatmentoftheSQLlanguageforbothtechnicalandnontechnicalusers, programmers,dataprocessingprofessionals,andmanagerswhowanttounderstand theimpactofSQLintoday’scomputerindustry.Thisbookoffersaconceptualframework forunderstandingandusingSQL,describesthehistoryofSQLandSQLstandards,and explainstheroleofSQLinvariouscomputerindustrysegments,fromenterprisedata processingtodatawarehousingtowebsitearchitectures.Thisneweditioncontainsnew chaptersspeciallyfocusedontheroleofSQLinapplicationserverarchitectures,andthe integrationofSQLwithXMLandotherobject-basedtechnologies. Thisbookwillshowyou,step-by-step,howtouseSQLfeatures,withmanyillustrations andrealisticexamplestoclarifySQLconcepts.ThebookalsocomparesSQLproductsfrom leadingDBMSvendors—describingtheiradvantages,benefits,andtrade-offs—tohelp youselecttherightproductforyourapplication.Mostoftheexamplesinthisbookare basedonthesampledatabasedescribedinAppendixA.Thesampledatabasecontains datathatsupportsasimpleorder-processingapplicationforasmalldistributioncompany. AppendixAalsocontainsinstructionsfordownloadingtheSQLstatementsrequiredto createandpopulatethesampledatabasetablesinaDBMSofyouchoice,suchasOracle, SQLServer,MySQL,andDB2.Thisallowsyoutotrytheexamplesinthebookyourself andgainactualexperiencewritingandrunningSQLstatements. Insomeofthechapters,thesubjectmatterisexploredattwodifferentlevels—a fundamentaldescriptionofthetopic,andanadvanceddiscussionintendedforcomputer professionalswhoneedtounderstandsomeoftheinternalsbehindSQL.Themore advancedinformationiscoveredinsectionsmarkedwithanasterisk(*).Youdonotneed toreadthesesectionstoobtainanunderstandingofwhatSQLisandwhatitdoes.
xxv
xxvi
SQL: The Complete Reference
How This Book Is Organized ThebookisdividedintosixpartsthatcovervariousaspectsoftheSQLlanguage: • PartI,“AnOverviewofSQL,”providesanintroductiontoSQLandamarket perspectiveofitsroleasadatabaselanguage.Itsfourchaptersdescribethehistory ofSQL,theevolutionofSQLstandards,andhowSQLrelatestotherelationaldata modelandtoearlierdatabasetechnologies.PartIalsocontainsaquicktourofSQL thatbrieflyillustratesitsmostimportantfeaturesandprovidesyouwithan overviewoftheentirelanguageearlyinthebook. • PartII,“RetrievingData,”describesthefeaturesofSQLthatallowyoutoperform databasequeries.Thefirstchapterinthispartdescribesthebasicstructureofthe SQLlanguage.ThenextfourchaptersstartwiththesimplestSQLqueriesand progressivelybuildtomorecomplexqueries,includingmultitablequeries, summaryqueries,andqueriesthatusesubqueries. • PartIII,“UpdatingData,”showshowyoucanuseSQLtoaddnewdatatoa database,deletedatafromadatabase,andmodifyexistingdatabasedata.Italso describesthedatabaseintegrityissuesthatarisewhendataisupdated,andhow SQLaddressestheseissues.Thelastofthethreechaptersinthispartdiscussesthe SQLtransactionconceptandSQLsupportformultiusertransactionprocessing. • PartIV,“DatabaseStructure,”dealswithcreatingandadministeringaSQL-based database.Itsfourchapterstellyouhowtocreatethetables,views,andindexesthat formthestructureofarelationaldatabase.ItalsodescribestheSQLsecurityscheme thatpreventsunauthorizedaccesstodata,andtheSQLsystemcatalogthat describesthestructureofadatabase.Thispartalsodiscussesthesignificant differencesbetweenthedatabasestructuressupportedbyvariousSQL-basedDBMS products. • PartV,“ProgrammingwithSQL,”describeshowapplicationprogramsuseSQLfor databaseaccess.ItdiscussestheembeddedSQLspecifiedbytheANSIstandardand usedbyIBM,Oracle,Ingres,Informix,andmanyotherSQL-basedDBMSproducts. ItalsodescribesthedynamicSQLinterfacethatisusedtobuildgeneral-purpose databasetables,suchasreportwritersanddatabasebrowsingprograms.Finally, thispartdescribesthepopularSQLAPIs,includingODBC,theISO-standardCallLevelInterface,andJDBC,thestandardcall-levelinterfaceforJava,aswellas proprietarycall-levelinterfacessuchasOracle’sOCIAPI. • PartVI,“SQLTodayandTomorrow,”examinestheuseofSQLinseveraloftoday’s “hottest”applicationareas,andthecurrentstateofSQL-basedDBMSproducts.Two chaptersdescribetheuseofSQLstoredproceduresandtriggersforonline transactionprocessing,andthecontrastinguseofSQLfordatawarehousing.Four additionalchaptersdescribeSQL-baseddistributeddatabases,theinfluenceof objecttechnologiesonSQL,specialtydatabases,andtheintegrationofSQLwith XMLtechnologies.Finally,thelastchapterexploresthefutureofSQLandsomeof themostimportanttrendsinSQL-baseddatamanagement.
Introduction
Conventions Used in This Book SQL:TheCompleteReference,ThirdEditiondescribestheSQLfeaturesandfunctionsavailable inthemostpopularSQL-basedDBMSproductsandthosedescribedintheANSI/ISOSQL standards.Wheneverpossible,theSQLstatementsyntaxdescribedinthisbookandusedinthe examplesappliestoalldialectsofSQL.Whenthedialectsdiffer,thedifferencesarepointedout inthetext,andtheexamplesfollowthemostcommonpractice.Inthesecases,youmayhave tomodifytheSQLstatementsintheexamplesslightlytosuityourparticularbrandofDBMS. Throughoutthebook,technicaltermsappearinitalicsthefirsttimetheyareusedand defined.SQLlanguageelements,includingSQLkeywords,tableandcolumnnames,and sampleSQLstatements,appearinanUPPERCASEMONOSPACEfont.SQLAPIfunction namesappearinalowercasemonospacefont.Programlistingsalsoappearin monospacefontandusethenormalcaseconventionsfortheparticularprogramming language(uppercaseforCOBOLandFORTRAN,lowercaseforCandJava).Notethat theseconventionsareusedsolelytoimprovereadability;mostSQLimplementationswill accepteitheruppercaseorlowercasestatements.ManyoftheSQLexamplesincludequery results,whichappearimmediatelyfollowingtheSQLstatement,astheywouldinan interactiveSQLsession.Insomecases,longqueryresultsaretruncatedafterafewrows; thisisindicatedbyaverticalellipsis(…)followingthelastrowofqueryresults.
Why This Book Is for You SQL:TheCompleteReference,ThirdEditionistherightbookforanyonewhowantsto understandandlearnSQL,includingdatabaseusers,dataprocessingprofessionalsand architects,programmers,students,andmanagers.Itdescribes—insimple,understandable languageliberallyillustratedwithfiguresandexamples—whatSQLis,whyitisimportant, andhowyouuseit.ThisbookisnotspecifictooneparticularbrandordialectofSQL. Rather,itdescribesthestandard,centralcoreoftheSQLlanguageandthengoesonto describethedifferencesamongthemostpopularSQLproducts,includingOracle,Microsoft SQLServer,IBM’sDB2UniversalDatabaseandInformix,Sybase,andMySQL.Italso explainstheimportanceofSQL-basedstandards,suchasODBCandJDBC,andtheANSI/ ISOstandardsforSQLandSQL-relatedtechnologies.Thisthirdeditioncontainsnew chaptersandsectionsthatcoverthelatestSQLinnovations,intheareasofobject-relational technologies,XML,andapplicationserverarchitectures. IfyouarenewtoSQL,thisbookofferscomprehensive,step-by-steptreatmentofthe language,buildingfromsimplequeriestomoreadvancedconcepts.Thestructureofthe bookwillallowyoutoquicklystartusingSQL,butthebookwillcontinuetobevaluableas youbegintousethemorecomplexfeaturesofthelanguage.Youcancreatethesample databaseusinganSQLscriptavailableontheMcGraw-Hillwebsite(seeAppendixA)and useittotryouttheexamplesandbuildyourSQLskills. Ifyouareadataprocessingprofessional,architect,ormanager,thisbookwillgive youaperspectiveontheimpactthatSQLishavingacrosstheinformationtechnology industry—frompersonalcomputerstomainframestodatawarehousingtoInternetweb sitesandInternet-baseddistributedapplications.Theearlychaptersdescribethehistory ofSQL,itsroleinthemarket,anditsevolutionfromearlierdatabasetechnologies.Later chaptersdescribethefutureofSQLandthedevelopmentofnewdatabasetechnologies, suchasdistributeddatabases,object-orientedextensionstoSQL,businessintelligence databases,anddatabase/XMLintegration.
xxvii
xxviii
SQL: The Complete Reference
Ifyouareaprogrammer,thisbookoffersaverycompletetreatmentofprogrammingwith SQL.UnlikethereferencemanualsofmanyDBMSproducts,itoffersaconceptualframework forSQLprogramming,explainingthewhyaswellasthehowofdevelopingaSQL-based application.ItcontraststheSQLprogramminginterfacesofferedbyalloftheleadingSQL products,includingembeddedSQL,dynamicSQL,ODBC,JDBC,andproprietaryAPIs suchastheOracleCallInterface.Thedescriptionandcomparisonofprogrammingtechniques providesaperspectivenotfoundinanyotherbook. IfyouareselectingaDBMSproduct,thisbookoffersacomparisonoftheSQLfeatures, advantages,andbenefitsofferedbythevariousDBMSvendors.Thedifferencesbetween theleadingDBMSproductsareexplained,notonlyintechnicalterms,butalsointerms oftheirimpactonapplicationsandtheirevolvingcompetitivepositioninthemarketplace. The“sampledatabase”canbeusedtotrythesefeaturesinaprototypeofyourown application. Inshort,bothtechnicalandnontechnicaluserscanbenefitfromthisbook.Itisthemost comprehensivesourceofinformationavailableabouttheSQLlanguage,SQLfeaturesand benefits,popularSQL-basedproducts,thehistoryofSQL,andtheimpactofSQLonthe futuredirectionoftheinformationtechnologyindustry.
I
PART
An Overview of SQL
T
hefirstfourchaptersofthisbookprovideaperspectiveand aquickintroductiontoSQL.Chapter1describeswhatSQLis andexplainsitsmajorfeaturesandbenefits.InChapter2, aquicktourofSQLshowsyoumanyofitscapabilitieswithsimple, rapid-fireexamples.Chapter3offersamarketperspectiveofSQL bytracingitshistory,describingtheSQLstandardsandthemajor vendorsofSQL-basedproducts,andbyidentifyingthereasonsfor SQL’sprominencetoday.Chapter4describestherelationaldata modeluponwhichSQLisbasedandcomparesitwithearlierdata models.
CHAPTER 1 Introduction CHAPTER 2 AQuickTourofSQL CHAPTER 3 SQLinPerspective CHAPTER 4 RelationalDatabases
This page intentionally left blank
1
CHAPTER
Introduction
T
heSQLlanguageandrelationaldatabasesystemsbasedonitconstituteoneofthe mostimportantfoundationtechnologiesinthecomputerindustry.Overthelastthree decades,SQLhasgrownfromitsfirstcommercialuseintoacomputerproductand servicesmarketsegmentworthtensofbillionsofdollarsperyear,andSQLstandstodayas thestandardcomputerdatabaselanguage.Hundredsofdatabaseproductsnowsupport SQL,runningoncomputersystemsfrommainframestopersonalcomputers.ASQL-based databasemayevenbeembeddedinyourmobilephoneorPDA,orintheentertainment systemofyourcar.AnofficialinternationalSQLstandardhasbeenadoptedandexpanded severaltimes.EverymajorenterprisesoftwareproductreliesonSQLforitsdatamanagement, andSQLisatthecoreoftheflagshipdatabaseproductsfromMicrosoft,Oracle,andIBM, threeofthelargestsoftwarecompaniesintheworld.SQLisalsoattheheartofopen-source databaseproductssuchasMySQLandPostgresthatarehelpingtofuelthepopularityof Linuxandtheopensourcemovement.FromitsobscurebeginningsasanIBMresearchproject, SQLhasgrowntobecomebothanimportantpieceofinformationtechnologyandapowerful marketforce. What,exactly,isSQL?Whyisitimportant?Whatcanitdo,andhowdoesitwork?If SQLisreallyastandard,whydowehavesomanydifferentversionsanddialects?Howdo popularSQLproductslikeSQLServer,Oracle,MySQL,Sybase,andDB2compare?How doesSQLrelatetoMicrosoftstandardssuchasODBCand.NET?HowdoesJDBClinkSQL totheworldofJavaandobjecttechnology?WhatroledoesitplayintheService-Oriented Architecture(SOA)andwebservicesbeingembracedbyenterpriseITorganizations?Does SQLreallyscalefrommainframestohandhelddevices?Hasitreallydeliveredthe performanceneededforhigh-volumetransactionprocessing?HowwillSQLimpactthe wayyouusecomputers,andhowcanyougetthemostoutofthisimportantdata managementtool?Thisbookanswersthosequestionsbygivingyouacompleteperspective andasolidworkingknowledgeofSQL.
3
4
Part I:
An Overview of SQL
The SQL Language SQLisatoolfororganizing,managing,andretrievingdatastoredbyacomputerdatabase. TheoriginalnamegivenitbyIBMwasStructuredEnglishQueryLanguage,shortenedtothe acronymSEQUEL.WhenIBMdiscoveredthatSEQUELwasatrademarkownedbytheHawker SiddeleyAircraftCompanyoftheUnitedKingdom,theyshortenedtheacronymtoSQL.The word“English”wasthendroppedfromthespelled-outnametomatchthenewacronym.To thisday,youwillheartheacronymSQLpronouncedaseitheraword(“sequel”)orasastring ofletters(“S-Q-L”),andwhilethelatterisgenerallypreferred,bothareconsideredcorrect.As thenameimplies,SQLisacomputerlanguagethatyouusetointeractwithadatabase.Infact, SQLworkswithonespecifictypeofdatabase,calledarelationaldatabase,whichhasbecome themainstreamwaytoorganizedataacrossaverybroadrangeofcomputerapplications. Figure1-1showshowSQLworks.Thecomputersysteminthefigurehasadatabasethat storesimportantinformation.Ifthecomputersystemisinabusiness,thedatabasemight storeinventory,production,sales,orpayrolldata.Onapersonalcomputer,thedatabase mightstoredataaboutthechecksyouhavewritten,listsofpeopleandtheirphonenumbers, ordataextractedfromalargercomputersystem.Thecomputerprogramthatcontrolsthe databaseiscalledadatabasemanagementsystem(DBMS). Whenyouneedtoretrievedatafromadatabase,youusetheSQLtomaketherequest. TheDBMSprocessestheSQLrequest,retrievestherequesteddata,andreturnsittoyou. Thisprocessofrequestingdatafromadatabaseandreceivingtheresultsiscalledadatabase query—hencethenameStructuredQueryLanguage. “StructuredQueryLanguage”isactuallysomewhatofamisnomer.Firstofall,SQLis farmorethanaquerytool,althoughthatwasitsoriginalpurpose,andretrievingdataisstill oneofitsmostimportantfunctions.SQLisusedtocontrolallofthefunctionsthataDBMS providesforitsusers,including
FIGURE 1-1 Using SQL for database access
Chapter 1:
Introduction
5
• Datadefinition SQLletsauserdefinethestructureandorganizationofthestored dataandrelationshipsamongthestoreddataitems.
• Datamanipulation SQLallowsauseroranapplicationprogramtoupdatethe databasebyaddingnewdata,removingolddata,andmodifyingpreviously storeddata. • Accesscontrol SQLcanbeusedtorestrictauser’sabilitytoretrieve,add,and modifydata,protectingstoreddataagainstunauthorizedaccess. • Datasharing SQLisusedtocoordinatedatasharingbyconcurrentusers,ensuring thatchangesmadebyoneuserdonotinadvertentlywipeoutchangesmadeat nearlythesametimebyanotheruser. • Dataintegrity SQLdefinesintegrityconstraintsinthedatabase,protectingitfrom corruptionduetoinconsistentupdatesorsystemfailures. SQListhusacomprehensivelanguageforcontrollingandinteractingwithadatabase managementsystem. Second,SQLisnotreallyacompletecomputerlanguagelikeCOBOL,C,C++,orJava. Instead,SQLisadatabasesublanguage,consistingofabout40statementsspecializedfor databasemanagementtasks.TheseSQLstatementscanbeembeddedintoanotherlanguage suchasCOBOLorCtoextendthatlanguageforuseindatabaseaccess.Alternatively, thestatementscanbeexplicitlysenttoadatabasemanagementsystemforprocessing, viaacall-levelinterfacefromalanguagesuchasC,C++,orJava,orviamessagessentover acomputernetwork. SQLalsodiffersfromothercomputerlanguagesbecauseitdescribeswhattheuser wantsthecomputertodoratherthanhowthecomputershoulddoit.(Inmoretechnical terms,SQLisadeclarativeordescriptivelanguageratherthanaproceduralone.)SQL containsnoIFstatementfortestingconditions,andnoGOTO,DO,orFORstatementsfor programflowcontrol.Rather,SQLstatementsdescribehowacollectionofdataistobe organized,orwhatdataistoberetrievedoraddedtothedatabase.Thesequenceofsteps todothosetasksisleftfortheDBMStodetermine. Finally,SQLisnotaparticularlystructuredlanguage,especiallywhencomparedwith highlystructuredlanguagessuchasC,Pascal,orJava.Instead,SQLstatementsresemble Englishsentences,completewith“noisewords”thatdon’taddtothemeaningofthe statementbutmakeitreadmorenaturally.TheSQLhasquiteafewinconsistenciesandalso somespecialrulestopreventyoufromconstructingSQLstatementsthatlookperfectlylegal butthatdon’tmakesense. Despitetheinaccuracyofitsname,SQLhasemergedasthestandardlanguageforusing relationaldatabases.SQLisbothapowerfullanguageandonethatisrelativelyeasyto learn.ThequicktourofSQLinChapter2willgiveyouagoodoverviewofthelanguage anditscapabilities.
PART I
• Dataretrieval SQLallowsauseroranapplicationprogramtoretrievestoreddata fromthedatabaseanduseit.
6
Part I:
An Overview of SQL
The Role of SQL SQLisnotitselfadatabasemanagementsystem,norisitastand-aloneproduct.Youcannot gotoacomputerretailerorawebsitesellingcomputersoftwareandbuySQL.Instead, SQLisanintegralpartofadatabasemanagementsystem,alanguageandatoolfor communicatingwiththeDBMS.Figure1-2showssomeofthecomponentsofatypical DBMSandhowSQLlinksthemtogether. ThedatabaseengineistheheartoftheDBMS,responsibleforactuallystructuring,storing, andretrievingthedatainthedatabase.ItacceptsSQLrequestsfromotherDBMScomponents (suchasaformsfacility,reportwriter,orinteractivequeryfacility),fromuser-written applicationprograms,andevenfromothercomputersystems.Asthefigureshows,SQLplays manydifferentroles: • SQLisaninteractivequerylanguage.UserstypeSQLcommandsintoaninteractive SQLprogramtoretrievedataanddisplayitonthescreen,providingaconvenient, easy-to-usetoolforadhocdatabasequeries. • SQLisadatabaseprogramminglanguage.ProgrammersembedSQLcommandsinto theirapplicationprogramstoaccessthedatainadatabase.Bothuser-written programsanddatabaseutilityprograms(suchasreportwritersanddataentry tools)usethistechniquefordatabaseaccess.
FIGURE 1-2 Components of a typical database management system
Chapter 1:
Introduction
• SQLisaclient/serverlanguage.PersonalcomputerprogramsuseSQLtocommunicate overanetworkwithdatabaseserversthatstoreshareddata.Thisclient/server architectureisusedbymanypopularenterprise-classapplications. • SQLisanInternetdataaccesslanguage.Internetwebserversthatinteractwith corporatedataandInternetapplicationserversalluseSQLasastandardlanguage foraccessingcorporatedatabases,oftenbyembeddingSQLdatabaseaccesswithin popularscriptinglanguageslikePHPorPerl. • SQLisadistributeddatabaselanguage.Distributeddatabasemanagementsystemsuse SQLtohelpdistributedataacrossmanyconnectedcomputersystems.TheDBMS softwareoneachsystemusesSQLtocommunicatewiththeothersystems,sending requestsfordataaccess. • SQLisadatabasegatewaylanguage.Inacomputernetworkwithamixofdifferent DBMSproducts,SQLisoftenusedinagatewaythatallowsonebrandofDBMSto communicatewithanotherbrand. SQLhasthusemergedasauseful,powerfultoolforlinkingpeople,computerprograms, andcomputersystemstothedatastoredinarelationaldatabase.
SQL Success Factors Inhistoricalterms,SQLhasbeenanextraordinarilysuccessfulinformationtechnology. Thinkaboutthecomputermarketinthemid-1980s,whenSQLfirststartedtobecome important.Mainframesandminicomputersdominatedcorporatecomputing.TheIBM personalcomputerhadbeenintroducedonlyafewyearsbefore,andtheMS-DOScommand linewasitsuserinterface.IBM’smainframeoperatingsystemsandminicomputeroperating systemsfromDigitalEquipment,DataGeneral,Hewlett-Packard,andothersdominated businesscomputing.ProprietarynetworkingschemeslikeIBM’sSNAorDigitalEquipment’s DECnetlinkedcomputerstogether.TheInternetwasstillatoolforcollaborationamong researchlabs,andtheWorldWideWebhadnotyetappearedonthescene.COBOL,C,and Pascalweredominantcomputerlanguages;object-orientedprogrammingwasonly beginningtoemerge;andJavahadnotbeeninvented. Acrossalloftheseareasofcomputertechnology—fromcomputerhardwaretooperating systemstonetworkingtolanguages—theimportantkeytechnologiesofthemid-1980s havefadedorbecomeobsolete,replacedbysignificantnewones.Butintheworldofdata management,therelationaldatabaseandSQLcontinuetodominatethelandscape.They haveexpandedovertheyearstosupportnewhardware,operatingsystems,networks,and languages,butdespitemanyattemptstodethronethem,thecorerelationalmodelandthe SQLhavethrivedandremainthedominantforcesindatamanagement.Herearesomeofthe majorfeaturesandmarketforcesthathavecontributedtothissuccessoverthepast25years: • Vendorindependence • Portabilityacrosscomputersystems
PART I
• SQLisadatabaseadministrationlanguage.Thedatabaseadministratorresponsiblefor managingaminicomputerormainframedatabaseusesSQLtodefinethedatabase structureandtocontrolaccesstothestoreddata.
7
8
Part I:
An Overview of SQL
• OfficialSQLstandards • EarlyIBMcommitment • Microsoftsupport • Relationalfoundation • High-level,English-likestructure • Interactive,adhocqueries • Programmaticdatabaseaccess • Multipleviewsofdata • Completedatabaselanguage • Dynamicdatadefinition • Client/Serverarchitecture • Enterpriseapplicationsupport • Extensibilityandobjecttechnology • Internetdatabaseaccess • Javaintegration(JDBC) • Opensourcesupport • Industryinfrastructure Thesectionsthatfollowbrieflydescribeeachoftheseandhowtheycontributedto SQL’ssuccess.
Vendor Independence SQLisofferedbyalloftheleadingDBMSvendors,andnonewdatabaseproductoverthe lastdecadehasbeenhighlysuccessfulwithoutSQLsupport.ASQL-baseddatabaseandthe programsthatuseitcanbemovedfromoneDBMStoanothervendor’sDBMSwith minimalconversioneffortandlittleretrainingofpersonnel.Databasetoolssuchasquery tools,reportwriters,andapplicationgeneratorsworkwithmanydifferentbrandsofSQL databases.ThevendorindependencethusprovidedbySQLwasoneofthemostimportant reasonsforitsearlypopularityandremainsanimportantfeaturetoday.
Portability Across Computer Systems SQL-baseddatabaseproductsrunoncomputersystemsrangingfrommainframesand midrangesystemstopersonalcomputers,workstations,awiderangeofspecializedserver computers,andevenhandhelddevices.Theyoperateonstand-alonecomputersystems,in departmentallocalareanetworks,andinenterprisewideorInternetwidenetworks.SQLbasedapplicationsthatbeginonsingle-userordepartmentalserversystemscanbemoved tolargerserversystemsastheygrow.DatafromcorporateSQL-baseddatabasescanbe extractedanddownloadedintodepartmentalorpersonaldatabases.Finally,economical personalcomputerscanbeusedtotestaprototypeofaSQL-baseddatabaseapplication beforemovingittoanexpensivemultiusersystem.
Chapter 1:
Introduction
9
Official SQL Standards
Early IBM Commitment SQLwasoriginallyinventedbyIBMresearchersandfairlyquicklybecameastrategic productforIBMbasedonitsflagshipDB2database.SQLsupportisavailableonallmajor IBMproductfamilies,frompersonalcomputersthroughmidrangesystemsandUNIX-based serverstoIBMmainframes.IBM’sinitialworkprovidedaclearsignalofIBM’sdirectionfor otherdatabaseandsystemvendorstofollowearlyinthedevelopmentofSQLandrelational databases.Later,IBM’scommitmentandbroadsupportspeededthemarketacceptanceof SQL.Inthe1970s,IBMwasthedominantforceinbusinesscomputing,soitsearlyand sustainedsupportastheinventorandchampionofSQLensureditsearlyimportance.
Microsoft Support MicrosofthaslongconsidereddatabaseaccessakeypartofitsWindowspersonalcomputer softwarearchitecture.BothdesktopandserverversionsofWindowsprovidestandardized relationaldatabaseaccessthroughOpenDatabaseConnectivity(ODBC),aSQL-based call-levelAPI(applicationprogramminginterface).LeadingWindowssoftwareapplications (spreadsheets,wordprocessors,databases,etc.)fromMicrosoftandothervendors supportODBC,andallleadingSQLdatabasesprovideODBCaccess.Microsofthas enhancedODBCsupportwithhigher-level,moreobject-orienteddatabaseaccesslayers overtheyears,includingdatamanagementsupportin.NETtoday.Butthesenew technologiescouldalwaysinteractwithrelationaldatabasesthroughtheODBC/SQL layersbelow.WhenMicrosoftbeganitseffortinthelate1980stomakeWindowsaviable serveroperatingsystem,itintroducedSQLServerasitsownSQL-basedoffering.SQL ServercontinuestodayasaflagshipMicrosoftproductandasakeycomponentofthe Microsoft.NETarchitectureforwebservices.
Relational Foundation SQLisalanguageforrelationaldatabases,andithasbecomepopularalongwiththe relationaldatabasemodel.Thetabular,row/columnstructureofarelationaldatabase isintuitivetousers,keepingtheSQLsimpleandeasytounderstand.Therelational modelalsohasastrongtheoreticalfoundationthathasguidedtheevolutionand implementationofrelationaldatabases.Ridingawaveofacceptancebroughtaboutby thesuccessoftherelationalmodel,SQLhasbecomethedatabaselanguageforrelational databases.
PART I
AnofficialstandardforSQLwasinitiallypublishedbytheAmericanNationalStandards Institute(ANSI)andtheInternationalStandardsOrganization(ISO)in1986,andwas expandedin1989andagainin1992,1999,2003,and2006.SQLisalsoaU.S.Federal InformationProcessingStandard(FIPS),makingitakeyrequirementforlargegovernment computercontracts.Overtheyears,otherinternational,government,andvendorgroups havepioneeredthestandardizationofnewSQLcapabilities,suchascall-levelinterfacesor object-basedextensions.Manyofthesenewinitiativeshavebeenincorporatedintothe ANSI/ISOstandardovertime.Theevolvingstandardsserveasanofficialstampof approvalforSQLandhavespeededitsmarketacceptance.
10
Part I:
An Overview of SQL
High-Level, English-Like Structure SQLstatementslooklikesimpleEnglishsentences,makingSQLrelativelyeasytolearnand understand.ThisisinpartbecauseSQLstatementsdescribethedatatoberetrieved,rather thanspecifyinghowtofindthedata.TablesandcolumnsinaSQLdatabasecanhavelong, descriptivenames.Asaresult,mostSQLstatements“saywhattheymean”andcanberead asclear,naturalsentences.
Interactive, Ad Hoc Queries SQLisaninteractivequerylanguagethatgivesusersadhocaccesstostoreddata.Using SQLinteractively,ausercangetanswerseventocomplexquestionsinminutesorseconds, insharpcontrasttothedaysorweeksitwouldtakeforaprogrammertowriteacustom reportprogram.BecauseoftheSQLadhocquerypower,dataismoreaccessibleandcanbe usedtohelpanorganizationmakebetter,moreinformeddecisions.SQL’sadhocquery capabilitywasanimportantadvantageovernonrelationaldatabasesearlyinitsevolution andmorerecentlyhascontinuedasakeyadvantageoverpureobject-baseddatabases.
Programmatic Database Access SQLisalsoadatabaselanguageusedbyprogrammerstowriteapplicationsthataccessa database.ThesameSQLstatementsareusedforbothinteractiveandprogrammaticaccess, sothedatabaseaccesspartsofaprogramcanbetestedfirstwithinteractiveSQLandthen embeddedintotheprogram.Incontrast,nonrelationalorobject-orienteddatabases providedonesetoftoolsforprogrammaticaccessandaseparatequeryfacilityforadhoc requests,withoutanysynergybetweenthetwomodesofaccess.
Multiple Views of Data UsingSQL,thecreatorofadatabasecangivedifferentusersofthedatabasedifferentviews ofitsstructureandcontents.Forexample,thedatabasecanbeconstructedsothateachuser seesdataonlyforhisorherdepartmentorsalesregion.Inaddition,datafromseveral differentpartsofthedatabasecanbecombinedandpresentedtotheuserasasimplerow/ columntable.SQLviewscanthusbeusedtoenhancethesecurityofadatabaseandtotailor ittotheparticularneedsofindividualuserswhilepreservingthefundamentalrow/column structureofthedata.
Complete Database Language SQLwasfirstdevelopedasanadhocquerylanguage,butitspowersnowgofarbeyond dataretrieval.SQLprovidesacomplete,consistentlanguageforcreatingadatabase, managingitssecurity,updatingitscontents,retrievingdata,andsharingdataamongmany concurrentusers.SQLconceptsthatarelearnedinonepartofthelanguagecanbeapplied tootherSQLcommands,makingusersmoreproductive.
Dynamic Data Definition UsingSQL,thestructureofadatabasecanbechangedandexpandeddynamically,even whileusersareaccessingdatabasecontents.Thisisamajoradvanceoverstaticdata definitionlanguages,whichpreventedaccesstothedatabasewhileitsstructurewasbeing changed.SQLthusprovidesmaximumflexibility,allowingadatabasetoadapttochanging requirementswhileonlineapplicationscontinueuninterrupted.
Chapter 1:
Introduction
11
Client/Server Architecture
Enterprise Application Support Thelargestenterpriseapplicationsthatsupportthedailyoperationoflargecompaniesand organizationsalluseSQL-baseddatabasestostoreandorganizetheirdata.Inthe1990s,driven bytheimpendingdeadlineforsupportingdatesintheyear2000andbeyond(theso-called “Y2K”problem),largeenterprisesmovedenmassetoabandontheirhomegrownsystemsand converttopackagedenterpriseapplicationsfromvendorslikeSAP,Oracle,PeopleSoft,Siebel, andothers.Thedataprocessedbytheseapplications(orders,salesamounts,customers, inventorylevels,paymentamounts,etc.)tendstohaveastructured,records-and-fieldsformat, whichconvertseasilyintotherow/columnformatofSQL.Byconstructingtheirapplications touseenterprise-classSQLdatabases,themajorapplicationvendorseliminatedtheneedto developtheirowndatamanagementsoftwareandbenefitedfromexistingtoolsand programmingskills.BecauseeverymajorenterpriseapplicationrequiresaSQL-baseddatabase foritsoperation,newsalesofenterpriseapplicationsautomaticallygenerate“drag-along” demandfornewcopiesofdatabasesoftware.
Extensibility and Object Technology ThemajorchallengetoSQL’scontinueddominanceasadatabasestandardhascomefrom theemergenceofobject-basedprogrammingthroughlanguagessuchasJavaandC++,and fromtheintroductionofobject-baseddatabasesasanextensionofthebroadmarkettrend towardobject-basedtechnology.SQL-baseddatabasevendorshaverespondedtothis challengebyslowlyexpandingandenhancingSQLtoincludeobjectfeatures.These“object/ relational”databases,whichcontinuetobebasedonSQL,haveemergedasamorepopular alternativeto“pureobject”databasesandhaveperpetuatedSQL’sdominancethroughthe lastdecade.Thenewestwaveofobjecttechnology,embodiedintheXMLstandardandweb servicesarchitectures,onceagaincreatedacropof“XMLdatabases”andalternativequery languagestochallengeSQLintheearly2000s.Butonceagain,themajorvendorsofSQLbaseddatabasesrespondedbyaddingXML-basedextensions,meetingthechallengeand securingSQL’scontinuingimportance.Historysuggeststhatthis“extendandintegrate” approachwillbesuccessfulinwardingoffnewchallengesinthefutureaswell.
Internet Database Access WiththeexplodingpopularityoftheInternetandtheWorldWideWeb,andtheir standards-basedfoundation,SQLfoundanewroleinthelate1990sasanInternetdata accessstandard.EarlyinthedevelopmentoftheWeb,developersneededawaytoretrieve andpresentdatabaseinformationonwebpagesandusedSQLasacommonlanguagefor databasegateways.Morerecently,theemergenceofthree-tieredInternetarchitectureswith distinctthinclient,applicationserver,anddatabaseserverlayers,hasestablishedSQLas thestandardlinkbetweentheapplicationanddatabasetiers.TheroleofSQLinmultitier
PART I
SQLisanaturalvehicleforimplementingapplicationsusingadistributed,client/server architecture.Inthisrole,SQLservesasthelinkbetween“front-end”computersystems optimizedforuserinteractionand“back-end”systemsspecializedfordatabasemanagement, allowingeachsystemtodowhatitdoesbest.SQLalsoallowspersonalcomputersto functionasfront-endstonetworkserversortolargerminicomputerandmainframe databases,providingaccesstocorporatedatafrompersonalcomputerapplications.
12
Part I:
An Overview of SQL
architecturesisnowbeginningtoextendbeyondtheback-enddatabaselayer,toinclude datacachingandreal-timedatamanagementinorneartheapplicationtier.
Java Integration (JDBC) AmajorareaofSQLdevelopmentoverthelastfivetotenyearshasbeentheintegrationof SQLwithJava.SeeingtheneedtolinktheJavalanguagetoexistingrelationaldatabases, SunMicrosystems(thecreatorofJava)introducedJavaDatabaseConnectivity(JDBC),a standardAPIthatallowsJavaprogramstouseSQLfordatabaseaccess.JDBCreceiveda furtherboostwhenitwasadoptedasthedataaccessstandardwithintheJava2Enterprise Edition(J2EE)specification,whichdefinestheoperatingenvironmentprovidedbymostof theleadingInternetapplicationservers.InadditiontotheroleofJavaasaprogramming languagefromwhichdatabasesareused,manyoftheleadingdatabasevendorshavealso announcedorimplementedJavasupportwithintheirdatabasesystems,allowingJavatobe usedasalanguageforstoredproceduresandbusinesslogicwithinthedatabaseitself.This trendtowardintegrationbetweenJavaandSQLwillensurethecontinuedimportanceof SQLintheneweraofJava-basedprogramming.
Open Source Support Oneofthenewerimportantdevelopmentsinthecomputerindustryistheemergenceof an“opensource”approachtobuildingcomplexsoftwaresystems.Withthisapproach,the sourcecodethatdefinestheoperationofasoftwaresystemisopenandfreelyavailable, andmanydifferentprogrammerscancontributetoit,addingfeatures,fixingbugs,enhancing itsfunctionality,andprovidingsupportforitsuse.Thiscommunityofprogrammers, potentiallyspreadacrossthousandsofdifferentorganizationsandaroundtheglobe,with somecoordinationbecomestheenginethatdrivesthefurtherdevelopmentofthetechnology. Opensourcesoftwareisgenerallyavailableatverylowprices(orfree),addingtoitsappeal. SeveralsuccessfulopensourceSQL-baseddatabaseshavebeenbuiltinthelastdecade,and oneofthese,MySQL,isastandardcomponentofthemostpopularopensource“stack”of software—theLAMPstack—whichalsoincludesLinux,theApachewebserver,andthePHP scriptinglanguage.ThewidespreadavailabilityoffreeSQL-basedopensourcedatabaseshas exposedSQLtoanevenbroaderrangeofprogrammers,continuingtobuilditspopularity.
Industry Infrastructure PerhapsthemostimportantfactorcontributingtothegrowingimportanceofSQListhe emergenceofanentirecomputerindustryinfrastructurebasedonSQL.SQL-based relationaldatabasesystemsareanimportantpartofthisinfrastructure.Enterprise applicationsthatuseSQLandrequireaSQL-baseddatabaseareanotherimportantpart,as arereportingtools,dataentrytools,designtools,programmingtools,andahostofother toolsthatsimplifytheuseofSQL.AlargepoolofexperiencedSQLprogrammersisacritical partoftheinfrastructure.Anotherimportantpartisthetrainingandsupportservicesthat surroundSQLandhelptocreateandperpetuateSQLexpertise.Anentiresubindustryhas emergedaroundSQLconsulting,optimization,andperformance-tuning.Allpartsofthis infrastructuretendtoreinforceoneanotherandtocontributetotheongoingsuccessofthe otherparts.Simplystated,tosolvedatamanagementproblems,theeasiest,lowest-risk, lowest-costsolutionisalmostalwaysasolutionbasedonSQL.
2
CHAPTER
A Quick Tour of SQL
B
eforewediveintothedetailsofSQL,it’sagoodideatodevelopanoverall perspectiveonthelanguageandhowitworks.Thischaptercontainsaquicktourof SQLthatillustratesitsmajorfeaturesandfunctions.Thegoalofthequicktourisnot tomakeyouproficientinwritingSQLstatements;that’sthegoalofPartIIofthisbook. Rather,bythetimeyou’vefinishedthischapter,youwillhaveabasicfamiliaritywiththe SQLandanoverviewofitscapabilities.
A Simple Database Theexamplesinthisquicktourarebasedonasimplerelationaldatabaseforasmall distributioncompany.Thedatabase,showninFigure2-1,storestheinformationneededto implementasmallorder-processingapplication.Youwillfindinstructionsforcreatingthe sampledatabaseinAppendixA,soyoucantrythesequeriesyourselfasyouread. Specifically,itstoresthefollowinginformation: • Thecustomerswhobuythecompany’sproducts • Theordersplacedbythosecustomers • Thesalespeoplewhoselltheproductstocustomers • Thesalesofficeswherethosesalespeoplework Thisdatabase,likemostothers,isamodelofthe“realworld.”Thedatastoredinthe databaserepresentsrealentities—customers,orders,salespeople,andoffices.Eachdifferent kindofentityhasaseparatetableofdata.Forexample,intheSALESREPStable,each salespersonisrepresentedbyonerow,andeachcolumnholdsonetypeofinformation aboutsalespeople,suchastheirnameorthesalesofficewheretheyareassigned.Database requeststhatyoumakeusingtheSQLparallelreal-worldactivities,ascustomersplace, cancel,andchangeorders;asyouhireandfiresalespeople;andsoon.Let’sseehowyou canuseSQLtomanipulatedata.
13
14
Part I:
An Overview of SQL
FIGURE 2-1 A simple relational database
Retrieving Data First,let’slistthesalesoffices,showingthecitywhereeachoneis,itsofficenumber,andits year-to-datesales.TheSQLstatementthatretrievesdatafromthedatabaseiscalledSELECT. ThisSQLstatementretrievesthedatayouwant: SELECTCITY,OFFICE,SALES FROMOFFICES; CITYOFFICESALES ------------------------------- Denver22$186,042.00 NewYork11$692,637.00 Chicago12$735,042.00 Atlanta13$367,911.00 LosAngeles21$835,915.00
Chapter 2:
A Q u i c k To u r o f S Q L
SELECTNAME,REP_OFFICE,SALES,QUOTA FROMSALESREPS; NAMEREP_OFFICESALESQUOTA ------------------------------------------------- BillAdams13$367,911.00$350,000.00 MaryJones11$392,725.00$300,000.00 SueSmith21$474,050.00$350,000.00 SamClark11$299,912.00$275,000.00 BobSmith12$142,594.00$200,000.00 DanRoberts12$305,673.00$300,000.00 TomSnyderNULL$75,985.00NULL LarryFitch21$361,865.00$350,000.00 PaulCruz12$286,775.00$275,000.00 NancyAngelli22$186,042.00$300,000.00
TheNULLvaluesforTomSnyderrepresentmissingorunknowndata.Heisnewtothe companyandhasnotyetbeenassignedtoasalesofficeorbeengivenasalesquota.However, hehasalreadymadesomesales.Thedatainhisrowofqueryresultsshowsthisclearly. SQLalsoletsyouaskforcalculatedresults.Forexample,youcanaskSQLtocalculate theamountbywhicheachsalespersonisoverorunderquota: SELECTNAME,SALES,QUOTA,(SALES–QUOTA) FROMSALESREPS; NAMESALESQUOTA(SALES–QUOTA) ---------------------------------------------------- BillAdams$367,911.00$350,000.00$17,911.00 MaryJones$392,725.00$300,000.00$92,725.00 SueSmith$474,050.00$350,000.00$124,050.00 SamClark$299,912.00$275,000.00$24,912.00 BobSmith$142,594.00$200,000.00–$57,406.00 DanRoberts$305,673.00$300,000.00$5,673.00 TomSnyder$75,985.00NULLNULL LarryFitch$361,865.00$350,000.00$11,865.00 PaulCruz$286,775.00$275,000.00$11,775.00 NancyAngelli$186,042.00$300,000.00–$113,958.00
Therequesteddata(includingthecalculateddifferencebetweensalesandquotafor eachsalesperson)onceagainappearsinarow/columntable.Perhapsyouwouldliketo focusonthesalespeoplewhosesalesarelessthantheirquotas.SQLletsyouretrievethat
PART I
TheSELECTstatementasksforthreepiecesofdata—thecity,theofficenumber,andthe amountofsales—foreachoffice.Italsospecifiesthatallofthisdatacomesfromthe OFFICEStable,whichstoresdataaboutsalesoffices.Theresultsofthequeryappear,in tabularform,immediatelyaftertherequest.Notethattheformattingofthequeryresults willvaryfromoneSQLimplementationtoanother. TheSELECTstatementisusedforallSQLqueries.Forexample,hereisaquerythatlists thenamesandyear-to-datesalesforeachsalespersoninthedatabase.Italsoshowsthe quota(salestarget)andtheofficenumberwhereeachpersonworks.Inthiscase,thedata comesfromtheSALESREPStable.
15
16
Part I:
An Overview of SQL
kindofselectiveinformationveryeasily,byaddingamathematicalcomparisontothe previousrequest: SELECTNAME,SALES,QUOTA,(SALES–QUOTA) FROMSALESREPS WHERESALES25000.00 ORDERBYAMOUNT; ORDER_NUMCUSTPRODUCTQTYAMOUNT -------------------------------------- 11298721034100Y11$27,500.00 1130692109775C22$31,350.00 11296121172A44L7$31,500.00 11304521122A44R10$45,000.00
Summarizing Data SQLnotonlyretrievesindividualpiecesofdatafromthedatabase,butitalsocan summarizethedatabasecontents.What’stheaveragesizeofanorderinthedatabase?This requestasksSQLtolookatalltheordersandfindtheaverageamount: SELECTAVG(AMOUNT) FROMORDERS; AVG(AMOUNT) ------------ $8,256.37
Youcouldalsoaskfortheaverageordersizeforaparticularcustomer: SELECTAVG(AMOUNT) FROMORDERS WHERECUST=2103; AVG(AMOUNT) ----------- $8,895.50
Chapter 2:
A Q u i c k To u r o f S Q L
SELECTCUST,SUM(AMOUNT) FROMORDERS GROUPBYCUST; CUSTSUM(AMOUNT) ----------------- 2101$1,458.00 2102$3,978.00 2103$35,582.00 2106$4,026.00 2107$23,132.00 2108$7,255.00 2109$31,350.00 2111$6,445.00 2112$47,925.00 2113$22,500.00 2114$22,100.00 2117$31,500.00 2118$3,608.00 2120$3,750.00 2124$3,082.00
Adding Data to the Database YoualsouseSQLtoaddnewdatatothedatabase.Forexample,supposeyoujustopeneda newWesternregionsalesofficeinDallas,withtargetsalesof$275,000.Here’stheINSERT statementthataddsthenewofficetothedatabase,asofficenumber23: INSERTINTOOFFICES(CITY,REGION,TARGET,SALES,OFFICE) VALUES('Dallas','Western',275000.00,0.00,23); 1rowinserted.
Similarly,ifMaryJones(employeenumber109)signsupanewcustomer,Acme Industries,thisINSERTstatementaddsthecustomertothedatabaseascustomernumber 2125witha$25,000creditlimit: INSERTINTOCUSTOMERS(COMPANY,CUST_REP,CUST_NUM,CREDIT_LIMIT) VALUES('AcmeIndustries',109,2125,25000.00); 1rowinserted.
YoumayhavenoticedthattheSQLenginereturnedfeedback(1rowinserted)totell youthatthestatementsworked.Theexactwordingandformattingofthisfeedbackwill varyfromoneSQLimplementationtoanother.
PART I
Finally,let’sfindoutthetotalvalueoftheordersplacedbyeachcustomer.Todothis, youcanaskSQLtogrouptheorderstogetherbycustomernumberandthentotaltheorders foreachcustomer:
17
18
Part I:
An Overview of SQL
Deleting Data JustastheSQLINSERTstatementaddsnewdatatothedatabase,theSQLDELETEstatement removesdatafromthedatabase.IfAcmeIndustriesdecidesafewdayslatertoswitchtoa competitor,youcandeleteAcme’scustomerinformationfromthedatabasewiththisstatement: DELETEFROMCUSTOMERS WHERECOMPANY='AcmeIndustries'; 1rowdeleted.
Andifyoudecidetoterminateallsalespeoplewhosesalesarelessthantheirquotas, youcanremovethemfromthedatabasewiththisDELETEstatement: DELETEFROMSALESREPS WHERESALES='05/30/2007'+15DAYS;
SQLServerwasintroducedwithasingledate/timedatatype,calledDATETIME,which closelyresemblestheDB2TIMESTAMPdatatype.IfHIRE_DATEcontainedDATETIMEdata, SQLServercouldacceptthisversionofthequery(withoutthedatearithmetic): SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>='06/14/2007';
SincenospecifictimeonJune14,2007,isspecifiedinthequery,SQLServerdefaultsto midnightonthatdate.TheSQLServerquerythusreallymeans SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>='06/14/200712:00AM';
SQLServeralsosupportsdatearithmeticthroughasetofbuilt-infunctions.Thus,the DB2-stylequerycanalsobespecifiedinthisway: SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>=DATEADD(DAY,15,'05/30/2007')
whichisconsiderablydifferentfromtheDB2syntax. Oraclehaslongsupporteddate/timedatawithasingledatatypecalledDATE.(Note, however,thatOracleaddedsupportfortheSQLStandardDATETIMEandTIMESTAMP datatypesstartingwithOracle9i.)LikeSQLServer’sDATETIMEtype,anOracleDATEis,in fact,atimestamp.AlsoaswithSQLServer,thetimepartofanOracleDATEvaluedefaultsto midnightifnotimeisexplicitlyspecified.ThedefaultOracledateformatisdifferentfrom theDB2andSQLServerformats,sotheOracleversionofthequerybecomes SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>='14-JUN-07';
PART II
Specificdatesandtimescanbespecifiedasstringconstants,anddatearithmeticis supported.HereisanexampleofavalidqueryusingDB2dates,assumingthattheHIRE_ DATEcolumncontainsDATEdata:
76
Part II:
Retrieving Data
Oraclealsosupportslimiteddatearithmetic,sotheDB2-stylequerycanalsobe specified,butwithouttheDAYSkeyword: SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>='30-MAY-07'+15;
Note,however,thatthisstatementrequirestheDBMStoimplicitlyconvertthestringto anappropriatedatedatatypebeforeadding15toit,andthatnotallSQLimplementations supportsuchconversion.Oracle,forexample,willreportanerrorunlessafunctionsuchas TO_DATEorCASTconvertsthecharacterstringtoanOracleDATEorDATETIMEtype beforeattemptingdatearithmetic. Fortunately,withtheadventoftheyear2000conversion,mostDBMSvendorsadded universalsupportfordatesinSQLstatementswithfour-digityearsinastandardYYYYMM-DDformat,whichweuseformostoftheexamplesinthisbook.InOracle’scase,the defaultformatisstillasshownintheprecedingexamples,butitcanbechangedateither thedatabaseorusersessionwithasimplecommand.IfyouareusingOracleandyoutry anyoftheexamplesinthisbook,simplyenterthiscommandtochangeyourdefaultdate format: ALTERSESSIONSETNLS_DATE_FORMAT='YYYY-MM-DD';
Caremustbetakenwhenformingqueriesthatsearchforexactdatematchesusingthe equal(=)operator,andthedateshavetimecomponentsstoredinthem.Considerthe followingexample: SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE='06/14/2007';
Ifasalesperson’shiredatewerestoredinthedatabaseasnoononJune14,2007,the salespersonwouldnotbeincludedinthequeryresultsfromOracleorSQLServerdatabases. TheDBMSwouldassumeatimeofmidnightforthestringsuppliedwiththeSQLstatement, andsincemidnightisnotequaltonoon,therowwouldnotbeselected.Ontheotherhand, foraDB2database,wherethetimeisnotstoredwithaDATEdatatype,therowwould appearinthequeryresults. Finally,startingwithSQL2,theANSI/ISOstandardaddedsupportfordate/timedata withasetofdatatypesbasedon,butnotidenticalto,theDB2types.InadditiontotheDATE, TIME,andTIMESTAMPdatatypes,thestandardspecifiesanINTERVALdatatype,whichcan beusedtostoreatimeinterval(forexample,atimespanmeasuredindays,oraduration measuredinhours,minutes,andseconds).Thestandardalsoprovidesaveryelaborateand complexmethodfordealingwithdate/timearithmetic,specifyingtheprecisionofintervals, adjustingfortimezonedifferences,andsoon.MostSQLimplementationsnowhavesupport forthesestandardtypes.Onenotableexception,however,isthatSQLServerhaslongused theTIMESTAMPdatatypeforanentirelydifferentpurpose,sosupportingtheANSI/ISO specificationforitpresentsaveryrealchallenge. Astheseexamplesillustrate,thesubtledifferencesindatatypesamongvariousSQL productsleadtosomesignificantdifferencesinSQLstatementsyntax.
Chapter 5:
SQL Basics
77
TheycanevencausethesameSQLquerytoproduceslightlydifferentresultson differentdatabasemanagementsystems.ThewidelypraisedportabilityofSQListhustrue butonlyatagenerallevel.AnapplicationcanbemovedfromoneSQLdatabasetoanother, anditcanbehighlyportableifitusesonlythemostmainstream,basicSQLcapabilities. However,thesubtlevariationsinSQLimplementationsmeanthatdatatypesandSQL statementsmustalmostalwaysbeadjustedsomewhatiftheyaretobemovedacrossDBMS brands.Themorecomplextheapplication,themorelikelyitistobecomedependenton DBMS-specificfeaturesandnuances,andthelessportableitwillbecome.
InsomeSQLstatements,anumeric,character,ordatedatavaluemustbeexpressedintext form.Forexample,inthisINSERTstatementwhichaddsasalespersontothedatabase: INSERTINTOSALESREPS(EMPL_NUM,NAME,QUOTA,HIRE_DATE,SALES) VALUES(115,'DennisIrving',175000.00,'2008-06-21',0.00);
thevalueforeachcolumninthenewlyinsertedrowisspecifiedintheVALUESclause. Constantdatavaluesarealsousedinexpressions,suchasinthisSELECTstatement: SELECTCITY FROMOFFICES WHERETARGET>(1.1*SALES)+10000.00;
TheANSI/ISOSQLstandardspecifiestheformatofnumericandstringconstants,or literals,whichrepresentspecificdatavalues.TheseconventionsarefollowedbymostSQL implementations.
Numeric Constants Integeranddecimalconstants(alsocalledexactnumericliterals)arewrittenasordinary decimalnumbersinSQLstatements,withanoptionalleadingplusorminussign: 21-3752000.00+497500.8778
Youmustnotputacommabetweenthedigitsofanumericconstant,andnotallSQL dialectsallowtheleadingplussign,soit’sbesttoavoidit.Formoneydata,mostSQL implementationssimplyuseintegerordecimalconstants,althoughsomeallowtheconstant tobespecifiedwithacurrencysymbol: $0.75$5000.00$-567.89
Floatingpointconstants(alsocalledapproximatenumericliterals)arespecifiedusingthe EnotationcommonlyfoundinprogramminglanguagessuchasCandFORTRAN.Hereare somevalidSQLfloatingpointconstants: 1.5E3-3.14159E12.5E-70.783926E21
TheEisread“timestentothepowerof,”sothefirstconstantbecomes“1.5timestento thethirdpower,”or1500.
PART II
Constants
78
Part II:
Retrieving Data
String Constants TheANSI/ISOstandardspecifiesthatSQLconstantsforcharacterdatabeenclosedinsingle quotes('...'),asintheseexamples: 'Jones,JohnJ.''NewYork''Western'
Ifasinglequoteistobeincludedintheconstanttext,itiswrittenwithintheconstantas twoconsecutivesingle-quotecharacters.Thus,thisconstantvalue: 'Ican''t'
becomestheseven-characterstring"Ican't". SomeSQLimplementations,suchasSQLServer,acceptstringconstantsenclosedin doublequotes("..."): "Jones,JohnJ.""NewYork""Western"
Unfortunately,thedoublequotescanposeportabilityproblemswithotherSQL products.TheSQLstandardprovidestheadditionalcapabilitytospecifystringconstants fromaspecificnationalcharacterset(forexample,FrenchorGerman)orfromauserdefinedcharacterset.Theuser-definedcharactersetcapabilitieshavetypicallynotbeen implementedinmainstreamSQLproducts.
Date and Time Constants InSQLproductsthatsupportdate/timedata,constantvaluesfordates,times,andtime intervalsarespecifiedasstringconstants.Theformatoftheseconstantsvariesfromone DBMStothenext.Evenmorevariationisintroducedbythedifferencesinthewaydates andtimesarewrittenindifferentcountries. IBM’sDB2supportsseveraldifferentinternationalformatsfordate,time,and timestampconstants,asshowninTable5-5.ThechoiceofformatismadewhentheDBMS isinstalled.DB2alsosupportsdurationsspecifiedasspecialconstants,asinthisexample: HIRE_DATE+30DAYS
Notethatadurationcan’tbestoredinthedatabase,however,becauseDB2doesn’thave anexplicitDURATIONdatatype. SQLServeralsosupportsdate/timedataandacceptsavarietyofdifferentformatsfor dateandtimeconstants.TheDBMSautomaticallyacceptsallofthealternateformats,andyou canintermixthemifyoulike.HerearesomeexamplesoflegalSQLServerdateconstants: March15,2008Mar1520083/15/20083-15-082008MAR15
Format Name
Date Format
Date Example
Time Format
Time Example
American
mm/dd/yyyy
5/19/2008
hh:mm am/pm
2:18 PM
European
dd.mm.yyyy
19.5.2008
hh.mm.ss
14.18.08
Japanese
yyyy-mm-dd
2008-5-19
hh:mm:ss
14:18:08
ISO
yyyy-mm-dd
2008-5-19
hh.mm.ss
14.18.08
TABLE 5-5
DB2 SQL Date and Time Formats
Chapter 5:
SQL Basics
79
andherearesomelegaltimeconstants: 15:30:253:30:25PM3:30:25pm3PM
Oracledatesandtimesarealsowrittenasstringconstants,usingthisformat: 15-MAR-90
YoucanalsouseOracle’sbuilt-inTO_DATE()functiontoconvertdateconstantswritten inotherformats,asinthisexample:
TheSQL2standardspecifiesaformatfordateandtimeconstants,basedontheISO formatinTable5-5,exceptthattimeconstantsarewrittenwithcolonsinsteadofperiods separatingthehours,minutes,andseconds.TheSQLStandardTIMESTAMPtype,not showninthetable,hasaformatofyyyy-mm-dd-hh.mm.ss.nnnnnn—forexample“1960-0519-14.18.08.048632”represents5/19/60atroughly2:18p.m.
Symbolic Constants Inadditiontouser-suppliedconstants,theSQLincludesspecialsymbolicconstantsthat returndatavaluesmaintainedbytheDBMSitself.Forexample,insomeDBMSbrands,the symbolicconstantCURRENT_DATEyieldsthevalueofthecurrentdateandcanbeusedin queriessuchasthefollowing,whichliststhesalespeoplewhosehiredateisstillinthefuture: SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>CURRENT_DATE;
TheSQL1standardspecifiedonlyasinglesymbolicconstant(theUSERconstant describedinChapter15),butmostSQLproductsprovidemanymore.Generally,asymbolic constantcanappearinaSQLstatementanywherethatanordinaryconstantofthesame datatypecouldappear.TheSQL2standardadoptedthemostusefulsymbolicconstants fromcurrentSQLimplementationsandprovidesforCURRENT_DATE,CURRENT_TIME, andCURRENT_TIMESTAMP(notetheunderscores)aswellasUSER,SESSION_USER,and SYSTEM_USER. SomeSQLproducts,includingSQLServer,provideaccesstosystemvaluesthroughbuilt-in functionsratherthansymbolicconstants.TheSQLServerversionoftheprecedingqueryis SELECTNAME,HIRE_DATE FROMSALESREPS WHEREHIRE_DATE>GETDATE();
Built-infunctionsaredescribedlaterinthischapter,inthesection“Built-InFunctions.”
PART II
SELECTNAME,AGE FROMSALESREPS WHEREHIRE_DATE=TO_DATE('JUN142007','MONDDYYYY');
80
Part II:
Retrieving Data
Expressions ExpressionsareusedintheSQLtocalculatevaluesthatareretrievedfromadatabaseandto calculatevaluesusedinsearchingthedatabase.Forexample,thisquerycalculatesthesales ofeachofficeasapercentageofitstarget: SELECTCITY,TARGET,SALES,(SALES/TARGET)*100 FROMOFFICES;
andthisqueryliststheofficeswhosesalesaremorethan$50,000overtarget: SELECTCITY FROMOFFICES WHERESALES>TARGET+50000.00;
TheANSI/ISOSQLstandardspecifiesfourarithmeticoperationsthatcanbeusedin expressions:addition(X+Y),subtraction(X–Y),multiplication(X*Y),anddivision(X/Y). Parenthesescanalsobeusedtoformmorecomplicatedexpressions,likethisone: (SALES*1.05)-(TARGET*.95)
Strictlyspeaking,theparenthesesarenotrequiredinthisquerybecausetheANSI/ISO standardspecifiesthatmultiplicationanddivisionhaveahigherprecedencethanaddition andsubtraction.However,youshouldalwaysuseparenthesestomakeyourexpressions unambiguous,becausedifferentSQLdialectsmayusedifferentrules.Theparenthesesalso increasethereadabilityofthestatementandmakeprogrammaticSQLstatementseasierto maintain. TheANSI/ISOSQLstandardalsospecifiesautomaticdatatypeconversionfromintegers todecimalnumbers,andfromdecimalnumberstofloatingpointnumbers,asrequired.You canthusmixthesedatatypesinanumericexpression.ManySQLimplementationssupport otheroperatorsandallowoperationsoncharacteranddatedata.TheSQLstandardspecifies astringconcatenationoperator,writtenastwoconsecutiveverticalbarcharacters(||), whichissupportedbymostimplementations.(AnotableexceptionisSQLServer,which usestheplussign(+)instead.)IftwocolumnsnamedFIRST_NAMEandLAST_NAME containthevalues“Jim”and“Jackson”,thenthisDB2expression: ('Mr./Mrs.'||FIRST_NAME||''||LAST_NAME)
producesthestring“Mr./Mrs.JimJackson”.Asalreadymentioned,DB2andmanyother implementationsalsosupportadditionandsubtractionofDATE,TIME,andTIMESTAMP data,foroccasionswhenthoseoperationsmakesense.Thiscapabilityhasbeenincluded intheSQLstandard.
Built-In Functions Anumberofusefulbuilt-infunctionsarespecifiedinSQLstandard,andmostSQL implementationsaddmanymore.Thesefacilitiesoftenprovidedatatypeconversionfacilities. Forexample,DB2’sbuilt-inMONTH()andYEAR()functionstakeaDATEorTIMESTAMP valueastheirinputandreturnanintegerthatisthemonthoryearportionofthevalue. Thisqueryliststhenameandmonthofhireforeachsalespersoninthesampledatabase: SELECTNAME,MONTH(HIRE_DATE) FROMSALESREPS;
Chapter 5:
SQL Basics
81
andthisonelistsallsalespeoplehiredin2006: SELECTNAME,MONTH(HIRE_DATE) FROMSALESREPS WHEREYEAR(HIRE_DATE)=2006;
Built-infunctionsarealsooftenusedfordatareformatting.Oracle’sbuilt-inTO_CHAR() function,forexample,takesaDATEdatatypeandaformatspecificationasitsarguments andreturnsastringcontainingaformattedcharacterstringversionofthedate.(Thissame functionisalsocapableofconvertingnumericvaluestoformattedcharacterstrings.)Inthe resultsproducedbythisquery:
thehiredateswillallhavetheformat“WednesdayJune14,2007”becauseofthebuilt-infunction. Ingeneral,abuilt-infunctioncanbespecifiedinaSQLexpressionanywherethata constantofthesamedatatypecanbespecified.Thebuilt-infunctionssupportedbypopular SQLdialectsaretoonumeroustolisthere.TheIBMDB2SQLdialectsincludeabouttwo dozenbuilt-infunctions,Oraclesupportsadifferentsetofabouttwodozenbuilt-infunctions, andSQLServerhasseveraldozen.TheSQL2standardincorporatedthemostusefulbuilt-in functionsfromtheseimplementations,inmanycaseswithslightlydifferentsyntax.These functionsaresummarizedinTable5-6. Function
Returns
BIT_LENGTH (string)
The number of bits in a bit string
CAST (value AS data_type)
The value, converted to the specified data type (e.g., a date converted to a character string)
CHAR_LENGTH (string)
The length of a character string
CONVERT (string USING conv)
A string converted as specified by a named conversion function
CURRENT_DATE
The current date
CURRENT_TIME (precision)
The current time, with the specified precision
CURRENT_TIMESTAMP (precision)
The current date and time, with the specified precision
EXTRACT (part FROM source)
The specified part (DAY, HOUR, etc.) from a DATETIME value
LOWER (string)
A string converted to all lowercase letters
OCTET_LENGTH (string)
The number of 8-bit bytes in a character string
POSITION (target IN source)
The position where the target string appears within the source string
SUBSTRING (source FROM n FOR len)
A portion of the source string, beginning at the nth character, for a length of len
TRANSLATE (string USING trans)
A string translated as specified by a named translation function
TRIM (BOTH char FROM string)
A string with both leading and trailing occurrences of char trimmed off
TRIM (LEADING char FROM string)
A string with any leading occurrences of char trimmed off
TRIM (TRAILING char FROM string)
A string with any trailing occurrences of char trimmed off
UPPER (string)
A string converted to all uppercase letters
TABLE 5-6
SQL Standard Built-In Functions
PART II
SELECTNAME,TO_CHAR(HIRE_DATE,'DAYMONTHDD,YYYY') FROMSALESREPS;
82
Part II:
Retrieving Data
Missing Data (NULL Values) Becauseadatabaseisusuallyamodelofareal-worldsituation,certainpiecesofdataare inevitablymissing,unknown,ordon’tapply.Inthesampledatabase,forexample,the QUOTAcolumnintheSALESREPStablecontainsthesalesgoalforeachsalesperson. However,thenewestsalespersonhasnotyetbeenassignedaquota;thisdataismissingfor thatrowofthetable.Youmightbetemptedtoputazerointhecolumnforthissalesperson, butthatwouldnotbeanaccuratereflectionofthesituation.Thesalespersondoesnothave azeroquota;thequotaisjust“notyetknown.” Similarly,theMANAGERcolumnintheSALESREPStablecontainstheemployeenumber ofeachsalesperson’smanager.ButSamClark,thevicepresidentofsales,hasnomanagerin thesalesorganization.ThiscolumndoesnotapplytoSam.Again,youmightthinkabout enteringazero,ora9999inthecolumn,butneitherofthesevalueswouldreallybethe employeenumberofSam’sboss.Nodatavalueisapplicabletothisrow. SQLsupportsmissing,unknown,orinapplicabledataexplicitly,throughtheconceptof anullvalue.AnullvalueisanindicatorthattellsSQL(andtheuser)thatthedataismissing ornotapplicable.Asaconvenience,amissingpieceofdataisoftensaidtohavethevalue NULL.ButtheNULLvalueisnotarealdatavaluelike0,473.83,or“SamClark.”Instead,it’s asignal,orareminder,thatthedatavalueismissingorunknown.Figure5-3showsthe contentsoftheSALESREPStable.NotethattheQUOTAandREP_OFFICEvaluesforTom Snyder’srowandtheMANAGERvalueforSamClark’srowofthetableallcontainNULL values.AlsonotethatSQLtoolsdonotdisplaynullvaluesinqueryresultsinthesame way—whilemanyusethestringNULLasshowninFigure5-3,othersuseemptyspaceor characterstrings. Inmanysituations,NULLvaluesrequirespecialhandlingbytheDBMS.Forexample,if theuserrequeststhesumoftheQUOTAcolumn,howshouldtheDBMShandlethemissing datawhencomputingthesum?Theanswerisgivenbyasetofspecialrulesthatgovern NULLvaluehandlinginvariousSQLstatementsandclauses.Becauseoftheserules,some leadingdatabaseauthoritiesfeelstronglythatNULLvaluesshouldnotbeused.Others, includingTedCodd,haveadvocatedtheuseofmultipleNULLvalues,withdistinct indicatorsfor“unknown”and“notapplicable”data.
FIGURE 5-3 NULL values in the SALESREPS table
Chapter 5:
SQL Basics
83
Regardlessoftheacademicdebates,NULLvaluesareawell-entrenchedpartofthe ANSI/ISOSQLstandardandaresupportedinvirtuallyallcommercialSQLproducts. Theyalsoplayanimportant,practicalroleinproductionofSQLdatabases.Thespecial rulesthatapplytoNULLvalues(andthecaseswhereNULLvaluesarehandled inconsistentlybyvariousSQLproducts)arepointedoutthroughoutthisbook.
Summary ThischapterdescribedthebasicelementsofSQL.ThebasicstructureofSQLcanbe summarizedasfollows:
• SQL-baseddatabasescanstorevarioustypesofdata,includingtext,integers,decimal numbers,floatingpointnumbers,andusuallymanymorevendor-specificdatatypes. • SQLstatementscanincludeexpressionsthatcombinecolumnnames,constants,and built-infunctions,usingarithmeticandothervendor-specificoperators. • Variationsindatatypes,constants,andbuilt-infunctionsmakeportabilityofSQL statementsmoredifficultthanitmayseematfirst. • NULLvaluesprovideasystematicwayofhandlingmissingorinapplicabledatain theSQL.
PART II
• SQLthatisincommonuseincludesabout30statements,eachconsistingofaverb andoneormoreclauses.Eachstatementperformsasingle,specificfunction.
This page intentionally left blank
6
CHAPTER
Simple Queries
I
nmanyways,queriesaretheheartofSQL.TheSELECTstatement,whichisusedtoexpress SQLqueries,isthemostpowerfulandcomplexoftheSQLstatements.Despitethemany optionsaffordedbytheSELECTstatement,it’spossibletostartsimplyandthenworkupto morecomplexqueries.ThischapterdiscussesthesimplestSQLqueries—thosethatretrieve datafromindividualrowsofasingletableinthedatabase.Ifyouhavenotdonesoalready,you willlearnmoreifyoucreatethesampledatabaseonyourownsystemandtrythequeriesfor yourselfasyouread.InstructionsforthesampledatabaseareinAppendixA.
The SELECT Statement TheSELECTstatementretrievesdatafromadatabaseandreturnsittoyouintheformof queryresults.Asareminder,theexactformatofthequeryresultswillvaryfromoneSQL producttoanother.YouhavealreadyseenmanyexamplesoftheSELECTstatementinthe quicktourpresentedinChapter2.Hereareseveralmoresamplequeriesthatretrieve informationaboutsalesoffices: Listthesalesofficeswiththeirtargetsandactualsales. SELECTCITY,TARGET,SALES FROMOFFICES; CITYTARGETSALES ------------------------------------ Denver$300,000.00$186,042.00 NewYork$575,000.00$692,637.00 Chicago$800,000.00$735,042.00 Atlanta$350,000.00$367,911.00 LosAngeles$725,000.00$835,915.00
85
86
Part II:
Retrieving Data
ListtheEasternregionsalesofficeswiththeirtargetsandsales. SELECTCITY,TARGET,SALES FROMOFFICES WHEREREGION='Eastern'; CITYTARGETSALES ------------------------------------ NewYork$575,000.00$692,637.00 Chicago$800,000.00$735,042.00 Atlanta$350,000.00$367,911.00
ListEasternregionsalesofficeswhosesalesexceedtheirtargets,sortedinalphabetical orderbycity. SELECTCITY,TARGET,SALES FROMOFFICES WHEREREGION='Eastern' ANDSALES>TARGET ORDERBYCITY; CITYTARGETSALES ------------------------------------ Atlanta$350,000.00$367,911.00 NewYork$575,000.00$692,637.00
Forsimplequeries,theEnglishlanguagerequestandtheSQLSELECTstatementare verysimilar.Whentherequestsbecomemorecomplex,morefeaturesoftheSELECT statementmustbeusedtospecifythequeryprecisely. Figure6-1showsthefullformoftheSELECTstatement,whichconsistsofsixclauses. TheSELECTandFROMclausesofthestatementarerequired.Theremainingfourclausesare optional.YouincludetheminaSELECTstatementonlywhenyouwanttousethefunctions theyprovide.Thefollowinglistsummarizesthefunctionofeachclause: • TheSELECTclauseliststhedataitemstoberetrievedbytheSELECTstatement.The itemsmaybecolumnsfromthedatabase,orcolumnstobecalculatedbySQLasit performsthequery.TheSELECTclauseisdescribedinthenextsection. • TheFROMclauseliststhetablesandviewsthatcontainthedatatoberetrievedby thequery.(ViewsarediscussedindetailinChapter14.)Queriesthatdrawtheirdata fromasingletablearedescribedinthischapter.Morecomplexqueriesthatcombine datafromtwoormoretablesarediscussedinChapter7. • TheWHEREclausetellsSQLtoincludeonlycertainrowsofdatainthequeryresults. Asearchconditionisusedtospecifythedesiredrows.ThebasicusesoftheWHERE clausearedescribedinthe“RowSelection(WHEREClause)”sectionlaterinthis chapter.ThosethatinvolvesubqueriesarediscussedinChapter9. • TheGROUPBYclausespecifiesasummaryquery.Insteadofproducingonerowof queryresultsforeachrowofdatainthedatabase,asummaryquerygroups togethersimilarrowsandthenproducesonesummaryrowofqueryresultsforeach group.SummaryqueriesaredescribedinChapter8.
Chapter 6:
Simple Queries
87
FIGURE 6-1 SELECT statement syntax diagram
PART II
• TheHAVINGclausetellsSQLtoincludeonlycertaingroupsproducedbytheGROUP BYclauseinthequeryresults.LiketheWHEREclause,itusesasearchconditionto specifythedesiredgroups.TheHAVINGclauseisdescribedinChapter8. • TheORDERBYclausesortsthequeryresultsbasedonthedatainoneormorecolumns. Ifitisomitted,thequeryresultsarenotsorted.TheORDERBYclauseisdescribedinthe “SortingQueryResults(ORDERBYClause)”sectionlaterinthischapter.
The SELECT Clause TheSELECTclausethatbeginseachSELECTstatementspecifiesthedataitemstobe retrievedbythequery.Theitemsareusuallyspecifiedbyaselectlist,alistofselectitems separatedbycommas.Eachselectiteminthelistgeneratesasinglecolumnofqueryresults, inleft-to-rightorder.Aselectitemcanbeoneofthefollowing: • Acolumnname,identifyingacolumnfromthetable(s)namedintheFROMclause.When acolumnnameappearsasaselectitem,SQLsimplytakesthevalueofthatcolumnfrom eachrowofthedatabasetableandplacesitinthecorrespondingrowofqueryresults. • Aconstant,specifyingthatthesameconstantvalueistoappearineveryrowofthe queryresults. • ASQLexpression,indicatingthatSQLmustcalculatethevaluetobeplacedintothe queryresults,asspecifiedbytheexpression. Eachtypeofselectitemisdescribedlaterinthischapter.
88
Part II:
Retrieving Data
The FROM Clause TheFROMclauseconsistsofthekeywordFROM,followedbyalistoftablespecifications separatedbycommas.Eachtablespecificationidentifiesatableorviewcontainingdatatobe retrievedbythequery.Thesetablesarecalledthesourcetablesofthequery(andoftheSELECT statement)becausetheyarethesourceofallofthedatainthequeryresults.Allofthequeries inthischapterhaveasinglesourcetable,andeveryFROMclausecontainsasingletablename.
Query Results TheresultofaSQLqueryisalwaysatableofdata,justlikethetablesinthedatabase.Ifyou typeaSELECTstatementusinginteractiveSQL,theDBMSdisplaysthequeryresults (whichsomevendorscallaresultset)intabularformonyourcomputerscreen.Ifa computerprogramsendsaquerytotheDBMSusingprogrammaticSQL,thetableofquery resultsisreturnedtotheprogramforprocessing.Ineithercase,thequeryresultsalways havethesametabular,row/columnformatastheactualtablesinthedatabase,asshownin Figure6-2.Usuallythequeryresultswillbeatablewithseveralcolumnsandseveralrows. Forexample,thefollowingqueryproducesatableofthreecolumns(becauseitasksfor threeitemsofdata)andtenrows(becausetherearetensalespeople): Listthenames,offices,andhiredatesofallsalespeople. SELECTNAME,REP_OFFICE,HIRE_DATE FROMSALESREPS; NAMEREP_OFFICEHIRE_DATE ----------------------------------- BillAdams132006-02-12 MaryJones112007-10-12 SueSmith212004-12-10 SamClark112006-06-14 BobSmith122005-05-19 DanRoberts122004-10-20 TomSnyderNULL2008-01-13 LarryFitch212007-10-12 PaulCruz122005-03-01 NancyAngelli222006-11-14
Incontrast,thefollowingqueryproducesasinglerowbecauseonlyonesalespersonhas therequestedemployeenumber.Eventhoughthissinglerowofqueryresultslooksless “tabular”thanthemultirowresults,SQLstillconsidersittobeatableofthreecolumnsand onerow. Whatarethename,quota,andsalesofemployeenumber107? SELECTNAME,QUOTA,SALES FROMSALESREPS WHEREEMPL_NUM=107; NAMEQUOTASALES -------------------------------------- NancyAngelli$300,000.00$186,042.00
Chapter 6:
Simple Queries
89
PART II
FIGURE 6-2
The tabular structure of SQL query results
Insomecasesthequeryresultscanbeasinglevalue,asinthefollowingexample: Whataretheaveragesalesofoursalespeople? SELECTAVG(SALES) FROMSALESREPS; AVG(SALES) ------------ $289,353.20
Thesequeryresultsarestillatable,althoughit’saverysmalloneconsistingofonecolumn andonerow. Finally,it’spossibleforaquerytoproducezerorowsofqueryresults,asinthisexample: Listthenameandhiredateofanyonewithsalesover$500,000. SELECTNAME,HIRE_DATE FROMSALESREPS WHERESALES>500000.00; NAMEHIRE_DATE ----------------------
Eveninthissituation,thequeryresultsarestillatable.Thisoneisanemptytablewith twocolumnsandzerorows. NotethatSQL’ssupportformissingdataextendstoqueryresultsaswell.Ifadataitem inthedatabasehasaNULLvalue,theNULLvalueappearsinthequeryresultswhenthe
90
Part II:
Retrieving Data
dataitemisretrieved.Forexample,theSALESREPStablecontainsNULLvaluesinitsQUOTA andMANAGERcolumns.ThenextqueryreturnstheseNULLvaluesinthesecondandthird columnsofqueryresults.NotethatnotallSQLproductsdisplayNULLvaluesinthesame way—OracleandDB2,forexample,displaynothingwhenaNULLvalueisencountered. Listthesalespeople,theirquotas,andtheirmanagers. SELECTNAME,QUOTA,MANAGER FROMSALESREPS; NAMEQUOTAMANAGER ---------------------------------- BillAdams$350,000.00104 MaryJones$300,000.00106 SueSmith$350,000.00108 SamClark$275,000.00NULL BobSmith$200,000.00106 DanRoberts$300,000.00104 TomSnyderNULL101 LarryFitch$350,000.00106 PaulCruz$275,000.00104 NancyAngelli$300,000.00108
ThefactthataSQLqueryalwaysproducesatableofdataisveryimportant.Itmeans thatthequeryresultscanbestoredbackintothedatabaseasatable.Itmeansthatthe resultsoftwosimilarqueriescanbecombinedtoformalargertableofqueryresults. Finally,itmeansthatthequeryresultscanthemselvesbethetargetoffurtherqueries.A relationaldatabase’stabularstructurethushasaverysynergisticrelationshipwiththe relationalqueryfacilitiesofSQL.Tablescanbequeried,andqueriesproducetables.
Simple Queries ThesimplestSQLqueriesrequestcolumnsofdatafromasingletableinthedatabase.For example,thisqueryrequeststhreecolumnsfromtheOFFICEStable: Listthelocation,region,andsalesofeachsalesoffice. SELECTCITY,REGION,SALES FROMOFFICES; CITYREGIONSALES -------------------------------- DenverWestern$186,042.00 NewYorkEastern$692,637.00 ChicagoEastern$735,042.00 AtlantaEastern$367,911.00 LosAngelesWestern$835,915.00
TheSELECTstatementforsimplequerieslikethisoneincludesonlythetworequired clauses.TheSELECTclausenamestherequestedcolumns;theFROMclausenamesthetable orviewthatcontainsthem.
Chapter 6:
Simple Queries
91
Conceptually,SQLprocessesthequerybygoingthroughthetablenamedintheFROM clause,onerowatatime.Foreachrow,SQLtakesthevaluesofthecolumnsrequestedin theselectlistandproducesasinglerowofqueryresults.Thequeryresultsthuscontainone rowofdataforeachrowinthetable.
Calculated Columns
Listthecity,region,andamountover/undertargetforeachoffice. SELECTCITY,REGION,(SALES-TARGET) FROMOFFICES; CITYREGION(SALES-TARGET) ----------------------------------- DenverWestern-$113,958.00 NewYorkEastern$117,637.00 ChicagoEastern-$64,958.00 AtlantaEastern$17,911.00 LosAngelesWestern$110,915.00
Toprocessthequery,SQLgoesthroughtheoffices,generatingonerowofqueryresults foreachrowoftheOFFICEStable,asshowninFigure6-3.Thefirsttwocolumnsofquery resultscomedirectlyfromtheOFFICEStable.Thethirdcolumnofqueryresultsis calculated,rowbyrow,usingthedatavaluesfromthecurrentrowoftheOFFICEStable. Hereareotherexamplesofqueriesthatusecalculatedcolumns: Showthevalueoftheinventoryforeachproduct.(Onlythefirst8rowsintheresultsetareshown.) SELECTMFR_ID,PRODUCT_ID,DESCRIPTION,(QTY_ON_HAND*PRICE) FROMPRODUCTS; MFR_IDPRODUCT_IDDESCRIPTION(QTY_ON_HAND*PRICE) ----------------------------------------------------- REI2A45CRatchetLink$16,590.00 ACI4100YWidgetRemover$68,750.00 QSAXK47Reducer$13,490.00 BIC41672Plate$0.00 IMM779C900-lbBrace$16,875.00 ACI41003Size3Widget$22,149.00 ACI41004Size4Widget$16,263.00 BIC41003Handle$1,956.00
PART II
Inadditiontocolumnswhosevaluescomedirectlyfromthedatabase,aSQLquerycan includecalculatedcolumnswhosevaluesarecalculatedfromthestoreddatavalues.To requestacalculatedcolumn,youspecifyaSQLexpressionintheselectlist.Asdiscussedin Chapter5,SQLexpressionscaninvolveaddition,subtraction,multiplication,anddivision. Youcanalsouseparenthesestobuildmorecomplexexpressions.Ofcoursethecolumns referencedinanarithmeticexpressionmusthaveanumerictype.Ifyoutrytoadd,subtract, multiply,ordividecolumnscontainingtextdata,SQLwillreportanerror. Thisqueryshowsasimplecalculatedcolumn:
92
Part II:
Retrieving Data
FIGURE 6-3 Query processing with a calculated column
ShowmetheresultifIraisedeachsalesperson’squotaby3percentoftheiryear-to-datesales. SELECTNAME,QUOTA,(QUOTA+(.03*SALES)) FROMSALESREPS; NAMEQUOTA(QUOTA+(.03*SALES)) ---------------------------------------------- BillAdams$350,000.00$361,037.33 MaryJones$300,000.00$311,781.75 SueSmith$350,000.00$364,221.50 SamClark$275,000.00$283,997.36 BobSmith$200,000.00$204,277.82 DanRoberts$300,000.00$309,170.19 TomSnyderNULLNULL LarryFitch$350,000.00$360,855.95 PaulCruz$275,000.00$283,603.25 NancyAngelli$300,000.00$305,581.26
AsmentionedinChapter5,manySQLproductsprovideadditionalarithmetic operations,characterstringoperations,andbuilt-infunctionsthatcanbeusedinSQL expressions.Thesecanappearinselectlistexpressions,asinthenextDB2example,which extractsthemonthandyearfromadate. Listthename,month,andyearofhireforeachsalesperson.(ForOracledatabases,theTO_CHAR functionmustbeusedinsteadoftheMONTHandYEARfunctions.) SELECTNAME,MONTH(HIRE_DATE),YEAR(HIRE_DATE) FROMSALESREPS;
Chapter 6:
Simple Queries
93
SQLconstantscanalsobeusedbythemselvesasitemsinaselectlist.Thiscanbeuseful forproducingqueryresultsthatareeasiertoreadandinterpret,asinthenextexample. Listthesalesforeachcity.
Thequeryresultsappeartoconsistofaseparate“sentence”foreachoffice,butthey’re reallyatableofthreecolumns.Thefirstandthirdcolumnscontainvaluesfromthe OFFICEStable.Thesecondcolumnalwayscontainsthesame12-charactertextstring.
Selecting All Columns (SELECT *) Sometimesit’sconvenienttodisplaythecontentsofallthecolumnsofatable.Thiscanbe particularlyusefulwhenyoufirstencounteranewdatabaseandwanttogetaquick understandingofitsstructureandthedataitcontains.Asaconvenience,SQLletsyouuse anasterisk(*)inplaceoftheselectlistasanabbreviationfor“allcolumns”: ShowmeallthedataintheOFFICEStable. SELECT* FROMOFFICES; OFFICECITYREGIONMGRTARGETSALES ------------------------------------------------------- 22DenverWestern108$300,000.00$186,042.00 11NewYorkEastern106$575,000.00$692,637.00 12ChicagoEastern104$800,000.00$735,042.00 13AtlantaEastern105$350,000.00$367,911.00 21LosAngelesWestern108$725,000.00$835,915.00
ThequeryresultscontainallsixcolumnsoftheOFFICEStable,inthesameleft-to-right orderasinthetableitself. Theall-columnsselectionismostappropriatewhenyouareusinginteractiveSQL casually.ItshouldbeavoidedinprogrammaticSQL,becausechangesinthedatabase structurecancauseaprogramtofail.Forexample,supposetheOFFICEStablewas droppedfromthedatabaseandthenre-createdwithitscolumnsrearrangedandanew seventhcolumnadded.SQLautomaticallytakescareofthedatabase-relateddetailsofsuch changes,butitcannotmodifyyourapplicationprogramforyou.Ifyourprogramexpectsa SELECT*FROMOFFICESquerytoreturnsixcolumnsofqueryresultswithcertaindata types,itwillalmostcertainlystopworkingwhenthecolumnsarerearrangedandanew oneisadded.
PART II
SELECTCITY,'hassalesof',SALES FROMOFFICES; CITYHASSALESOFSALES ------------------------------------- Denverhassalesof$186,042.00 NewYorkhassalesof$692,637.00 Chicagohassalesof$735,042.00 Atlantahassalesof$367,911.00 LosAngeleshassalesof$835,915.00
94
Part II:
Retrieving Data
Thesedifficultiescanbeavoidedifyouwritetheprogramtorequestthecolumns itneedsbyname.Forexample,thefollowingqueryproducesthesameresultsas SELECT*FROMOFFICES.Itisalsoimmunetochangesinthedatabasestructure,aslong asthenamedcolumnscontinuetoexistintheOFFICEStable. SELECTOFFICE,CITY,REGION,MGR,TARGET,SALES FROMOFFICES;
Duplicate Rows (DISTINCT) Ifaqueryincludestheprimarykeyofatableinitsselectlist,theneveryrowofquery resultswillbeunique(becausetheprimarykeyhasadifferentvalueineachrow).Ifthe primarykeyisnotincludedinthequeryresults,duplicaterowscanoccur.Forexample, supposeyoumadethisrequest: Listtheemployeenumbersofallsalesofficemanagers. SELECTMGR FROMOFFICES; MGR ---- 108 106 104 105 108
Thequeryresultshavefiverows(oneforeachoffice),buttwoofthemareexact duplicatesofoneanother.Why?BecauseLarryFitchmanagesboththeLosAngelesand Denveroffices,andhisemployeenumber(108)appearsinbothrowsoftheOFFICEStable. Thesequeryresultsareprobablynotexactlywhatyouhadinmind.Iftherearefour differentmanagers,youmighthaveexpectedonlyfouremployeenumbersinthequery results. YoucaneliminateduplicaterowsofqueryresultsbyinsertingthekeywordDISTINCT intheSELECTstatementjustbeforetheselectlist.Hereisaversionofthepreviousquery thatproducestheresultsyouwant: Listtheemployeenumbersofallsalesofficemanagers. SELECTDISTINCTMGR FROMOFFICES; MGR ---- 104 105 106 108
Conceptually,SQLcarriesoutthisquerybyfirstgeneratingafullsetofqueryresults (fiverows)andtheneliminatingrowsthatareexactduplicatesofoneanothertoformthe
Chapter 6:
Simple Queries
95
finalqueryresults.TheDISTINCTkeywordcanbespecifiedregardlessofthecontentsof theSELECTlist(withcertainrestrictionsforsummaryqueries,asdescribedinChapter8). BeawarethattheSQLenginemayhavetoapplyasorttoidentifytheduplicaterowsand thatsortsoflargenumbersofrowscancauseperformanceproblems. IftheDISTINCTkeywordisomitted,SQLdoesnoteliminateduplicaterows.Youcan alsospecifythekeywordALLtoexplicitlyindicatethatduplicaterowsaretoberetained, butitisunnecessarysincethisisthedefaultbehavior.
Row Selection (WHERE Clause)
Showmetheofficeswheresalesexceedtarget. SELECTCITY,SALES,TARGET FROMOFFICES WHERESALES>TARGET; CITYSALESTARGET ------------------------------------ NewYork$692,637.00$575,000.00 Atlanta$367,911.00$350,000.00 LosAngeles$835,915.00$725,000.00
Showmethename,sales,andquotaofemployeenumber105. SELECTNAME,SALES,QUOTA FROMSALESREPS WHEREEMPL_NUM=105; NAMESALESQUOTA ----------------------------------- BillAdams$367,911.00$350,000.00
ShowmetheemployeesmanagedbyBobSmith(employee104). SELECTNAME,SALES FROMSALESREPS WHEREMANAGER=104; NAMESALES ------------------------ BillAdams$367,911.00 DanRoberts$305,673.00 PaulCruz$286,775.00
TheWHEREclauseconsistsofthekeywordWHEREfollowedbyasearchconditionthat specifiestherowstoberetrieved.Inthepreviousquery,forexample,thesearchconditionis MANAGER=104.Figure6-4showshowtheWHEREclauseworks.Conceptually,SQLgoes
PART II
SQLqueriesthatretrieveallrowsofatableareusefulfordatabasebrowsingandreports, butforlittleelse.Usuallyyou’llwanttoselectonlysomeoftherowsinatableandinclude onlytheserowsinthequeryresults.TheWHEREclauseisusedtospecifytherowsyouwant toretrieve.HerearesomeexamplesofsimplequeriesthatusetheWHEREclause:
96
Part II:
FIGURE 6-4
Retrieving Data
Row selection with the WHERE clause
througheachrowoftheSALESREPStable,onebyone,andappliesthesearchconditionto therow.Whenacolumnnameappearsinthesearchcondition(suchastheMANAGER columninthisexample),SQLusesthevalueofthecolumninthecurrentrow.Foreachrow, thesearchconditioncanproduceoneofthreeresults: • IfthesearchconditionisTRUE,therowisincludedinthequeryresults.Forexample, therowforBillAdamshasthecorrectMANAGERvalueandisincluded. • IfthesearchconditionisFALSE,therowisexcludedfromthequeryresults.For example,therowforSueSmithhasthewrongMANAGERvalueandisexcluded. • IfthesearchconditionhasaNULL(unknown)value,therowisexcludedfromthe queryresults.Forexample,therowforSamClarkhasaNULLvalueforthe MANAGERcolumnandisexcluded. Figure6-5showsanotherwaytothinkabouttheroleofthesearchconditioninthe WHEREclause.Basically,thesearchconditionactsasafilterforrowsofthetable.Rowsthat satisfythesearchconditionpassthroughthefilterandbecomepartofthequeryresults. Rowsthatdonotsatisfythesearchconditionaretrappedbythefilterandexcludedfrom thequeryresults.
FIGURE 6-5 The WHERE clause as a filter
Chapter 6:
Simple Queries
97
Search Conditions SQLoffersarichsetofsearchconditionsthatallowsyoutospecifymanydifferentkindsof queriesefficientlyandnaturally.Fivebasicsearchconditions(calledpredicatesintheANSI/ ISOstandard)aresummarizedhereandaredescribedinthesectionsthatfollow: • Comparisontest Comparesthevalueofoneexpressionwiththevalueofanother expression.UsethistesttoselectofficesintheEasternregion,orsalespeoplewhose salesareabovetheirquotas.
• Setmembershiptest Checkswhetherthevalueofanexpressionmatchesone ofasetofvalues.UsethistesttoselectofficeslocatedinNewYork,Chicago,or LosAngeles. • Patternmatchingtest Checkswhetherthevalueofacolumncontainingstring datamatchesaspecifiedpattern.Usethistesttoselectcustomerswhosenames startwiththeletterE. • Nullvaluetest CheckswhetheracolumnhasaNULL(unknown)value.Use thistesttofindthesalespeoplewhohavenotyetbeenassignedtoamanager.
The Comparison Test (=, , =) ThemostcommonsearchconditionusedinaSQLqueryisacomparisontest.Ina comparisontest,SQLcomputesandcomparesthevaluesoftwoSQLexpressionsforeach rowofdata.Theexpressionscanbeassimpleasacolumnnameoraconstant,ortheycan bemorecomplexarithmeticexpressions.SQLofferssixdifferentwaysofcomparingthe twoexpressions,asshowninFigure6-6.
FIGURE 6-6
Comparison test syntax diagram
PART II
• Rangetest Testswhetherthevalueofanexpressionfallswithinaspecifiedrange ofvalues.Usethistesttofindsalespeoplewhosesalesarebetween$100,000and $500,000.
98
Part II:
Retrieving Data
Someexamplesoftypicalcomparisontestsfollow. Findsalespeoplehiredbefore2006. SELECTNAME FROMSALESREPS WHEREHIRE_DATE30000.00; MFRPRODUCT ------------ IMM775C REI2A44L REI2A44R
AsshowninFigure6-14,theUNIONoperationproducesasingletableofqueryresults thatcombinestherowsofthetopqueryresultswiththerowsofthebottomqueryresults. TheSELECTstatementthatspecifiestheUNIONoperationlookslikethis: Listalltheproductswherethepriceoftheproductexceeds$2,000orwheremorethan$30,000ofthe producthasbeenorderedinasingleorder. SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE>2000.00 UNION SELECTDISTINCTMFR,PRODUCT FROMORDERS WHEREAMOUNT>30000.00; ACI4100Y ACI4100Z IMM775C REI2A44L REI2A44R
TherearesevererestrictionsonthetablesthatcanbecombinedbyaUNIONoperation: • ThetwoSELECTclausesmustcontainthesamenumberofcolumns.
Chapter 6:
Simple Queries
115
• Thedatatypeofeachcolumnselectedfromthefirsttablemustbethesameasthe datatypeofthecorrespondingcolumnselectedfromthesecondtable. • NeitherofthetwotablescanbesortedwiththeORDERBYclause.However,the combinedqueryresultscanbesorted,asdescribedinthefollowingsection.
Unions and Duplicate Rows* BecausetheUNIONoperationcombinestherowsfromtwosetsofqueryresults,itwould tendtoproducequeryresultscontainingduplicaterows.Forexample,inthequeryof Figure6-14,productREI-2A44Lsellsfor$4500.00,soitappearsinthetopsetofquery results.Thereisalsoanorderfor$31,500.00worthofthisproductintheORDERStable,soit alsoappearsinthebottomsetofqueryresults.Bydefault,theUNIONoperationeliminates duplicaterowsaspartofitsprocessing.Thus,thecombinedsetofqueryresultscontains onlyonerowforproductREI-2A44L. IfyouwanttoretainduplicaterowsinaUNIONoperation,youcanspecifytheALL keywordimmediatelyfollowingthewordUNION.Thisformofthequeryproducestwo duplicaterowsforproductREI-2A44L: Listalltheproductswherethepriceoftheproductexceeds$2,000orwheremorethan$30,000ofthe producthasbeenorderedinasingleorder. SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE>2000.00 UNIONALL SELECTDISTINCTMFR,PRODUCT FROMORDERS WHEREAMOUNT>30000.00; ACI4100Y REI2A44L ACI4100Z REI2A44R IMM775C REI2A44L REI2A44R
PART II
NotethatthecolumnnamesofthetwoqueriescombinedbyUNIONdonothavetobe identical.Intheprecedingexample,thefirsttableofqueryresultshascolumnsnamedMFR_ IDandPRODUCT_ID,whilethesecondtableofqueryresultshascolumnsnamedMFRand PRODUCT.Becausethecolumnsinthetwotablescanhavedifferentnames,thecolumnsof queryresultsproducedbytheUNIONoperationareunnamed. TheoriginalANSI/ISOSQLstandardspecifiedafurtherrestrictiononaSELECT statementthatparticipatesinaUNIONoperation.Itpermitsonlycolumnnamesoranallcolumnsspecification(SELECT*)intheselectlistandprohibitsexpressionsintheselect list.MostcommercialSQLimplementationsrelaxthisrestrictionandpermitsimple expressionsintheselectlist.However,manySQLimplementationsdonotallowthe SELECTstatementstoincludetheGROUPBYorHAVINGclauses,andsomedonotallow columnfunctionsintheselectlist(prohibitingsummaryqueriesasdescribedinChapter8). Infact,somesimpleSQLimplementationsdonotsupporttheUNIONoperationatall.
116
Part II:
Retrieving Data
NotethatthedefaultduplicaterowhandlingfortheUNIONoperationandforthe simpleSELECTstatementisexactlyopposite.FortheSELECTstatement,SELECTALL (duplicatesretained)isthedefault.Toeliminateduplicaterows,youmustexplicitlyspecify SELECTDISTINCT.FortheUNIONoperation,UNION(duplicateseliminated)isthedefault. Toretainduplicaterows,youmustexplicitlyspecifyUNIONALL. DatabaseexpertshavecriticizedthehandlingofduplicaterowsinSQLandpointtothis inconsistencyasanexampleoftheproblems.Thereasonfortheinconsistencyisthatthe SQLdefaultswerechosentoproducethecorrectbehaviormostofthetime: • Inpractice,mostsimpleSELECTstatementsdonotproduceduplicaterows,sothe defaultisnoduplicateelimination. • Inpractice,mostUNIONoperationswouldproduceunwantedduplicaterows,sothe defaultisduplicateelimination. Eliminatingduplicaterowsfromqueryresultsisaverytime-consumingprocess,especially ifthequeryresultscontainalargenumberofrows.Ifyouknow,basedontheindividual queriesinvolved,thataUNIONoperationcannotproduceduplicaterows,youshould specificallyusetheUNIONALLoperationbecausethequerywillexecutemuchmorequickly.
Unions and Sorting* TheORDERBYclausecannotappearineitherofthetwoSELECTstatementscombined byaUNIONoperation.Itwouldn’tmakemuchsensetosortthetwosetsofqueryresults anyway,becausetheyarefeddirectlyintotheUNIONoperationandarenevervisibleto theuser.However,thecombinedsetofqueryresultsproducedbytheUNIONoperationcan besortedbyspecifyinganORDERBYclauseafterthesecondSELECTstatement.Sincethe columnsproducedbytheUNIONoperationarenotnamed,theORDERBYclausespecifies thecolumnsbycolumnnumber.However,manySQLproducts,includingOracle,SQL ServerandMySQL,usethecolumnnamesfromthefirstSELECTstatement,andtherefore allowyoutousethosecolumnnamesintheORDERBYclause. HereisthesameproductsqueryasthatshowninFigure6-14,withthequeryresults sortedbymanufacturerandproductnumber: Listalltheproductswherethepriceoftheproductexceeds$2,000orwheremorethan$30,000ofthe producthasbeenorderedinasingleorder,sortedbymanufacturerandproductnumber. SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE>2000.00 UNION SELECTDISTINCTMFR,PRODUCT FROMORDERS WHEREAMOUNT>30000.00 ORDERBY1,2; ACI4100Y ACI4100Z IMM775C REI2A44L REI2A44R
Chapter 6:
Simple Queries
117
Multiple UNIONs* YoucanusetheUNIONoperationrepeatedlytocombinethreeormoresetsofqueryresults, asshowninFigure6-15.TheunionofTableBandTableCinthefigureproducesasingle, combinedtable.ThistableisthencombinedwithTableAinanotherUNIONoperation.The queryinthefigureiswrittenthisway:
TheparenthesesinthequeryindicatewhichUNIONoperationshouldbeperformed first.Infact,ifalloftheUNIONsinthestatementeliminateduplicaterows,orifallofthem retainduplicaterows,theorderinwhichtheyareperformedisunimportant.Thesethree expressionsarecompletelyequivalent AUNION(BUNIONC) (AUNIONB)UNIONC (AUNIONC)UNIONB
FIGURE 6-15
Nested UNION operations
PART II
SELECT* FROMA UNION(SELECT* FROMB UNION SELECT* FROMC); Bill Mary George Fred Sue Julia Harry
118
Part II:
Retrieving Data
andproducesevenrowsofqueryresults.Similarly,thefollowingthreeexpressionsare completelyequivalentandproduce12rowsofqueryresults,becausetheduplicatesareretained: AUNIONALL(BUNIONALLC) (AUNIONALLB)UNIONALLC (AUNIONALLC)UNIONALLB
However,iftheUNIONsinvolveamixtureofUNIONandUNIONALL,theorderof evaluationmatters.Ifthisexpression: AUNIONALLBUNIONC
isinterpretedas: AUNIONALL(BUNIONC)
thenitproducestenrowsofqueryresults(sixfromtheinnerUNION,plusfourrowsfrom TableA).However,ifitisinterpretedas: (AUNIONALLB)UNIONC
thenitproducesonlyfourrows,becausetheouterUNIONeliminatesallduplicaterows. Forthisreason,it’salwaysagoodideatouseparenthesesinUNIONsofthreeormoretables tospecifytheorderofevaluationintended.
Summary ThischapteristhefirstoffourchaptersaboutSQLqueries.Itdescribedthefollowingquery features: • TheSELECTstatementisusedtoexpressaSQLquery.EverySELECTstatement producesatableofqueryresultscontainingoneormorecolumnsandzeroor morerows. • TheFROMclausespecifiesthetable(s)containingthedatatoberetrievedbyaquery. • TheSELECTclausespecifiesthecolumn(s)ofdatatobeincludedinthequery results,whichcanbecolumnsofdatafromthedatabase,orcalculatedcolumns. • TheWHEREclauseselectstherowstobeincludedinthequeryresultsbyapplyinga searchconditiontorowsofthedatabase. • Asearchconditioncanselectrowsbycomparingvalues,bycheckingavalueagainsta rangeorsetofvalues,bymatchingastringpattern,andbycheckingforNULLvalues. • SimplesearchconditionscanbecombinedwithAND,OR,andNOTtoformmore complexsearchconditions. • TheORDERBYclausespecifiesthatthequeryresultsshouldbesortedinascending ordescendingorder,basedonthevaluesofoneormorecolumns. • TheUNIONoperationcanbeusedwithinaSELECTstatementtocombinetwoor moresetsofqueryresultsintoasingleset.
7
CHAPTER
Multitable Queries (Joins)
M
ostusefulqueriesrequestdatafromtwoormoretablesinadatabase.Forexample, theserequestsfordatainthesampledatabasedrawdatafromtwo,three,andfour tablesrespectively:
• Listthesalespeopleandtheofficeswheretheywork(SALESREPSandOFFICES tables). • Listeachorderplacedlastweek,showingtheorderamount,thenameofthe customerwhoplacedit,andthenameoftheproductordered(ORDERS, CUSTOMERS,andPRODUCTStables). • ShowallorderstakenbysalespeopleintheEasternregion,showingtheproduct descriptionandsalesperson(ORDERS,SALESREPS,OFFICES,andPRODUCTStables).
SQLallowsyoutoretrievedatathatanswerstheserequeststhroughmultitablequeries thatjoindatafromtwoormoretables.ThesequeriesandtheSQLjoinfacilityaredescribedin thischapter.WebeginwiththejoincapabilitiesthathavebeenapartofSQLfromtheearliest daysandarefoundinallSQLproductstoday.Thelatersectionsdescribeadditionaljoin capabilitiesthatfirstappearedinSQL2standardandarefoundinmostmainstreamproducts.
A Two-Table Query Example ThebestwaytounderstandthefacilitiesthatSQLprovidesformultitablequeriesistostart withasimplerequestthatcombinesdatafromtwodifferenttables: “Listallorders,showingtheordernumberandamount,andthenameandcreditlimitofthe customerwhoplacedit.” Thefourspecificdataitemsrequestedareclearlystoredintwodifferenttables,as showninFigure7-1. • TheORDERStablecontainstheordernumberandamountofeachorder,butdoesn’t havecustomernamesorcreditlimits. • TheCUSTOMERStablecontainsthecustomernamesandcreditlimits,butitlacks anyinformationaboutorders.
119
120
Part II:
Retrieving Data
Primary key/ foreign key relationship
ORDERS Table ORDER_NUM ORDER_DATE
CUST
REP
QTY
AMOUNT
17-DEC-89 11-JAN-90 03-JAN-90
2117 2111 2101
106 105 106
7 35 6
$31,500.00 $3,745.00 $1,458.00
112961 113012 112989 • • •
List each order, showing the order number and amount, and the name and credit limit of the customer who placed it CUSTOMERS Table CUST_NUM COMPANY • • • 2108 Holm & Landis 2117 J.P. Sinclair 2122 Three-Way Lines • • •
FIGURE 7-1
CUST_REP
CREDIT_LIMIT
109 106 105
$55,000.00 $35,000.00 $30,000.00
A request that spans two tables
Thereisalinkbetweenthesetwotables,however.IneachrowoftheORDERStable,the CUSTcolumncontainsthecustomernumberofthecustomerwhoplacedtheorder,which matchesthevalueintheCUST_NUMcolumninoneoftherowsintheCUSTOMERStable. Clearly,theSELECTstatementthathandlestherequestmustsomehowusethislink betweenthetablestogenerateitsqueryresults. BeforeexaminingtheSELECTstatementforthequery,it’sinstructivetothinkabout howyouwouldmanuallyhandletherequest,usingpaperandpencil.Figure7-2shows whatyouwouldprobablydo:
1. Startbywritingdownthefourcolumnnamesforthequeryresults.Thenmoveto theORDERStable,andstartwiththefirstorder.
2. Lookacrosstherowtofindtheordernumber(112961)andtheorderamount ($31,500.00),andcopybothvaluestothefirstrowofqueryresults.
3. Lookacrosstherowtofindthenumberofthecustomerwhoplacedtheorder (2117),andmovetotheCUSTOMERStabletofindcustomernumber2117by searchingtheCUST_NUMcolumn.
4. MoveacrosstherowoftheCUSTOMERStabletofindthecustomer’sname(“J.P. Sinclair”)andcreditlimit($35,000.00),andcopythemtothequeryresultstable.
5. You’vegeneratedarowofqueryresults!MovebacktotheORDERStable,andgoto thenextrow.Repeattheprocess,startingwithStep2,untilyourunoutoforders.
Chapter 7:
CUSTOMERS Table CUST_NUM COMPANY • • • 2108 Holm & Landis 2117 J.P. Sinclair 2122 Three-Way Lines • • •
3
17-DEC-89 11-JAN-90 03-JAN-90
2
CUST_REP
CREDIT_LIMIT
109 106 105
$55,000.00 $35,000.00 $30,000.00
CUST
REP
QTY
AMOUNT
2117 2111 2101
106 105 106
7 35 6
$31,500.00 $3,745.00 $1,458.00
1
4
4
2
QUERY Results ORDER_NUM 112961 • • •
121
PART II
ORDERS Table ORDER_NUM ORDER_DATE 112961 113012 112989 • • •
Multitable Queries (Joins)
AMOUNT
COMPANY
CREDIT_LIMIT
$31,500.00
J.P. Sinclair
$35,000.00
FIGURE 7-2 Manually processing a multitable query
Ofcoursethisisn’ttheonlywaytogeneratethequeryresults,butregardlessofhow youdoit,twothingswillbetrue: • Eachrowofqueryresultsdrawsitsdatafromaspecificpairofrows,onefromthe ORDERStableandonefromtheCUSTOMERStable. • Thepairsofrowsarefoundbymatchingthedatavaluesincorrespondingcolumns fromthetables.
Simple Joins (Equi-Joins) Theprocessofformingpairsofrowsbymatchingthecontentsofrelatedcolumnsiscalled joiningthetables.Theresultingtable(containingdatafrombothoftheoriginaltables)is calledajoinbetweenthetwotables.(Ajoinbasedonanexactmatchbetweentwocolumns ismorepreciselycalledanequi-join.Joinscanalsobebasedonotherkindsofcolumn comparisons,asdescribedlaterinthischapter.)
122
Part II:
Retrieving Data
JoinsarethefoundationofmultitablequeryprocessinginSQL.Allofthedataina relationaldatabaseisstoredinitscolumnsasexplicitdatavalues,soallpossiblerelationships betweentablescanbeformedbymatchingthecontentsofrelatedcolumns.Joinsthusprovide apowerfulfacilityforexercisingthedatarelationshipsinadatabase.Infact,becauserelational databasesdonotcontainpointersorothermechanismsforrelatingrowstooneanother,joins aretheonlymechanismforexercisingcross-tabledatarelationships. BecauseSQLhandlesmultitablequeriesbymatchingcolumns,itshouldcomeasno surprisethattheSELECTstatementforamultitablequerycontainsasearchconditionthat specifiesthecolumnmatch.HereisaSELECTstatementforthequerythatwasperformed manuallyinFigure7-2: Listallordersshowingordernumber,amount,customername(“company”),andthecustomer’s creditlimit. SELECTORDER_NUM,AMOUNT,COMPANY,CREDIT_LIMIT FROMORDERS,CUSTOMERS WHERECUST=CUST_NUM; ORDER_NUMAMOUNTCOMPANYCREDIT_LIMIT ---------------------------------------------------- 112989$1,458.00JonesMfg.$65,000.00 112968$3,978.00FirstCorp.$65,000.00 112963$3,276.00AcmeMfg.$50,000.00 112987$27,500.00AcmeMfg.$50,000.00 112983$702.00AcmeMfg.$50,000.00 113027$4,104.00AcmeMfg.$50,000.00 112993$1,896.00FredLewisCorp.$65,000.00 113065$2,130.00FredLewisCorp.$65,000.00 113036$22,500.00AceInternational$35,000.00 113034$632.00AceInternational$35,000.00 113058$1,480.00Holm&Landis$55,000.00 113055$150.00Holm&Landis$55,000.00 113003$5,625.00Holm&Landis$55,000.00 . . .
RecallthatdifferentSQLtoolsformatresultsindifferentways,soyourresultsmayvary, particularlyforthedollaramountsshownintheexample.Thisquerylooksjustlikethe queriesfromthepreviouschapter,withtwonewfeatures.First,theFROMclauseliststwo tablesinsteadofjustone.Second,thesearchcondition CUST=CUST_NUM
comparescolumnsfromtwodifferenttables.Wecallthesetwocolumnsthematching columnsforthetwotables.Likeallsearchconditions,thisonerestrictstherowsthatappear inthequeryresults.Becausethisisatwo-tablequery,thesearchconditionrestrictsthepairs ofrowsthatgeneratethequeryresults.Infact,thesearchconditionspecifiesthesame matchingcolumnsyouusedinthepaper-and-pencilqueryprocessing.Itactuallycaptures thespiritofthemanualcolumnmatchingverywell,saying:
Chapter 7:
Multitable Queries (Joins)
123
“Generatequeryresultsonlyforpairsofrowswherethecustomernumber(CUST)inthe ORDERStablematchesthecustomernumber(CUST_NUM)intheCUSTOMERStable.” NoticethattheSELECTstatementdoesn’tsayanythingabouthowtheDBMSshould executethequery.Thereisnomentionof“startingwithorders”or“startingwith customers.”Instead,thequerytellstheDBMSwhatthequeryresultsshouldlooklikeand leavesituptotheDBMStodecidehowtogeneratethem.
Parent/Child Queries
Listeachsalespersonandthecityandregionwheretheywork. SELECTNAME,CITY,REGION FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE; NAMECITYREGION ---------------------------------- MaryJonesNewYorkEastern SamClarkNewYorkEastern BobSmithChicagoEastern PaulCruzChicagoEastern DanRobertsChicagoEastern BillAdamsAtlantaEastern SueSmithLosAngelesWestern LarryFitchLosAngelesWestern NancyAngelliDenverWestern
TheSALESREPS(child)tablecontainsREP_OFFICE,aforeignkeyfortheOFFICES (parent)table.ThisrelationshipisusedtofindthecorrectOFFICESrowforeach salesperson,sothatthecorrectcityandregioncanbeincludedinthequeryresults. Here’sanotherqueryinvolvingthesametwotables,butwiththeparentandchildroles reversed,asshowninFigure7-4.
PART II
Themostcommonmultitablequeriesinvolvetwotablesthathaveanaturalparent/child relationship.Thequeryaboutordersandcustomersintheprecedingsectionisanexample ofsuchaquery.Eachorder(child)hasanassociatedcustomer(parent),andeachcustomer (parent)canhavemanyassociatedorders(children).Thepairsofrowsthatgeneratethe queryresultsareparent/childrowcombinations. YoumayrecallfromChapter4thatforeignkeysandprimarykeyscreatetheparent/ childrelationshipinaSQLdatabase.Thetablecontainingtheforeignkeyisthechildinthe relationship;thetablewiththeprimarykeyistheparent.Toexercisetheparent/child relationshipinaquery,youspecifyasearchconditionthatcomparestheforeignkeyandthe primarykey.Hereisanotherexampleofaquerythatexercisesaparent/childrelationship, showninFigure7-3.
124
Part II:
Retrieving Data
OFFICES Table OFFICE
CITY
22 11 12 13 21
Denver New York Chicago Atlanta Los Angeles
REGION
MGR
SALESREPS Table EMPL_NUM NAME 105 109 102 106 104 101 110 108 103 107
TARGET
Western 108 $300,000.00 Eastern 106 $575,000.00 Eastern 104 $800,000.00 Eastern NULL $350,000.00 Western 108 $725,000.00
SALES $186,042.00 $692,637.00 $735,042.00 $367,911.00 $835,915.00
AGE REP_OFFICE
Bill Adams Mary Jones Sue Smith Sam Clark Bob Smith Dan Roberts Tom Snyder Larry Fitch Paul Cruz Nancy Angelli
37 31 48 52 33 45 41 62 29 49
13 11 21 11 12 12 NULL 21 12 22
Query Results NAME CITY REGION
TITLE Sales Rep Sales Rep Sales Rep VP Sales Sales Mgr Sales Rep Sales Rep Sales Mgr Sales Rep Sales Rep
FIGURE 7-3 A parent/child query with the OFFICES and SALESREPS tables
SALESREPS Table EMPL_NUM NAME 105 109 102 106 104 101 110 108 103 107
Bill Adams Mary Jones Sue Smith Sam Clark Bob Smith Dan Roberts Tom Snyder Larry Fitch Paul Cruz Nancy Angelli
OFFICES Table OFFICE CITY 22 11 12 13 21
Denver New York Chicago Atlanta Los Angeles
AGE
REP_OFFICE
TITLE
37 31 48 52 33 45 41 62 29 49
13 11 21 11 12 12 NULL 21 12 22
Sales Rep Sales Rep Sales Rep VP Sales Sales Mgr Sales Rep Sales Rep Sales Mgr Sales Rep Sales Rep
REGION
MGR
TARGET
Query Results CITY NAME
Western 108 $300,000.00 Eastern 106 $575,000.00 Eastern 104 $800,000.00 Eastern NULL $350,000.00 Western 108 $725,000.00
FIGURE 7-4 A different parent/child query with the OFFICES and SALESREPS tables
TITLE
Chapter 7:
Multitable Queries (Joins)
125
Listtheofficesandthenamesandtitlesoftheirmanagers.
TheOFFICES(child)tablecontainsMGR,aforeignkeyfortheSALESREPS(parent) table.ThisrelationshipisusedtofindthecorrectSALESREPSrowforeachsalesperson,so thatthecorrectnameandtitleofthemanagercanbeincludedinthequeryresults. SQLdoesnotrequirethatthematchingcolumnsbeincludedintheresultsofamultitable query.Theyareoftenomittedinpractice,asinthetwoprecedingexamples.That’sbecause primarykeysandforeignkeysareoftenIDnumbers(suchastheofficenumbersand employeenumbersintheexamples),whichhumansfindhardtoremember,whilethe associatednames(cities,regions,names,titles)areeasiertounderstand.It’squitecommon forIDnumberstobeusedintheWHEREclausetojointwotables,andformoredescriptive namestobespecifiedintheSELECTclausetogeneratecolumnsofqueryresults.
An Alternative Way to Specify Joins Thesimplestwaytospecifythetablestobejoinedinamultitablequeryistonamethem inacomma-separatedlist,intheFROMclauseoftheSELECTstatement,asshowninthe previousexamples.ThismethodforspecifyingjoinedtablesappearedintheearliestIBM SQLimplementations.ItwasincludedintheoriginalSQLstandardandissupportedby allSQL-baseddatabases. Subsequentversionsofthestandardsignificantlyexpandedthejoincapabilityand addednewoptionstotheFROMclause.Usingthenewerform,theprevioustwoquery examplescouldalsobewrittenlikethis: Listeachsalespersonandthecityandregionwheretheywork. SELECTNAME,CITY,REGION FROMSALESREPSJOINOFFICES ONREP_OFFICE=OFFICE; NAMECITYREGION ---------------------------------- MaryJonesNewYorkEastern SamClarkNewYorkEastern BobSmithChicagoEastern PaulCruzChicagoEastern DanRobertsChicagoEastern BillAdamsAtlantaEastern SueSmithLosAngelesWestern LarryFitchLosAngelesWestern NancyAngelliDenverWestern
PART II
SELECTCITY,NAME,TITLE FROMOFFICES,SALESREPS WHEREMGR=EMPL_NUM; CITYNAMETITLE ---------------------------------- ChicagoBobSmithSalesMgr AtlantaBillAdamsSalesRep NewYorkSamClarkVPSales DenverLarryFitchSalesMgr LosAngelesLarryFitchSalesMgr
126
Part II:
Retrieving Data
Listtheofficesandthenamesandtitlesoftheirmanagers. SELECTCITY,NAME,TITLE FROMOFFICESJOINSALESREPS ONMGR=EMPL_NUM; CITYNAMETITLE ---------------------------------- ChicagoBobSmithSalesMgr AtlantaBillAdamsSalesRep NewYorkSamClarkVPSales DenverLarryFitchSalesMgr LosAngelesLarryFitchSalesMgr
Insteadofacomma-separatedlistoftablenames,theFROMclauseintheseexamplesuses theJOINkeywordtospecificallydescribethejoinoperation.Also,thematchingcolumnsto beusedinthejoinarespecifiedintheONclause,whichoccursattheendoftheFROMclause. Forthesesimpleexamples,theexpandedstandardSQLsyntaxaddsverylittletotheolder formoftheSELECTstatement.Buttherangeofjoinsthatcanbeexpressedusingthe expandedformismuchbroader,asdescribedinlatersectionsofthischapter.Manyofthe majorDBMSvendorsareencouragingtheuseofthisnewJOINclauseforthatreason.
Joins with Row Selection Criteria Thesearchconditionthatspecifiesthematchingcolumnsinamultitablequerycanbe combinedwithothersearchconditionstofurtherrestrictthecontentsofthequeryresults. Supposeyouwanttoreruntheprecedingquery,showingonlyofficeswithlargesalestargets: Listtheofficeswithatargetover$600,000andtheirmanagerinformation. SELECTCITY,NAME,TITLE FROMOFFICES,SALESREPS WHEREMGR=EMPL_NUM ANDTARGET>600000.00; CITYNAMETITLE ---------------------------------- ChicagoBobSmithSalesMgr LosAngelesLarryFitchSalesMgr
Withtheadditionalsearchcondition,therowsthatappearinthequeryresultsarefurther restricted.Thefirsttest(MGR=EMPL_NUM)selectsonlypairsofOFFICESandSALESREPS rowsthathavetheproperparent/childrelationship;thesecondtestfurtherselectsonly thosepairsofrowswheretheofficetargetisabove$600,000.Inthisformofthequery,the matchingconditionforthejoinandthesearchconditionthatrestrictswhichofficesare selectedbothappearintheWHEREclause.UsingthenewerstandardSQLsyntax,the matchingconditionappearsintheONclause,andthesearchconditionappearsintheWHERE clause,whichmakesthequeryslightlyeasiertounderstand:
Chapter 7:
Multitable Queries (Joins)
127
Listtheofficeswithatargetover$600,000andtheirmanagerinformation. SELECTCITY,NAME,TITLE FROMOFFICESJOINSALESREPS ONMGR=EMPL_NUM WHERETARGET>600000.00; CITYNAMETITLE ---------------------------------- ChicagoBobSmithSalesMgr LosAngelesLarryFitchSalesMgr
TheORDERStableandthePRODUCTStableinthesampledatabasearerelatedbya compositeforeignkey/primarykeypair.TheMFRandPRODUCTcolumnsoftheORDERS tabletogetherformaforeignkeyforthePRODUCTStable,matchingitsMFR_IDand PRODUCT_IDcolumns,respectively.Tojointhetablesbasedonthisparent/child relationship,youmustspecifybothpairsofmatchingcolumns,asshowninthisexample: Listalltheorders,showingamountsandproductdescriptions. SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERS,PRODUCTS WHEREMFR=MFR_ID ANDPRODUCT=PRODUCT_ID; ORDER_NUMAMOUNTDESCRIPTION ------------------------------------ 113027$4,104.00Size2Widget 112992$760.00Size2Widget 113012$3,745.00Size3Widget 112968$3,978.00Size4Widget 112963$3,276.00Size4Widget 112983$702.00Size4Widget 113055$150.00WidgetAdjuster 113057$600.00WidgetAdjuster . . .
ThesearchconditioninthequerytellsSQLthattherelatedpairsofrowsfromtheORDERS andPRODUCTStablesarethosewherebothpairsofmatchingcolumnscontainthesame values.Thealternativeformofthequeryspecifiesthematchingcolumnsinthesameway: SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSJOINPRODUCTS ONMFR=MFR_ID ANDPRODUCT=PRODUCT_ID;
Multicolumnjoinsareusuallyfoundinqueriesinvolvingcompoundforeignkeyssuchas thisone.ThereisnoSQLrestrictiononthenumberofcolumnsthatareinvolvedinthe matchingcondition,butjoinsnormallymirrorthereal-worldrelationshipsbetweenentities representedinthedatabasetables,andthoserelationshipsareusuallyembodiedinoneor justafewcolumnsofthetables.
PART II
Multiple Matching Columns
128
Part II:
Retrieving Data
Natural Joins Oftenthematchingcolumnorcolumnsthatwillbeusedtojointwotableshavethesame nameinbothtables.Thisisn’ttrueinthesampledatabase,wheretheprimarykeysand relatedforeignkeyshavebeengivenslightlydifferentnamessothattheycanbeeasily distinguishedinourexamples.Butinpractice,adatabasecreatorwilloftenusethesame nameforacolumnthatcontainsacustomerIDoranemployeenumberacrossallofthe tablesthatcontainsuchdata. SupposethatthemanufacturerIDandproductIDwerecalledMFRandPRODUCTinboth theORDERStableandthePRODUCTStableinthesampledatabase.Ifthatweretrue,thenthe mostnaturaljoinbetweenthetwotableswouldbeanequi-joinbasedonallofthecolumn namesthatappearinbothtables.Suchajoinis,infact,calledanaturaljoininSQLstandard. Thestandardjoinsyntaxallowsyoutoeasilyindicatethatyouwantanaturaljoin: SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSNATURALJOINPRODUCTS;
ThisstatementtellstheDBMStojointheORDERSandPRODUCTStablesonallofthe columnsthathavethesamenamesinbothtables.Inthisexample,thatwouldbetheMFR andPRODUCTcolumns. Youcanalsoexplicitlynamethecolumnstobematchedinthissituationwiththis alternativeformofthejoinspecification: SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSJOINPRODUCTS USING(MFR,PRODUCT);
Thecolumnstobematchedforthejoin(whichhavethesamenameinbothtables)are listed,enclosedinparentheses,intheUSINGclause.NotethattheUSINGclauseisamore compactalternativetotheONclause,buttheprecedingquerywouldbecompletely equivalenttothisone(stillassumingthatthecolumnshavethesamenamesinbothtables): SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSJOINPRODUCTS ONORDERS.MFR=PRODUCTS.MFR ANDORDERS.PRODUCT=PRODUCTS.PRODUCT;
Inmanycases,theformofthejoinwiththeUSINGclauseispreferabletospecifyinganexplicit NATURALJOIN.IftwodifferentadministratorsareresponsibleformaintainingtheORDERS andPRODUCTStable,forexample(completelyplausibleinalargeproductiondatabase),it’s possiblethattheymightbothaccidentallychoosethesamenameforanewcolumntobeadded totheirtable,eventhoughthecolumnshavenothingtodowithoneanother.Inthissituation, theNATURALJOINformofthestatementwouldpickupthenewcolumnswithmatching namesandattempttousethemwhenjoiningthetables,probablyresultinginanerror.The USINGclauseinsulatesthequeryfromthistypeofaccidentalconsequenceofdatabase structurechanges.Inaddition,theUSINGclauseallowsyoutoselectwhichindividualcolumns areusedtojointhetables,whiletheNATURALJOINautomaticallyusesallcolumnswith matchingnames.Finally,iftherearenomatchingcolumnnames,aqueryusingtheNATURAL JOINmightreturnaCartesianproduct(describedlaterinthischapter),oritmightreturnan error,dependingontheDBMS;however,aqueryformedwiththeUSINGclausewillalways returnanerrorifthenamedcolumnsdonotappearinbothtables.
Chapter 7:
Multitable Queries (Joins)
129
Queries with Three or More Tables SQLcancombinedatafromthreeormoretablesusingthesamebasictechniquesusedfor two-tablequeries.Hereisasimpleexampleofathree-tablejoin: Listordersover$25,000,includingthenameofthesalespersonwhotooktheorderandthenameof thecustomerwhoplacedit.
PART II
SELECTORDER_NUM,AMOUNT,COMPANY,NAME FROMORDERS,CUSTOMERS,SALESREPS WHERECUST=CUST_NUM ANDREP=EMPL_NUM ANDAMOUNT>25000.00; ORDER_NUMAMOUNTCOMPANYNAME --------------------------------------------------- 112987$27,500.00AcmeMfg.BillAdams 113069$31,350.00ChenAssociatesNancyAngelli 113045$45,000.00ZetacorpLarryFitch 112961$31,500.00J.P.SinclairSamClark
ThisqueryusestwoforeignkeysintheORDERStable,asshowninFigure7-5.TheCUST columnisaforeignkeyfortheCUSTOMERStable,linkingeachordertothecustomerwho placedit.TheREPcolumnisaforeignkeyfortheSALESREPStable,linkingeachorderto thesalespersonwhotookit.Informallyspeaking,thequerylinkseachordertoitsassociated customerandsalesperson. Thealternativeformofthisqueryspecifieseachjoinanditsmatchingcolumnsmore explicitly: SELECTORDER_NUM,AMOUNT,COMPANY,NAME FROMORDERSJOINCUSTOMERSONCUST=CUST_NUM JOINSALESREPSONREP=EMPL_NUM WHEREAMOUNT>25000.00;
CUSTOMERS Table CUST_NUM 2111 2102 2103 • • •
SALESREPS Table
COMPANY
CUST_REP
CREDIT_LIMIT
EMPL_NUM
NAME
JCP Inc. First Corp. Acme Mfg.
103 101 105
$55,000.00 $35,000.00 $30,000.00
105 109 102 • • •
Bill Adams Mary Jones Sue Smith
…
…
AGE REP_OFFICE 37 31 48
13 11 21
Query Results
ORDERS Table ORDER_NUM
ORDER_DATE
CUST
REP
MFR
QTY
AMOUNT
112961 113012 112989 • • •
17-DEC-89 11-JAN-90 03-JAN-90
2117 2111 2101
106 REI 105 ACI 106 FEA
7 35 6
$31,500.00 $3,745.00 $1,458.00
FIGURE 7-5 A three-table join
ORDER_NUM
AMOUNT
COMPANY
NAME
130
Part II:
Retrieving Data
Hereisanotherthree-tablequerythatusesadifferentarrangementofparent/child relationships: Listtheordersover$25,000,showingthenameofthecustomerwhoplacedtheorderandthenameof thesalespersonassignedtothatcustomer. SELECTORDER_NUM,AMOUNT,COMPANY,NAME FROMORDERS,CUSTOMERS,SALESREPS WHERECUST=CUST_NUM ANDCUST_REP=EMPL_NUM ANDAMOUNT>25000.00; ORDER_NUMAMOUNTCOMPANYNAME ------------------------------------------------- 112987$27,500.00AcmeMfg.BillAdams 113069$31,350.00ChenAssociatesPaulCruz 113045$45,000.00ZetacorpLarryFitch 112961$31,500.00J.P.SinclairSamClark
Figure7-6showstherelationshipsexercisedbythisquery.Thefirstrelationshipagain usestheCUSTcolumnfromtheORDERStableasaforeignkeytotheCUSTOMERStable.
SALESREPS Table EMPL_NUM NAME • • • 108 103 107
Larry Fitch Paul Cruz Nancy Angelli
AGE REP_OFFICE
62 29 49
21 12 22
CUSTOMERS Table CUST_NUM
COMPANY
2111 2102 2103 • • •
JCP Inc. First Corp. Acme Mfg.
CUST_REP
CREDIT_LIMIT
103 101 105
$50,000.00 $65,000.00 $50,000.00
Query Results
ORDERS Table ORDER_NUM
ORDER_DATE
CUST
REP
QTY
112961 113012 112989 • • •
17-DEC-89 11-JAN-90 03-JAN-90
2117 2111 2101
106 105 106
7 35 6
FIGURE 7-6
AMOUNT $31,500.00 $3,745.00 $1,458.00
A three-table join with cascaded parent/child relationships
Chapter 7:
Multitable Queries (Joins)
Listtheordersover$25,000,showingthenameofthecustomerwhoplacedtheorder,thecustomer’s salesperson,andtheofficewherethesalespersonworks. SELECTORDER_NUM,AMOUNT,COMPANY,NAME,CITY FROMORDERS,CUSTOMERS,SALESREPS,OFFICES WHERECUST=CUST_NUM ANDCUST_REP=EMPL_NUM ANDREP_OFFICE=OFFICE ANDAMOUNT>25000.00; ORDER_NUMAMOUNTCOMPANYNAMECITY ------------------------------------------------------------ 112987$27,500.00AcmeMfg.BillAdamsAtlanta 113069$31,350.00ChenAssociatesPaulCruzChicago 113045$45,000.00ZetacorpLarryFitchLosAngeles 112961$31,500.00J.P.SinclairSamClarkNewYork
Figure7-7showstheparent/childrelationshipsinthisquery.Logically,itextendsthe joinsequenceofthepreviousexampleonemorestep,linkinganordertoitscustomer,the customertotheirsalesperson,andthesalespersontotheiroffice.
Other Equi-Joins Thevastmajorityofmultitablequeriesarebasedonparent/childrelationships,butSQL doesnotrequirethatthematchingcolumnsberelatedasaforeignkeyandprimarykey. Anypairofcolumnsfromtwotablescanserveasmatchingcolumns,providedtheyhave
PART II
ThesecondusestheCUST_REPcolumnfromtheCUSTOMERStableasaforeignkeytothe SALESREPStable.Informallyspeaking,thisquerylinkseachordertoitscustomer,and eachcustomertotheirsalesperson. Notethattheorderofthejoinsinthesemultitablequeriesdoesn’tmatter.TheDBMS canjointheORDERStabletotheCUSTOMERStable,andthenjointheresulttothe SALESREPStable.Alternatively,itcanjointheCUSTOMERStabletotheSALESREPStable first,andthenjointheresulttotheORDERStable.Eitherway,theresultswillbeexactlythe same,sotheDBMScanperformthejoinsintheorderthatismostefficient.However,some ofthemoreadvancedjoinsdescribedlaterinthischapteraresensitivetothesequenceof theindividualjoins.OneoftheadvantagesofthenewerstandardSQLjoinsyntaxisthatit allowsyoutospecifythejoinorderinthesecases. It’snotuncommontofindqueriesthatjointhreeormoretablesinproductionSQL applications,andbusinessintelligencequeriesagainstalargedatawarehousecaneasily growtoinvolveatleastadozentables.Evenwithintheconfinesofthesmall,five-table sampledatabase,it’snottoohardtofindafour-tablequerythatmakessense:
131
132
Part II:
Retrieving Data
comparabledatatypes(ordatatypesthatcanbeconvertedtocompatibletypes).This exampleshowsaquerythatusesapairofdatesasmatchingcolumns: Findallordersreceivedonadaywhenanewsalespersonwashired. SELECTORDER_NUM,AMOUNT,ORDER_DATE,NAME FROMORDERS,SALESREPS WHEREORDER_DATE=HIRE_DATE; ORDER_NUMAMOUNTORDER_DATENAME -------------------------------------------- 112968$3,978.0012-OCT-07MaryJones 112979$15,000.0012-OCT-07MaryJones 112975$2,100.0012-OCT-07MaryJones 112968$3,978.0012-OCT-07LarryFitch 112979$15,000.0012-OCT-07LarryFitch 112975$2,100.0012-OCT-07LarryFitch OFFICES Table OFFICE
CITY
22 11 12 13 21
Denver New York Chicago Atlanta Los Angeles
REGION
…
SALESREPS Table EMPL_NUM NAME • • • 108 103 107
MGR
Western 108 Eastern 106 Eastern 104 Eastern NULL Western 108
Larry Fitch Paul Cruz Nancy Angelli
…
AGE REP_OFFICE
62 29 49
21 12 22
TITLE
Sales Mgr Sales Rep Sales Rep
CUSTOMERS Table CUST_NUM 2111 2102 2103 • • •
COMPANY JCP Inc. First Corp. Acme Mfg.
CUST_REP
CREDIT_LIMIT
103 101 105
$50,000.00 $65,000.00 $50,000.00
… Query Results
ORDERS Table ORDER_NUM
ORDER_DATE
CUST
AMOUNT
112961 113012 112989 • • •
17-DEC-89 11-JAN-90 03-JAN-90
2117 2111 2101
$31,500.00 $3,745.00 $1,458.00
FIGURE 7-7
A four-table join
Chapter 7:
Multitable Queries (Joins)
133
ORDERS Table ORDER_NUM
SALESREPS Table EMPL_NUM NAME
FIGURE 7-8
Bill Adams Mary Jones Sue Smith Sam Clark Bob Smith Dan Roberts Tom Snyder Larry Fitch Paul Cruz Nancy Angelli
12-FEB-88 12-OCT-89 10-DEC-86 14-JUN-88 19-MAY-88 20-OCT-86 13-JAN-90 12-OCT-89 01-MAR-87 14-NOV-89
ORDER_DATE
CUST
10-FEB-90 12-OCT-89 30-JAN-90
2118 2102 2107
24-FEB-90 12-OCT-89 22-JAN-90
2124 2114 2103
04-NOV-89 12-OCT-89 15-FEB-90
2118 2111 2108
A join not involving primary and foreign keys
TheresultsofthisquerycomefrompairsofrowsintheORDERSandSALESREPStables wheretheORDER_DATEhappenstomatchtheHIRE_DATEforthesalesperson,asshownin Figure7-8.Neitherofthesecolumnsisaforeignkeyoraprimarykey,andtherelationship betweenthepairsofrowsisadmittedlyastrangeone—theonlythingthematchedorders andsalespeoplehaveincommonisthattheyhappentohavethesamedates.However,SQL happilyjoinsthetablesanyway. Matchingcolumnsliketheonesinthisexamplegenerateamany-to-manyrelationship betweenthetwotables.Manyorderscanshareasinglesalesperson’shiredate,andmore thanonesalespersonmayhavebeenhiredonthesamedate.Forexample,notethatthree differentorders(112968,112975,and112979)werereceivedonOctober12,2007,andtwo differentsalespeople(LarryFitchandMaryJones)werehiredthatsameday.Thethree orders,eachmatchedtobothofthetwosalespeople,producesixrowsofqueryresults. Thismany-to-manyrelationshipisdifferentfromtheone-to-manyrelationshipcreated byprimarykey/foreignkeymatchingcolumns.Thesituationcanbesummarizedasfollows: • Joinsthatmatchprimarykeystoforeignkeysalwayscreateone-to-many,parent/ childrelationships. • Otherjoinsmayalsogenerateone-to-manyrelationshipsifthematchingcolumnin atleastoneofthetableshasuniquevaluesforallrowsofthetable. • Ingeneral,joinsonarbitrarymatchingcolumnsgeneratemany-to-manyrelationships. Notethatthesethreedifferentsituationshavenothingtodowithhowyouwritethe SELECTstatementthatexpressesthejoin.Allthreetypesofjoinsarewrittenthesame way—byincludingacomparisontestforthematchingcolumnpairsintheWHEREclauseor intheONclause.Nonetheless,it’susefultothinkaboutjoinsinthiswaytounderstandhow toturnanEnglish-languagerequestintothecorrectSELECTstatement.
PART II
105 109 102 106 104 101 110 108 103 107
HIRE_DATE
• • • 113051 112978 113076 • • • 113062 112379 113027 • • • 112992 112875 113055 • • •
134
Part II:
Retrieving Data
Non-Equi-Joins Thetermjoinappliestoanyquerythatcombinesdatafromtwotablesbycomparingthe valuesinapairofcolumnsfromthetables.Althoughjoinsbasedonequalitybetween matchingcolumns(equi-joins)arebyfarthemostcommonjoins,SQLalsoallowsyouto jointablesbasedonothercomparisonoperators.Here’sanexamplewhereagreater-than (>)comparisontestisusedasthebasisforajoin: Listallcombinationsofsalespeopleandofficeswherethesalesperson’squotaismorethanthatoffice’s target,regardlessofwhetherthesalespersonworksthere. SELECTNAME,QUOTA,CITY,TARGET FROMSALESREPS,OFFICES WHEREQUOTA>TARGET; NAMEQUOTACITYTARGET ------------------------------------------- BillAdams$350,000.00Denver$300,000.00 SueSmith$350,000.00Denver$300,000.00 LarryFitch$350,000.00Denver$300,000.00
Asinalltwo-tablequeries,eachrowofthequeryresultscomesfromapairofrows,in thiscasefromtheSALESREPSandOFFICEStables.Thesearchcondition QUOTA>TARGET
selectspairsofrowswheretheQUOTAcolumnfromtheSALESREPSrowexceedsthe TARGETcolumnfromtheOFFICESrow.NotethatthepairsofSALESREPSandOFFICES rowsselectedarerelatedonlyinthisway;itisspecificallynotrequiredthattheSALESREPS rowrepresentsomeonewhoworksintheofficerepresentedbytheOFFICESrow. Admittedly,theexampleisabitfarfetched,anditillustrateswhyjoinsbasedoninequalities arenotverycommon.However,theycanbeusefulindecision-supportapplicationsand otherapplicationsthatexploremorecomplexinterrelationshipsinthedatabase.
SQL Considerations for Multitable Queries ThemultitablequeriesdescribedthusfarhavenotrequiredanyspecialSQLsyntaxor languagefeaturesbeyondthosedescribedforsingle-tablequeries.However,somemultitable queriescannotbeexpressedwithoutsomeadditionalSQLfeatures.Specifically: • Qualifiedcolumnnamesaresometimesneededinmultitablequeriestoeliminate ambiguouscolumnreferences. • All-columnselections(SELECT*)haveaspecialmeaningformultitablequeries. • Self-joinscanbeusedtocreateamultitablequerythatrelatesatabletoitself. • TablealiasescanbeusedintheFROMclausetosimplifyqualifiedcolumnnamesand toallowunambiguouscolumnreferencesinself-joins.
Chapter 7:
Multitable Queries (Joins)
135
Qualified Column Names Thesampledatabaseincludesseveralinstanceswheretwotablescontaincolumnswiththe samename.TheOFFICEStableandtheSALESREPStable,forexample,bothhaveacolumn namedSALES.ThecolumnintheOFFICEStablecontainsyear-to-datesalesforeachoffice; theoneintheSALESREPStablecontainsyear-to-datesalesforeachsalesperson.Normally, thereisnoconfusionbetweenthetwocolumns,becausetheFROMclausedetermineswhich ofthemisappropriateinanygivenquery,asintheseexamples: Showthecitieswheresalesexceedtarget.
Showallsalespeoplewithsalesover$350,000. SELECTNAME,SALES FROMSALESREPS WHERESALES>350000.00;
However,hereisaquerywheretheduplicatenamescauseaproblem: Showthename,sales,andofficeforeachsalesperson. SELECTNAME,SALES,CITY FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE; Error:Ambiguouscolumnname"SALES"
AlthoughtheEnglishdescriptionofthequeryimpliesthatyouwanttheSALEScolumnin theSALESREPStable,theSQLqueryisambiguous.TheDBMShasnowayofknowing whetheryouwanttheSALEScolumnfromtheSALESREPStableortheonefromtheOFFICES table,sincebothtablesarecontributingdatatothequeryresults.Toeliminatetheambiguity, youmustuseaqualifiedcolumnnametoidentifythecolumn.RecallfromChapter5thata qualifiedcolumnnamespecifiesthenameofacolumnandthetablecontainingthecolumn. ThequalifiednamesofthetwoSALEScolumnsinthesampledatabaseare OFFICES.SALESandSALESREPS.SALES
AqualifiedcolumnnamecanbeusedinaSELECTstatementanywherethatacolumn nameispermitted.Thetablespecifiedinthequalifiedcolumnnamemust,ofcourse, matchoneofthetablesspecifiedintheFROMlist.Hereisacorrectedversionoftheprevious querythatusesaqualifiedcolumnname:
PART II
SELECTCITY,SALES FROMOFFICES WHERESALES>TARGET;
136
Part II:
Retrieving Data
Showthename,sales,andofficeforeachsalesperson. SELECTNAME,SALESREPS.SALES,CITY FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE; NAMESALESREPS.SALESCITY ------------------------------------------ MaryJones$392,725.00NewYork SamClark$299,912.00NewYork BobSmith$142,594.00Chicago PaulCruz$286,775.00Chicago DanRoberts$305,673.00Chicago BillAdams$367,911.00Atlanta SueSmith$474,050.00LosAngeles LarryFitch$361,865.00LosAngeles NancyAngelli$186,042.00Denver
Usingqualifiedcolumnnamesinamultitablequeryisalwaysagoodidea.Thedisadvantage, ofcourse,isthattheymakethequerytextlonger.WhenusinginteractiveSQL,youmaywant tofirsttryaquerywithunqualifiedcolumnnamesandletSQLfindanyambiguouscolumns. IfSQLreportsanerror,youcanedityourquerytoqualifytheambiguouscolumns.
All-Column Selections AsdiscussedinChapter6,SELECT*canbeusedtoselectallcolumnsofthetablenamedin theFROMclause.Inamultitablequery,theasteriskselectsallcolumnsofalltablesintheFROM clause.Thefollowingquery,forexample,wouldproduce15columnsofqueryresults—the ninecolumnsfromtheSALESREPStablefollowedbythesixcolumnsfromtheOFFICEStable: Tellmeallaboutsalespeopleandtheofficeswheretheywork. SELECT* FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE;
Obviously,theSELECT*formofaquerybecomesmuchlesspracticalwhenthereare two,three,ormoretablesintheFROMclause. ManySQLdialectstreattheasteriskasaspecialkindofwildcardcolumnnamethatis expandedintoalistofcolumns.Inthesedialects,theasteriskcanbequalifiedwithatablename, justlikeaqualifiedcolumnreference.Inthefollowingquery,theselectitemSALESREPS.*is expandedintoalistcontainingonlythecolumnsfoundintheSALESREPStable: Tellmeallaboutsalespeopleandtheplaceswheretheywork. SELECTSALESREPS.*,CITY,REGION FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE;
Chapter 7:
Multitable Queries (Joins)
137
Thequerywouldproduce11columnsofqueryresults—theninecolumnsoftheSALESREPS table,followedbythetwoothercolumnsexplicitlyrequestedfromtheOFFICEStable.This typeof“qualifiedall-columns”selectitemwasintroducedintheSQL2versionoftheANSI/ISO standard.ItissupportedinthemainstreamSQLproducts,butnotinsomelow-endsystems.
Self-Joins
SELECTNAME,NAME FROMSALESREPS,SALESREPS WHEREMANAGER=EMPL_NUM;
ThisSELECTstatementisillegalbecauseoftheduplicatereferencetotheSALESREPS tableintheFROMclause.Youmightalsotryeliminatingthesecondreferencetothe SALESREPStable: SELECTNAME,NAME FROMSALESREPS WHEREMANAGER=EMPL_NUM;
Thisqueryislegal,butitwon’tdowhatyouwantittodo!It’sasingle-tablequery,so SQLgoesthroughtheSALESREPStableonerowatatime,applyingthesearchcondition: MANAGER=EMPL_NUM
Therowsthatsatisfythisconditionarethosewherethetwocolumnshavethesame value—thatis,rowswhereasalespersonistheirownmanager.Therearenosuchrows,so thequerywouldproducenoresults—whichisquitedifferentfromthedatathatthe English-languagestatementofthequeryrequested. TounderstandhowSQLsolvesthisproblem,imaginethereweretwoidenticalcopiesof theSALESREPStable,onenamedEMPS,containingemployees,andonenamedMGRS, containingmanagers,asshowninFigure7-9.TheMANAGERcolumnoftheEMPStable wouldthenbeaforeignkeyfortheMGRStable,andthefollowingquerywouldwork: Listthenamesofsalespeopleandtheirmanagers. SELECTEMPS.NAME,MGRS.NAME FROMEMPS,MGRS WHEREEMPS.MANAGER=MGRS.EMPL_NUM;
Becausethecolumnsinthetwotableshaveidenticalnames,allofthecolumnreferences arequalified.Otherwise,thislookslikeanordinarytwo-tablequery.
PART II
Somemultitablequeriesinvolvearelationshipthatatablehaswithitself.Forexample, supposeyouwanttolistthenamesofallsalespeopleandtheirmanagers.Eachsalesperson appearsasarowintheSALESREPStable,andtheMANAGERcolumncontainstheemployee numberofthesalesperson’smanager.ItwouldappearthattheMANAGERcolumnshouldbe aforeignkeyforthetablethatholdsdataaboutmanagers.Infactitis—it’saforeignkeyfor theSALESREPStableitself! Ifyoutriedtoexpressthisquerylikeanyothertwo-tablequeryinvolvingaforeign key/primarykeymatch,itwouldlooklikethis:
138
Part II:
Retrieving Data
MGRS (copy of SALESREPS) Table EMPL_NUM NAME AGE REP_OFFICE 105 109 102 106 104 101 110 108 103 107
EMPS (copy of SALESREPS) Table EMPL_NUM NAME AGE REP_OFFICE 105 109 102 106 104 101 110 108 103 107
FIGURE 7-9
Bill Adams Mary Jones Sue Smith Sam Clark Bob Smith Dan Roberts Tom Snyder Larry Fitch Paul Cruz Nancy Angelli
37 31 48 52 33 45 41 62 29 49
13 11 21 11 12 12 NULL 21 12 22
Bill Adams Mary Jones Sue Smith Sam Clark Bob Smith Dan Roberts Tom Snyder Larry Fitch Paul Cruz Nancy Angelli
37 31 48 52 33 45 41 62 29 49
TITLE
HIRE_DATE
MANAGER
Sales Rep Sales Rep Sales Rep VP Sales Sales Mgr Sales Rep Sales Rep Sales Mgr Sales Rep Sales Rep
12-JAN-88 12-OCT-89 10-DEC-86 14-JUN-88 19-MAY-87 20-OCT-86 13-JAN-90 12-OCT-89 01-MAR-87 14-NOV-88
104 106 108 NULL 106 104 101 106 104 108
13 11 21 11 12 12 NULL 21 12 22
A self-join of the SALESREPS table
SQLusesexactlythis“imaginaryduplicatetable”approachtojoinatabletoitself. Insteadofactuallyduplicatingthecontentsofthetable,SQLletsyousimplyrefertoitby adifferentname,calledatablealias.Here’sthesamequery,writtenusingthealiasesEMPS andMGRSfortheSALESREPStable: Listthenamesofsalespeopleandtheirmanagers. SELECTEMPS.NAME,MGRS.NAME FROMSALESREPSEMPS,SALESREPSMGRS WHEREEMPS.MANAGER=MGRS.EMPL_NUM; EMPS.NAMEMGRS.NAME -------------------------- TomSnyderDanRoberts BillAdamsBobSmith DanRobertsBobSmith PaulCruzBobSmith MaryJonesSamClark BobSmithSamClark LarryFitchSamClark SueSmithLarryFitch NancyAngelliLarryFitch
Chapter 7:
Multitable Queries (Joins)
139
TheFROMclauseassignsadifferentaliastoeachofthetwo“virtualcopies”ofthe SALESREPStablethatareinvolvedinthequerybyspecifyingthealiasnameimmediately aftertheactualtablename.Astheexampleshows,whenaFROMclausecontainsatable alias,thealiasmustbeusedtoidentifythetableinqualifiedcolumnreferences.Ofcourse, it’sreallyonlynecessarytouseanaliasforoneofthetwotableoccurrencesinthisquery.It couldjustaseasilyhavebeenwritten SELECTSALESREPS.NAME,MGRS.NAME FROMSALESREPS,SALESREPSMGRS WHERESALESREPS.MANAGER=MGRS.EMPL_NUM;
Listsalespeoplewithahigherquotathantheirmanager. SELECTSALESREPS.NAME,SALESREPS.QUOTA,MGRS.QUOTA FROMSALESREPS,SALESREPSMGRS WHERESALESREPS.MANAGER=MGRS.EMPL_NUM ANDSALESREPS.QUOTA>MGRS.QUOTA; SALESREPS.NAMESALESREPS.QUOTAMGRS.QUOTA ------------------------------------------- BillAdams$350,000.00$200,000.00 DanRoberts$300,000.00$200,000.00 PaulCruz$275,000.00$200,000.00 MaryJones$300,000.00$275,000.00 LarryFitch$350,000.00$275,000.00
Listsalespeoplewhoworkindifferentofficesthantheirmanager,showingthenameandofficewhere eachworks. SELECTEMPS.NAME,EMP_OFFICE.CITY,MGRS.NAME,MGR_OFFICE.CITY FROMSALESREPSEMPS,SALESREPSMGRS, OFFICESEMP_OFFICE,OFFICESMGR_OFFICE WHEREEMPS.REP_OFFICE=EMP_OFFICE.OFFICE ANDMGRS.REP_OFFICE=MGR_OFFICE.OFFICE ANDEMPS.MANAGER=MGRS.EMPL_NUM ANDEMPS.REP_OFFICEMGRS.REP_OFFICE; EMPS.NAMEEMP_OFFICE.CITYMGRS.NAMEMGR_OFFICE.CITY ---------------------------------------------------------- BobSmithChicagoSamClarkNewYork BillAdamsAtlantaBobSmithChicago LarryFitchLosAngelesSamClarkNewYork NancyAngelliDenverLarryFitchLosAngeles
Table Aliases Asdescribedintheprevioussection,tablealiasesarerequiredinqueriesinvolvingself-joins. However,youcanuseanaliasinanyquery.Forexample,ifaqueryreferstoanotheruser’s table,orifthenameofatableisverylong,thetablenamecanbecometedioustotypeasa
PART II
HerethealiasMGRSisassignedtoone“virtualcopy”ofthetable,whilethetable’sown nameisusedfortheothercopy. Herearesomeadditionalexamplesofself-joins:
140
Part II:
Retrieving Data
columnqualifier.Thisquery,whichreferencestheBIRTHDAYStableownedbytheuser namedSAM: Listnames,quotas,andbirthdaysofsalespeople. SELECTSALESREPS.NAME,QUOTA,SAM.BIRTHDAYS.BIRTH_DATE FROMSALESREPS,SAM.BIRTHDAYS WHERESALESREPS.NAME=SAM.BIRTHDAYS.NAME;
becomeseasiertoreadandtypewhenthealiasesSandBareusedforthetwotables: Listnames,quotas,andbirthdaysofsalespeople. SELECTS.NAME,S.QUOTA,B.BIRTH_DATE FROMSALESREPSS,SAM.BIRTHDAYSB WHERES.NAME=B.NAME;
Figure7-10showsthebasicformoftheFROMclauseforamultitableSELECTstatement, completewithtablealiases.Theclausehastwoimportantfunctions: • TheFROMclauseidentifiesallofthetablesthatcontributedatatothequeryresults. AnycolumnsreferencedintheSELECTstatementmustcomefromoneofthetables namedintheFROMclause.(Thereisanexceptionforouterreferencescontainedina subquery,asdescribedinChapter9.) • TheFROMclausespecifiesthetagthatisusedtoidentifythetableinqualified columnreferenceswithintheSELECTstatement.Ifatablealiasisspecified,it becomesthetabletag;otherwise,thetable’sname,exactlyasitappearsintheFROM clause,becomesthetag. TheonlyrequirementfortabletagsintheFROMclauseisthatallofthetabletagsina givenFROMclausemustbedistinctfromeachother.Evenifyoudon’tusetablealiasesin SQLqueriesthatyouwrite,youarelikelytoencounterthemifyouexaminetheSQL generatedbyreport-writingorbusinessanalysistools.Thesetoolstypicallypresenta graphicalinterfacethatallowsyoutoeasilychoosethecolumns,tables,matchingcolumns, searchconditions,andotherelementsofyourquery,andtheyautomaticallygeneratethe correspondingSQLstatementsthatarepassedtotheDBMS.Thetoolwillalmostalwaysuse tabletags(typicallyusingtagslikeT1,T2,T3,etc.)intheFROMclauseofthegeneratedSQL, allowingittoeasilyandunambiguouslyspecifytherestofthequery,regardlessofthe actualnamesofthetables,columns,andotherdatabaseelements. TheSQLstandardoptionallyallowsthekeywordAStoappearbetweenatablename andtablealias.Italsousesthetermcorrelationnametorefertowhatwehavecalleda tablealias.Thefunctionandmeaningofacorrelationnameareexactlyasdescribedhere; FROM
table-name table-alias ,
FIGURE 7-10
The FROM clause syntax diagram
Chapter 7:
Multitable Queries (Joins)
141
manySQLproductsusethetermalias,anditismoredescriptiveofthefunctionthata tablealiasperforms.TheSQLstandardspecifiesasimilartechniquefordesignating alternatecolumnnames,andinthatsituationthecolumnaliasnameisactuallycalledan aliasinthestandard.
Multitable Query Performance
• Theuserentersacustomernumberintoaform,andtheDBMSretrievesthe customer’screditlimit,accountbalance,andotherdata(asingle-tablequery). • Acashregisterscansaproductnumberfromapackageandretrievestheproduct’s nameandpricefromthedatabase(asingle-tablequery). • Theuserentersasalesperson’sname,andtheprogramliststhecurrentordersfor thatsalesperson(atwo-tableinquiry). Indecision-supportapplications,bycontrast,it’scommonforaquerytoinvolvemany differenttablesandtoexercisecomplexrelationshipsinthedatabase.Intheseapplications, thequeryresultsareoftenusedtohelpmakeexpensivedecisions,soaquerythatrequires severalminutesorevenmanyhourstocompleteisperfectlyacceptable.Herearesome typicaldecision-supportqueriesforthesampledatabase: • Theuserentersanofficename,andtheprogramliststhe25largestorderstakenby salespeopleinthatoffice(athree-tablequery). • Areportsummarizessalesbyproducttypeforeachsalesperson,showingwhich salespeoplearesellingwhichproducts(athree-tablequery). • AmanagerconsidersopeninganewSeattlesalesofficeandrunsaqueryanalyzing theimpactonorders,products,customers,andthesalespeoplewhocallonthem (afour-tablequery). Inthesmalltablesofthesampledatabase,eventhesequerieswouldrequireonlysecondsto completeonlow-costcomputerhardware.Butifthetablescontainedtensofmillionsof rows,thetimetoexecutethequerieswouldlikelybemuchlonger.Theperformanceof multitablejoinscanbehighlydependentontheindexstructuresandotherinternaldata structuresthattheDBMSusestoorganizethedatathatitstores.Ingeneral,queriesthat exerciseprimary/foreignkeyrelationshipswillperformfairlywell,becausetheDBMS tendstooptimizeforthose.
PART II
Asthenumberoftablesinaquerygrows,theamountofeffortrequiredtocarryoutthequery increasesrapidly.TheSQLitselfplacesnolimitonthenumberoftablesjoinedbyaquery. Somelow-endandembeddedSQLproductsdolimitthenumberoftables,withalimitof abouteighttablesbeingfairlycommon.Thehighprocessingcostofqueriesthatjoinmany tablesimposesanevenlowerpracticallimitinmanyapplications. Inonlinetransactionprocessing(OLTP)applications,it’scommonforaquerytoinvolve onlyoneortwotables.Intheseapplications,responsetimeiscritical—theusertypically entersoneortwoitemsofdataandneedsaresponsefromthedatabasewithinasecondor two.HerearesometypicalOLTPqueriesforthesampledatabase:
142
Part II:
Retrieving Data
The Structure of a Join Forsimplejoins,it’sfairlyeasytowritethecorrectSELECTstatementbasedonanEnglishlanguagerequestortolookataSELECTstatementandfigureoutwhatitdoes.Whenmany tablesarejoinedorwhenthesearchconditionsbecomecomplex,however,itbecomesvery difficultjusttolookataSELECTstatementandfigureoutwhatitmeans.Forthisreason, it’simportanttodefinemorecarefullyandjustabitmoreformallywhatajoinis,what queryresultsareproducedbyagivenSELECTstatement,andtounderstandjustalittlebit ofthetheoryofrelationaldatabaseoperationthatunderliesjoins.
Table Multiplication Ajoinisaspecialcaseofamoregeneralcombinationofdatafromtwotables,knownasthe Cartesianproduct(orjusttheproduct)oftwotables.Theproductoftwotablesisanothertable (theproducttable),whichconsistsofallpossiblepairsofrowsfromthetwotables.The columnsoftheproducttableareallthecolumnsofthefirsttable,followedbyallthe columnsofthesecondtable.Figure7-11showstwosmallsampletablesandtheirproduct. Ifyouspecifyatwo-tablequerywithoutaWHEREclause,SQLproducestheproductof thetwotablesasthequeryresult.Forexample,thisquery: Showallpossiblecombinationsofsalespeopleandcities. SELECTNAME,CITY FROMSALESREPS,OFFICES;
wouldproducetheproductoftheSALESREPSandOFFICEStables,showingallpossible salesperson/citypairs.Therewouldbe50rowsofqueryresults(5offices×10salespeople= 50combinations).NoticethattheprecedingSELECTstatementisexactlythesameasthe followingoneyouwouldnaturallyusetojointhetwotables,butwithoutthespecification ofthematchingcolumns: Showallsalespeopleandthecitieswheretheywork. SELECTNAME,CITY FROMSALESREPSJOINOFFICES ONREP_OFFICE=OFFICE;
Girls Table NAME CITY Mary Susan Betty
Boys Table NAME CITY Sam James
FIGURE 7-11
Product Table GIRLS.NAME GIRLS.CITY BOYS.NAME
Boston Chicago Chicago
Product
Chicago Dallas
The product of two tables
Mary Susan Betty Mary Susan Betty
Boston Chicago Chicago Boston Chicago Chicago
Sam Sam Sam James James James
BOYS.CITY Chicago Chicago Chicago Dallas Dallas Dallas
Chapter 7:
Multitable Queries (Joins)
143
Thesetwoqueriespointoutanimportantrelationshipbetweenjoinsandproducts: Ajoinbetweentwotablesisjusttheproductofthetwotableswithsomeoftherowsremoved. Theremovedrowsarepreciselythosethatdonotmeetthematchingcolumnconditionfor thejoin.ProductsareimportantbecausetheyarepartoftheformaldefinitionofhowSQL processesamultitablequery,describedinthenextsection.
Rules for Multitable Query Processing
Listthecompanynameandallordersforcustomernumber2103. SELECTCOMPANY,ORDER_NUM,AMOUNT FROMCUSTOMERSJOINORDERS ONCUST_NUM=CUST WHERECUST_NUM=2103 ORDERBYORDER_NUM; COMPANYORDER_NUMAMOUNT ------------------------------- AcmeMfg.112963$3,276.00 AcmeMfg.112983$702.00 AcmeMfg.112987$27,500.00 AcmeMfg.113027$4,104.00
TogeneratethequeryresultsforaSELECTstatement:
1. IfthestatementisaUNIONofSELECTstatements,applySteps2through5toeach ofthestatementstogeneratetheirindividualqueryresults.
2. FormtheproductofthetablesnamedintheFROMclause.IftheFROMclausenames asingletable,theproductisthattable.
3. IfthereisanONclause,applyitsmatching-columnconditiontoeachrowofthe producttable,retainingthoserowsforwhichtheconditionisTRUE(anddiscarding thoseforwhichitisFALSEorNULL).
4. IfthereisaWHEREclause,applyitssearchconditiontoeachrowoftheresulting table,retainingthoserowsforwhichthesearchconditionisTRUE(anddiscarding thoseforwhichitisFALSEorNULL).
5. Foreachremainingrow,calculatethevalueofeachitemintheselectlisttoproduce asinglerowofqueryresults.Foreachcolumnreference,usethevalueofthe columninthecurrentrow.
6. IfSELECTDISTINCTisspecified,eliminateanyduplicaterowsofqueryresults thatwereproduced.
PART II
ThestepsafterthecodethatfollowsrestatetherulesforSQLqueryprocessingoriginally introducedintheRulesforSingle-TableQueryProcessingtopicinChapter6andexpands themtoincludemultitablequeries.TherulesdefinethemeaningofanymultitableSELECT statementbyspecifyingaprocedurethatalwaysgeneratesthecorrectsetofqueryresults. Toseehowtheprocedureworks,considerthisquery:
144
Part II:
Retrieving Data
7. IfthestatementisaUNIONofSELECTstatements,mergethequeryresultsforthe individualstatementsintoasingletableofqueryresults.Eliminateduplicaterows unlessUNIONALLisspecified.
8. IfthereisanORDERBYclause,sortthequeryresultsasspecified. Therowsgeneratedbythisprocedurecomprisethequeryresults. Followingtheprevioussteps:
1. TheFROMclausegeneratesallpossiblecombinationsofrowsfromtheCUSTOMERS table(21rows)andtheORDERStable(30rows),producingaproducttableof630 rows.
2. TheONclauseselectsonlythoserowsoftheproducttablewherethecustomernumbers match(CUST_NUM=CUST),reducingthe630rowstoonly30(oneforeachorder).
3. TheWHEREclauseselectsonlythoserowsoftheresultingtablewherethecustomer numberistheonespecified(CUST_NUM=2103).Onlyfourrowsareselected;the other26rowsareeliminated.
4. TheSELECTclauseextractsthethreerequestedcolumns(COMPANY,ORDER_ NUM,andAMOUNT)fromeachremainingrowoftheresultingtabletogeneratefour rowsofdetailedqueryresults.
5. TheORDERBYclausesortsthefourrowsontheORDER_NUMcolumntogeneratethe finalqueryresults.
ObviouslynoSQL-basedDBMSwouldactuallycarryoutthequerythisway,butthe purposeofthepreviousdefinitionisnottodescribehowthequeryiscarriedoutbya DBMS.Instead,itconstitutesadefinitionofhowtofigureoutexactlywhataparticular multitablequery“means”—thatis,thesetofqueryresultsthatitshouldproduce.
Outer Joins TheSQLjoinoperationcombinesinformationfromtwotablesbyformingpairsofrelated rowsfromthetwotableswherethematchingcolumnsineachofthetableshavethesame values.Ifoneoftherowsofatableisunmatchedinthisprocess,thejoincanproduce unexpectedresults,asillustratedbythesequeries: Listthesalespeopleandtheofficeswheretheywork. SELECTNAME,REP_OFFICE FROMSALESREPS; NAMEREP_OFFICE ------------------------- BillAdams13 MaryJones11 SueSmith21 SamClark11 BobSmith12 DanRoberts12 TomSnyderNULL
Chapter 7:
Multitable Queries (Joins)
145
LarryFitch21 PaulCruz12 NancyAngelli22
RecallthatnotallSQLtoolsdisplayNULLvaluesinthemannershown. Listthesalespeopleandthecitieswheretheywork.
BasedontheEnglish-languagedescriptionsofthesetwoqueries,youwouldprobably expectthemtoproducetenrows,oneforeachsalesperson.Thefirstqueryindeedproduces tenrows,butthesecondqueryproducesonlyninerows.Why?BecauseTomSnyderis currentlynotassignedtoanoffice.HisrowhasaNULLvalueintheREP_OFFICEcolumn (whichisthematchingcolumnforthejoin).ThisNULLvaluedoesn’tmatchanyoftheoffice numbersintheOFFICEStable,soTom’srowintheSALESREPStableisunmatched.Asa result,it“vanishes”inthejoin,whetherthejoinisspecifiedusingtheONclauseorthe WHEREclause.ThestandardSQLjointhushasthepotentialtoloseinformationifthetables beingjoinedcontainunmatchedrows. BasedontheEnglish-languageversionoftherequest,youwouldprobablyexpectthe secondquerytoproduceresultslikethese: Listthesalespeopleandthecitieswheretheywork. SELECTNAME,CITY FROMSALESREPSLEFTOUTERJOINOFFICES ONREP_OFFICE=OFFICE; NAMECITY -------------------------- TomSnyderNULL MaryJonesNewYork SamClarkNewYork BobSmithChicago PaulCruzChicago DanRobertsChicago BillAdamsAtlanta SueSmithLosAngeles LarryFitchLosAngeles NancyAngelliDenver
PART II
SELECTNAME,CITY FROMSALESREPSJOINOFFICES ONREP_OFFICE=OFFICE; NAMECITY -------------------------- MaryJonesNewYork SamClarkNewYork BobSmithChicago PaulCruzChicago DanRobertsChicago BillAdamsAtlanta SueSmithLosAngeles LarryFitchLosAngeles NancyAngelliDenver
146
Part II:
Retrieving Data
Thesequeryresultsaregeneratedbyadifferenttypeofjoinoperation,calledanouterjoin, asindicatedbytheadditionalkeywordsintheFROMclause.Theouterjoinisanextensionof thestandardjoindescribedearlierinthischapter,whichistechnicallycalledaninnerjoin.The originalSQLstandardspecifiedonlytheinnerjoin,andtheearlyIBMSQLproductsalso supportedonlytheinnerjoin.However,theouterjoinisawell-understood,useful,and increasinglyimportantpartoftherelationaldatabasemodel.Itwasimplementedinmany non-IBMSQLproducts,includingtheflagshipdatabaseproductsfromMicrosoft,Sybase,and Oracle.OuterjoinswereincludedintheSQLstandardstartingwithSQL2andarenow broadlysupportedinmainstreamproducts,althoughmanyentry-levelSQLimplementations suchasthoseforembeddeddeviceapplicationsstillsupportonlyinnerjoins. Tounderstandtheouterjoinwell,it’susefultomoveawayfromthesampledatabase andconsiderthetwosimpletablesatthetopofFigure7-12.(Ascripttocreatethesetables andinsertthesamplerowscanbefoundonthedownloadsiteasdescribedinAppendixA.) TheGIRLStablelistsfivegirlsandthecitieswheretheylive;theBOYStablelistsfiveboys andthecitieswheretheylive.Tofindthegirl/boypairswholiveinthesamecity,you couldusethisquery,whichformstheinnerjoinofthetwotables: Listthegirlsandboyswholiveinthesamecity. SELECT* FROMGIRLSINNERJOINBOYS ONGIRLS.CITY=BOYS.CITY; GIRLS.NAMEGIRLS.CITYBOYS.NAMEBOYS.CITY ------------------------------------------ MaryBostonJohnBoston MaryBostonHenryBoston SusanChicagoSamChicago BettyChicagoSamChicago
Thisqueryexplicitlyrequeststheinnerjoinofthetwotablesandproducesfourrowsof queryresults.Theinnerjoinisthedefault,soexactlythesameresultswouldbeproducedifthe optionalkeywordINNERhadbeenomittedfromtheFROMclause.Noticethattwoofthegirls (AnneandNancy)andtwooftheboys(JamesandGeorge)arenotrepresentedinthequery results.Theserowscannotbepairedwithanyrowfromtheothertable,andsotheyaremissing fromtheinnerjoinresults.Twooftheunmatchedrows(AnneandJames)havevalidvaluesin theirCITYcolumns,buttheydon’tmatchanycitiesintheoppositetable.Theothertwo unmatchedrows(NancyandGeorge)haveNULLvaluesintheirCITYcolumns,andbytherules ofSQLNULLhandling,theNULLvaluedoesn’tmatchanyothervalue(evenanotherNULLvalue). Supposeyouwantedtolistthegirl/boypairswhosharethesamecitiesandincludethe unmatchedgirlsandboysinthelist.ThefullouterjoinoftheGIRLSandBOYStables producesexactlythisresult.Thefollowinglistshowstheprocedureforconstructingthefull outerjoin,andtheprocessisshowngraphicallyinFigure7-12.
1. Beginwiththeinnerjoinofthetwotables,usingmatchingcolumnsinthenormal way.(Thisproducesthefirstfourrowsoftheresultstableinthefigure.)
2. Foreachrowofthefirsttablethatisnotmatchedbyanyrowinthesecondtable, addonerowtothequeryresults,usingthevaluesofthecolumnsinthefirsttable, andassumingaNULLvalueforallcolumnsofthesecondtable.(Thisproducesthe fifthandsixthrowsofresultsinthefigure.)
Chapter 7:
Boston NULL Chicago Chicago Denver
John Henry George Sam James
Boston Boston NULL Chicago Dallas
Unmatched rows
FIGURE 7-12
INNER JOIN
Mary Mary Susan Betty Anne Nancy NULL NULL
Boston Boston Chicago Chicago Denver NULL NULL NULL
John Henry Sam Sam NULL NULL James Jeorge
BOYS.CITY Boston Boston Chicago Chicago NULL NULL Dallas NULL
Anatomy of an outer join
3. Foreachrowofthesecondtablethatisnotmatchedbyanyrowinthefirsttable, addonerowtothequeryresults,usingthevaluesofthecolumnsinthesecond table,andassumingaNULLvalueforallcolumnsofthefirsttable.(Thisproduces theseventhandeighthrowsofresultsinthefigure.)
4. Theresultingtableistheouterjoinofthetwotables.(Alleightrowsofqueryresults inthefigure.) HereistheSQLstatementthatproducestheouterjoin:
Listgirlsandboysinthesamecity,includinganyunmatchedgirlsorboys. SELECT* FROMGIRLSFULLOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY; GIRLS.NAMEGIRLS.CITYBOYS.NAMEBOYS.CITY ------------------------------------------ MaryBostonJohnBoston MaryBostonHenryBoston SusanChicagoSamChicago BettyChicagoSamChicago AnneDenverNULLNULL NancyNULLNULLNULL NULLNULLJamesDallas NULLNULLGeorgeNULL
PART II
Outer Join Table GIRLS.NAME GIRLS.CITY BOYS.NAME
Unmatched rows
147
BOYS Table CITY NAME
GIRLS Table NAME CITY Mary Nancy Susan Betty Anne
Multitable Queries (Joins)
148
Part II:
Retrieving Data
Asthisexampleshows,thefullouterjoinisan“information-preserving”join.(Some DBMSproducts,suchasMySQL5.0,donotyetsupportfullouterjoins.)Everyrowofthe BOYStableisrepresentedinthequeryresults(somemorethanonce).Similarly,everyrow oftheGIRLStableisrepresentedinthequeryresults(again,somemorethanonce).
Left and Right Outer Joins Thefullouterjoinoftwotables,illustratedinthepreviousquery,treatsbothofthejoined tablessymmetrically.Twootherusefulandwell-definedouterjoinsdonot. TheleftouterjoinbetweentwotablesisproducedbyfollowingStep1andStep2inthe previousnumberedlistbutomittingStep3.TheleftouterjointhusincludesNULL-extended copiesoftheunmatchedrowsfromthefirst(left)table,butdoesnotincludeanyunmatched rowsfromthesecond(right)table.HereisaleftouterjoinbetweentheGIRLSandBOYStables: Listgirlsandboysinthesamecityandanyunmatchedgirls. SELECT* FROMGIRLSLEFTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY; GIRLS.NAMEGIRLS.CITYBOYS.NAMEBOYS.CITY ------------------------------------------ MaryBostonJohnBoston MaryBostonHenryBoston SusanChicagoSamChicago BettyChicagoSamChicago AnneDenverNULLNULL NancyNULLNULLNULL
Thequeryproducessixrowsofqueryresults,showingthematchedgirl/boypairsand theunmatchedgirls.Theunmatchedboysaremissingfromtheresults. Similarly,therightouterjoinbetweentwotablesisproducedbyfollowingStep1and Step3inthepreviousnumberedlistbutomittingStep2.Therightouterjointhusincludes NULL-extendedcopiesoftheunmatchedrowsfromthesecond(right)table,butdoesnot includetheunmatchedrowsofthefirst(left)table.Hereisarightouterjoinbetweenthe GIRLSandBOYStables: Listgirlsandboysinthesamecityandanyunmatchedboys. SELECT* FROMGIRLSRIGHTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY; GIRLS.NAMEGIRLS.CITYBOYS.NAMEBOYS.CITY ------------------------------------------ MaryBostonJohnBoston MaryBostonHenryBoston SusanChicagoSamChicago BettyChicagoSamChicago NULLNULLJamesDallas NULLNULLGeorgeNULL
Chapter 7:
Multitable Queries (Joins)
Listthesalespeopleandthecitieswheretheywork. SELECTNAME,CITY FROMSALESREPSLEFTOUTERJOINOFFICES ONREP_OFFICE=OFFICE; NAMECITY -------------------------- TomSnyderNULL MaryJonesNewYork SamClarkNewYork BobSmithChicago PaulCruzChicago DanRobertsChicago BillAdamsAtlanta SueSmithLosAngeles LarryFitchLosAngeles NancyAngelliDenver
Noteinthiscase(aleftouterjoin),the“child”table(SALESREPS,thetablewiththe foreignkey)isthemajortable,andthe“parent”table(OFFICES)istheminortable.The objectiveistoretainrowscontainingNULLforeignkeyvalues(likeTomSnyder’s)fromthe childtableinthequeryresults,sothechildtablebecomesthemajortable.Itdoesn’tmatter
PART II
Thisqueryalsoproducessixrowsofqueryresults,showingthematchedgirl/boypairs andtheunmatchedboys.Thistimetheunmatchedgirlsaremissingfromtheresults. Asnotedbefore,theleftandrightouterjoinsdonottreatthetwojoinedtables symmetrically.Itisoftenusefultothinkaboutoneofthetablesbeingthe“major”table(theone whoserowsareallrepresentedinthequeryresults)andtheothertablebeingthe“minor”table (theonewhosecolumnscontainNULLvaluesinthejoinedqueryresults).Inaleftouterjoin, theleft(first-mentioned)tableisthemajortable,andtheright(later-named)tableistheminor table.Therolesarereversedinarightouterjoin(therighttableismajor,thelefttableisminor). Inpractice,theleftandrightouterjoinsaremoreusefulthanthefullouterjoin,especially whenjoiningdatafromtwotablesusingaparent/child(primarykey/foreignkey)relationship. WehavealreadyseenoneexampleinvolvingtheSALESREPSandOFFICEStableinthesample database.TheREP_OFFICEcolumnintheSALESREPStableisaforeignkeytotheOFFICES table;ittellstheofficewhereeachsalespersonworks,anditisallowedtohaveaNULLvaluefor anewsalespersonwhohasnotyetbeenassignedtoanoffice,suchasTomSnyder.Anyjoin thatexercisesthisSALESREPS-to-OFFICESrelationshipandexpectstoincludedataforTom Snydermustbeanouterjoin,withtheSALESREPStableasthemajortable.Hereistheexample usedearlier:
149
150
Part II:
Retrieving Data
whetherthequeryisactuallyexpressedasaleftouterjoin(asjustshown)orifitisflipped tobecomearightouterjoinlikethis: Listthesalespeopleandthecitieswheretheywork. SELECTNAME,CITY FROMOFFICESRIGHTOUTERJOINSALESREPS ONOFFICE=REP_OFFICE; NAMECITY -------------------------- TomSnyderNULL MaryJonesNewYork SamClarkNewYork BobSmithChicago PaulCruzChicago DanRobertsChicago BillAdamsAtlanta SueSmithLosAngeles LarryFitchLosAngeles NancyAngelliDenver
Whatmattersisthatthechildtableisthemajortableintheouterjoin. Therearealsousefuljoinedquerieswheretheparentisthemajortableandthechild tableistheminortable.Forexample,supposethecompanyinthesampledatabaseopensa newsalesofficeinDallas,butinitiallytheofficehasnosalespeopleassignedtoit.Ifyou wanttogenerateareportlistingalloftheofficesandthenamesofthesalespeoplewho workthere,youmightwanttoincludearowrepresentingtheDallasoffice.Hereisthe outerjoinquerythatproducesthoseresults: Listtheofficesandthesalespeoplewhoworkineachone. SELECTCITY,NAME FROMOFFICESLEFTOUTERJOINSALESREPS ONOFFICE=REP_OFFICE; CITYNAME -------------------------- NewYorkMaryJones NewYorkSamClark ChicagoBobSmith ChicagoPaulCruz ChicagoDanRoberts AtlantaBillAdams LosAngelesSueSmith LosAngelesLarryFitch DenverNancyAngelli DallasNULL
Inthiscase,theparenttable(OFFICES)isthemajortableintheouterjoin,andthechild table(SALESREPS)istheminortable.Theobjectiveistoensurethatallrowsfromthe OFFICEStablearerepresentedinthequeryresults,soitplaystheroleofmajortable.The rolesofthetwotablesarepreciselyreversedfromthepreviousexample.Ofcourse,the rowforTomSnyder,whichwasincludedinthequeryresultsfortheearlierexample
Chapter 7:
Multitable Queries (Joins)
151
(whenSALESREPSwasthemajortable),ismissingfromthissetofqueryresultsbecause SALESREPSisnowtheminortable.
Older Outer Join Notation*
Listgirlsandboysinthesamecity,includinganyunmatchedgirlsorboys. SELECT* FROMGIRLSFULLOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
becomesthisqueryusingtheSQLServernotation: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY*=*BOYS.CITY;
Toindicatethefullouterjoinbetweenthetwotables,anasterisk(*)isplacedbeforeand aftertheequalsignthatdefinesthejoin.Toindicatealeftouterjoin,onlytheleading asteriskisspecified,producingthisquery: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY*=BOYS.CITY;
whichisequivalenttothisstandards-basedform: SELECT* FROMGIRLSLEFTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Similarly,arightouterjoinisindicatedbyanasteriskfollowingtheequalsign: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY=*BOYS.CITY;
PART II
BecausetheouterjoinwasnotpartoftheoriginalSQLstandardandwasnotimplemented inearlyIBMSQLproducts,theDBMSvendorswhopioneeredsupportfortheouterjoin eachinventedtheirownnotationforexpressingouterjoins.Usersoftheseproductsbegan todevelopprogramsthatusedtheseproprietaryouterjoincapabilities,creatinganinstalled baseofuser-writtenprogramsthatdependedonthespecificOracleorSQLServernotation. ThewritersoftheSQL2standardwantedtoaddouterjoinsupportinawaythatwouldnot “break”theseexistingprograms,sotheycouldcoexistwithnew,standards-based programs.AllofthemajorvendorsnowsupportsomeoralloftheSQLstandardouterjoin notation,andtheyencourageitsuse.However,youmayencounterolderprogramsthatuse theolderproprietaryforms,sotheyaredescribedhere. SQLServersupportedouterjoinsinitsearlyimplementationsfromSybaseand continuedtosupportouterjoinsafteritwasadoptedbyMicrosoft.TheSQLServernotation appendsanasterisk(*)totheequalsigninthecomparisontestintheWHEREclausethat definesthejoincondition.SothisfullouterjoinbetweentheGIRLSandBOYStables, expressedusingtheSQLstandardnotation:
152
Part II:
Retrieving Data
Theasteriskmayalsobeusedinconjunctionwithothercomparisonoperators,suchasthe greater-thanorless-thansigns,tospecifyouternon-equi-joins.ThisolderSQLServer notationisstillsupportedbycurrentversionsoftheproduct,iftheappropriate compatibilitylevelisset,butasofSQLServer2005,itisconsideredadeprecatedfeature.It mayalsobefoundinstoredprocedureswrittenusingSQLServer’sTransact-SQLlanguage. Oraclealsoprovidedearlysupportforouterjoins,butusesadifferentnotationfrom SQLServer.ThisnotationindicatestheouterjoinintheWHEREclausebyincludinga parenthesizedplussignfollowingthecolumnwhosetableistohavetheimaginaryNULLrow added(thatis,theminortableintheouterjoin).TheleftouterjoinoftheGIRLSandBOYS tablesproducesanOraclequerythatlookslikethis: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY=BOYS.CITY(+);
whichisonceagainequivalenttothisstandards-basedform: SELECT* FROMGIRLSLEFTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Notethattheplussignappearsontheoppositesideofthecomparisonfromwherethe asteriskappearsintheSQLServernotation.Similarly,arightouterjoinisindicatedonthe oppositesideoftheequalsign: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY(+)=BOYS.CITY;
Oracledidnotsupportaproprietaryformofthefullouterjoin,butasnotedearlier,thisdid notdiminishthepracticalusefulnessofOracle’souterjoins,andyouwillfindtheolder notationinexistingprogramswrittenforusewithOracle. Both,SQLServerandOraclenotationshavesomesignificantlimitationscomparedwith thestandardform.Forexample,whenthreeormoretablesarecombinedusinganouter join,theorderinwhichthetablesarejoinedaffectsthequeryresults.Theresultsof (TBL1OUTER-JOINTBL2)OUTER-JOINTBL3
willingeneralbedifferentfromtheresultsof TBL1OUTER-JOIN(TBL2OUTER-JOINTBL3)
UsingeithertheSQLServerorOraclenotations,it’simpossibletospecifytheevaluation orderoftheouterjoins.Becauseofthis,theresultsproducedbytheouterjoinofthreeor moretablesdependuponthespecificsoftheDBMSimplementation.Forthisandother reasons,youshouldalwayswritenewprogramsusingtheSQLstandardouterjoin notation.It’salsousuallyagoodideatoconvertexistingprogramstothestandardnotation whentheyarebeingrevised.
Chapter 7:
Multitable Queries (Joins)
153
Joins and the SQL Standard
Inner Joins in Standard SQL Figure7-13showsasimplifiedformoftheextendedstandardSQLsyntaxfortheFROMclause. It’seasiesttounderstandalloftheoptionsprovidedbyconsideringeachtypeofjoin,oneby one,startingwiththebasicinnerjoinandthenmovingtothevariousformsofouterjoin.The standardinnerjoinoftheGIRLSandBOYStables,expressedintheoriginalSQLnotation: SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY=BOYS.CITY;
isstillanacceptablestatementinthelatestversionofthestandard.Thestandardwriters reallycouldn’thavemadeitillegalwithout“breaking”allofthemillionsofmultitableSQL queriesthathadalreadybeenwrittenbytheearly1990s.ButthemodernSQLstandard allowsthesealternativewaysofexpressinganinnerjoin,whichwehavealreadyseenin earlierexamples: SELECT* FROMGIRLSINNERJOINBOYS ONGIRLS.CITY=BOYS.CITY; SELECT* FROMGIRLSINNERJOINBOYS USING(CITY); SELECT* FROMGIRLSNATURALINNERJOINBOYS;
TheINNERkeywordisoptional;aninnerjoinisthedefault.TheNATURALJOINform ofthestatementcanbeusedifalloftheidenticallynamedcolumnsinthetwotablesare matchingcolumns;otherwise,theUSINGclausemustbeusedtoindicatespecificmatching columns.Inthiscase,thematchingcolumnsareNAMEandCITY,andsincenoneoftheboys hasthesamenameasoneofthegirls,thatNATURALJOINformofthequeryreturnsno rows.Ifthematchingcolumnsdonothaveidenticalnamesinthetwotables,orifanonequi-joinisneeded,thenthefullONclauseorWHEREclausemustbeusedtospecifythe matchingcolumnconditions.TheONandWHEREclausesarealsomorewidelysupported thantheNATURALandUSINGvariations.
PART II
TheSQL2revisiondramaticallyexpandedthesupportforjoinsintheANSI/ISOSQLstandard, throughanew,expandedformoftheFROMclausethatcanexpresseventhemostcomplex ofjoins.Atthiswriting,allofthemajorSQLproductshavesupportforall,ornearlyall,of theSQL2expandedjoincapability.Theexpandedjoinsupportcomesattheexpenseofsome significantaddedcomplexityforwhathadpreviouslybeenoneofthesimplerpartsofSQL. Infact,theexpandedjoinsupportispartofamuchlargerexpansionofquerycapabilitiesin SQL2andsubsequentversionsoftheSQLstandard,whichaddevenmorecapabilityand complexity.Theotherexpandedfeaturesincludesetoperationsonqueryresults(union, intersection,anddifferencesoftables)andmuchricherqueryexpressionsthatmanipulate rowsandtablesandallowthemtobeusedinsubqueries.Thesecapabilitiesaredescribedin thenextchapter,afterthediscussionofbasicsubqueries.
154
Part II:
Retrieving Data
table-specification ,
FROM
natural-join-expression join-expression cross-product-expression union-expression natural-join expression: JOIN table2
table1 NATURAL INNER FULL LEFT RIGHT
OUTER
join expression: JOIN table2
table1 INNER FULL LEFT RIGHT
ON sends condition USING (column list)
OUTER
cross-product expression: table1
CROSS JOIN
table2
table1
UNION JOIN
table2
union-expression:
FIGURE 7-13
Extended FROM clause in the SQL standard
Outer Joins in Standard SQL* WehavealreadyseenhowtheexpandedSQLstandardsupportsouterjoins,suchasthe full,left,andrightouterjoinsspecifiedbythesequeries: SELECT* FROMGIRLSFULLOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY; SELECT* FROMGIRLSLEFTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Chapter 7:
Multitable Queries (Joins)
155
SELECT* FROMGIRLSRIGHTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Cross Joins in Standard SQL* Thesupportforextendedjoinsincludestwoothermethodsforcombiningdatafromtwo tables.AcrossjoinisanothernamefortheCartesianproductoftwotables,asdescribed earlierinthischapter.HereisaquerythatgeneratesthecompleteproductoftheGIRLSand BOYStables: SELECT* FROMGIRLSCROSSJOINBOYS;
Bydefinition,theCartesianproduct(alsosometimescalledthecrossproduct,hencethe name“CROSSJOIN”)containseverypossiblepairofrowsfromthetwotables.It “multiplies”thetwotables,turningtablesof,forexample,threegirlsandtwoboysintoa tableofsix(3×2=6)boy/girlpairs.No“matchingcolumns”or“selectioncriteria”are associatedwiththecrossproducts,sotheONclauseandtheUSINGclausearenotallowed. Notethatthecrossjoinreallydoesn’taddanynewcapabilitiestotheSQLlanguage.Exactly thesamequeryresultscanbegeneratedwithaninnerjointhatspecifiesnomatching columns.Sotheprecedingquerycouldjustaswellhavebeenwrittenas SELECT* FROMGIRLS,BOYS;
TheuseofthekeywordsCROSSJOINintheFROMclausesimplymakesthecrossjoin moreexplicit.Inmostdatabases,thecrossjoinoftwotablesbyitselfisofverylittlepractical use.Itsusefulnessreallycomesasabuildingblockformorecomplexqueryexpressionsthat startwiththecrossproductoftwotablesandthenusesummaryquerycapabilities (describedinthenextchapter)orsetoperationstofurthermanipulatetheresults.Atthis writing,DB2doesnotsupportthecrossjoinsyntax,butthesameeffectcanbeachieved withtheolderSQLsyntax. TheunionjoincombinessomeofthefeaturesoftheUNIONoperation(describedinthe previouschapter)withsomeofthefeaturesofthejoinoperationsdescribedinthischapter. However,theUNIONJOINwasdeprecatedintheSQL:1999standardandremovedentirely fromtheSQL:2003standard.So,ifyouareusingaDBMSthatsupportsanewerversionof thestandard,it’slikelythatithasnosupportfortheUNIONJOINsyntax.Infact,noneof thecurrentversionsofOracle,SQLServer,MySQL,andDB2supportsit.
PART II
TheuseoftheOUTERkeywordisoptional;theDBMScaninferfromthekeywordFULL, LEFT,orRIGHTthatanouterjoinisrequired.Theresultsoftheexamplesshownwillallbe different—theFULLOUTERJOINwillreturnalltherowsfrombothtables,theLEFT OUTERJOINwillreturnalltherowsfromtheleft(GIRLS)tableplusmatchingrowsfrom therighttable(BOYS),andtheRIGHTOUTERJOINwillreturnalltherowsfromtheright (BOYS)tableplusmatchingrowsfromtheleft(GIRLS)table.AsforINNERjoins,anatural joincanbespecifiedwiththeNATURALkeyword,eliminatingtheneedtoexplicitlyname thematchingcolumns.Similarly,thematchingcolumnscanbenamedinaUSINGclause.
156
Part II:
Retrieving Data
RecallthattheUNIONoperationeffectivelycombinestherowsoftwotables,whichmust havethesamenumberofcolumnsandthecompatibledatatypesforeachcorresponding column.Thisquery,whichusesasimpleUNIONoperation: SELECT* FROMGIRLS UNIONALL SELECT* FROMBOYS;
whenappliedtoafive-rowtableofgirlsandafive-rowtableofboys,yieldsaten-rowtable ofqueryresults.EachrowofqueryresultscorrespondspreciselytoeitherarowoftheGIRLS tableorarowoftheBOYStablefromwhichitwasderived.Thequeryresultshavetwo columns,NAMEandCITY,becausetheGIRLSandBOYStableseachhavethesetwocolumns. TheunionjoinoftheGIRLSandBOYStablesisspecifiedbythisquery: SELECT* FROMGIRLS UNIONJOINBOYS;
Thequeryresultsagainhavefiverows,andagaineachrowofresultsiscontributedby exactlyoneoftherowsintheGIRLStableortheBOYStable.Butunlikethesimpleunion, thesequeryresultshavefourcolumns—allofthecolumnsofthefirsttableplusallofthe columnsofthesecondtable.Inthisaspect,theunionjoinislikealloftheotherjoins.Foreach rowofqueryresultscontributedbytheGIRLStable,thecolumnsthatcomefromtheGIRLS tablereceivethecorrespondingdatavalues;theothercolumns(thosethatcomefromthe BOYStable)haveNULLvalues.Similarly,foreachrowofqueryresultscontributedbythe BOYStable,thecolumnsthatcomefromtheBOYStablereceivethecorrespondingdatavalues; theothercolumns(thistime,thosethatcomefromtheGIRLStable)haveNULLvalues. Anotherwayoflookingattheresultsoftheunionjoinistocomparethemtotheresults ofafullouterjoinoftheGIRLSandBOYStables.TheunionjoinresultsincludetheNULLextendedrowsofdatafromtheGIRLStableandtheNULL-extendedrowsofdatafromthe BOYStable,buttheydonotincludeanyoftherowsgeneratedbymatchingcolumns. Referringbacktothedefinitionofanouterjoin,inFigure7-14theunionjoinisproducedby omittingStep1andfollowingSteps2and3. Finally,it’susefultoexaminetherelationshipsbetweenthesetsofrowsproducedby thecrossjoin,thevarioustypesofouterjoins,andtheinnerjoinshowninFigure7-14. Whenjoiningtwotables,TBL1withmrowsandTBL2withnrows,thefigureshowsthat • Thecrossjoinwillcontainm×nrows,consistingofallpossiblerowpairsfromthe twotables. • TBL1INNERJOINTBL2willcontainsomenumberofrows,r,whichislessthan m×n.Theinnerjoinisstrictlyasubsetofthecrossjoin.Itisformedbyeliminating thoserowsfromthecrossjointhatdonotsatisfythematchingconditionforthe innerjoin. • Theleftouterjoincontainsalloftherowsfromtheinnerjoin,pluseachunmatched rowfromTBL1,NULL-extended. • Therightouterjoinalsocontainsalloftherowsfromtheinnerjoin,pluseach unmatchedrowfromTBL2,NULL-extended.
Chapter 7:
Multitable Queries (Joins)
157
• Thefullouterjoincontainsalloftherowsfromtheinnerjoin,pluseachunmatched rowfromTBL1,NULL-extended,pluseachunmatchedrowfromTBL2,NULLextended.Roughlyspeaking,itsqueryresultsareequaltotheleftouterjoin“plus” therightouterjoin. • TheunionjoincontainsalloftherowsofTBL1,NULL-extended,plusalloftherows ofTBL2,NULL-extended.Roughlyspeaking,itsqueryresultsarethefullouterjoin “minus”theinnerjoin.
Multitable Joins in Standard SQL
CHILD
Matches the NAME column in the GIRLS or BOYS table
TYPE
Specifies FATHER or MOTHER
PNAME
First name of the parent Full Outer Join Left Outer Join
Right Outer Join
Matched TBL1/TBL2 row pairs
Matched TBL1 rows with NULL values for TBL2 columns
Matched TBL2 rows with NULL values for TBL1 columns
Inner Join
Unmatched TBL1/TBL2 row pairs
Unmatched TBL1 rows with NULL values for TBL2 columns
Cross Join
Unmatched TBL2 rows with NULL values for TBL1 columns
Union Join
TBL1, NULL-extended (m rows)
FIGURE 7-14
All TBL1 × TBL2 pairs (m × n rows)
Relationships among join types
TBL2, NULL-extended (n rows)
PART II
AnimportantadvantageofthestandardSQLnotationisthatitallowsveryclear specificationofthree-tableorfour-tablejoins.Tobuildthesemorecomplexjoins,anyofthe joinexpressionsshowninFigure7-13anddescribedintheprecedingsectionscanbe enclosedinparentheses.Theresultingjoinexpressioncanitselfbeusedinanotherjoin expression,asifitwereasimpletable.JustasSQLallowsyoutocombinemathematical operations(+,−,*,and/)withparenthesesandbuildmorecomplexexpressions,theSQL standardallowsyoutobuildmorecomplexjoinexpressionsinthesameway. Toillustratemultitablejoins,assumethatanewPARENTStablehasbeenaddedtothe databasecontainingtheGIRLSandBOYSexamplewehavebeenusing.ThePARENTStable hasthreecolumns:
158
Part II:
Retrieving Data
ArowintheGIRLSorBOYStablecanhavetwomatchingrowsinthePARENTStable, onespecifyingaMOTHERandoneaFATHER,oritcanhaveonlyoneoftheserows,oritcan havenomatchingrowsifnodataonthechild’sparentsisavailable.TheGIRLS,BOYS,and PARENTStablestogetherprovidearichsetofdataforsomemultitablejoinexamples. Supposeyouwantedtomakealistofallofthegirls,alongwiththenamesoftheir mothersandthenamesoftheboyswholiveinthesamecity.Hereisonequerythat producesthelist: SELECTGIRLS.NAME,PNAME,BOYS.NAME FROM((GIRLSJOINPARENTS ONPARENTS.CHILD=NAME) JOINBOYS ON(GIRLS.CITY=BOYS.CITY)) WHERETYPE='MOTHER';
Becausebothofthesejoinsareinnerjoins,anygirlwhodoesnothaveaboylivinginthe samecityoranygirlwhodoesnothaveamotherinthedatabasewillnotshowupinthe queryresults.Thismayormaynotbethedesiredresult.Toincludethosegirlswithouta matchingmotherinthedatabase,youwouldchangethejoinbetweentheGIRLSandthe PARENTStabletoaleftouterjoin,likethis: SELECTGIRLS.NAME,PNAME,BOYS.NAME FROM((GIRLSLEFTJOINPARENTS ONPARENTS.CHILD=NAME) JOINBOYS ON(GIRLS.CITY=BOYS.CITY)) WHERE(TYPE='MOTHER')OR(TYPEISNULL);
Thisquerywillincludeallofthegirl/boypairs,regardlessofwhetherthegirlshave amotherinthedatabase,butitwillstillomitgirlswhodonotliveinacitywithanyof theboys.Toincludethesegirlsaswell,thesecondjoinmustalsobeconvertedtoaleft outerjoin: SELECTGIRLS.NAME,PNAME,BOYS.NAME FROM((GIRLSLEFTJOINPARENTS ONPARENTS.CHILD=NAME) LEFTJOINBOYS ON(GIRLS.CITY=BOYS.CITY)) WHERE(TYPE='MOTHER')OR(TYPEISNULL);
NotethattheNULL-extensionoftheGIRLSrowsbytheouterjoinwiththeirmothers alsocreatessomeadditionalcomplicationintheWHEREclause.Thegirlswithoutmatching motherswillgeneraterowswithnotonlyaNULLmother’sname(PNAME)column,butalso aNULLvalueintheTYPEcolumn.Thesimpleselectioncriterion WHERE(TYPE='MOTHER')
wouldgeneratean“unknown”resultfortheserows,andtheywillnotbeincludedinthe queryresults.Buttheentirereasonforusingtheleftouterjoinwastomakecertainthey wereincluded!Tosolvethisproblem,theWHEREclauseisexpandedtoalsotestfor,and allow,rowswheretheparenttypeisNULL.
Chapter 7:
Multitable Queries (Joins)
SELECTGIRLS.NAME,MOTHERS.PNAME,BOYS.NAME,FATHERS.PNAME FROMGIRLSLEFTJOINPARENTSASMOTHERS ON((MOTHERS.CHILD=GIRLS.NAME)AND(MOTHERS.TYPE='MOTHER')) JOINBOYSON(GIRLS.CITY=BOYS.CITY)LEFTJOINPARENTSASFATHERS ON((FATHERS.CHILD=BOYS.NAME)AND(FATHERS.TYPE='FATHER'));
ThisquerysolvestheWHERE-clausetestprobleminadifferentway—bymovingthetest fortheTYPEofparentintotheONclauseofthejoinspecification.Inthisposition,thetestfor appropriateTYPEofparentwillbeperformedwhentheDBMSfindsmatchingcolumnsto constructthejoin,beforetheNULL-extendedrowsareaddedtotheouterjoinresults. BecausethePARENTStableisbeingusedtwiceintheFROMclause,intwodifferentroles,it’s necessarytogiveittwodifferenttablealiasessothatthecorrectnamescanbespecifiedin theselectlist. Asthisexampleshows,evenafour-joinquerylikethisonecanbecomequite complexwiththeexpandedstandardSQLjoinsyntax.SyntaxcanvaryacrossSQL implementations.Forexample,Oracledoesn’taccepttheASkeywordbetweenthetable nameandaliasintheJOINclause.However,despitethecomplexity,thequerydoes specifypreciselythequerythattheDBMSistocarryout.Thereisnoambiguityaboutthe orderinwhichthetablesarejoined,oraboutwhichjoinsareinnerorouterjoins. Overall,theaddedcapabilityiswellworththeaddedcomplexityintroducedbythe extendedstandardSQLFROMclause. AlthoughnoneofthequeryexamplesincludedinthissectionhadWHEREorORDERBY clauses,theycanbefreelyusedwiththeextendedjoinsupport.Therelationshipamongthe clausesissimpleandremainsasdescribedearlierinthischapter.Theprocessingspecified intheFROMclausesgenerallyoccursfirst,includinganyjoinsorunions.Thejoincriteria specifiedinaUSINGorONclauseareappliedasapartoftheparticularjoinspecification wheretheyappear.WhenprocessingoftheFROMclassiscomplete,theresultingtableis usedtoapplytheselectioncriteriaintheWHEREclause.Thus,theONclausespecifiessearch criteriathatapplytospecificjoins;theWHEREclausespecifiessearchcriteriathatapplyto theentiretableresultingfromthesejoins. Table7-1summarizesSQLjoinsyntax,showingbotholdandnew(SQLstandard) variantsusingmanyoftheexamplesfromthischapter.
PART II
Asonefinalexample,supposeyouwanttogenerateagirl/boylistingagain,butthis timeyouwanttoincludethenameoftheboy’sfatherandthegirl’smotherinthequery results.Thisqueryrequiresafour-tablejoin(BOYS,GIRLS,andtwocopiesofthe PARENTStable,oneforjoiningtotheboys’informationtogetfathernamesandonefor joiningtothegirls’informationtoobtainmothernames).Againthepotentialfor unmatchedrowsinthejoinsmeansthereareseveralpossible“right”answerstothe query.Suppose,asbefore,thatyouwanttoincludeallgirlsandboysintheboy/girl pairing,eveniftheboyorgirldoesnothaveamatchingrowinthePARENTStable.You needtouseouterjoinsforthe(BOYSjoinPARENTS)and(GIRLSjoinPARENTS)partsof thequery,butaninnerjoinforthe(BOYSjoinGIRLS)partofthequery.Thisqueryyields thedesiredresults:
159
160
Type
Old Syntax
Standard SQL Syntax
Description
SELECTNAME,CITY FROMSALESREPS,OFFICES WHEREREP_OFFICE=OFFICE;
SELECTNAME,CITY FROMSALESREPSJOINOFFICES ONREP_OFFICE=OFFICE;
Forms pairs of rows by matching the contents of related columns based on an exact match between pairs of columns.
Explicit equi-join
n/a
SELECTNAME,CITY FROMSALESREPSINNERJOINOFFICES ONREP_OFFICE=OFFICE;
Syntax variation using INNERJOIN keywords instead of simply JOIN.
Parent/child query
SELECTCITY,NAME,TITLE FROMOFFICES,SALESREPS WHEREMGR=EMPL_NUM;
SELECTCITY,NAME,TITLE FROMOFFICESJOINSALESREPS ONMGR=EMPL_NUM;
An equi-join that matches the primary key in one table with the corresponding foreign key in the other.
Row selection criteria
SELECTCITY,NAME,TITLE FROMOFFICES,SALESREPS WHEREMGR=EMPL_NUM ANDTARGET>600000.00;
SELECTCITY,NAME,TITLE FROMOFFICESJOINSALESREPS ONMGR=EMPL_NUM WHERETARGET>600000.00;
Unwanted rows are filtered out from the query results by adding a WHERE predicate.
Multiple matching columns
SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERS,PRODUCTS WHEREMFR=MFR_ID ANDPRODUCT=PRODUCT_ID;
SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSJOINPRODUCTS ONMFR=MFR_ID ANDPRODUCT=PRODUCT_ID;
Multicolumn primary and foreign keys require multiple column matching in the join predicate.
Three-table join
SELECTORDER_NUM,AMOUNT,COMPANY,NAME FROMORDERS,CUSTOMERS,SALESREPS WHERECUST=CUST_NUM ANDREP=EMPL_NUM ANDAMOUNT>25000.00;
SELECTORDER_NUM,AMOUNT,COMPANY,NAME FROMORDERSJOINCUSTOMERS ONCUST=CUST_NUM JOINSALESREPS ONREP=EMPL_NUM WHEREAMOUNT>25000.00;
More than two tables are joined together by adding additional JOIN clauses.
Non-equi-join
SELECTNAME,QUOTA,TARGET FROMSALESREPS,OFFICES WHEREQUOTA>TARGET;
SELECTNAME,QUOTA,TARGET FROMSALESREPSJOINOFFICES ONQUOTA>TARGET;
The comparison operator in the join predicate is other than equal (=).
Natural join
SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERS,PRODUCTS WHEREMFR=MFR_ID ANDPRODUCT=PRODUCT_ID;
SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSNATURALJOINPRODUCTS;4
An equi-join that matches rows based on all the columns that share the same name between the joined tables.
Join with USING clause
n/a
SELECTORDER_NUM,AMOUNT,DESCRIPTION FROMORDERSJOINPRODUCTS USING(MFR,PRODUCT);5
An equi-join based on the explicitly identified column names that share the same name in the joined tables.
Self-join
SELECTEMPS.NAME,MGRS.NAME FROMSALESREPSEMPS,SALESREPSMGRS WHEREEMPS.MANAGER=MGRS.EMPL_NUM;
SELECTEMPS.NAME,MGRS.NAME FROMSALESREPSEMPSJOINSALESREPSMGRS ONEMPS.MANAGER=MGRS.EMPL_NUM;
An equi-join of a table to itself with each row matched with other rows in the same table.
SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY=BOYS.CITY(+) UNION SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY(+)=BOYS.CITY;
SELECT* FROMGIRLSFULLOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Adds a NULL-extended row to the query results for each unmatched row of each joined table.
Inner Joins
1
Simple equi-join
Outer Joins2,3
Full outer join
n/a
SELECT* FROMGIRLSNATURALFULLOUTERJOIN BOYS;
A full outer join that matches rows based on all the columns that share the same name between the joined tables.
n/a
SELECT* FROMGIRLSFULLOUTERJOINBOYS USING(CITY);
A full outer join based on the explicitly identified column names that share the same name in the joined tables.
Full outer join with keyword OUTER implied
n/a
SELECT* FROMGIRLSFULLJOINBOYS USING(CITY);
Many SQL implementations allow the keyword OUTER to be left out because it is implied by the keyword FULL.
Left outer join
SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY=BOYS.CITY(+);
SELECT* FROMGIRLSLEFTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Adds a NULL-extended row to the query results for each unmatched row of the first (left) table.
Left outer join with USING clause
n/a
SELECT* FROMGIRLSLEFTOUTERJOINBOYS USING(CITY);
A left outer join based on the explicitly identified column names that share the same name in the joined tables.
Right outer join
SELECT* FROMGIRLS,BOYS WHEREGIRLS.CITY(+)=BOYS.CITY;
SELECT* FROMGIRLSRIGHTOUTERJOINBOYS ONGIRLS.CITY=BOYS.CITY;
Adds a NULL-extended row to the query results for each unmatched row of the second (right) table.
n/a
SELECT* FROMGIRLSRIGHTOUTERJOINBOYS USING(CITY);
A right outer join based on the explicitly identified column names that share the same name in the joined tables.
Cross join
SELECT* FROMGIRLS,BOYS;
SELECT* FROMGIRLSCROSSJOINBOYS;
Explicitly requests the Cartesian product, which is the product consisting of all possible pairs of rows from the two tables.
Union “join”
SELECT* FROMGIRLS UNIONALL SELECT* FROMBOYS;
SELECT* FROMGIRLS UNIONALL SELECT* FROMBOYS;
Technically not a join; the SELECTs process independently and the result sets are then concatenated by the UNION operator.
Natural full outer join Full outer join with USING clause
Outer Joins2,3
Right outer join with USING clause Other Joins
Innerjoinshavethepotentialtoloseinformationifthetablesbeingjoinedcontainunmatchedrows. Outerjoinsdonotloseinformationbecausethey“addback”theunmatchedrows. 3 OraclesyntaxusedinOldSyntaxexamples. 4 ThisqueryisforillustrationonlybecausenocolumnssharethesamenameintheORDERSandPRODUCTStablesofthesampledatabase.Ifyourunthisoranyquerythat performsanaturaljoinontwotableswithnomatchingcolumnnamesbetweenthem,manybrandsofSQLDBMSwillreturntheCartesianproduct. 5 ThisqueryisforillustrationonlyandwillnotrunonthesampledatabasebecausethePRODUCTStabledoesnotcontaincolumnsnamedMFRandPRODUCT. 1 2
TABLE 7-1
Join Summary
161
PART II
162
Part II:
Retrieving Data
Summary ThischapterdescribedhowSQLhandlesqueriesthatcombinedatafromtwoormoretables: • Inamultitablequery(ajoin),thetablescontainingthedataarenamedintheFROM clause. • Eachrowofqueryresultsisacombinationofdatafromasinglerowineachofthe tables,anditistheonlyrowthatdrawsitsdatafromthatparticularcombination. • Themostcommonmultitablequeriesusetheparent/childrelationshipscreatedby primarykeysandforeignkeys. • Ingeneral,joinscanbebuiltbycomparinganypair(s)ofcolumnsfromthetwo joinedtables,usingeitheratestforequalityoranyothercomparisontest. • Ajoincanbethoughtofastheproductoftwotablesfromwhichsomeoftherows havebeenremoved. • Atablecanbejoinedtoitself;self-joinsrequiretheuseofatablealias. • Outerjoinsextendthestandard(inner)joinbyretainingunmatchedrowsofoneor bothofthejoinedtablesinthequeryresults,andusingNULLvaluesfordatafrom theothertable. • TheSQLstandardprovidescomprehensivesupportforinnerandouterjoins,and forcombiningtheresultsofjoinswithothermultitableoperationssuchasunions, intersections,anddifferences.
8
CHAPTER
Summary Queries
M
anyrequestsforinformationdon’trequirethelevelofdetailprovidedbythe SQLqueriesdescribedinthelasttwochapters.Forexample,eachofthefollowing requestsasksforasinglevalueorasmallnumberofvaluesthatsummarizesthe contentsofthedatabase: • Whatisthetotalquotaforallsalespeople? • Whatarethesmallestandlargestassignedquotas? • Howmanysalespeoplehaveexceededtheirquota? • Whatisthesizeoftheaverageorder? • Whatisthesizeoftheaverageorderforeachsalesoffice? • Howmanysalespeopleareassignedtoeachsalesoffice? SQLsupportstheserequestsforsummarydatathroughcolumnfunctionsandthe GROUPBYandHAVINGclausesoftheSELECTstatement,whicharedescribedinthischapter.
Column Functions SQLletsyousummarizedatafromthedatabasethroughasetofcolumnfunctions.ASQL columnfunctiontakesanentirecolumnofdataasitsargumentandproducesasingledata itemthatsummarizesthecolumn.Forexample,theAVG()columnfunctiontakesacolumn ofdataandcomputesitsaverage.HereisaquerythatusestheAVG()columnfunctionto computetheaveragevalueoftwocolumnsfromtheSALESREPStable: Whataretheaveragequotaandaveragesalesofoursalespeople? SELECTAVG(QUOTA),AVG(SALES) FROMSALESREPS; AVG(QUOTA)AVG(SALES) ------------------------ $300,000.00$289,353.20
163
164
Part II:
Retrieving Data
SALESREPS Table
FIGURE 8-1 A summary query in operation
Figure8-1graphicallyshowshowthequeryresultsareproduced.Thefirstcolumn functioninthequerytakesvaluesintheQUOTAcolumnandcomputestheiraverage; thesecondoneaveragesthevaluesintheSALEScolumn.Thequeryproducesasinglerow ofqueryresultssummarizingthedataintheSALESREPStable. TheSQLstandardspecifiesanumberofcolumnfunctions,andDBMSvendorshave addedmanymoretotheirproducts.Thesixmostcommonlysupportedcolumnfunctions areshowninFigure8-2.Thesecolumnfunctionsofferdifferentkindsofsummarydata: • SUM()computesthetotalofacolumn. • AVG()computestheaveragevalueinacolumn. • MIN()findsthesmallestvalueinacolumn. • MAX()findsthelargestvalueinacolumn. • COUNT()countsthenumberofvaluesinacolumn.(NULLvaluesarenotcounted.) • COUNT(*)countsrowsofqueryresults.(Thisisactuallyanalternateformofthe COUNT()function.) Theargumenttoacolumnfunctioncanbeasimplecolumnname,asintheprevious example,oritcanbeaSQLexpression,asshownhere: Whatistheaveragesalesperformanceacrossallofoursalespeople? SELECTAVG(100*(SALES/QUOTA)) FROMSALESREPS; AVG(100*(SALES/QUOTA)) ----------------------- 102.60
Chapter 8:
expression
SUM (
Summary Queries
165
)
DISTINCT column-name expression
AVG (
)
DISTINCT column-name MIN (expression)
PART II
MAX (expression)
column-name )
COUNT ( DISTINCT COUNT (*)
FIGURE 8-2 Column functions syntax diagram
Toprocessthisquery,SQLconstructsatemporarycolumncontainingthevalueofthe expression(100*(SALES/QUOTA))foreachrowoftheSALESREPStableandthen computestheaveragesofthetemporarycolumn.
Computing a Column Total (SUM) TheSUM()columnfunctioncomputesthesumofacolumnofdatavalues.Thedatainthe columnmusthaveanumerictype(suchasinteger,decimal,floatingpoint,ormoney). TheresultoftheSUM()functionhasthesamebasicdatatypeasthedatainthecolumn, buttheresultmayhaveahigherprecision.Forexample,ifyouapplytheSUM()function toacolumnof16-bitintegers,itmayproducea32-bitintegerasitsresult. HerearesomeexamplesthatusetheSUM()columnfunction: Whatarethetotalquotasandsalesforallsalespeople? SELECTSUM(QUOTA),SUM(SALES) FROMSALESREPS; SUM(QUOTA)SUM(SALES) ---------------------------- $2,700,000.00$2,893,532.00
166
Part II:
Retrieving Data
WhatisthetotaloftheorderstakenbyBillAdams? SELECTSUM(AMOUNT) FROMORDERS,SALESREPS WHERENAME='BillAdams' ANDREP=EMPL_NUM; SUM(AMOUNT) ------------ $39,327.00
Computing a Column Average (AVG) TheAVG()columnfunctioncomputestheaverageofacolumnofdatavalues.Aswiththe SUM()function,thedatainthecolumnmusthaveanumerictype.BecausetheAVG() functionaddsthevaluesinthecolumnandthendividesbythenumberofvalues,itsresult mayhaveadifferentdatatypethanthatofthevaluesinthecolumn.Forexample,ifyou applytheAVG()functiontoacolumnofintegers,theresultwillbeeitheradecimalora floatingpointnumber,dependingonthebrandofDBMSyouareusing. HerearesomeexamplesoftheAVG()columnfunction: CalculatetheaveragepriceofproductsfrommanufacturerACI. SELECTAVG(PRICE) FROMPRODUCTS WHEREMFR_ID='ACI'; AVG(PRICE) ----------- $804.29
CalculatetheaveragesizeofanorderplacedbyAcmeMfg.(customernumber2103). SELECTAVG(AMOUNT) FROMORDERS WHERECUST=2103; AVG(AMOUNT) ------------ $8,895.50
Finding Extreme Values (MIN and MAX) TheMIN()andMAX()columnfunctionsfindthesmallestandlargestvaluesinacolumn, respectively.Thedatainthecolumncancontainnumeric,string,ordate/timeinformation. TheresultoftheMIN()orMAX()functionhasexactlythesamedatatypeasthedatainthe column. Herearesomeexamplesthatshowtheuseofthesecolumnfunctions: Whatarethesmallestandlargestassignedquotas? SELECTMIN(QUOTA),MAX(QUOTA) FROMSALESREPS;
Chapter 8:
Summary Queries
167
MIN(QUOTA)MAX(QUOTA) ------------------------ $200,000.00$350,000.00
Whatistheearliestorderdateinthedatabase? SELECTMIN(ORDER_DATE) FROMORDERS; MIN(ORDER_DATE) ---------------- 2007-01-04
SELECTMAX(100*(SALES/QUOTA)) FROMSALESREPS; MAX(100*(SALES/QUOTA)) ----------------------- 135.44
WhentheMIN()andMAX()columnfunctionsareappliedtonumericdata,SQL comparesthenumbersinalgebraicorder(largenegativenumbersarelessthansmall negativenumbers,whicharelessthanzero,whichislessthanallpositivenumbers).Dates arecomparedsequentially.(Earlierdatesaresmallerthanlaterones.)Durationsare comparedbasedontheirlength.(Shorterdurationsaresmallerthanlongerones.) WhenusingMIN()andMAX()withstringdata,thecomparisonoftwostringsdepends onthecharactersetbeingused.Onapersonalcomputeroratypicalserver,bothofwhich usetheASCIIcharacterset,digitscomebeforethelettersinthesortingsequence,andallof theuppercasecharacterscomebeforeallofthelowercasecharacters.Onmainframes,which usetheEBCDICcharacterset,thelowercasecharactersprecedetheuppercasecharacters, anddigitscomeaftertheletters.HereisacomparisonoftheASCIIandEBCDICcollating sequencesofalistofstrings,fromsmallesttolargest: ASCII 1234ABC 5678ABC ACMEMFG. AcmeMfg. ZETACORP. ZetaCorp. acmemfg. zetacorp.
EBCDIC acmemfg. zetacorp. AcmeMfg. ACMEMFG. ZetaCorp. ZETACORP. 1234ABC 5678ABC
ThedifferenceinthecollatingsequencesmeansthataquerywithanORDERBYclause canproducedifferentresultsontwodifferentsystems.
PART II
Whatisthebestsalesperformanceofanysalesperson?
168
Part II:
Retrieving Data
Internationalcharacters(forexample,accentedcharactersinFrench,German,Spanish, orItalian,ortheCyrillicalphabetlettersusedinGreekorRussian,ortheKanjisymbols usedinJapanese)poseadditionalproblems.SomebrandsofDBMSusespecialinternational sortingalgorithmstosortthesecharactersintotheircorrectpositionforeachlanguage. Otherssimplysortthemaccordingtothenumericvalueofthecodeassignedtothe character.Toaddresstheseissues,theSQLstandardincludeselaboratesupportfornational charactersets,user-definedcharactersets,andalternatecollatingsequences.Unfortunately, supportfortheseSQLfeaturesvarieswidelyamongpopularDBMSproducts.Ifyour applicationinvolvesinternationaltext,youwillwanttoexperimentwithyourparticular DBMStofindouthowithandlesthesecharacters.
Counting Data Values (COUNT) TheCOUNT()columnfunctioncountsthenumberofdatavaluesinacolumn.Thedatain thecolumncanbeofanytype.TheCOUNT()functionalwaysreturnsaninteger,regardless ofthedatatypeofthecolumn.HerearesomeexamplesofqueriesthatusetheCOUNT() columnfunction: Howmanycustomersarethere? SELECTCOUNT(CUST_NUM) FROMCUSTOMERS; COUNT(CUST_NUM) ---------------- 21
Howmanysalespeopleareoverquota? SELECTCOUNT(NAME) FROMSALESREPS WHERESALES>QUOTA; COUNT(NAME) ------------ 7
Howmanyordersformorethan$25,000areonthebooks? SELECTCOUNT(AMOUNT) FROMORDERS WHEREAMOUNT>25000.00; COUNT(AMOUNT) -------------- 4
NotethattheCOUNT()functionthatincludesacolumnnamedoesnotcountNULL valuesinthatcolumn,butCOUNT(*)countsallrowsregardlessofcolumnvalues.Aside fromNULLvalues,however,COUNT()ignoresthevaluesofthedataitemsinthecolumn;it simplycountshowmanydataitemsthereare.Asaresult,itdoesn’treallymatterwhich
Chapter 8:
Summary Queries
169
columnyouspecifyastheargumentoftheCOUNT()function.Thelastexamplecouldjust aswellhavebeenwrittenthisway: SELECTCOUNT(ORDER_NUM) FROMORDERS WHEREAMOUNT>25000.00; COUNT(ORDER_NUM) ----------------- 4
SELECTCOUNT(*) FROMORDERS WHEREAMOUNT>25000.00; COUNT(*) --------- 4
IfyouthinkoftheCOUNT(*)functionasa“rowcount”function,itmakesthequery easiertoread.Inpractice,theCOUNT(*)functionisalmostalwaysusedinsteadofthe COUNT()functiontocountrows.
Column Functions in the Select List Simplequerieswithacolumnfunctionintheirselectlistarefairlyeasytounderstand. However,whentheselectlistincludesseveralcolumnfunctions,orwhentheargumenttoa columnfunctionisacomplexexpression,thequerycanbehardertoreadandunderstand. ThefollowingstepsshowtherulesforSQLqueryprocessingexpandedoncemoreto describehowcolumnfunctionsarehandled.Asbefore,therulesareintendedtoprovidea precisedefinitionofwhataquerymeans,notadescriptionofhowtheDBMSactuallygoes aboutproducingthequeryresults. TogeneratethequeryresultsforaSELECTstatement:
1. IfthestatementisaUNIONofSELECTstatements,applySteps2through5toeach ofthestatementstogeneratetheirindividualqueryresults.
2. FormtheproductofthetablesnamedintheFROMclause.IftheFROMclausenames asingletable,theproductisthattable.
3. IfthereisaWHEREclause,applyitssearchconditiontoeachrowoftheproduct table,retainingthoserowsforwhichthesearchconditionisTRUE(anddiscarding thoseforwhichitisFALSEorNULL).
4. Foreachremainingrow,calculatethevalueofeachitemintheselectlisttoproducea singlerowofqueryresults.Forasimplecolumnreference,usethevalueofthecolumn inthecurrentrow.Foracolumnfunction,usetheentiresetofrowsasitsargument.
PART II
Infact,it’sawkwardtothinkofthequeryas“countinghowmanyorderamounts”or “countinghowmanyordernumbers”;it’smucheasiertothinkabout“countinghowmany orders.”Forthisreason,SQLsupportsaspecialCOUNT(*)columnfunction,whichcounts rowsratherthandatavalues.Hereisthesamequery,rewrittenonceagaintousethe COUNT(*)function:
170
Part II:
Retrieving Data
5. IfSELECTDISTINCTisspecified,eliminateanyduplicaterowsofqueryresults thatwereproduced.
6. IfthestatementisaUNIONofSELECTstatements,mergethequeryresultsforthe individualstatementsintoasingletableofqueryresults.Eliminateduplicaterows unlessUNIONALLisspecified.
7. IfthereisanORDERBYclause,sortthequeryresultsasspecified.
Therowsgeneratedbythisprocedurecomprisethequeryresults. Oneofthebestwaystothinkaboutsummaryqueriesandcolumnfunctionsistoimagine thequeryprocessingbrokendownintotwosteps.First,youshouldimaginehowthequery wouldworkwithoutthecolumnfunctions,producingmanyrowsofdetailedqueryresults. ThenyoushouldimagineSQLapplyingthecolumnfunctionstothedetailedqueryresults, producingasinglesummaryrow.Forexample,considerthefollowingcomplexquery: Findtheaverageorderamount,totalorderamount,averageorderamountasapercentageofthe customer’screditlimit,andaverageorderamountasapercentageofthesalesperson’squota. SELECTAVG(AMOUNT),SUM(AMOUNT),(100*AVG(AMOUNT/CREDIT_LIMIT)), (100*AVG(AMOUNT/QUOTA)) FROMORDERS,CUSTOMERS,SALESREPS WHERECUST=CUST_NUM ANDREP=EMPL_NUM; AVG(AMOUNT)SUM(AMOUNT)(100*AVG(AMOUNT/CREDIT_LIMIT)) ------------------------------------------------------- $8,256.37$247,691.0024.45 (100*AVG(AMOUNT/QUOTA)) ------------------------ 2.51
Notethattherowsizeinthequeryresultsisratherlargebecauseoftheverylongcolumn headings.IfyouareusinganSQLclientthatrestrictsqueryresultrowsto80charactersor less,eachrowwillwraptomultiplelinesanditwon’tbenearlyasreadableaswhatisshown here.Youwilllaterlearnhowtoaddacolumnaliastothequeryresultstoeliminatethelong columnheadingsgeneratedbytheDBMSwhencolumnfunctionsareused. Withoutthecolumnfunctions,itwouldlooklikethis: SELECTAMOUNT,AMOUNT,AMOUNT/CREDIT_LIMIT,AMOUNT/QUOTA FROMORDERS,CUSTOMERS,SALESREPS WHERECUST=CUST_NUMAND ANDREP=EMPL_NUM;
andwouldproduceonerowofdetailedqueryresultsforeachorder.Thecolumnfunctions usethecolumnsofthisdetailedqueryresultstabletogenerateasingle-rowtableof summaryqueryresults. AcolumnfunctioncanappearinaSQLstatementanywherethatacolumnnamecan appear.Itcan,forexample,bepartofanexpressionthataddsorsubtractsthevaluesof twocolumnfunctions.However,insomeSQLimplementations,particularlyolderones basedontheSQL1standard,theargumentofacolumnfunctioncannotcontainanother
Chapter 8:
Summary Queries
171
columnfunction,becausetheresultingexpressiondoesn’tmakesense.Thisruleis sometimessummarizedas“it’sillegaltonestcolumnfunctions.” It’salsoillegaltomixcolumnfunctionsandordinarycolumnnamesinaselectlist (exceptingroupedqueriesandsubqueriesasdescribedinthe“GroupedQueries”section laterinthischapter),againbecausetheresultingquerydoesn’tmakesense.Forexample, considerthisquery: SELECTNAME,SUM(SALES) FROMSALESREPS;
NULL Values and Column Functions TheSUM(),AVG(),MIN(),MAX(),andCOUNT()columnfunctionseachtakeacolumnof datavaluesastheirargumentandproduceasingledatavalueasaresult.Whathappensif oneormoreofthedatavaluesinthecolumnisaNULLvalue?TheANSI/ISOSQLstandard specifiesthatNULLvaluesinthecolumnareignoredbythecolumnfunctions. ThisqueryshowshowtheCOUNT()columnfunctionignoresanyNULLvaluesina column: SELECTCOUNT(*),COUNT(SALES),COUNT(QUOTA) FROMSALESREPS; COUNT(*)COUNT(SALES)COUNT(QUOTA) ----------------------------------- 10109
TheSALESREPStablecontainstenrows,soCOUNT(*)returnsacountoften.The SALEScolumncontainstennon-NULLvalues,sothefunctionCOUNT(SALES)alsoreturnsa countoften.TheQUOTAcolumnisNULLforthenewestsalesperson.TheCOUNT(QUOTA) functionignoresthisNULLvalueandreturnsacountofnine.Becauseoftheseanomalies, theCOUNT(*)functionisalmostalwaysusedinsteadoftheCOUNT()function,unlessyou specificallywanttoexcludeNULLvaluesinaparticularcolumnfromthetotal. IgnoringNULLvalueshaslittleimpactontheMIN()andMAX()columnfunctions. However,itcancausesubtleproblemsfortheSUM()andAVG()columnfunctions,as illustratedbythisquery: SELECTSUM(SALES),SUM(QUOTA),(SUM(SALES)−SUM(QUOTA)),SUM(SALES−QUOTA) FROMSALESREPS; SUM(SALES)SUM(QUOTA)(SUM(SALES)−SUM(QUOTA))SUM(SALES−QUOTA) --------------------------------------------------------------------- $2,893,532.00$2,700,000.00$193,532.00$117,547.00
PART II
ThefirstselectitemasksSQLtogenerateamultirowtableofdetailedqueryresults—one rowforeachsalesperson.ThesecondselectitemasksSQLtogenerateaone-rowcolumnof summaryqueryresultscontainingthetotaloftheSALEScolumn.ThetwoSELECTitems contradicteachother,producinganerror.Forthisreason,eitherallcolumnreferencesinthe selectlistmustappearwithintheargumentofacolumnfunction(producingasummary query),ortheselectlistmustnotcontainanycolumnfunctions(producingadetailedquery), exceptasdescribedinthe“GroupedQueries”sectionlaterinthischapter.
172
Part II:
Retrieving Data
Youwouldexpectthetwoexpressions (SUM(SALES)−SUM(QUOTA))ANDSUM(SALES−QUOTA)
intheselectlisttoproduceidenticalresults,buttheexampleshowsthattheydonot.The salespersonwithaNULLvalueintheQUOTAcolumnisagainthereason.Theexpression SUM(SALES)
totalsthesalesforalltensalespeople,whiletheexpression SUM(QUOTA)
totalsonlytheninenon-NULLquotavalues.Theexpression SUM(SALES)−SUM(QUOTA)
computesthedifferenceofthesetwoamounts.However,thecolumnfunction SUM(SALES−QUOTA)
hasanon-NULLargumentvalueforonlynineofthetensalespeople.IntherowwithaNULL quotavalue,thesubtractionproducesaNULL,whichisignoredbytheSUM()function. Thus,thesalesforthesalespersonwithoutaquota,whichareincludedintheprevious calculation,areexcludedfromthiscalculation. Whichisthe“correct”answer?Bothare!Thefirstexpressioncalculatesexactlywhatit says:“thesumofSALES,lessthesumofQUOTA.”Thesecondexpressionalsocalculates exactlywhatitsays:“thesumof(SALES–QUOTA).”WhenNULLvaluesoccur,however,the twocalculationsarenotquitethesame. TheANSI/ISOSQLstandardspecifiesthesepreciserulesforhandlingNULLvaluesin columnfunctions: • IfanyofthedatavaluesinacolumnareNULL,theyareignoredforthepurposeof computingthecolumnfunction’svalue. • IfeverydataiteminthecolumnisNULL,thentheSUM(),AVG(),MIN(),andMAX() columnfunctionsreturnaNULLvalue;theCOUNT()functionreturnsavalueofzero. • Ifnodataitemsareinthecolumn(thatis,thecolumnisempty),thentheSUM(), AVG(),MIN(),andMAX()columnfunctionsreturnaNULLvalue;theCOUNT() functionreturnsavalueofzero. • TheCOUNT(*)countsrowsanddoesnotdependonthepresenceorabsenceof NULLvaluesinacolumn.Iftherearenorows,itreturnsavalueofzero. Althoughthestandardisveryclearinthisarea,commercialSQLproductsmayproduce resultsdifferentfromthestandard,especiallyifallofthedatavaluesinacolumnareNULL orwhenacolumnfunctionisappliedtoanemptytable.Beforeassumingitwillbehaveas specifiedbythestandard,youshouldtestyourparticularDBMS.
Chapter 8:
Summary Queries
173
Duplicate Row Elimination (DISTINCT) RecallfromChapter6thatyoucanspecifytheDISTINCTkeywordatthebeginningofthe selectlisttoeliminateduplicaterowsofqueryresults.YoucanalsoaskSQLtoeliminate duplicatevaluesfromacolumnbeforeapplyingacolumnfunctiontoit.Toeliminate duplicatevalues,thekeywordDISTINCTisincludedbeforethecolumnfunctionargument, immediatelyaftertheopeningparenthesis. Herearetwoqueriesthatillustrateduplicateroweliminationforcolumnfunctions: Howmanydifferenttitlesareheldbysalespeople?
Howmanysalesofficeshavesalespeoplewhoareoverquota? SELECTCOUNT(DISTINCTREP_OFFICE) FROMSALESREPS WHERESALES>QUOTA; COUNT(DISTINCTREP_OFFICE) --------------------------- 4
TheDISTINCTkeywordcanbespecifiedonlyonceinaquery.Ifitappearsinthe argumentofonecolumnfunction,itcan’tappearinanyother.Ifitisspecifiedbeforethe selectlist,itcan’tappearinanycolumnfunctions.TheonlyexceptionisthatDISTINCT maybespecifiedasecondtimeinsideasubquery(containedwithinthequery).Subqueries aredescribedinChapter9.
Grouped Queries (GROUP BY Clause) Thesummaryqueriesdescribedthusfararelikethetotalsatthebottomofareport.They condenseallofthedetaileddatainthereportintoasingle,summaryrowofdata.Justas subtotalsareusefulinprintedreports,it’softenconvenienttosummarizequeryresultsata “subtotal”level.TheGROUPBYclauseoftheSELECTstatementprovidesthiscapability. ThefunctionoftheGROUPBYclauseismosteasilyunderstoodbyexample.Consider thesetwoqueries: Whatistheaverageordersize? SELECTAVG(AMOUNT) FROMORDERS; AVG(AMOUNT) ------------ $8,256.37
PART II
SELECTCOUNT(DISTINCTTITLE) FROMSALESREPS; COUNT(DISTINCTTITLE) ---------------------- 3
174
Part II:
Retrieving Data
Whatistheaverageordersizeforeachsalesperson? SELECTREP,AVG(AMOUNT) FROMORDERS GROUPBYREP; REPAVG(AMOUNT) ---------------- 101$8,876.00 102$5,694.00 103$1,350.00 105$7,865.40 106$16,479.00 107$11,477.33 108$8,376.14 109$3,552.50 110$11,566.00
Thefirstqueryisasimplesummaryquerylikethepreviousexamplesinthischapter. Thesecondqueryproducesseveralsummaryrows—onerowforeachgroup,summarizing theorderstakenbyasinglesalesperson.Figure8-3showshowthesecondqueryworks. Conceptually,SQLcarriesoutthequeryasfollows:
1. SQLdividestheordersintogroupsoforders,withonegroupforeachsalesperson. Withineachgroup,alloftheordershavethesamevalueintheREPcolumn.
ORDERS Table
GROUPED Table ORDER_NUM
•
GROUP • BY •
REP
AMOUNT
112961 112989
106 106
$31,500.00 $1,458.00
112975 113057
103 103
$2,100.00 $600.00
108 108 108 108 108 108 108
$1,420.00 $45,000.00 $652.00 $7,100.00 $2,925.00 $760.00 $776.00
• • • 113051 113045 113013 113024 113007 112992 113049
FIGURE 8-3 A grouped query in operation
QUERY Results REP AVG (AMOUNT) 106 103 • • • 108
$16,479.00 $1,350.00
$8,376.14
Chapter 8:
Summary Queries
175
2. Foreachgroup,SQLcomputestheaveragevalueoftheAMOUNTcolumnforallof therowsinthegroupandgeneratesasingle,summaryrowofqueryresults.The rowcontainsthevalueoftheREPcolumnforthegroupandthecalculatedaverage ordersize.
AquerythatincludestheGROUPBYclauseiscalledagroupedquerybecauseitgroups thedatafromitssourcetablesandproducesasinglesummaryrowforeachrowgroup.The columnsnamedintheGROUPBYclausearecalledthegroupingcolumnsofthequery,because theydeterminehowtherowsaredividedintogroups.Herearesomeadditionalexamples ofgroupedqueries:
SELECTREP_OFFICE,MIN(QUOTA),MAX(QUOTA) FROMSALESREPS GROUPBYREP_OFFICE; REP_OFFICEMIN(QUOTA)MAX(QUOTA) ----------------------------------- NULLNULLNULL 11$275,000.00$300,000.00 12$200,000.00$300,000.00 13$350,000.00$350,000.00 21$350,000.00$350,000.00 22$300,000.00$300,000.00
Howmanysalespeopleareassignedtoeachoffice? SELECTREP_OFFICE,COUNT(*) FROMSALESREPS GROUPBYREP_OFFICE; REP_OFFICECOUNT(*) -------------------- NULL1 112 123 131 212 221
Howmanydifferentcustomersareservedbyeachsalesperson? SELECTCOUNT(DISTINCTCUST_NUM),'customersforsalesrep',CUST_REP FROMCUSTOMERS GROUPBYCUST_REP; COUNT(DISTINCTCUST_NUM)CUSTOMERSFORSALESREPCUST_REP --------------------------------------------------------- 3customersforsalesrep101 4customersforsalesrep102 3customersforsalesrep103 1customersforsalesrep104
PART II
Whatistherangeofassignedquotasineachoffice?
176
Part II:
Retrieving Data
2customersforsalesrep105 2customersforsalesrep106 . . .
ThereisanintimatelinkbetweentheSQLcolumnfunctionsandtheGROUPBYclause. Rememberthatthecolumnfunctionstakeacolumnofdatavaluesandproduceasingle result.WhentheGROUPBYclauseispresent,ittellsSQLtodividethedetailedqueryresults intogroupsandtoapplythecolumnfunctionseparatelytoeachgroup,producingasingle resultforeachgroup.ThefollowingstepsshowtherulesforSQLqueryprocessing, expandedonceagainforgroupedqueries. TogeneratethequeryresultsforaSELECTstatement:
1. IfthestatementisaUNIONofSELECTstatements,applySteps2through7toeach ofthestatementstogeneratetheirindividualqueryresults.
2. FormtheproductofthetablesnamedintheFROMclause.IftheFROMclausenames asingletable,theproductisthattable.
3. IfthereisaWHEREclause,applyitssearchconditiontoeachrowoftheproduct table,retainingthoserowsforwhichthesearchconditionisTRUE(anddiscarding thoseforwhichitisFALSEorNULL).
4. IfthereisaGROUPBYclause,arrangetheremainingrowsoftheproducttableinto rowgroups,sothattherowsineachgrouphaveidenticalvaluesinallofthe groupingcolumns.
5. IfthereisaHAVINGclause,applyitssearchconditiontoeachrowgroup,retaining thosegroupsforwhichthesearchconditionisTRUE(anddiscardingthosefor whichitisFALSEorNULL).
6. Foreachremainingrow(orrowgroup),calculatethevalueofeachitemintheselect listtoproduceasinglerowofqueryresults.Forasimplecolumnreference,usethe valueofthecolumninthecurrentrow(orrowgroup).Foracolumnfunction,use thecurrentrowgroupasitsargumentifGROUPBYisspecified;otherwise,usethe entiresetofrows.
7. IfSELECTDISTINCTisspecified,eliminateanyduplicaterowsofqueryresults thatwereproduced.
8. IfthestatementisaUNIONofSELECTstatements,mergethequeryresultsforthe individualstatementsintoasingletableofqueryresults.Eliminateduplicaterows unlessUNIONALLisspecified.
9. IfthereisanORDERBYclause,sortthequeryresultsasspecified. Therowsgeneratedbythisprocedurecomprisethequeryresults.
Multiple Grouping Columns SQLcangroupqueryresultsbasedonthecontentsoftwoormorecolumns.Forexample, supposeyouwanttogrouptheordersbysalespersonandbycustomer.Thisquerygroups thedatabasedonbothcriteria:
Chapter 8:
Summary Queries
177
Calculatethetotalordersforeachcustomerofeachsalesperson.
Evenwithmultiplegroupingcolumns,olderSQLversionsprovideonlyasinglelevelof grouping.Thequeryproducesaseparatesummaryrowforeachsalesperson/customer pair.ToproducemorethanonelevelofsubtotalsinmoremodernSQL,youcanusethe WITHROLLUPandWITHCUBEoperatorsincombinationwiththeGROUPBYoperator. WITHROLLUPcausestheGROUPBYoperationtodisplayasubtotalforeachlevelof groupingworkinglefttorightacrossthelistofgroupingcolumns.WITHCUBEgoesfurther byshowingsubtotalsforeverypossiblecombinationofgroupingcolumns.WITHCUBEand WITHROLLUPalsoprovideagrandtotalintheresultset,butthegrandtotalmightnot alwaysappearattheendoftheresultset.Oracle’sCUBEoption,forexample,displaysthe grandtotalfirst.Youcanspotthesubtotalrowsbecausegroupingcolumnsthatdon’tapply areNULL.Similarly,thegrandtotallinewillhaveNULLvaluesinallofthegrouping columns. Calculatethetotalordersforeachcustomerofeachsalespersonwithsubtotalsforeachsalesperson. SELECTREP,CUST,SUM(AMOUNT) FROMORDERS GROUPBYREP,CUSTWITHROLLUP; REPCUSTSUM(AMOUNT) ------------------------------- 10121023978 1012108150 101211322500 10126628 10221064026 102211415000 10221203750 10222776 10321112700 1032700
PART II
SELECTREP,CUST,SUM(AMOUNT) FROMORDERS GROUPBYREP,CUST; REPCUSTSUM(AMOUNT) --------------------- 1012102$3,978.00 1012108$150.00 1012113$22,500.00 1022106$4,026.00 1022114$15,000.00 1022120$3,750.00 1032111$2,700.00 1052103$35,582.00 1052111$3,745.00 . . .
178
Part II:
Retrieving Data
105210335582 10521113745 10539327 . . . 110210723132 11023132 247691
Calculatethetotalordersforeachcustomerofeachsalespersonwithsubtotalsforeachsalesperson andeachcustomer. SELECTREP,CUST,SUM(AMOUNT) FROMORDERS GROUPBYREP,CUSTWITHCUBE; REPCUSTSUM(AMOUNT) ------------------------------- 10126628 10121023978 1012108150 101211322500 10222776 10221064026 102211415000 10221203750 1032700 10321112700 10539327 105210335582 10521113745 . . . 247691 21011458 21023978 210335582 21064026 210723132 21087255 210931350 21116445 211247925 211322500 211422100 211731500 21183608 21203750 21243082
Chapter 8:
Summary Queries
Calculatethetotalordersforeachcustomerofeachsalesperson,sortedbycustomer,andwithineach customerbysalesperson. SELECTCUST,REP,SUM(AMOUNT) FROMORDERS GROUPBYCUST,REP ORDERBYCUST,REP; CUSTREPSUM(AMOUNT) --------------------- 2101106$1,458.00 2102101$3,978.00 2103105$35,582.00 2106102$4,026.00 2107110$23,132.00 2108101$150.00 2108109$7,105.00 2109107$31,350.00 2111103$2,700.00 2111105$3,745.00 . . .
Restrictions on Grouped Queries Groupedqueriesaresubjecttosomeratherstrictlimitations.Thegroupingcolumnsmust beactualcolumnsofthetablesnamedintheFROMclauseofthequery.However,some implementationsalsopermitcolumnexpressionsandevenallowyoutogroupon expressionsbysimplyrepeatingthecolumnexpressionintheGROUPBYclause. Therearealsorestrictionsontheitemsthatcanappearintheselectlistofagrouped query.Alloftheitemsintheselectlistmusthaveasinglevalueforeachgroupofrows. Basically,thismeansthataselectiteminagroupedquerycanbe • Acolumn(provideditisoneofthegroupingcolumns) • Aconstant • Acolumnfunction,whichproducesasinglevaluesummarizingtherowsinthegroup
PART II
ThesyntaxforWITHROLLUPandWITHCUBEvariessomewhatfromoneSQLproductto another,socheckyourvendor’sdocumentation.TheSQLstandardsyntax,whichissupported bySQLServer,DB2UniversalDatabase(UDB),andMySQL,isshowninthepreceding examples.(However,asofversion5.1,MySQLdoesnotyetsupportWITHCUBE.)Oracle requiresthekeywordsGROUPBYROLLUPorGROUPBYCUBEfollowedbythegrouping columnlist,whichmustbeenclosedinparentheses,suchas:GROUPBYCUBE(REP, CUST).DB2UDBsupportsboththestandardsyntaxandthevariationrequiredbyOracle. IfyourSQLimplementationdoesnotsupportROLLUPorCUBE,thebestyoucandois sortthedatasothattherowsofqueryresultsappearintheappropriateorder.InmanySQL implementations,theGROUPBYclausewillautomaticallyhavetheside-effectofsortingthe data,butyoucanoverridethissortwithanORDERBYclause,asshownnext:
179
180
Part II:
Retrieving Data
• Agroupingcolumn,whichbydefinitionhasthesamevalueineveryrowofthegroup • Anexpressioninvolvingcombinationsofthese Inpractice,agroupedquerywillalwaysincludebothagroupingcolumnandacolumn functioninitsselectlist.Ifnocolumnfunctionappears,thequerycanbeexpressedmore simplyusingSELECTDISTINCT,withoutGROUPBY.Conversely,ifyoudon’tincludea groupingcolumninthequeryresults,youwon’tbeabletotellwhichrowofqueryresults camefromwhichgroup! AnotherlimitationofgroupedqueriesisthatSQLignoresinformationaboutprimary keysandforeignkeyswhenanalyzingthevalidityofagroupedquery.Considerthisquery, whichproducesanerror: Calculatethetotalordersforeachsalesperson. SELECTEMPL_NUM,NAME,SUM(AMOUNT) FROMORDERS,SALESREPS WHEREREP=EMPL_NUM GROUPBYEMPL_NUM; Error:"NAME"notaGROUPBYexpression
Giventhenatureofthedata,thequerymakesperfectlygoodsense,becausegrouping onthesalesperson’semployeenumberisineffectthesameasgroupingonthesalesperson’s name.Moreprecisely,EMPL_NUM,thegroupingcolumn,istheprimarykeyofthe SALESREPStable,sotheNAMEcolumnmustbesingle-valuedforeachgroup.Nonetheless, SQLreportsanerrorbecausetheNAMEcolumnisnotexplicitlyspecifiedasagrouping column.(TheexacterrormessagewillvaryfromoneDBMSproducttoanother.)Tocorrect theproblem,youcansimplyincludetheNAMEcolumnasasecond(redundant)grouping column: Calculatethetotalordersforeachsalesperson. SELECTEMPL_NUM,NAME,SUM(AMOUNT) FROMORDERS,SALESREPS WHEREREP=EMPL_NUM GROUPBYEMPL_NUM,NAME; EMPL_NUMNAMESUM(AMOUNT) ----------------------------------- 101DanRoberts$26,628.00 102SueSmith$22,776.00 103PaulCruz$2,700.00 105BillAdams$39,327.00 106SamClark$32,958.00 107NancyAngelli$34,432.00 108LarryFitch$58,633.00 109MaryJones$7,105.00 110TomSnyder$23,132.00
Ofcourse,ifthesalesperson’semployeenumberisnotneededinthequeryresults,you caneliminateitentirelyfromtheselectlist:
Chapter 8:
Summary Queries
181
Calculatethetotalordersforeachsalesperson.
NULL Values in Grouping Columns ANULLvalueposesaspecialproblemwhenitoccursinagroupingcolumn.Ifthevalueof thecolumnisunknown,intowhichgroupshouldtherowbeplaced?IntheWHEREclause, whentwodifferentNULLvaluesarecompared,theresultisNULL(notTRUE),thatis,the twoNULLvaluesarenotconsideredtobeequal.Applyingthesameconventiontothe GROUPBYclausewouldforceSQLtoplaceeachrowwithaNULLgroupingcolumnintoa separategroupbyitself. Inpractice,thisruleprovestoounwieldy.Instead,theANSI/ISOSQLstandard considerstwoNULLvaluestobeequalforpurposesoftheGROUPBYclause.Iftworows haveNULLsinthesamegroupingcolumnsandidenticalvaluesinalloftheirnon-NULL groupingcolumns,theyaregroupedtogetherintothesamerowgroup.Thesmallsample tableinFigure8-4illustratestheANSI/ISOhandlingofNULLvaluesbytheGROUPBY clause,asshowninthisquery: SELECTHAIR,EYES,COUNT(*) FROMPEOPLE GROUPBYHAIR,EYES; HAIREYESCOUNT(*) --------------------- BrownBlue1 NULLBlue2 NULLNULL2 BrownNULL3 BrownBrown2 BrownBrown2
AlthoughthisbehaviorofNULLsingroupingcolumnsisclearlyspecifiedintheANSI/ ISOstandard,itisnotimplementedinallSQLdialects.It’sagoodideatobuildasmalltest tableandcheckthebehaviorofyourDBMSbrandbeforecountingonaspecificbehavior.
PART II
SELECTNAME,SUM(AMOUNT) FROMORDERS,SALESREPS WHEREREP=EMPL_NUM GROUPBYNAME; NAMESUM(AMOUNT) -------------------------- BillAdams$39,327.00 DanRoberts$26,628.00 LarryFitch$58,633.00 MaryJones$7,105.00 NancyAngelli$34,432.00 PaulCruz$2,700.00 SamClark$32,958.00 SueSmith$22,776.00 TomSnyder$23,132.00
182
Part II:
Retrieving Data
NAME Cincly Louise Harry Samantha Joanne George Mary Paula Kevin Joel Susan Marie
HAIR Brown NULL NULL NULL NULL Brown Brown Brown Brown Brown Blonde Blonde
EYES Blue Blue Blue NULL NULL NULL NULL NULL NULL Brown Blue Blue
FIGURE 8-4 The PEOPLE table
Group Search Conditions (HAVING Clause) JustastheWHEREclausecanbeusedtoselectandrejecttheindividualrowsthatparticipatein aquery,theHAVINGclausecanbeusedtoselectandrejectrowgroups.Theformatofthe HAVINGclauseparallelsthatoftheWHEREclause,consistingofthekeywordHAVINGfollowed byasearchcondition.TheHAVINGclausethusspecifiesasearchconditionforgroups. AnexampleprovidesthebestwaytounderstandtheroleoftheHAVINGclause. Considerthisquery: Whatistheaverageordersizeforeachsalespersonwhoseorderstotalmorethan$30,000? SELECTREP,AVG(AMOUNT) FROMORDERS GROUPBYREP HAVINGSUM(AMOUNT)>30000.00; REPAVG(AMOUNT) ---------------- 105$7,865.40 106$16,479.00 107$11,477.33 108$8,376.14
Figure8-5showsgraphicallyhowSQLcarriesoutthequery.TheGROUPBYclausefirst arrangestheordersintogroupsbysalesperson.TheHAVINGclausetheneliminatesany groupwherethetotaloftheordersinthegroupdoesnotexceed$30,000.Finally,the SELECTclausecalculatestheaverageordersizeforeachoftheremaininggroupsand generatesthequeryresults. ThesearchconditionsyoucanspecifyintheHAVINGclausearethesameonesusedin theWHEREclause,asdescribedinChapters6and9.Hereisanotherexampleoftheuseofa groupsearchcondition:
Chapter 8:
Summary Queries
183
ORDERS Table
GROUPED Table REP
AMOUNT
112961 112989
106 106
$31,500.00 $1,458.00
112975 113057
103 103
$2,100.00 $600.00
SUM(AMOUNT) > $30,000?
REP
AVG (AMOUNT)
106
$16,479.00
• • •
FALSE
• • • 113051 113045 113013 113024 113007 112992 113049 • • •
TRUE SUM(AMOUNT) > $30,000?
108 108 108 108 108 108 108
$1,420.00 $45,000.00 $652.00 $7,100.00 $2,925.00 $760.00 $776.00
FIGURE 8-5 A grouped search condition in operation
Foreachofficewithtwoormorepeople,computethetotalquotaandtotalsalesforallsalespeoplewho workintheoffice. SELECTCITY,SUM(QUOTA),SUM(SALESREPS.SALES) FROMOFFICES,SALESREPS WHEREOFFICE=REP_OFFICE GROUPBYCITY HAVINGCOUNT(*)>=2; CITYSUM(QUOTA)SUM(SALESREPS.SALES) --------------------------------------------- Chicago$775,000.00$735,042.00 LosAngeles$700,000.00$835,915.00 NewYork$575,000.00$692,637.00
ThefollowingstepsshowtherulesforSQLqueryprocessing,expandedonceagainto includegroupsearchconditions. TogeneratethequeryresultsforaSELECTstatement:
1. IfthestatementisaUNIONofSELECTstatements,applySteps2through7toeach ofthestatementstogeneratetheirindividualqueryresults.
2. FormtheproductofthetablesnamedintheFROMclause.IftheFROMclausenames asingletable,theproductisthattable.
3. IfthereisaWHEREclause,applyitssearchconditiontoeachrowoftheproduct table,retainingthoserowsforwhichthesearchconditionisTRUE(anddiscarding thoseforwhichitisFALSEorNULL).
PART II
• GROUP • BY •
QUERY Results
ORDER_NUM
184
Part II:
Retrieving Data
4. IfthereisaGROUPBYclause,arrangetheremainingrowsoftheproducttableinto rowgroups,sothattherowsineachgrouphaveidenticalvaluesinallofthe groupingcolumns.
5. IfthereisaHAVINGclause,applyitssearchconditiontoeachrowgroup,retaining thosegroupsforwhichthesearchconditionisTRUE(anddiscardingthosefor whichitisFALSEorNULL).
6. Foreachremainingrow(orrowgroup),calculatethevalueofeachitemintheselect listtoproduceasinglerowofqueryresults.Forasimplecolumnreference,usethe valueofthecolumninthecurrentrow(orrowgroup).Foracolumnfunction,use thecurrentrowgroupasitsargumentifGROUPBYisspecified;otherwise,usethe entiresetofrows.
7. IfSELECTDISTINCTisspecified,eliminateanyduplicaterowsofqueryresults thatwereproduced.
8. IfthestatementisaUNIONofSELECTstatements,mergethequeryresultsforthe individualstatementsintoasingletableofqueryresults.Eliminateduplicaterows unlessUNIONALLisspecified.
9. IfthereisanORDERBYclause,sortthequeryresultsasspecified.
Therowsgeneratedbythisprocedurecomprisethequeryresults. Followingthisprocedure,SQLhandlesthequeryinthepreviousexampleasfollows:
1. JoinstheOFFICESandSALESREPStablestofindthecitywhereeachsalesperson works.
2. Groupstheresultingrowsbyoffice.
3. Eliminatesgroupswithtwoorfewerrows—theserepresentofficesthatdon’tmeet theHAVINGclausecriterion.
4. Calculatesthetotalquotaandtotalsalesforeachgroup. Hereisonemoreexample,whichusesalloftheSELECTstatementclauses:
Showtheprice,quantityonhand,andtotalquantityonorderforeachproductwherethetotal quantityonorderismorethan75percentofthequantityonhand. SELECTDESCRIPTION,PRICE,QTY_ON_HAND,SUM(QTY) FROMPRODUCTS,ORDERS WHEREMFR=MFR_ID ANDPRODUCT=PRODUCT_ID GROUPBYMFR_ID,PRODUCT_ID,DESCRIPTION,PRICE,QTY_ON_HAND HAVINGSUM(QTY)>(.75*QTY_ON_HAND) ORDERBYQTY_ON_HANDDESC; DESCRIPTIONPRICEQTY_ON_HANDSUM(QTY) ----------------------------------------------- Reducer$355.003832 WidgetAdjuster$25.003730 MotorMount$243.001516 RightHinge$4,500.001215 500-lbBrace$1,425.00522
Chapter 8:
Summary Queries
185
Toprocessthisquery,SQLconceptuallyperformsthefollowingsteps: 1. JoinstheORDERSandPRODUCTStablestofindthedescription,price,andquantity onhandforeachproductordered.
2. GroupstheresultingrowsbymanufacturerandproductID.
3. Eliminatesgroupswherethequantityordered(thetotaloftheQTYcolumnforall ordersinthegroup)islessthan75percentofthequantityonhand.
4. Calculatesthetotalquantityorderedforeachgroup.
5. Generatesonesummaryrowofqueryresultsforeachgroup.
6. Sortsthequeryresultssothatproductswiththelargestquantityonhandappearfirst.
Asdescribedpreviously,DESCRIPTION,PRICE,andQTY_ON_HANDmustbespecified asgroupingcolumnsinthisquerysolelybecausetheyappearintheselectlist.Theyactually contributenothingtothegroupingprocess,becausetheMFR_IDandPRODUCT_ID completelyspecifyasinglerowofthePRODUCTStable,automaticallymakingtheother threecolumnssingle-valuedpergroup.
Restrictions on Group Search Conditions TheHAVINGclauseisusedtoincludeorexcluderowgroupsfromthequeryresults,sothe searchconditionitspecifiesmustbeonethatappliestothegroupasawholeratherthanto individualrows.Thismeansthatanitemappearingwithinthesearchconditionina HAVINGclausecanbe • Aconstant • Acolumnfunction,whichproducesasinglevaluesummarizingtherowsinthegroup • Agroupingcolumn,whichbydefinitionhasthesamevalueineveryrowofthegroup • Anexpressioninvolvingcombinationsofthese Inpractice,thesearchconditionintheHAVINGclausewillalwaysincludeatleastone columnfunction.Ifitdidnot,thesearchconditioncouldbemovedtotheWHEREclauseand appliedtoindividualrows.Theeasiestwaytofigureoutwhetherasearchcondition belongsintheWHEREclauseorintheHAVINGclauseistorememberhowthetwoclauses areapplied: • TheWHEREclauseisappliedtoindividualrows,sotheexpressionsitcontainsmust becomputableforindividualrows. • TheHAVINGclauseisappliedtorowgroups,sotheexpressionsitcontainsmustbe computableforagroupofrows.
PART II
186
Part II:
Retrieving Data
NULL Values and Group Search Conditions LikethesearchconditionintheWHEREclause,theHAVINGclausesearchconditioncan produceoneofthreeresults: • IfthesearchconditionisTRUE,therowgroupisretained,anditcontributesa summaryrowtothequeryresults. • IfthesearchconditionisFALSE,therowgroupisdiscarded,anditdoesnot contributeasummaryrowtothequeryresults. • IfthesearchconditionisNULL,therowgroupisdiscarded,anditdoesnot contributeasummaryrowtothequeryresults. TheanomaliesthatcanoccurwithNULLvaluesinthesearchconditionarethesameas thosefortheWHEREclauseandhavebeendescribedinChapter6.
HAVING Without GROUP BY TheHAVINGclauseisalmostalwaysusedinconjunctionwiththeGROUPBYclause,butthe syntaxoftheSELECTstatementdoesnotrequireit.IfaHAVINGclauseappearswithouta GROUPBYclause,SQLconsiderstheentiresetofdetailedqueryresultstobeasinglegroup. Inotherwords,thecolumnfunctionsintheHAVINGclauseareappliedtoone,andonlyone, grouptodeterminewhetherthegroupisincludedorexcludedfromthequeryresults,and thatgroupconsistsofalltherows.TheuseofaHAVINGclausewithoutacorresponding GROUPBYclauseisseldomseeninpractice.
Summary Thischapterdescribedsummaryqueries,whichsummarizedatafromthedatabase: • SummaryqueriesuseSQLcolumnfunctionstocollapseacolumnofdatavalues intoasinglevaluethatsummarizesthecolumn. • Columnfunctionscancomputetheaverage,sum,minimum,andmaximumvalues ofacolumn,countthenumberofdatavaluesinacolumn,orcountthenumberof rowsofqueryresults. • AsummaryquerywithoutaGROUPBYclausegeneratesasinglerowofquery results,summarizingalltherowsofatableorajoinedsetoftables. • AsummaryquerywithaGROUPBYclausegeneratesmultiplerowsofqueryresults, eachsummarizingtherowsinaparticulargroup. • TheHAVINGclauseactsasaWHEREclauseforgroups,selectingtherowgroupsthat contributetothesummaryqueryresults.
9
CHAPTER
Subqueries and Query Expressions
T
heSQLsubqueryfeatureletsyouusetheresultsofonequeryaspartofanotherquery. Theabilitytouseaquerywithinaquerywastheoriginalreasonfortheword “structured”inthenameStructuredQueryLanguage.Thesubqueryfeatureisless well-knownthanSQL’sjoinfeature,butitplaysanimportantroleinSQLforthreereasons: • ASQLstatementwithasubqueryisoftenthemostnaturalwaytoexpressaquery, becauseitmostcloselyparallelstheEnglish-languagedescriptionofthequery. • SubqueriesmakeiteasiertowriteSELECTstatements,becausetheyletyoubreak aquerydownintopieces(thequeryanditssubqueries)andthenputthepieces backtogether. • SomequeriescannotbeexpressedinSQLwithoutusingasubquery. Thefirstseveralsectionsofthischapterdescribesubqueriesandshowhowtheyare usedintheWHEREandHAVINGclausesofaSQLstatement.Thelatersectionsofthischapter describetheadvancedqueryexpressioncapabilitiesthathavebeenaddedtotheSQL standard,whichsubstantiallyexpandsthepowerofSQLtoperformeventhemostcomplex ofdatabaseoperations.
Using Subqueries Asubqueryisaquerywithinaquery.TheresultsofthesubqueryareusedbytheDBMSto determinetheresultsofthehigher-levelquerythatcontainsthesubquery.Inthesimplest formsofasubquery,thesubqueryappearswithintheWHEREorHAVINGclauseofanother SQLstatement.Subqueriesprovideanefficient,naturalwaytohandlequeryrequeststhat arethemselvesexpressedintermsoftheresultsofotherqueries.Hereisanexampleofsuch arequest: Listtheofficeswherethesalestargetfortheofficeexceedsthesumofthesalespeople’squotas.
187
188
Part II:
Retrieving Data
TherequestasksforalistofofficesfromtheOFFICEStable,wherethevalueofthe TARGETcolumnmeetssomecondition.ItseemsreasonablethattheSELECTstatementthat expressesthequeryshouldlooksomethinglikethis: SELECTCITYFROMOFFICESWHERETARGET>???
Thevalue“???”needstobefilledinandshouldbeequaltothesumofthequotasof thesalespeopleassignedtotheofficeinquestion.Howcanyouspecifythatvalueinthe query?FromChapter8,youknowthatthesumofthequotasforaspecificoffice(say,office number21)canbeobtainedwiththisquery: SELECTSUM(QUOTA) FROMSALESREPS WHEREREP_OFFICE=21;
Butitwouldbeinefficienttohavetotypeinthisquery,writedowntheresults,andthen typeinthepreviousquerywiththecorrectamount.Howcanyouputtheresultsofthis queryintotheearlierqueryinplaceofthequestionmarks?Itwouldseemreasonableto startwiththefirstqueryandreplacethe“???”withthesecondquery,asfollows: SELECTCITY FROMOFFICES WHERETARGET>(SELECTSUM(QUOTA) FROMSALESREPS WHEREREP_OFFICE=OFFICE);
Infact,thisisacorrectlyformedSQLquery.Foreachoffice,theinnerquery(thesubquery) calculatesthesumofthequotasforthesalespeopleworkinginthatoffice.Theouterquery (themainquery)comparestheoffice’stargetwiththecalculatedtotalanddecideswhetherto addtheofficetothemainqueryresults.Workingtogether,themainqueryandthesubquery expresstheoriginalrequestandretrievetherequesteddatafromthedatabase. SQLsubqueriestypicallyappearaspartoftheWHEREclauseortheHAVINGclause.In theWHEREclause,theyhelptoselecttheindividualrowsthatappearinthequeryresults.In theHAVINGclause,theyhelptoselecttherowgroupsthatappearinthequeryresults.
What Is a Subquery? Figure9-1showstheformofaSQLsubquery.Thesubqueryisenclosedinparentheses,but otherwiseithasthefamiliarformofaSELECTstatement,withaFROMclauseandoptional WHERE,GROUPBY,HAVING,andORDERBYclauses.Theformoftheseclausesinasubquery isidenticaltothatinaSELECTstatement,andtheyperformtheirnormalfunctionswhen usedwithinasubquery.Thereare,however,afewdifferencesbetweenasubqueryandan actualSELECTstatement: • Inthemostcommonuses,asubquerymustproduceasinglecolumnofdataasits queryresults.Thismeansthatasubqueryalmostalwayshasasingleselectitemin itsSELECTclause. • WhiletheORDERBYclausecanbespecifiedinasubquery,itisrarelyusedthere. Thesubqueryresultsareusedinternallybythemainqueryandarenevervisible
Chapter 9:
FIGURE 9-1 Basic subquery syntax diagram
Subqueries and Query Expressions
select-item
(SELECT ALL DISTINCT
FROM
, *
table-specification ,
PART II
WHERE search-condition
GROUP BY
group-column ,
HAVING search-condition
ORDER BY
189
order-column , )
totheuser,soitmakeslittlesensetosortthem.Moreover,sortinglargenumbersof rowscanadverselyaffectperformance. • Columnnamesappearinginasubquerymayrefertocolumnsoftablesinthemain query.Theseouterreferencesaredescribedindetaillaterinthe“OuterReferences” section. • Inmostimplementations,asubquerycannotbetheUNIONofseveraldifferent SELECTstatements;onlyasingleSELECTisallowed.(TheSQLstandardallows muchmorepowerfulqueryexpressionsandrelaxesthisrestriction,asdescribed laterinthesection“AdvancedQueries.”)
Subqueries in the WHERE Clause SubqueriesaremostfrequentlyusedintheWHEREclauseofaSQLstatement.Whenasubquery appearsintheWHEREclause,itworksaspartoftherowselectionprocess.Theverysimplest subqueriesappearwithinasearchconditionandproduceavaluethatisusedtotestthesearch condition.Thefollowingisanexampleofasimplesubquery.
190
Part II:
Retrieving Data
Listthesalespeoplewhosequotaislessthan10percentofthecompanywidesalestarget. SELECTNAME FROMSALESREPS WHEREQUOTA?
SELECT SUM (QUOTA) FROM SALESREPS WHERE REP_OFFICE =22
OFFICES Table OFFICE
CITY
22 11 12 13 21
Denver New York Chicago Atlanta Los Angeles
TARGET $300,000.00 $575,000.00 $800,000.00 $350,000.00 $725,000.00
• • •
SALESREPS Table Subquery >?
SELECT SUM (QUOTA) FROM SALESREPS WHERE REP_OFFICE=21
FIGURE 9-2 Subquery operation in the WHERE clause
PART II
Inthis(moretypical)case,thesubquerycannotbecalculatedoncefortheentirequery. Thesubqueryproducesadifferentvalueforeachoffice,basedonthequotasofthe salespeopleinthatparticularoffice.Figure9-2showsconceptuallyhowSQLcarriesoutthe query.ThemainquerydrawsitsdatafromtheOFFICEStable,andtheWHEREclauseselects whichofficeswillbeincludedinthequeryresults.SQLgoesthroughtherowsofthe OFFICEStableonebyone,applyingtheteststatedintheWHEREclause.TotesttheTARGET value,SQLcarriesoutthesubquery,findingthesumofthequotasforsalespeopleinthe currentoffice.Thesubqueryproducesasinglenumber,andtheWHEREclausecomparesthe numberwiththeTARGETvalue,selectingorrejectingthecurrentofficebasedonthe comparison.Asthefigureshows,SQLcarriesoutthesubqueryrepeatedly,onceforeach rowtestedbytheWHEREclauseofthemainquery.
191
192
Part II:
Retrieving Data
TheroleofthesubqueryinthisSELECTstatementistocalculatethetotalquotafor thosesalespeoplewhoworkinaparticularoffice—specifically,theofficecurrentlybeing testedbytheWHEREclauseofthemainquery.Thesubquerydoesthisbyscanningthe SALESREPStable.ButnoticethattheOFFICEcolumnintheWHEREclauseofthesubquery doesn’trefertoacolumnoftheSALESREPStable;itreferstoacolumnoftheOFFICES table,whichisapartofthemainquery.AsSQLmovesthrougheachrowoftheOFFICES table,itusestheOFFICEvaluefromthecurrentrowwhenitcarriesoutthesubquery. TheOFFICEcolumninthissubqueryisanexampleofanouterreference,whichisa columnnamethatdoesnotrefertoanyofthetablesnamedintheFROMclauseofthe subqueryinwhichthecolumnnameappears.Instead,thecolumnnamereferstoacolumn ofatablespecifiedintheFROMclauseofthemainquery.Asthepreviousexampleshows, whentheDBMSexaminesthesearchconditioninthesubquery,thevalueofthecolumnin anouterreferenceistakenfromtherowcurrentlybeingtestedbythemainquery.
Subquery Search Conditions AsubqueryusuallyappearsaspartofasearchconditionintheWHEREorHAVINGclause. Chapter6describedthesimplesearchconditionsthatcanbeusedintheseclauses.In addition,mostSQLproductsofferthesesubquerysearchconditions: • Subquerycomparisontest Comparesthevalueofanexpressionwithasingle valueproducedbyasubquery.Thistestresemblesthesimplecomparisontest. • Subquerysetmembershiptest Checkswhetherthevalueofanexpression matchesoneofthesetofvaluesproducedbyasubquery.Thistestresemblesthe simplesetmembershiptest. • Existencetest Testswhetherasubqueryproducesanyrowsofqueryresults. • Quantifiedcomparisontest Comparesthevalueofanexpressionwitheachofthe setsofvaluesproducedbyasubquery.
The Subquery Comparison Test (=, , =) Thesubquerycomparisontestisamodifiedformofthesimplecomparisontest,asshown inFigure9-3.Itcomparesthevalueofanexpressionwiththevalueproducedbyasubquery
FIGURE 9-3 Subquery comparison test syntax diagram
expression
=
=
subquery
Chapter 9:
Subqueries and Query Expressions
193
andreturnsaTRUEresultifthecomparisonistrue.Youusethistesttocompareavalue fromtherowbeingtestedwithasinglevalueproducedbyasubquery,asinthisexample: ListthesalespeoplewhosequotasareequaltoorhigherthanthetargetoftheAtlantasalesoffice.
ThesubqueryintheexampleretrievesthesalestargetoftheAtlantaoffice.Thevalueis thenusedtoselectthesalespeoplewhosequotasarehigherthantheretrievedtarget. Thesubquerycomparisontestoffersthesamesixcomparisonoperators(=,,=)availablewiththesimplecomparisontest.Thesubqueryspecifiedinthistestmust produceasinglevalueoftheappropriatedatatype—thatis,itmustproduceasinglerowof queryresultscontainingexactlyonecolumn.Ifthesubqueryproducesmultiplerowsor multiplecolumns,thecomparisondoesnotmakesense,andSQLreportsanerrorcondition. IfthesubqueryproducesnorowsorproducesaNULLvalue,thecomparisontestreturns NULL(unknown). Herearesomeadditionalexamplesofsubquerycomparisontests: ListallcustomersservedbyBillAdams. SELECTCOMPANY FROMCUSTOMERS WHERECUST_REP=(SELECTEMPL_NUM FROMSALESREPS WHERENAME='BillAdams'); COMPANY ---------------- AcmeMfg. Three-WayLines
ListallproductsfrommanufacturerACIwherethequantityonhandisabovethequantityonhand ofproductACI-41004. SELECTDESCRIPTION,QTY_ON_HAND FROMPRODUCTS WHEREMFR_ID='ACI' ANDQTY_ON_HAND>(SELECTQTY_ON_HAND FROMPRODUCTS WHEREMFR_ID='ACI' ANDPRODUCT_ID='41004');
PART II
SELECTNAME FROMSALESREPS WHEREQUOTA>=(SELECTTARGET FROMOFFICES WHERECITY='Atlanta'); NAME ------------ BillAdams SueSmith LarryFitch
194
Part II:
Retrieving Data
DESCRIPTIONQTY_ON_HAND -------------------------- Size3Widget207 Size1Widget277 Size2Widget167
ThesubquerycomparisontestspecifiedbytheoriginalSQLstandard(SQL1)and supportedbyalloftheleadingDBMSproductsallowsasubqueryonlyontherightsideof thecomparisonoperator.Thiscomparison: AA
isnotpermitted.Thisdoesn’tlimitthepowerofthecomparisontest,becausetheoperator inanyunequalcomparisoncanalwaysbeturnedaroundsothatthesubqueryisputonthe rightsideoftheinequality.However,itdoesmeanthatyoumustsometimesturnaround thelogicofanEnglish-languagerequesttogetaformoftherequestthatcorrespondstoa legalSQLstatement. SubsequentversionsoftheSQLstandardeliminatedthisrestrictionandallowthe subquerytoappearoneithersideofthecomparisonoperator.Infact,thecurrentSQLstandard goesconsiderablyfurtherandallowsacomparisontesttobeappliedtoanentirerowof valuesinsteadoftoasinglevalue.Thisandothermoreadvancedqueryexpressionfeatures oftheSQLstandardaredescribedinthelattersectionsofthischapter.However,theyarenot uniformlysupportedbythecurrentversionsofthemajorSQLproducts.Forportability,it’s besttowritesubqueriesthatconformtotheSQL1restrictions,asdescribedpreviously.
The Set Membership Test (IN) Thesubquerysetmembershiptest(IN)isamodifiedformofthesimplesetmembership test,asshowninFigure9-4.Itcomparesasingledatavaluewithacolumnofdatavalues producedbyasubqueryandreturnsaTRUEresultifthedatavaluematchesoneofthe valuesinthecolumn.Youusethistestwhenyouneedtocompareavaluefromtherow beingtestedwithasetofvaluesproducedbyasubquery.Hereisasimpleexample: Listthesalespeoplewhoworkinofficesthatareovertarget. SELECTNAME FROMSALESREPS WHEREREP_OFFICEIN(SELECTOFFICE FROMOFFICES WHERESALES>TARGET); NAME ------------ MaryJones SamClark BillAdams SueSmith LarryFitch
Chapter 9:
FIGURE 9-4 Subquery set membership test (IN) syntax diagram
Subqueries and Query Expressions
test-expression
IN
195
subquery
NOT
ListthesalespeoplewhodonotworkinofficesmanagedbyLarryFitch(employee108). SELECTNAME FROMSALESREPS WHEREREP_OFFICENOTIN(SELECTOFFICE FROMOFFICES WHEREMGR=108); NAME ------------ BillAdams MaryJones SamClark BobSmith DanRoberts PaulCruz
ListallofthecustomerswhohaveplacedordersforACIWidgets(manufacturerACI,product numbersstartingwith4100)betweenJanuaryandJune2008. SELECTCOMPANY FROMCUSTOMERS WHERECUST_NUMIN(SELECTDISTINCTCUST FROMORDERS WHEREMFR='ACI' ANDPRODUCTLIKE'4100%' ANDORDER_DATEBETWEEN'2008-01-01' AND'2008-06-30'); COMPANY ------------------ AcmeMfg. AceInternational Holm&Landis JCPInc.
PART II
Thesubqueryproducesasetofofficenumberswherethesalesareabovetarget.(Inthe sampledatabase,therearethreesuchoffices,numbered11,13,and21.)Themainquery thencheckseachrowoftheSALESREPStabletodeterminewhetherthatparticular salespersonworksinanofficewithoneofthesenumbers.Herearesomeotherexamplesof subqueriesthattestsetmembership:
196
Part II:
Retrieving Data
NotethattheuseofDISTINCTinthesubqueryisn’tstrictlynecessary.Ifthesame customerappearsmultipletimesinthesubqueryresultsinsteadofonlyonce,theouter queryyieldsthesameresults.Oftenthereisaperformancetrade-offbetweentheoverhead theDBMSrequirestoeliminateduplicates(usuallyasortisrequired)andtheoverheadof processingadditionalrowsinthesubqueryresultswhenprocessingtheWHEREclauseofthe mainquery.Usuallythelargerintermediateresultsetisalotmoreefficientthanthesort requiredtoeliminateduplicates.Andthereareoftenotherconsiderations.Forexample,in Oracle,aGROUPBYisusuallymoreefficientthanaDISTINCT.Asyoucansee,writingthe mostefficientSQLpossiblerequiressomedetailedknowledgeabouthowtheparticular DBMSbeingusedprocessesSQLstatements. Ineachoftheseexamples,thesubqueryproducesacolumnofdatavalues,andthe WHEREclauseofthemainquerycheckstoseewhetheravaluefromarowofthemainquery matchesoneofthevaluesinthecolumn.ThesubqueryformoftheINtestthusworks exactlylikethesimpleINtest,exceptthatthesetofvaluesisproducedbyasubquery insteadofbeingexplicitlylistedinthestatement.
The Existence Test (EXISTS) Theexistencetest(EXISTS)checkswhetherasubqueryproducesanyrowsofqueryresults, asshowninFigure9-5.Nosimplecomparisontestresemblestheexistencetest;itisused onlywithsubqueries. Hereisanexampleofarequestthatcanbeexpressednaturallyusinganexistencetest: Listtheproductsforwhichanorderof$25,000ormorehasbeenreceived. Therequestcouldeasilyberephrasedas: ListtheproductsforwhichthereexistsatleastoneorderintheORDERStable(a)thatisforthe productinquestionand(b)thathasanamountofatleast$25,000. TheSELECTstatementusedtoretrievetherequestedlistofproductscloselyresembles therephrasedrequest: SELECTDISTINCTDESCRIPTION FROMPRODUCTS WHEREEXISTS(SELECTORDER_NUM FROMORDERS WHEREPRODUCT=PRODUCT_ID ANDMFR=MFR_ID ANDAMOUNT>=25000.00); DESCRIPTION --------------- 500-lbBrace LeftHinge RightHinge WidgetRemover
Chapter 9:
FIGURE 9-5 Existence test (EXISTS) syntax diagram
Subqueries and Query Expressions
EXISTS
197
subquery
NOT
Listtheproductsforwhichanorderof$25,000ormorehasbeenreceived. SELECTDESCRIPTION FROMPRODUCTS WHEREEXISTS(SELECT* FROMORDERS WHEREPRODUCT=PRODUCT_ID ANDMFR=MFR_ID ANDAMOUNT>=25000.00);
Inpractice,thesubqueryinanEXISTStestisusuallywrittenusingtheSELECT* notation. HerearesomeadditionalexamplesofqueriesthatuseEXISTS: ListanycustomersassignedtoSueSmithwhohavenotplacedanorderforover$3000. SELECTCOMPANY FROMCUSTOMERS WHERECUST_REP=(SELECTEMPL_NUM FROMSALESREPS WHERENAME='SueSmith') ANDNOTEXISTS(SELECT* FROMORDERS WHERECUST=CUST_NUM ANDAMOUNT>3000.00); COMPANY ----------------- Carter&Sons FredLewisCorp.
PART II
Conceptually,SQLprocessesthisquerybygoingthroughthePRODUCTStableand performingthesubqueryforeachproduct.Thesubqueryproducesacolumncontainingthe ordernumbersofanyordersforthe“current”productthatareover$25,000.Ifthereareany suchorders(thatis,ifthecolumnisnotempty),theEXISTStestisTRUE.Ifthesubquery producesnorows,theEXISTStestisFALSE.TheEXISTStestcannotproduceaNULLvalue. YoucanreversethelogicoftheEXISTStestusingtheNOTEXISTSform.Inthiscase, thetestisTRUEifthesubqueryproducesnorows,andFALSEotherwise. NoticethattheEXISTSsearchconditiondoesn’treallyusetheresultsofthesubqueryat all.Itmerelyteststoseewhetherthesubqueryproducesanyresults.Forthisreason,SQL relaxestherulethat“subqueriesmustreturnasinglecolumnofdata”andallowsyoutouse theSELECT*forminthesubqueryofanEXISTStest.Theprevioussubquerycouldthus havebeenwrittenas:
198
Part II:
Retrieving Data
Listtheofficeswherethereisasalespersonwhosequotarepresentsmorethan55percentoftheoffice’s target. SELECTCITY FROMOFFICES WHEREEXISTS(SELECT* FROMSALESREPS WHEREREP_OFFICE=OFFICE ANDQUOTA>(.55*TARGET)); CITY -------- Denver Atlanta
Notethatineachoftheseexamples,thesubqueryincludesanouterreferencetoa columnofthetableinthemainquery.Inpractice,thesubqueryinanEXISTStestwill alwayscontainanouterreferencethatlinksthesubquerytotherowcurrentlybeingtested bythemainquery.
Quantified Tests (ANY and ALL)* ThesubqueryversionoftheINtestcheckswhetheradatavalueisequaltosomevalueina columnofsubqueryresults.SQLprovidestwoquantifiedtests,ANYandALL,thatextend thisnotiontoothercomparisonoperators,suchasgreaterthan(>)andlessthan(=
FIGURE 9-6 Quantified comparison tests (ANY and ALL) syntax diagrams
subquery
Chapter 9:
Subqueries and Query Expressions
199
The ANY Test*
TheANYtestisusedinconjunctionwithoneofthesixSQLcomparisonoperators(=,,=)tocompareasingletestvaluewithacolumnofdatavaluesproducedbyasubquery. Toperformthetest,SQLusesthespecifiedcomparisonoperatortocomparethetestvaluewith eachdatavalueinthecolumn,oneatatime.IfanyoftheindividualcomparisonsyieldsaTRUE result,theANYtestreturnsaTRUEresult. HereisanexampleofarequestthatcanbehandledwiththeANYtest: Listthesalespeoplewhohavetakenanorderthatrepresentsmorethan10percentoftheirquota.
Conceptually,themainquerytestseachrowoftheSALESREPStable,onebyone.The subqueryfindsalloftheorderstakenbythecurrentsalespersonandreturnsacolumn containingtheorderamountsforthoseorders.TheWHEREclauseofthemainquerythen computes10percentofthecurrentsalesperson’squotaandusesitasatestvalue, comparingitwitheveryorderamountproducedbythesubquery.Ifanyorderamount exceedsthecalculatedtestvalue,theANYtestreturnsTRUE,andthesalespersonisincluded inthequeryresults.Ifnot,thesalespersonisnotincludedinthequeryresults.Thekeyword SOMEisanalternativeforANYspecifiedbytheANSI/ISOSQLstandard.Eitherkeyword generallycanbeused,butsomeDBMSbrandsdonotsupportSOME. TheANYtestcansometimesbedifficulttounderstandbecauseitinvolvesanentireset ofcomparisons,notjustone.Ithelpsifyoureadthetestinaslightlydifferentwaythanit appearsinthestatement.IfthisANYtestappears: WHEREXQUOTA); NAME ------------ SamClark LarryFitch
208
Part II:
Retrieving Data
Subqueries in the HAVING Clause* AlthoughsubqueriesaremostoftenfoundintheWHEREclause,theycanalsobeusedinthe HAVINGclauseofaquery.WhenasubqueryappearsintheHAVINGclause,itworksaspartof therowgroupselectionperformedbytheHAVINGclause.Considerthisquerywithasubquery: ListthesalespeoplewhoseaverageordersizeforproductsmanufacturedbyACIishigherthanthe overallaverageordersize. SELECTNAME,AVG(AMOUNT) FROMSALESREPS,ORDERS WHEREEMPL_NUM=REP ANDMFR='ACI' GROUPBYNAME HAVINGAVG(AMOUNT)>(SELECTAVG(AMOUNT) FROMORDERS); NAMEAVG(AMOUNT) ----------------------- SueSmith$15,000.00 TomSnyder$22,500.00
Figure9-7showsconceptuallyhowthisqueryworks.Thesubquerycalculatestheoverall averageordersize.Itisasimplesubqueryandcontainsnoouterreferences,soSQLcancalculate theaverageonceandthenuseitrepeatedlyintheHAVINGclause.Themainquerygoesthrough SALESREPS Table ORDERS Table
JOIN
GROUP BY GROUPED Table ORDER_NUM 112968 113055 • • • 112963 112983 112987 113012 113027 • • •
ORDERS Table
NAME
MFR
Dan Roberts ACI Dan Roberts ACI
Bill Bill Bill Bill Bill
Adams Adams Adams Adams Adams
ACI ACI ACI ACI ACI
AMOUNT $3,978.00 $150.00
$3,276.00 $702.00 $27,500.00 $3,745.00 $4,104.00
FIGURE 9-7 Subquery operation in the HAVING clause
AVG
>?
• • •
• • •
AVG
>?
• • •
• • •
Subquery SELECT AVG (AMOUNT)
Chapter 9:
Subqueries and Query Expressions
ListthesalespeoplewhoseaverageordersizeforproductsmanufacturedbyACIisatleastasbigas thatsalesperson’soverallaverageordersize. SELECTNAME,AVG(AMOUNT) FROMSALESREPS,ORDERS WHEREEMPL_NUM=REP ANDMFR='ACI' GROUPBYNAME,EMPL_NUM HAVINGAVG(AMOUNT)>=(SELECTAVG(AMOUNT) FROMORDERS WHEREREP=EMPL_NUM); NAMEAVG(AMOUNT) ----------------------- BillAdams$7,865.40 SueSmith$15,000.00 TomSnyder$22,500.00
Inthisnewexample,thesubquerymustproducetheoverallaverageordersizeforthe salespersonwhoserowgroupiscurrentlybeingtestedbytheHAVINGclause.Thesubquery selectsordersforthatparticularsalesperson,usingtheouterreferenceEMPL_NUM.Theouter referenceislegalbecauseEMPL_NUMhasthesamevalueinallrowsofagroupproducedby themainquery.
Subquery Summary Thischaptersofarhasdescribedsubqueries,whichallowyoutousetheresultsofone querytohelpdefineanotherquery.Beforemovingontotheadvancedqueryfacilitiesofthe SQLspecification,let’ssummarizesubqueries: • Asubqueryisa“querywithinaquery.”Subqueriesappearwithinoneofthe subquerysearchconditionsintheWHEREorHAVINGclause. • WhenasubqueryappearsintheWHEREclause,theresultsofthesubqueryareused toselecttheindividualrowsthatcontributedatatothequeryresults. • WhenasubqueryappearsintheHAVINGclause,theresultsofthesubqueryare usedtoselecttherowgroupsthatcontributedatatothequeryresults. • Subqueriescanbenestedwithinothersubqueries.
PART II
theORDERStable,findingallordersforACIproducts,andgroupsthembysalesperson.The HAVINGclausethencheckseachrowgrouptoseewhethertheaverageordersizeinthatgroup isbiggerthantheaverageforallorders,calculatedearlier.Ifso,therowgroupisretained;ifnot, therowgroupisdiscarded.Finally,theSELECTclauseproducesonesummaryrowforeach group,showingthenameofthesalespersonandtheaverageordersizeforeach. YoucanalsouseacorrelatedsubqueryintheHAVINGclause.Becausethesubqueryis evaluatedonceforeachrowgroup,however,allouterreferencesinthecorrelatedsubquery mustbesingle-valuedforeachrowgroup.Effectively,thismeansthattheouterreference musteitherbeareferencetoagroupingcolumnoftheouterqueryorbecontainedwithin acolumnfunction.Inthelattercase,thevalueofthecolumnfunctionfortherowgroup beingtestediscalculatedaspartofthesubqueryprocessing. Ifthepreviousrequestischangedslightly,thesubqueryintheHAVINGclausebecomes acorrelatedsubquery:
209
210
Part II:
Retrieving Data
• Thesubqueryformofthecomparisontestusesoneofthesimplecomparison operatorstocompareatestvaluewiththesinglevaluereturnedbyasubquery. • Thesubqueryformofthesetmembershiptest(IN)matchesatestvaluetothesetof valuesreturnedbyasubquery. • Theexistencetest(EXISTS)checkswhetherasubqueryreturnsanyvalues. • Thequantifiedtests(ANYandALL)useoneofthesimplecomparisonoperatorsto compareatestvaluewithallofthevaluesreturnedbyasubquery,checkingtosee whetherthecomparisonholdsforsomeorallofthevalues. • Asubquerymayincludeanouterreferencetoatableinanyofthequeriesthat containsit,linkingthesubquerytothecurrentrowofthatquery. Figure9-8showsthefinalversionoftherulesforSQLqueryprocessing,extendedto includesubqueries.Itprovidesacompletedefinitionofthequeryresultsproducedbya SELECTstatement. To generate the query results for a SELECT statement: 1.
If the statement is a UNION of SELECT statements, apply Steps 2 through 7 to each of the statements to generate their individual query results.
2.
Form the product of the tables named in the FROM clause. If the FROM clause names a single table, the product is that table.
3.
If there is a WHERE clause, apply its search condition to each row of the product table, retaining those rows for which the search condition is TRUE (and discarding those for which it is FALSE or NULL). If the WHERE clause contains a subquery, the subquery is performed for each row as it is tested.
4.
If there is a GROUP BY clause, arrange the remaining rows of the product table into row groups, so that the rows in each group have identical values in all of the grouping columns.
5.
If there is a HAVING clause, apply its search condition to each row group, retaining those groups for which the search condition is TRUE (and discarding those for which it is FALSE or NULL). If the HAVING clause contains a subquery, the subquery is performed for each row group as it is tested.
6.
For each remaining row (or row group), calculate the value of each item in the select list to produce a single row of query results. For a simple column reference, use the value of the column in the current row (or row group). For a column function, use the current row group as its argument if GROUP BY is specified; otherwise, use the entire set of rows.
7.
If SELECT DISTINCT is specified, eliminate any duplicate rows of query results that were produced.
8.
If the statement is a UNION of SELECT statements, merge the query results for the individual statements into a single table of query results. Eliminate duplicate rows unless UNION ALL is specified.
9.
If there is an ORDER BY clause, sort the query results as specified. The rows generated by this procedure comprise the query results.
FIGURE 9-8 SQL query processing rules (final version)
Chapter 9:
Subqueries and Query Expressions
211
Advanced Queries* TheSQLqueriesdescribedthusfarinChapters6through9arethemainstreamcapabilities providedbymostSQLimplementations.Thecombinationoffeaturestheyrepresent— columnselectionintheSELECTclause,rowselectioncriteriaintheWHEREclause, multitablejoinsintheFROMclause,summaryqueriesintheGROUPBYandHAVINGclauses, andsubqueriesformorecomplexrequests—givetheuserapowerfulsetofdataretrieval anddataanalysiscapabilities.However,databaseexpertshavepointedoutmany limitationsofthesemainstreamquerycapabilities,includingthese:
• Limiteduseofsubqueries ThesimplestexampleofthislimitationistheSQL1 restrictionthatasubquerycanappearonlyontherightsideofacomparisontestina WHEREclause.Thedatabaserequest“Listtheofficeswherethesumofthesalespeople’s quotasislessthantheofficetarget.”ismostdirectlyexpressedasthisquery: SELECTOFFICE FROMOFFICES WHERE(SELECTSUM(QUOTA) FROMSALESREPS WHEREREP_OFFICE=OFFICE)(SELECTSUM(QUOTA) FROMSALESREPS WHEREREP_OFFICE=OFFICE);
Inthissimpleexample,itisn’thardtoturnthelogicaround,buttherestrictionisa nuisanceatbest,anditdoespreventyoufromcomparingtheresultsoftwosubqueries, forexample.
PART II
• Nodecisionmakingwithinqueries Supposeyouwantedtogenerateatwocolumnreportfromthesampledatabaseshowingthenameofeachsalesofficeand eitheritsannualsalestargetoritsyear-to-datesales,whicheverislarger.Withthe mainstreamSQLqueryfeatures,thisishardtodo.Orsupposeyouhadadatabase thatkepttrackofsalesbyquarter(fourcolumnsofdataforeachoffice)andwanted towriteaprogramthatdisplayedofficesandtheirsalesforaspecific(usersupplied)quarter.Again,thisprogramismoredifficulttowriteusingmainstream SQLqueries.YoumustincludefourseparateSQLqueries(oneforeachquarter), andtheprogramlogicmustselectwhichquerytorun,basedonuserinput.This simplecaseisn’ttoodifficult,butinamoregeneralcase,theprogramcouldbecome muchmorecomplex.
212
Part II:
Retrieving Data
• Limited-rowexpressions Supposeyouwantedtolistthesuppliers,itemnumbers, andpricesforasetofproductsthataresubstitutesforoneanother.Conceptually, theseareasetofproductswhoseidentification(amanufacturer-ID/product-IDpair) matchesoneofasetofvalues,anditwouldbenaturaltowritethequeryusingaset membershiptest: SELECTMFR_ID,PRODUCT_ID,PRICE FROMPRODUCTS WHERE(MFR_ID,PRODUCT_ID)IN(('ACI',41003),('BIC',41089),…);
TheSQL1standarddoesn’tpermitthiskindofsetmembershiptest.Instead,you mustconstructthequeryasalongsetofindividualcomparisons,connectedby ANDsandORs. • Limited-tableexpressions SQLallowsyoutodefineaviewlikethisoneforlarge orders: SELECT* FROMORDERS WHEREAMOUNT>10000;
andthentousetheviewasifitwerearealtableintheFROMclauseofaqueryto findoutwhichproducts,inwhichquantities,wereorderedintheselargeorders: SELECTMFR,PRODUCT,SUM(QTY) FROMBIGORDERS GROUPBYMFR,PRODUCT;
Conceptually,SQLshouldletyousubstitutetheviewdefinitionrightintothequery, likethis: SELECTMFR,PRODUCT,SUM(QTY) FROM(SELECT*FROMORDERSWHEREAMOUNT>10000)A GROUPBYMFR,PRODUCT;
ButtheSQL1standarddoesn’tallowasubqueryinthispositionintheWHEREclause. Yetclearly,theDBMSshouldbeabletodeterminethemeaningofthisquery,sinceitmust basicallydothesameprocessingtointerprettheBIGORDERSviewdefinition. Astheseexamplesshow,theSQL1standardandDBMSproductsthatimplementtothis levelofthestandardarerelativelyrestrictiveintheirpermitteduseofexpressionsinvolving individualdataitems,setsofdataitems,rows,andtables.SubsequentversionsoftheSQL standardincludeanumberofadvancedquerycapabilitiesthatarefocusedonremoving theserestrictionsandmakingtheSQLlanguagemoregeneral.Thespiritofthesecapabilities tendstobethatausershouldbeabletowriteaqueryexpressionthatmakessenseand havethequeryexpressionbealegalSQLquery.Becausethesecapabilitiesconstitutemajor expansionsofthelanguageovertheoriginalSQL1standard,mostofthemarerequired onlyatafulllevelofthestandard.
Chapter 9:
Subqueries and Query Expressions
213
Scalar-Valued Expressions ThesimplestextendedquerycapabilitiesinSQLarethosethatprovidemoredatamanipulation andcalculationpowerinvolvingindividualdatavalues(calledscalarsintheSQLstandard). WithintheSQLlanguage,individualdatavaluestendtohavethreesources: • Thevalueofanindividualcolumnwithinanindividualrowofatable • Aliteralvalue,suchas125.7orABC • Auser-supplieddatavalue,enteredintoaprogram InthisSQLquery:
PART II
SELECTNAME,EMPL_NUM,HIRE_DATE,(QUOTA*.9) FROMSALESREPS WHERE(REP_OFFICE=13)ORTITLE='VPSales';
thecolumnnamesNAME,EMPL_NUM,HIRE_DATE,andQUOTAgenerateindividualdata valuesforeachrowofqueryresults,asdothecolumnnamesREP_OFFICEandTITLEin theWHEREclause.Thenumbers.9and13andthecharacterstring“VPSales”similarly generateindividualdatavalues.IfthisSQLstatementweretoappearwithinanembedded SQLprogram(describedinChapter17),theprogramvariableoffice_nummightcontain anindividualdatavalue,andthequerymightappearas: SELECTNAME,EMPL_NUM,HIRE_DATE,(QUOTA*.9) FROMSALESREPS WHERE(REP_OFFICE=:office_num)ORTITLE='VPSALES';
Asthisqueryandmanypreviousexampleshaveshown,individualdatavaluescanbe combinedinsimpleexpressions,likethecalculatedvalueQUOTA*.9.Tothesebasic expressions,theSQLstandardaddstheCASToperatorforexplicitdatatypeconversion,the CASEoperatorfordecisionmaking,theCOALESCEoperatorforconditionallycreatingnonNULLvalues,andtheNULLIFoperationforconditionallycreatingaNULLvalue.
The CAST Expression
TheSQLstandardhasfairlyrestrictiverulesaboutcombiningdataofdifferenttypesin expressions.ItspecifiesthattheDBMSshallautomaticallyconvertamongverysimilardata types,suchas2-byteand4-byteintegers.However,ifyoutrytocomparenumbersand characterdata,forexample,thestandardsaysthattheDBMSshouldgenerateanerror.The standardconsidersthisanerrorconditionevenifthecharacterstringcontainsnumeric data.Youcan,however,explicitlyasktheDBMStoconvertamongdatatypesusingthe CASTexpression,whichhasthesyntaxshowninFigure9-9.
FIGURE 9-9 CAST expression syntax diagram
CAST (
value-expression NULL
AS
data-type domain-name
)
214
Part II:
Retrieving Data
TheCASTexpressiontendstobeoflittleimportancewhenyouaretypingSQL statementsdirectlyintoaninteractiveSQLinterface.However,itcanbecriticalwhenusing SQLfromwithinaprogramminglanguagewheredatatypesdon’tmatchthedatatypes supportedbytheSQLstandard.Forexample,theCASTexpressionintheSELECTclauseof thisqueryconvertsthevaluesforREP_OFFICE(integersinthesampledatabase)andHIRE_ DATE(adateinthesampledatabase)intocharacterstringsforthereturnedqueryresults: SELECTNAME,CAST(REP_OFFICEASCHAR),CAST(HIRE_DATEASCHAR) FROMSALESREPS;
SupportfortheCASTexpressionvariesacrossSQLimplementations.Forexample, OraclerequiresthatCHARandVARCHARdatatypesusedinaCASTexpressionincludea lengthspecification,whileMySQLandDB2UDBdonotsupporttheDATEdatatypeina CASTexpression. TheCASTexpressioncangenerallyappearanywherethatascalar-valuedexpressioncan appearwithinaSQLstatement.Inthisexample,it’susedintheWHEREclausetoconverta character-stringcustomernumberintoaninteger,sothatitcanbecomparedwiththedata inthedatabase: SELECTPRODUCT,QTY,AMOUNT FROMORDERS WHERECUST=CAST('2107'ASINTEGER);
InsteadofspecifyingadatatypeintheCASTexpression,youcanspecifyadomain. Domainsarespecificcollectionsoflegaldatavaluesthatcanbedefinedinthedatabase. TheyarefullydescribedinChapter11becauseoftheroletheyplayinSQLdataintegrity. NotethatyoucanalsogenerateaNULLvalueoftheappropriatedatatypeforuseinSQL expressionsusingtheCASTexpression. ThemostcommonusesfortheCASTexpressionare • Toconvertdatafromwithinadatabasetablewherethecolumnisdefinedwiththe wrongdatatype,forexample,whenacolumnisdefinedasacharacterstring,but youknowitactuallycontainsnumbers(thatis,stringsofdigits)ordates(strings thatcanbeinterpretedasacalendardate). • ToconvertdatafromdatatypessupportedbytheDBMSthatarenotsupportedbya hostprogramminglanguage.Forexample,mosthostprogramminglanguagesdo nothaveexplicitdateandtimedatatypesandrequirethatdate/timevaluesbe convertedintocharacterstringsforhandlingbyaprogram. • Toeliminatedifferencesbetweendatatypesintwodifferenttables.Forexample,if anorderdateisstoredinonetableasDATEdata,butaproductavailabilitydateis storedinadifferenttableasacharacterstring,youcanstillcomparethecolumns fromthetwotablesbyCASTingoneofthecolumnsintothedatatypeoftheother. Similarly,ifyouwanttocombinedatafromtwodifferenttableswithaUNION operation,theircolumnsmusthaveidenticaldatatypes.Youcanachievethisby CASTingthecolumnsofoneofthetables.
Chapter 9:
CASE
WHEN search-condition THEN
Subqueries and Query Expressions
result-expression NULL
215
END ELSE
result-expression NULL
FIGURE 9-10 CASE expression syntax diagram
The CASE Expression
SELECTCOMPANY, CASEWHENCREDIT_LIMIT>60000THEN'A' WHENCREDIT_LIMIT>30000THEN'B' ELSE'C' ENDASCREDIT_RATING FROMCUSTOMERS;
Foreachrowofqueryresults,theDBMSevaluatestheCASEexpressionbyfirst comparingthecreditlimitwith$60,000,andifthecomparisonisTRUE,returninganAinthe secondcolumnofqueryresults.Ifthatcomparisonfails,thecomparisonto$30,000ismade andaBisreturnedifthissecondcomparisonisTRUE.Otherwise,thethirdcolumnofquery resultsreturnsaC. ThisisaverysimpleexampleofaCASEexpression.TheresultsoftheCASE expressionareallliteralshere,butingeneral,theycanbeanySQLexpression.Similarly, thereisnorequirementthatthetestsineachWHENclausebesimilar,astheyarehere. TheCASEexpressioncanalsoappearinotherclausesofaqueryprovidedtheSQL implementationsupportssuchuse.HereisanexampleofaquerywheretheCASE expressionisusefulintheWHEREclause.Supposeyouwanttofindthetotalofthe salespeople’ssales,byoffice.Ifasalespersonisnotyetassignedtoanoffice,thatperson
PART II
TheCASEexpressionprovidesforlimiteddecision-makingwithinSQLexpressions.Itsbasic structure,showninFigure9-10,issimilartotheIF…THEN…ELSEstatementfoundinmany programminglanguages.WhentheDBMSencountersaCASEexpression,itevaluatesthe firstsearchcondition,andifitisTRUE,thenthevalueoftheCASEexpressionisthevalueof thefirstresultexpression.IftheresultofthefirstsearchconditionisnotTRUE,theDBMS proceedstothesecondsearchconditionandcheckswhetheritisTRUE.Ifso,thevalueof theCASEexpressionisthevalueofthesecondresultexpression,andsoon. HereisasimpleexampleoftheuseoftheCASEexpression.Supposeyouwanttodoan A/B/Canalysisofthecustomersfromthesampledatabaseaccordingtotheircreditlimits. TheAcustomersaretheoneswithcreditlimitsover$60,000,theBcustomersarethosewith limitsover$30,000,andtheCcustomersaretheothers.WithouttheCASEexpression,you wouldhavetoretrievecustomernamesandcreditlimitsfromthedatabaseandthenrely onanapplicationprogramtolookatthecreditlimitvaluesandassignanA,B,orCrating. UsingaCASEexpression,youcanhavetheDBMSdotheworkforyou:
216
Part II:
Retrieving Data
shouldbeincludedinthetotalforhisorhermanager’soffice.Hereisaquerythat generatestheappropriateofficegroupings: SELECTCITY,SUM(SALESREPS.SALES) FROMOFFICES,SALESREPS WHEREOFFICE= CASEWHEN(REP_OFFICEISNOTNULL)THENREP_OFFICE ELSE(SELECTREP_OFFICE FROMSALESREPSMGRS WHEREMGRS.EMPL_NUM=MANAGER) END GROUPBYCITY;
TheSQLstandardprovidesashorthandversionoftheCASEexpressionforthecommon situationwhereyouwanttocompareatestvalueofsomekindwithasequenceofdata values(usuallyliterals).ThisversionoftheCASEsyntaxisshowninFigure9-11.Insteadof repeatingasearchconditionoftheform: test_value=value1
ineachWHENclause,itletsyouspecifythetest_valuecalculationonce.Forexample, supposeyouwantedtogeneratealistofalloftheoffices,showingthenamesoftheir managersandthecitiesandstateswheretheyare.Thesampledatabasedoesn’tinclude statenames,sothequerymustgeneratethisinformationitself.Hereisaquery,withaCASE expressionintheSELECTlist,thatdoesthejob: SELECTNAME,CITY,CASEOFFICEWHEN11THEN'NewYork' WHEN12THEN'Illinois' WHEN13THEN'Georgia' WHEN21THEN'California' WHEN22THEN'Colorado' ENDASSTATE FROMOFFICES,SALESREPS WHEREMGR=EMPL_NUM;
The COALESCE Expression
Oneofthemostcommonusesforthedecision-makingcapabilityoftheCASEexpressionis forhandlingNULLvalueswithinthedatabase.Forexample,it’sfrequentlydesirabletohave aNULLvaluefromthedatabaserepresentedbysomeliteralvalue(suchastheword “missing”)orbysomedefaultvaluewhenusingSQLtogenerateareport.Hereisareport thatliststhesalespeopleandtheirquotas.Ifasalespersonhasnotyetbeenassigneda quota,assumethatthesalesperson’sactualyear-to-datesalesshouldbelistedinstead.Iffor
CASE
test-value
WHEN value THEN
result-expression NULL
FIGURE 9-11 CASE expression alternate syntax
ELSE
result-expression NULL
FIGURE 9-12 COALESCE expression syntax diagram
Chapter 9:
Subqueries and Query Expressions
COALESCE (
value-expression
217
)
,
somereasontheactualyear-to-datesalesarealsoNULL(unknown),thenazeroamount shouldbelisted.TheCASEstatementgeneratesthedesiredIF…THEN…ELSElogic:
ThistypeofNULL-handlinglogicisneededfrequently,sotheSQLstandardincludes aspecializedformoftheCASEexpression,theCOALESCEexpression,tohandleit.The syntaxfortheCOALESCEexpressionisshowninFigure9-12.Theprocessingrulesfor theCOALESCEexpressionareverystraightforward.TheDBMSexaminesthefirstvalue inthelist.IfitsvalueisnotNULL,itbecomesthevalueoftheCOALESCEexpression.If thefirstvalueisNULL,theDBMSmovestothesecondvalueandcheckstoseewhether itisNULL.Ifnot,itbecomesthevalueoftheexpression.Otherwise,theDBMSmovesto thethirdvalue,andsoon.Hereisthesameexamplejustgiven,expressedwiththe COALESCEexpressioninsteadofaCASEexpression: SELECTNAME,COALESCE(QUOTA,SALES,0.00) FROMSALESREPS;
Asyoucanseebycomparingthetwoqueries,thesimplicityoftheCOALESCEsyntax makesiteasiertosee,ataglance,themeaningofthequery.However,theoperationofthe twoqueriesisidentical.TheCOALESCEexpressionaddssimplicity,butnonewcapability, toSQL.
The NULLIF Expression
JustastheCOALESCEexpressionisusedtoeliminateNULLvalueswhentheyarenotdesired forprocessing,sometimesyoumayneedtocreateNULLvalues.Inmanydataprocessing applications(especiallyolderonesthatweredevelopedbeforerelationaldatabaseswere popular),missingdataisnotrepresentedbyNULLvalues.Instead,somespecialcodevalue thatisotherwiseinvalidisusedtoindicatethatthedataismissing. Forexample,supposethatinthesampledatabase,thesituationwhereasalespersonhad notyetbeenassignedamanagerwasindicatedbyazero(0)valueintheMANAGERcolumn insteadofaNULLvalue.Insomecircumstances,youwillwanttodetectthissituationwithin aSQLqueryandsubstitutetheNULLvalueforthezero“code.”TheNULLIFexpression, showninFigure9-13,isusedforthispurpose.WhentheDBMSencountersaNULLIF expression,itexaminesthefirstvalue(usuallyacolumnname)andcomparesitwiththe FIGURE 9-13 NULLIF expression syntax diagram
NULLIF (
value-expression ,
)
PART II
SELECTNAME,CASEWHEN(QUOTAISNOTNULL)THENQUOTA WHEN(SALESISNOTNULL)THENSALES ELSE0.00 ENDASADJUSTED_QUOTA FROMSALESREPS;
218
Part II:
Retrieving Data
secondvalue(usuallythecodevalueusedtoindicatemissingdata).Ifthetwovaluesareequal, theexpressiongeneratesaNULLvalue.Otherwise,theexpressiongeneratesthefirstvalue. Hereisaquerythathandlesthecasewheremissingofficenumbersarerepresentedby azero: SELECTCITY,SUM(SALESREPS.SALES) FROMOFFICES,SALESREPS WHEREOFFICE=NULLIF(REP_OFFICE,0) GROUPBYCITY;
Together,theCASE,COALESCE,andNULLIFexpressionsprovideasoliddecisionmakinglogiccapabilityforusewithinSQLstatements.Theyfallfarshortofthecomplete logicalflowconstructsprovidedbymostprogramminglanguages(looping,branching,and soon),butdoprovideformuchgreaterflexibilityinqueryexpressions.Thenetresultis thatmoreprocessingworkcanbedonebytheDBMSandreflectedinqueryresults,leaving lessworktobedonebythehumanuserortheapplicationprogram.
Row-Valued Expressions Althoughcolumnsandthescalardatavaluestheycontainaretheatomicbuildingblocksofa relationaldatabase,thestructuringofcolumnsintorowsthatrepresentreal-worldentities, suchasindividualofficesorcustomersororders,isoneofthemostimportantfeaturesofthe relationalmodel.TheSQL1standard,andmostmainstreamcommercialdatabaseproducts, certainlyreflectthisrow/columnstructure,buttheyprovideverylimitedcapabilityto actuallymanipulaterowsandgroupsofrows.Basically,SQL1operationsallowyoutoinsert arowintoatable,ortoretrieve,update,ordeletegroupsofrowsfromadatabase(usingthe INSERT,SELECT,UPDATE,orDELETEstatements). NewerversionsoftheSQLstandardgowellbeyondthesecapabilities,allowingyouto generallyuserowsinSQLexpressionsinmuchthesamewaythatyoucanusescalarvalues. Theyprovidesyntaxforconstructingrowsofdata.Theyallowrow-valuedsubqueries.And theydefinerow-valuedmeaningsfortheSQLcomparisonoperatorsandotherSQLstructures.
The Row-Value Constructor
SQLallowsyoutospecifyarowofdatavaluesbyusingarow-valueconstructorexpression, whosesyntaxisshowninFigure9-14.Initsmostcommonform,therowconstructorisa comma-separatedlistofliteralvalues,orexpressions.Forexample,hereisarow-value constructorforarowofdatawhosestructurematchestheOFFICEStableinthesampledatabase: (23,'SanDiego','Western',NULL,DEFAULT,0.00) FIGURE 9-14 Row-value constructor syntax diagram
(
value-expression NULL DEFAULT , value-expression NULL DEFAULT row-valued subquery
)
Chapter 9:
Subqueries and Query Expressions
219
Theresultofthisexpressionisasinglerowofdatawithsixcolumns.TheNULLkeywordin thefourthcolumnpositionindicatesthatthefourthcolumnintheconstructedrowshould containaNULL(unknown)value.TheDEFAULTkeywordinthefifthcolumnpositionindicates thatthefifthcolumnintheconstructedrowshouldcontainthedefaultvalueforthecolumn. Thiskeywordmayappearinarow-valueconstructoronlyincertainsituations—forexample, whentherow-valueconstructorappearsinanINSERTstatementtoaddanewrowtoatable. WhenarowconstructorisusedintheWHEREclauseofaSQLstatement,columnnames canalsoappearasindividualdataitemswithintherowconstructor,oraspartofan expressionwithintherowconstructor.Forexample,considerthisquery:
SELECTORDER_NUM,QTY,AMOUNT FROMORDERS WHERE(MGR,PRODUCT)=('ACI','41002');
NotethatwhilethissyntaxisspecifiedintheSQLstandard,veryfewSQLimplementations supportit.UnderthenormalrulesofSQLquery-processing,theWHEREclauseisappliedto eachrowoftheORDERStable,onebyone.Thefirstrow-valueconstructorintheWHEREclause (totheleftoftheequalsign)generatesatwo-columnrow,containingthemanufacturercode andtheproductnumberforthecurrentorderbeingconsidered.Thesecondrow-value constructor(totherightoftheequalsign)generatesatwo-columnrow,containingthe(literal) manufacturercodeACIandproductnumber41002.Theequalsignisnowcomparingtwo rowsofvalues,nottwoscalarvalues.TheSQLstandarddefinesthistypeofrow-valued comparisonforequality,whichisprocessedbycomparing,pairwise,eachofthecolumnsinthe tworows.TheresultofthecomparisonisTRUEonlyifallofthepairwisecolumncomparisons areTRUE.Ofcourse,it’spossibletowritethequerywithouttherow-valueconstructors,likethis: Listtheordernumber,quantity,andamountofallordersforACI-41002widgets. SELECTORDER_NUM,QTY,AMOUNT FROMORDERS WHERE(MFR='ACI')AND(PRODUCT='41002');
andinthissimpleexample,themeaningofthequeryisprobablyequallyclearwitheither form.However,row-valueconstructorscanbeveryusefulinsimplifyingtheappearanceof morecomplexqueries,andtheybecomeevenmoreusefulwhencombinedwithrow-valued subqueries.
Row-Valued Subqueries
Asdescribedthroughouttheearlierpartsofthischapter,theSQL1standardprovidesa subquerycapabilityforexpressingmorecomplexdatabasequeries.Thesubquerytakesthe sameformasaSQLquery(thatis,aSELECTstatement),butaSQL1subquerymustbe scalar-valued—thatis,itmustproduceasingledatavalueasitsqueryresults.Thevalue generatedbythesubqueryisthenusedaspartofanexpressionwithinthemainSQL statementthatcontainsthesubquery.Thisuseofsubqueriesissupportedbythemajor enterprise-classrelationaldatabasesystemstoday. SubsequentversionsoftheSQLstandarddramaticallyexpandthesubqueryfacility, includingsupportforrow-valuedsubqueries.Arow-valuedsubqueryreturnsnotjustasingle dataitem,butarowofdataitems,whichcanbeusedinSQLexpressionsandcompared
PART II
Listtheordernumber,quantity,andamountofallordersforACI-41002widgets.
220
Part II:
Retrieving Data
withotherrows.Forexample,supposeyouwantedtoshowtheordernumbersanddates foralloftheordersplacedagainstthehighest-pricedproductinthesampledatabase. AlogicalwaytostartbuildingtheappropriateSQLqueryistofindanexpressionthatwill giveyoutheidentity(manufacturerIDandproductID)ofthehigh-pricedproductin question.Hereisaquerythatfindstherightproduct: FindthemanufacturerIDandproductIDoftheproductwiththehighestunitprice. SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE=(SELECTMAX(PRICE) FROMPRODUCTS);
Ignoringthepossibilityofatieforthemostexpensiveproductforamoment,thisquery willgenerateasinglerowofqueryresults,consistingoftwocolumns.UsingSQL’srow-valued subquerycapability,youcanembedthisentirequeryasasubquerywithinaSELECTstatement toretrievetheorderinformation,asshowninthenextexample. Listtheordernumbersanddatesofallordersplacedforthehighest-pricedproduct. SELECTORDER_NUM,ORDER_DATE FROMORDERS WHERE(MFR,PRODUCT)=(SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE=(SELECTMAX(PRICE) FROMPRODUCTS));
Thetop-levelWHEREclauseinthisquerycontainsarow-valuedcomparison.Ontheleft sideoftheequalsignisarow-valueconstructorconsistingoftwocolumnnames.Eachtime theWHEREclauseisexaminedtocarryoutthetop-levelquery,thevalueofthisrow-valued expressionisamanufacturer-ID/product-IDpairfromarowoftheORDERStable.Onthe rightsideoftheequalsignisthesubquerythatgeneratestheidentityoftheproductwiththe highestdollarvalue.Theresultofthissubqueryisagainarowvalue,withtwocolumns, whosedatatypesmatchthoseoftherow-valuedexpressionontheleftsideoftheequalsign. It’spossibletoexpressthisquerywithouttherow-valuedsubquery,buttheresulting querywillbemuchlessstraightforward: Listtheordernumbersanddatesofallordersplacedforthehighest-pricedproduct(s). SELECTORDER_NUM,ORDER_DATE FROMORDERS WHERE(MFRIN(SELECTMFR_ID FROMPRODUCTS WHEREPRICE=(SELECTMAX(PRICE) FROMPRODUCTS))) AND(PRODUCTIN(SELECTPRODUCT_ID FROMPRODUCTS WHEREPRICE=(SELECTMAX(PRICE) FROMPRODUCTS)));
Insteadofasinglerow-valuedcomparisonintheWHEREclause,theresultingqueryhas twoseparatescalar-valuedcomparisons,oneforthemanufacturerIDandoneforthe productID.Becausethecomparisonmustbesplit,thelower-levelsubquerytofindthe
Chapter 9:
Subqueries and Query Expressions
221
maximumpricemustberepeatedtwiceaswell.Overall,theformofthequeryusingthe row-valuedexpressionisamoredirecttranslationoftheEnglish-languagerequest,andit’s easiertoreadandunderstand.
Row-Valued Comparisons
('ACI','41002',54)30000.00) UNION (SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHERE(PRICE*QTY_ON_HAND)>30000);
Showallproductsforwhichthereisanorderover$30,000andmorethan$30,000worthof inventoryonhand. (SELECTMFR,PRODUCT FROMORDERS WHEREAMOUNT>30000.00) INTERSECT (SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHERE(PRICE*QTY_ON_HAND)>30000);
PART II
• UNION TheSQLUNIONoperationprovidesexplicitsupportformergingtherows oftwocompatibletables(thatis,twotableshavingthesamenumberofcolumns andwithcorrespondingcolumnshavingthesamedatatypes).TheUNIONoperation takestwotablesasitsinputandproducesasinglemergedtableofqueryresults.
226
Part II:
Retrieving Data
Showallproductsforwhichthereisanorderover$30,000exceptforthoseproductsthatsellfor under$100. (SELECTMFR,PRODUCT FROMORDERS WHEREAMOUNT>30000.00) EXCEPT (SELECTMFR_ID,PRODUCT_ID FROMPRODUCTS WHEREPRICE50000.00) AND(CUST_NUM=CUST);
Thesecond“tablename”intheFROMclauseofthemainqueryisnotatablenameatall, butafull-blownqueryexpression.Infact,theexpressioncouldhavebeenmuchmore complex,involvingUNIONorJOINoperations.WhenaqueryexpressionappearsintheFROM clause,asitdoeshere,theDBMSconceptuallycarriesitoutfirst,beforeanyotherprocessing ofthequery,andcreatesatemporarytableofthequeryresultsgeneratedbythequery expression.Inthiscase,thistemporarytableconsistsoftwocolumns,listingeachcustomer numberandthetotalofordersforthatcustomernumber.Thistemporarytablethenactsas oneofthesourcetablesforthemainquery.Inthisexample,itscontentsarejoinedtothe CUSTOMERtabletoobtainthecompanynameandgeneratetheanswertothemainquestion.
Chapter 9:
Subqueries and Query Expressions
SQL Queries: A Final Summary ThisconcludesthediscussionoftheSQLqueriesandtheSELECTstatementthatbeganin Chapter6.AsdescribedinChapters6through9,theclausesoftheSELECTstatement provideapowerful,flexiblesetofcapabilitiesforretrievingdatafromthedatabase.Each clauseplaysaspecificroleindataretrieval: • TheFROMclausespecifiesthesourcetablesthatcontributedatatothequeryresults. EverycolumnnameinthebodyoftheSELECTstatementmustunambiguously identifyacolumnfromoneofthesetables,oritmustbeanouterreferencetoa columnfromasourcetableofanouterquery. • TheWHEREclause,ifpresent,selectsindividualcombinationsofrowsfromthe sourcetablestoparticipateinthequeryresults.SubqueriesintheWHEREclauseare evaluatedforeachindividualrow. • TheGROUPBYclause,ifpresent,groupstheindividualrowsselectedbytheWHERE clauseintorowgroups. • TheHAVINGclause,ifpresent,selectsrowgroupstoparticipateinthequeryresults. SubqueriesintheHAVINGclauseareevaluatedforeachrowgroup. • TheSELECTclausedetermineswhichdatavaluesactuallyappearascolumnsinthe finalqueryresults. • TheDISTINCTkeyword,ifpresent,eliminatesduplicaterowsofqueryresults. • TheUNIONoperator,ifpresent,mergesthequeryresultsproducedbyindividual SELECTstatementsintoasinglesetofqueryresults. • TheORDERBYclause,ifpresent,sortsthefinalqueryresultsbasedononeormore columns. • TheSQLqueryexpressioncapabilitiesaddrow-valuedandtable-valued expressionsandINTERSECTandEXCEPToperationstotheSQL1capabilities.The fundamentalflowofqueryprocessingisnotchanged,butthecapabilitytoexpress querieswithinqueriesisgreatlyenhanced.
PART II
Therearemanyotherwaysinwhichthisquerycouldbewritten.Theentirequerycould bewrittenasonetop-levelgroupedquerythatjoinstheCUSTOMERandORDERStable.The joinoperationcouldbemadeexplicitwithaJOINoperator,andthentheresultsofthejoin couldbegroupedinthetop-levelquery.Asthisexampleshows,oneofthebenefitsofthe SQLqueryexpressioncapabilitiesisthattheytypicallyprovideseveraldifferentwaysto obtainthesamequeryresults. ThegeneralphilosophybehindthecapabilitiesinthisareaisthatSQLshouldprovidethe flexibilitytoexpressaqueryinthemostnaturalform.TheunderlyingDBMSmustbeableto takethequery,howeverexpressed,breakitdownintoitsfundamentals,andthendetermine themostefficientwaytocarryoutthequery.Thisinternalqueryexecutionplanmaybequite differentfromtheapparentplancalledforbytheactualSQLstatement,butaslongasit producesthesamequeryresults,theneteffectistoshifttheoptimizationworkloadfromthe humanuserorprogrammertotheDBMS.
227
This page intentionally left blank
III
PART
Updating Data
S
QLisnotonlyaquerylanguage,butit’salsoacomplete languageforretrievingandmodifyingdatainadatabase. Chapters10–12focusondatabaseupdates.Chapter10 describesSQLstatementsthatadddatatoadatabase,removedata fromadatabase,andmodifyexistingdatabasedata.Chapter11 describeshowSQLmaintainstheintegrityofstoreddatawhenthe dataismodified.Chapter12describestheSQLtransaction-processing featuresthatsupportconcurrentdatabaseupdatesbymanydifferent users.
CHAPTER 10 DatabaseUpdates CHAPTER 11 DataIntegrity CHAPTER 12 TransactionProcessing
This page intentionally left blank
10
CHAPTER
Database Updates
S
QLisacompletedatamanipulationlanguagethatisusednotonlyfordatabase queries,butalsotomodifyandupdatedatainthedatabase.Comparedwiththe complexityoftheSELECTstatement,whichsupportsSQLqueries,theSQLstatements thatmodifydatabasecontentsareextremelysimple.However,databaseupdatesposesome challengesforaDBMSbeyondthosepresentedbydatabasequeries.TheDBMSmust protecttheintegrityofstoreddataduringchanges,ensuringthatonlyvaliddatais introducedintothedatabase,andthatthedatabaseremainsself-consistent,eveninthe eventofsystemfailures.TheDBMSmustalsocoordinatesimultaneousupdatesbymultiple users,ensuringthattheusersandtheirchangesdonotinterferewithoneanother. ThischapterdescribesthethreeSQLstatementsthatareusedtomodifythecontentsof adatabase: • INSERT Addsnewrowsofdatatoatable • DELETE Removesrowsofdatafromatable • UPDATE Modifiesexistingdatainthedatabase InChapter11,SQLfacilitiesformaintainingdataintegrityaredescribed.Chapter12 coversSQLsupportformultiuserconcurrency.
Adding Data to the Database Anewrowofdataistypicallyaddedtoarelationaldatabasewhenanewentityrepresented bytherowappearsintheoutsideworld.Forexample,inthesampledatabase: • Whenyouhireanewsalesperson,anewrowmustbeaddedtotheSALESREPS tabletostorethesalesperson’sdata. • Whenasalespersonsignsanewcustomer,anewrowmustbeaddedtothe CUSTOMERStable,representingthenewcustomer. • Whenacustomerplacesanorder,anewrowmustbeaddedtotheORDERStableto containtheorderdata.
231
232
Part III:
Updating Data
Ineachcase,thenewrowisaddedtomaintainthedatabaseasanaccuratemodelofthe realworld.Thesmallestunitofdatathatcanbeaddedtoarelationaldatabaseisasinglerow. Ingeneral,aSQL-basedDBMSprovidesthreewaystoaddnewrowsofdatatoadatabase: • Single-rowINSERT Asingle-rowINSERTstatementaddsasinglenewrowofdatato atable.Itiscommonlyusedindailyapplications—forexample,dataentryprograms. • MultirowINSERT AmultirowINSERTstatementextractsrowsofdatafrom anotherpartofthedatabaseandaddsthemtoatable.Itiscommonlyused,for example,inend-of-monthprocessingwhenoldrowsofatablearemovedtoan inactivetable,orwhenmonthlyresultsaresummarizedintoatablethathasbeen setuptoholdthem. • Bulkload Abulkloadutilityaddsdatatoatablefromafilethatisoutsideofthe database.Itiscommonlyusedtoinitiallyloadthedatabaseortoincorporatedata downloadedfromanothercomputersystemorcollectedfrommanysites.
The Single-Row INSERT Statement Thesingle-rowINSERTstatement,showninFigure10-1,addsanewrowtoatable.The INTOclausespecifiesthetablethatreceivesthenewrow(thetargettable),andtheVALUES clausespecifiesthedatavaluesthatthenewrowwillcontain.Thecolumnlistindicates whichdatavaluegoesintowhichcolumnofthenewrow. Supposeyoujusthiredanewsalesperson,HenryJacobsen,withthefollowing personaldata: Name:
Henry Jacobsen
Age:
36
Employee Number:
111
Title:
Sales Manager
Office:
Atlanta (office number 13)
Hire Date:
July 25, 2008
Quota:
Not yet assigned
Year-to-Date Sales:
$0.00
INSERT INTO table-name (
column-name ,
VALUES (
constant NULL ,
FIGURE 10-1
Single-row INSERT statement syntax diagram
)
)
Chapter 10:
Database Updates
233
HereistheINSERTstatementthataddsMr.Jacobsentothesampledatabase: AddHenryJacobsenasanewsalesperson. INSERTINTOSALESREPS(NAME,AGE,EMPL_NUM,SALES,TITLE, HIRE_DATE,REP_OFFICE) VALUES('HenryJacobsen',36,111,0.00,'SalesMgr', '2008-07-25',13); 1rowinserted.
SQL Statement INSERT INTO SALESREPS (NAME, AGE, EMPL_NUM, SALES, QUOTA, TITLE, ...) VALUES (‘Henry Jacobsen’, 36, 111, 0.00, NULL, ‘Sales Mgr’, NULL, ‘2008-07-25’, 13);
New Row 111
Henry Jacobson
36
13
Sales Mgr
2008-07-2 5
NULL
NULL
0.00
SALESREPS Table EMPL_NUM
NAME
105
Bill Adams
109
Mary Jones
102
Sue Smith
106
Sam Clark
104
Bob Smith
AGE
TITLE
HIRE_DATE
13
Sales Rep
2006-02-12
104
31
11
Sales Rep
2007-10-12
106
$300,000.00
$392.725.00
48
21
Sales Rep
2004-12-10
108
$350,000.00
$474,050.00
52
11
VP Sales
2006-06-14
NULL
$275,000.00
$299,912.00
33
12
Sales Mgr
2005-05-19
106
$200,000.00
$142,594.00 $305,673.00
37
REP_OFFICE
MANAGER
QUOTA $350,000.00
SALES $367,911.00
101
Dan Roberts
45
12
Sales Rep
2004-10-20
104
$300,000.00
110
Tom Snyder
41
NULL
Sales Rep
2008-01-13
101
NULL
$75,985.00
108
Larry Fitch
62
21
Sales Mgr
2007-10-12
106
$350,000,00
$361,865.00
103
Paul Cruz
29
12
Sales Rep
2005-03-01
104
$275,000.00
$286,775.00
107
Nancy Angelli
49
22
Sales Rep
2006-11-14
108
$300,000.00
$186,042.00
FIGURE 10-2
Inserting a single row
PART III
Figure10-2graphicallyillustrateshowSQLcarriesoutthisINSERTstatement. Conceptually,theINSERTstatementbuildsasinglerowofdatathatmatchesthecolumn structureofthetable,fillsitwiththedatafromtheVALUESclause,andthenaddsthenew rowtothetable.Therowsofatableareunordered,sothereisnonotionofinsertingthe rowatthetop,atthebottom,orbetweentworowsofthetable.AftertheINSERT statement,thenewrowissimplyapartofthetable.Asubsequentqueryagainstthe SALESREPStablewillincludethenewrow,butitmayappearanywhereamongtherows ofqueryresults. SupposeMr.Jacobsennowreceiveshisfirstorder,fromInterCorp,anewcustomer whoisassignedcustomernumber2126.Theorderisfor20ACI-41004widgets,foratotal
234
Part III:
Updating Data
priceof$2340,andhasbeenassignedordernumber113069.HerearetheINSERTstatements thataddthenewcustomerandtheordertothedatabase: InsertanewcustomerandorderforMr.Jacobsen. INSERTINTOCUSTOMERS(COMPANY,CUST_NUM,CREDIT_LIMIT,CUST_REP) VALUES('InterCorp',2126,15000.00,111); 1rowinserted. INSERTINTOORDERS(AMOUNT,MFR,PRODUCT,QTY,ORDER_DATE, ORDER_NUM,CUST,REP) VALUES(2340.00,'ACI','41004',20,CURRENT_DATE,113069, 2126,111); 1rowinserted.
Asthisexampleshows,theINSERTstatementcanbecomelengthyiftherearemany columnsofdata,butitsformatisstillverystraightforward.ThesecondINSERTstatement usesthesystemconstantCURRENTDATEinitsVALUESclause,causingthecurrentdateto beinsertedastheorderdate.ThissystemconstantisspecifiedintheSQLstandardandis supportedbymanyofthepopularSQLproducts,includingOracleandMySQL.Other brandsofDBMSsuchasSQLServerandDB2UDBprovideothersystemconstantsorbuiltinfunctionstoobtainthecurrentdateandtime. YoucanusetheINSERTstatementwithinteractiveSQLtoaddrowstoatablethat growsveryrarely,suchastheOFFICEStable.Inpractice,however,dataaboutanew customer,order,orsalespersonisalmostalwaysaddedtoadatabasethroughadataentry programthatpresentsaformtotheusertocollectthedata.Whenthedataentryis complete,theapplicationprograminsertsthenewrowofdatausingprogrammaticSQL. RegardlessofwhetherinteractiveorprogrammaticSQLisused,however,theINSERT statementisthesame. ThetablenamespecifiedintheINSERTstatementisnormallyanunqualifiedtable name,specifyingatablethatyouown.Toinsertdataintoatableownedbyanotheruser, youcanspecifyaqualifiedtablename.Ofcourse,youmustalsohavepermissiontoinsert dataintothetable,ortheINSERTstatementwillfail.TheSQLsecurityschemeand permissionsaredescribedinChapter15. ThepurposeofthecolumnlistintheINSERTstatementistomatchthedatavaluesin theVALUESclausewiththecolumnsthataretoreceivethem.Thelistofvaluesandthelist ofcolumnsmustbothcontainthesamenumberofitems,andthedatatypeofeachvalue mustbecompatiblewiththedatatypeofthecorrespondingcolumn,oranerrorwilloccur. TheANSI/ISOstandardmandatesunqualifiedcolumnnamesinthecolumnlist,butmany implementationsallowqualifiednames.Ofcourse,therecanbenoambiguityinthecolumn namesanyway,becausetheymustallreferencecolumnsofthetargettable.
Chapter 10:
Database Updates
235
Inserting NULL Values
WhenSQLinsertsanewrowofdataintoatable,itautomaticallyassignsaNULLvalueto anycolumnwhosenameismissingfromthecolumnlistintheINSERTstatement.Inthis INSERTstatement,whichaddedMr.JacobsentotheSALESREPStable,theQUOTAand MANAGERcolumnswereomitted: INSERTINTOSALESREPS(NAME,AGE,EMPL_NUM,SALES,TITLE, HIRE_DATE,REP_OFFICE) VALUES('HenryJacobsen',36,111,0.00,'SalesMgr', '2008-07-25',13);
Asaresult,thenewlyaddedrowhasaNULLvalueintheQUOTAandMANAGER columns,asshowninFigure10-2.YoucanmaketheassignmentofaNULLvaluemore explicitbyincludingthesecolumnsinthecolumnlistandspecifyingthekeywordNULLin thevalueslist.ThisINSERTstatementhasexactlythesameeffectasthepreviousone:
Inserting All Columns
Asaconvenience,SQLallowsyoutoomitthecolumnlistfromtheINSERTstatement. Whenthecolumnlistisomitted,SQLautomaticallygeneratesacolumnlistconsistingofall columnsofthetable,inleft-to-rightsequence.Thisisthesamecolumnsequencegenerated bySQLwhenyouuseaSELECT*query.Usingthisshortcut,thepreviousINSERT statementcouldberewrittenequivalentlyas: INSERTINTOSALESREPS VALUES(111,'HenryJacobsen',36,13,'SalesMgr', '2008-07-25',NULL,NULL,0.00);
Whenyouomitthecolumnlist,theNULLkeywordmustbeusedinthevalueslistto explicitlyassignNULLvaluestocolumns,asshownintheexample.Inaddition,the sequenceofdatavaluesmustcorrespondexactlytothesequenceofcolumnsinthetable. OmittingthecolumnlistisconvenientininteractiveSQLbecauseitreducesthelengthof theINSERTstatementyoumusttype.ForprogrammaticSQL,thecolumnlistshouldalways bespecifiedbecauseitmakestheprogrameasiertoreadandunderstand.Inaddition,table structuresoftenchangeovertimetoincludenewcolumnsortodropcolumnsthatareno longerused.AprogramthatcontainsanINSERTstatementwithoutanexplicitcolumnlist mayworkcorrectlyformonthsoryears,andthensuddenlybeginproducingerrorswhenthe numberofcolumnsordatatypesofcolumnsischangedbyadatabaseadministrator.
The Multirow INSERT Statement ThesecondformoftheINSERTstatement,showninFigure10-3,addsmultiplerowsof datatoitstargettable.InthisformoftheINSERTstatement,thedatavaluesforthenew rowsarenotexplicitlyspecifiedwithinthestatementtext.Instead,thesourceofnewrowsis adatabasequery,specifiedinthestatement.
PART III
INSERTINTOSALESREPS(NAME,AGE,EMPL_NUM,SALES,QUOTA,TITLE, MANAGER,HIRE_DATE,REP_OFFICE) VALUES('HenryJacobsen',36,111,0.00,NULL,'SalesMgr', NULL,'2008-07-25',13);
236
Part III:
Updating Data
query
INSERT INTO table-name (
column-name
)
,
FIGURE 10-3 Multirow INSERT statement syntax diagram
Addingrowswhosevaluescomefromwithinthedatabaseitselfmayseemstrangeat first,butit’sveryusefulinsomespecialsituations.Forexample,supposeyouwanttocopy theordernumber,date,andamountofallordersplacedbeforeJanuary1,2008,fromthe ORDERStableintoanothertable,calledOLDORDERS.ThemultirowINSERTstatement providesaconcise,efficientwaytocopythedata: CopyoldordersintotheOLDORDERStable. INSERTINTOOLDORDERS(ORDER_NUM,ORDER_DATE,AMOUNT) SELECTORDER_NUM,ORDER_DATE,AMOUNT FROMORDERS WHEREORDER_DATE sqldaid, "SQLDA "); parmda->sqldabc = (16 = (44 * parmcnt)); parmda->sqln = parmcnt;
1
/* Start building the UPDATE statement in statement buffer */ strcpy(stmtbuf, "update orders set "); /* Loop through columns, processing the selected ones */ for (i = 0; j = 0; i++; i < COLCNT) {
2
/* Skip over non-selected columns */ if (columns[i].selected == 'n') continue; /* Add an assignment to the dynamic UPDATE statement */ if (parmcnt > 0) strcat(stmtbuf, ", "); strcat(stmtbuf, columns[i].name); strcat(stmtbuf, " = ?"); /* Allocate space for data and indicator variable, and */ /* fill in the SQLVAR with information for this column */ parmvar = parmda -> sqlvar + j; parmvar -> sqltype = columns[i].typecode; parmvar -> sqllen = columns[i].buflen; parmvar -> sqldata = malloc(columns[i].buflen); parmvar -> sqlind = malloc(2); strcpy(parmvar -> sqlname.data, columns[i].prompt); j += 1;
3 4 5 6
} /* Fill in the last SQLVAR for parameter in the WHERE clause */ strcat(stmbuf, " where empl_num = ?"); parmvar = parmda + parmcnt; parmvar->sqltype = 496; parmvar->sqllen = 4; parmvar->sqldata = &empl_num; parmvar->sqlind = 0; /* Ask the DBMS to compile the complete dynamic UPDATE statement */ exec sql prepare updatestmt from :stmtbuf; if (sqlca.sqlcode < 0) { printf("PREPARE error: %ld\n", sqlca.sqlcode); exit(); } /* Now loop, prompting for parameters and doing UPDATEs */ for ( ; ; ) { /* Prompt user for order number of order to be updated */ printf("\nEnter Salesperson's Employee Number: "); scanf("%ld", &empl_num);
FIGURE 18-8 Using EXECUTE with a SQLDA(continued)
7
Chapter 18:
Dynamic SQL*
491
if (empl_num == 0) break; /* Get new values for the updated columns */ for (j = 0; j < (parmcnt-1); j++) { parmvar = parmda + j; printf("Enter new value for %s: ", parmvar->sqlname.data); gets(inbuf);
8
if (inbuf[0] == '*') { /* If user enters '*', set column to a NULL value */ *(parmvar -> sqlind) = -1; continue; } else { /* Otherwise, set indicator for non-NULL value */ *(parmvar -> sqlind) = 0; switch(parmvar -> sqltype) { case 481: /* Convert entered data to 8-byte floating point */ sscanf(inbuf, "%lf", parmvar -> sqldata); break;
8
case 449: /* Pass entered data as variable-length string */ stccpy(parmvar -> sqldata, inbuf, strlen(inbuf)); parmvar -> sqllen = strlen(inbuf); break; case 501: /* Convert entered data to 4-byte integer */ sscanf(inbuf, "%ld", parmvar->sqldata); break; } } }
} /* All finished with updates */ exec sql execute immediate "commit work"; if (sqlca.sqlcode) printf("COMMIT error: %ld\n", sqlca.sqlcode); else printf("\nAll updates committed.\n"); exit(); }
FIGURE 18-8 Using EXECUTE with a SQLDA(continued)
9
PART V
/* Execute the statement */ exec sql execute updatestmt using :parmda; if (sqlca.sqlcode < 0) { printf("EXECUTE error: %ld\n", sqlca.sqlcode); exit(); }
492
Part V:
Programming with SQL
4. TheprogramdeterminesthelengthoftheparameterandplacesitintheSQLLENfield.
5. Theprogramallocatesmemorytoholdtheparametervalueandputstheaddressof theallocatedmemoryintheSQLDATAfield.
6. Theprogramallocatesmemorytoholdanindicatorvariablefortheparameterand putstheaddressoftheindicatorvariableintheSQLINDfield.
7. TheprogramsetstheSQLDfieldintheSQLDAheadertoindicatehowmany parametersarebeingpassed.ThistellstheDBMShowmanySQLVARstructures withintheSQLDAcontainvaliddata.
8. Theprogrampromptstheuserfordatavaluesandplacesthemintothedataareas allocatedinSteps5and6.
9. TheprogramusesanEXECUTEstatementwiththeUSINGclausetopassparameter valuesviatheSQLDA.
Notethatthisparticularprogramcopiesthepromptstringforeachparametervalue intotheSQLNAMEstructure.Theprogramdoesthissolelyforitsownconvenience;the DBMSignorestheSQLNAMEstructurewhenyouusetheSQLDAtopassparameters.Hereis asampleuserdialogwiththeprograminFigure18-8: ***SalespersonUpdateProgram*** UpdateNamecolumn(y/n)?y UpdateOfficecolumn(y/n)?y UpdateManagercolumn(y/n)?n UpdateHireDatecolumn(y/n)?n UpdateQuotacolumn(y/n)?y UpdateSalescolumn(y/n)?n EnterSalesperson'sEmployeeNumber:106 EnternewvalueforName:SueJackson EnternewvalueforOffice:22 EnternewvalueforQuota:175000.00 EnterSalesperson'sEmployeeNumber:104 EnternewvalueforName:JoeSmith EnternewvalueforOffice:* EnternewvalueforQuota:275000.00 EnterSalesperson'sEmployeeNumber:0 Allupdatescommitted.
Basedontheuser’sresponsetotheinitialquestions,theprogramgeneratesthis dynamicUPDATEstatementandpreparesit: updatesalesreps setname=?,office=?,quota=? whereempl_num=?
Chapter 18:
Dynamic SQL*
493
Thestatementspecifiesfourparameters,andtheprogramallocatesaSQLDAbigenough tohandlefourSQLVARstructures.Whentheusersuppliesthefirstsetofparametervalues, thedynamicUPDATEstatementbecomes updatesalesreps setname='SueJackson',office=22,quota=175000.00 whereempl_num=106
andwiththesecondsetofparametervalues,itbecomes updatesalesreps setname='JoeSmith',office=NULL,quota=275000.00 whereempl_num=104
Thisprogramissomewhatcomplex,butit’ssimplecomparedwitharealgeneralpurposedatabaseupdateutility.ItalsoillustratesallofthedynamicSQLfeaturesrequired todynamicallyexecutestatementswithavariablenumberofparameters.
Dynamic Queries TheEXECUTEIMMEDIATE,PREPARE,andEXECUTEstatementsasdescribedthusfar supportdynamicexecutionofmostSQLstatements.However,theycan’tsupportdynamic queriesbecausetheylackamechanismforretrievingthequeryresults.Tosupportdynamic queries,SQLcombinesthedynamicSQLfeaturesofthePREPAREandEXECUTEstatements withextensionstothestaticSQLquery-processingstatements,andaddsanewstatement. Hereisanoverviewofhowaprogramperformsadynamicquery: 1. AdynamicversionoftheDECLARECURSORstatementdeclaresacursorforthe query.UnlikethestaticDECLARECURSORstatement,whichincludesahard-coded SELECTstatement,thedynamicformoftheDECLARECURSORstatementspecifies thestatementnamethatwillbeassociatedwiththedynamicSELECTstatement.
2. TheprogramconstructsavalidSELECTstatementandstoresitinavariable,justas itwouldconstructadynamicUPDATEorDELETEstatement.TheSELECTstatement maycontainparametermarkerslikethoseusedinotherdynamicSQLstatements.
3. TheprogramusesthePREPAREstatementtopassthestatementstringtotheDBMS, whichparses,validates,andoptimizesthestatementandgeneratesanapplicationplan. ThisisidenticaltothePREPAREprocessingusedforotherdynamicSQLstatements.
4. TheprogramusestheDESCRIBEstatementtorequestadescriptionofthequery resultsthatwillbeproducedbythequery.TheDBMSreturnsacolumn-by-column descriptionofthequeryresultsinaSQLDataArea(SQLDA)suppliedbythe program,tellingtheprogramhowmanycolumnsofqueryresultsthereare,andthe name,datatype,andlengthofeachcolumn.TheDESCRIBEstatementisused exclusivelyfordynamicqueries.
5. TheprogramusesthecolumndescriptionsintheSQLDAtoallocateablockof memorytoreceiveeachcolumnofqueryresults.Theprogrammayalsoallocate spaceforanindicatorvariableforthecolumn.Theprogramplacestheaddressof thedataareaandtheaddressoftheindicatorvariableintotheSQLDAtotellthe DBMSwheretoreturnthequeryresults.
PART V
494
Part V:
Programming with SQL
6. AdynamicversionoftheOPENstatementaskstheDBMStostartexecutingthequery andpassesvaluesfortheparametersspecifiedinthedynamicSELECTstatement. TheOPENstatementpositionsthecursorbeforethefirstrowofqueryresults.
7. AdynamicversionoftheFETCHstatementadvancesthecursortothefirstrowof queryresultsandretrievesthedataintotheprogram’sdataareasandindicator variables.UnlikethestaticFETCHstatement,whichspecifiesalistofhostvariables toreceivethedata,thedynamicFETCHstatementusestheSQLDAtotelltheDBMS wheretoreturnthedata.SubsequentexecutionsofthisdynamicFETCHstatement movethroughthequeryresultsrowbyrow,advancingthecursortothenextrowof queryresultsandretrievingitsdataintotheprogram’sdataareas.
8. TheCLOSEstatementendsaccesstothequeryresultsandbreakstheassociation betweenthecursorandthequeryresults.ThisCLOSEstatementisidenticaltothe staticSQLCLOSEstatement;noextensionsarerequiredfordynamicqueries.
Theprogrammingrequiredtoperformadynamicqueryismoreextensivethanthe programmingforanyotherembeddedSQLstatement.However,theprogrammingis typicallymoretediousthancomplex.Figure18-9showsasmallqueryprogramthatuses dynamicSQLtoretrieveanddisplayselectedcolumnsfromauser-specifiedtable.The calloutnumbersinthefigureidentifytheeightstepsintheprecedinglist. Theprograminthefigurebeginsbypromptingtheuserforthetablenameandthen queriesthesystemcatalogtodiscoverthenamesofthecolumnsinthattable.Itasksthe usertoselectthecolumn(s)toberetrievedandconstructsadynamicSELECTstatement basedontheuser’sresponses.Thestep-by-stepmechanicalconstructionofaselectlistin thisexampleisverytypicalofdatabasefront-endprogramsthatgeneratedynamicSQL.In realapplications,thegeneratedselectlistmightincludeexpressionsoraggregatefunctions, andtheremightbeadditionalprogramlogictogenerateGROUPBY,HAVING,andORDERBY clauses.Agraphicaluserinterfacewouldalsobeusedinsteadoftheprimitiveuser promptinginthesampleprogram.However,theprogrammingstepsandconceptsremain thesame.NoticethatthegeneratedSELECTstatementisidenticaltotheinteractiveSELECT statementthatyouwouldusetoperformtherequestedquery. ThehandlingofthePREPAREandDESCRIBEstatementsandthemethodofallocating storagefortheretrieveddatainthisprogramarealsotypicalofdynamicqueryprograms. NotehowtheprogramusesthecolumndescriptionsplacedintheSQLVARarraytoallocate adatastorageblockofthepropersizeforeachcolumn.Thisprogramalsoallocatesspace foranindicatorvariableforeachcolumn.Theprogramplacestheaddressofthedatablock andindicatorvariablebackintotheSQLVARstructure. TheOPEN,FETCH,andCLOSEstatementsplaythesamerolefordynamicqueriesasthey doforstaticqueries,asillustratedbythisprogram.NotethattheFETCHstatementspecifies theSQLDAinsteadofalistofhostvariables.Becausetheprogramhaspreviouslyfilledin theSQLDATAandSQLINDfieldsoftheSQLVARarray,theDBMSknowswheretoplaceeach retrievedcolumnofdata. Asthisexampleshows,muchoftheprogrammingrequiredforadynamicqueryis concernedwithsettinguptheSQLDAandallocatingstoragefortheSQLDAandtheretrieved data.Theprogrammustalsosortoutthevarioustypesofdatathatcanbereturnedbythe queryandhandleeachonecorrectly,takingintoaccountthepossibilitythatthereturned datawillbeNULL.Thesecharacteristicsofthesampleprogramaretypicalofproduction
Chapter 18:
Dynamic SQL*
495
applicationsthatusedynamicqueries.Despitethecomplexity,theprogrammingisnottoo difficultinlanguageslikeC,C++,Pascal,PL/I,orJava.LanguagessuchasCOBOLand FORTRAN,whichlackthecapabilitytodynamicallyallocatestorageandworkwith variable-lengthdatastructures,arenotpracticalfordynamicqueryprocessing. ThefollowingsectionsdiscusstheDESCRIBEstatementandthedynamicversionsof theDECLARECURSOR,OPEN,andFETCHstatements.
The DESCRIBE Statement TheDESCRIBEstatement,showninFigure18-10,isuniquetodynamicqueries.Itisusedto requestadescriptionofadynamicqueryfromtheDBMS.TheDESCRIBEstatementisused afterthedynamicqueryhasbeencompiledwiththePREPAREstatementbutbeforeitis executedwiththeOPENstatement.Thequerytobedescribedisidentifiedbyitsstatement name.TheDBMSreturnsthequerydescriptioninaSQLDAsuppliedbytheprogram. main() { /* This is a simple general-purpose query program. It prompts the user for a table name, and then asks the user which columns of the table are to be included in the query. After the user's selections are complete, the program runs the requested query and displays the results. */ exec sql include sqlca; exec sql include sqlda; exec sql begin declare section; char stmtbuf[2001]; char querytbl[32]; char querycol[32]; exec sql end declare section;
/* SQL text to be executed */ /* user-specified table */ /* user-specified column */
/* Cursor for system catalog query that retrieves column names */ exec sql declare tblcurs cursor for select colname from system.syscolumns where tblname = :querytbl and owner = user; exec sql declare qrycurs cursor for querystmt; */ /* /* /* /* /*
number of columns chosen */ allocated SQLDA for query */ SQLVAR for current column */ index for SQLVAR array in SQLDA */ input entered by user */
/* Prompt the user for which table to query */ printf("*** Mini-Query Program ***\n\n") printf("Enter name of table for query: "); gets(querytbl); /* Start the SELECT statement in the buffer */
FIGURE 18-9 Data retrieval with dynamic SQL (continued)
PART V
/* Data structures for the program int colcount = 0; struct sqlda *qry_da; struct sqlvar *qry_var; int i; char inbuf[101];
1
496
Part V:
Programming with SQL
strcpy(stmtbuf, "select "); /* Set up error processing */ exec sql whenever sqlerror goto handle_error; exec sql whenever not found goto no_more_columns; /* Query the system catalog to get column names for the table */ exec sql open tblcurs; for ( ; ; ) { 2 /* Get name of next column and prompt the user */ exec sql fetch tblcurs into :querycol; printf("Include column %s (y/n)? ", querycol); gets(inbuf); if (inbuf[0] == 'y') { /* User wants the column; add it to the select list */ if (colcount++ > 0) strcat(stmtbuf, ", "); strcat(stmtbuf, querycol); } } no_more_columns: exec sql close tblcurs; /* Finish the SELECT statement with a FROM clause */ strcat(stmtbuf, "from "); strcat(stmtbuf, querytbl); /* Allocate SQLDA for the dynamic query */ query_da = (SQLDA *)malloc(sizeof(SQLDA) + colcount * sizeof(SQLVAR)); query_da->sqln = colcount; /* Prepare the query and ask the DBMS to describe it */ exec sql prepare querystmt from :stmtbuf; exec sql describe querystmt into qry_da; /* Loop through SQLVARs, allocating memory for each column */ for (i = 0; i < colcount; I++) { qry_var = qry_da->sqlvar + I; qry_var->sqldat = malloc(qry_var->sqllen); qry_var->sqlind = malloc(sizeof(short)); } /* SQLDA is all set; do the query and retrieve the results! */ exec sql open qrycurs; exec sql whenever not found goto no_more_data; for ( ; ; ) { /* Fetch the row of data into our buffers */ exec sql fetch sqlcurs using descriptor qry_da;
FIGURE 18-9 Data retrieval with dynamic SQL (continued)
3 4
5
6
7
Chapter 18:
Dynamic SQL*
497
printf("\n"); /* Loop printing data for each column of the row */ for (i = 0; i < colcount; I++) { /* Find the SQLVAR for this column; print column label */ qry_var = qry_da->sqlvar + I; printf(" Column # %d (%s): ", i+1, qry_var->sqlname); /* Check indicator variable for NULL indication */ if (*(qry_var -> sqlind)) != 0) { puts("is NULL!\n"); continue; } /* Actual data returned; handle each type separately */ switch (qry_var -> sqltype) { case 448: case 449: /* VARCHAR data -– just display it */ puts(qry_var -> sqldata); break; case 496: case 497: /* Four-byte integer data -– convert & display it */ printf("%ld", *((int *) (qry_var->sqldata))); break; case 500: case 501: /* Two-byte integer data -– convert & display it */ printf("%d", *((short *)(qry_var->sqldata))); break;
} } no_more_data: printf("\nEnd of data.\n"); /* Clean up allocated storage */
FIGURE 18-9 Data retrieval with dynamic SQL (continued)
PART V
case 480: case 481: /* Floating-point data -– convert & display it */ printf("%lf", *((double *)(qry_var->sqldat))); break; }
498
Part V:
Programming with SQL
for (i = 0; i < colcount; I++) { qry_var = qry_da->sqlvar + I; free(qry_var->sqldata); free(qry_var->sqlind); } free(qry_da); close qrycurs;
8
exit(); }
FIGURE 18-9 Data retrieval with dynamic SQL (continued)
TheSQLDAisavariable-lengthstructurewithanarrayofoneormoreSQLVAR structures,asdescribedearlierinthesection“EXECUTEwithSQLDA,”andshowninFigure 18-7.BeforepassingtheSQLDAtotheDESCRIBEstatement,yourprogrammustfillinthe SQLNfieldintheSQLDAheader,tellingtheDBMShowlargetheSQLVARarrayisinthis particularSQLDA.AsthefirststepofitsDESCRIBEprocessing,theDBMSfillsintheSQLD fieldintheSQLDAheaderwiththenumberofcolumnsofqueryresults.Ifthesizeofthe SQLVARarray(asspecifiedbytheSQLNfield)istoosmalltoholdallofthecolumn descriptions,theDBMSdoesnotfillintheremainderoftheSQLDA.Otherwise,theDBMS fillsinoneSQLVARstructureforeachcolumnofqueryresults,inleft-to-rightorder.The fieldsofeachSQLVARdescribethecorrespondingcolumn: • TheSQLNAMEstructurespecifiesthenameofthecolumn(withthenameinthe DATAfieldandthelengthofthenameintheLENGTHfield).Ifthecolumnisderived fromanexpression,theSQLNAMEfieldisnotused. • TheSQLTYPEfieldspecifiesanintegerdatatypecodeforthecolumn.Thedatatype codesusedbydifferentbrandsofDBMSvary.FortheIBMSQLproducts,thedata typecodeindicatesboththedatatypeandwhetherNULLvaluesareallowed,as showninTable18-1. • TheSQLLENfieldspecifiesthelengthofthecolumn.Forvariable-lengthdatatypes (suchasVARCHAR),thereportedlengthisthemaximumlengthofthedata;the lengthofthecolumnsinindividualrowsofqueryresultswillnotexceedthis length.ForDB2(andmanyotherSQLproducts),thelengthreturnedforaDECIMAL datatypespecifiesboththesizeofthedecimalnumber(intheupperbyte)andthe scaleofthenumber(inthelowerbyte). • TheSQLDATAandSQLINDfieldsarenotfilledinbytheDBMS.Yourapplication programfillsinthesefieldswiththeaddressesofthedatabufferandindicator variableforthecolumnbeforeusingtheSQLDAlaterinaFETCHstatement.
DESCRIBE
INPUT statement-name object-name
DESCRIPTOR descriptor-name
USING SQL
OUTPUT
FIGURE 18-10 The DESCRIBE statement syntax diagram
WITH NESTING WITHOUT NESTING
Chapter 18:
Data Type
NULL Allowed
NOT NULL
CHAR
452
453
VARCHAR
448
449
LONGVARCHAR
456
457
SMALLINT
500
501
INTEGER
496
497
FLOAT
480
481
DECIMAL
484
485
DATE
384
385
TIME
388
389
TIMESTAMP
392
393
GRAPHIC
468
469
VARGRAPHIC
464
465
Dynamic SQL*
499
TABLE 18-1 SQLDA Data Type Codes for DB2
AcomplicationofusingtheDESCRIBEstatementisthatyourprogrammaynotknowin advancehowmanycolumnsofqueryresultstherewillbe;therefore,itmaynotknowhow largeaSQLDAmustbeallocatedtoreceivethedescription.Oneofthreestrategiesis typicallyusedtoensurethattheSQLDAhasenoughspaceforthereturneddescriptions: • Iftheprogramhasgeneratedtheselectlistofthequery,itcankeeparunningcount oftheselectitemsasitgeneratesthem.Inthiscase,theprogramcanallocatea SQLDAwithexactlytherightnumberofSQLVARstructurestoreceivethecolumn descriptions.ThisapproachwasusedintheprogramshowninFigure18-9.
• Alternatively,theprogramcanallocateaSQLDAwithaSQLVARarraylargeenough toaccommodateatypicalquery.ADESCRIBEstatementusingthisSQLDAwill succeedmostofthetime.IftheSQLDAturnsouttobetoosmallforthequery,the SQLDvaluetellstheprogramhowlargetheSQLDAmustbe,anditcanallocatea largeroneandDESCRIBEthestatementagainintothatSQLDA. TheDESCRIBEstatementisnormallyusedfordynamicqueries,butyoucanaskthe DBMStoDESCRIBEanypreviouslypreparedstatement.Thisfeatureisuseful,forexample, ifaprogramneedstoprocessanunknownSQLstatementtypedbyauser.Theprogram canPREPAREandDESCRIBEthestatementandexaminetheSQLDfieldintheSQLDA.
PART V
• Ifitisinconvenientfortheprogramtocountthenumberofselectlistitems,itcan initiallyDESCRIBEthedynamicqueryintoaminimalSQLDAwithaone-element SQLVARarray.WhentheDESCRIBEstatementreturns,theSQLDvaluetellsthe programhowlargetheSQLDAmustbe.TheprogramcanthenallocateaSQLDAof thecorrectsizeandreexecutetheDESCRIBEstatement,specifyingthenewSQLDA. Thereisnolimittothenumberoftimesthatapreparedstatementcanbedescribed.
500
Part V:
Programming with SQL
IftheSQLDfieldiszero,thestatementtextwasnotaquery,andtheEXECUTEstatement canbeusedtoexecuteit.IftheSQLDfieldispositive,thestatementtextwasaquery,and theOPEN/FETCH/CLOSEstatementsequencemustbeusedtoexecuteit.
The DECLARE CURSOR Statement ThedynamicDECLARECURSORstatement,showninFigure18-11,isavariationofthestatic DECLARECURSORstatement.RecallfromChapter17thatthestaticDECLARECURSOR statementliterallyspecifiesaquerybyincludingtheSELECTstatementasoneofitsclauses. Bycontrast,thedynamicDECLARECURSORstatementspecifiesthequeryindirectly,by specifyingthestatementnameassociatedwiththequerybythePREPAREstatement. LikethestaticDECLARECURSORstatement,thedynamicDECLARECURSORstatementis adirectivetotheSQLprecompilerratherthananexecutablestatement.Itmustappear beforeanyotherreferencestothecursorthatitdeclares.Thecursornamedeclaredbythis statementisusedinsubsequentOPEN,FETCH,andCLOSEstatementstoprocesstheresults ofthedynamicquery.
The Dynamic OPEN Statement ThedynamicOPENstatement,showninFigure18-12,isavariationofthestaticOPEN statement.ItcausestheDBMStobeginexecutingaqueryandpositionstheassociated cursorjustbeforethefirstrowofqueryresults.WhentheOPENstatementcompletes successfully,thecursorisinanopenstateandisreadytobeusedinaFETCHstatement. TheroleoftheOPENstatementfordynamicqueriesparallelstheroleoftheEXECUTE statementforotherdynamicSQLstatements.BoththeEXECUTEandtheOPENstatements causetheDBMStoexecuteastatementpreviouslycompiledbythePREPAREstatement.If thedynamicquerytextincludesoneormoreparametermarkers,thentheOPENstatement, liketheEXECUTEstatement,mustsupplyvaluesfortheseparameters.TheUSINGclause specifiesparametervalues,andithasanidenticalformatinboththeEXECUTEandOPEN statements.
DECLARE cursor-name
CURSOR SENSITIVE
SCROLL
INSENSITIVE
NO SCROLL
ASENSITIVE
FOR statement-name WITH HOLD
WITH RETURN
WITHOUT HOLD
WITHOUT RETURN
FIGURE 18-11
The dynamic DECLARECURSOR statement syntax diagram
Chapter 18:
Dynamic SQL*
501
OPEN cursor-name host-variable
USING
, DESCRIPTOR descriptor-name
FIGURE 18-12 The dynamic OPEN statement syntax diagram
Ifthenumberofparametersthatwillappearinadynamicqueryisknowninadvance, theprogramcanpasstheparametervaluestotheDBMSthroughalistofhostvariablesin theUSINGclauseoftheOPENstatement.AsintheEXECUTEstatement,thenumberofhost variablesmustmatchthenumberofparameters;thedatatypeofeachhostvariablemustbe compatiblewiththetyperequiredbythecorrespondingparameter;andanindicator variablecanbespecifiedforeachhostvariable,ifnecessary.Figure18-13showsaprogram excerptwherethedynamicqueryhasthreeparameterswhosevaluesarespecifiedbyhost variables. Ifthenumberofparametersisnotknownuntilruntime,theprogrammustpassthe parametervaluesusingaSQLDAstructure.Thistechniqueforpassingparametervalueswas describedfortheEXECUTEstatementearlierinthesection“EXECUTEwithSQLDA.”The sametechniqueisusedfortheOPENstatement.Figure18-14showsaprogramexcerptlike theoneinFigure18-13,exceptthatitusesaSQLDAtopassparameters.
. . . /* Program has previously generated and prepared a SELECT statement like this one: SELECT A, B, C ... FROM SALESREPS WHERE SALES BETWEEN ? AND ? with two parameters to be specified */
/*Open the cursor to start the query, passing parameters */ exec sql open qrycursor using :low_end, :high_end; . . .
FIGURE 18-13 OPEN statement with host variable parameter passing
PART V
/* Prompt the user for low & high values and do the query */ printf("Enter low end of sales range: "); scanf("%f", &low_end); printf("Enter high end of sales range: "); scanf("%f", &high_end);
502
Part V:
Programming with SQL
. . . /* Program has previously generated and prepared a SELECT statement like this one: SELECT A, B, C ... FROM SALESREPS WHERE EMPL_NUM IN (?, ?, ... ?) with a variable number of parameters to be specified. The number of parameters for this execution is stored in the variable parmcnt. */ char *malloc() SQLDA *parmda; SQLVAR *parmvar; long parm_value[101]; /* Allocate a SQLDA to pass parameter values */ parmda = (SQLDA *)malloc(sizeof(SQLDA) + parmcnt * sizeof(SQLVAR)); parmda->sqln = parmcnt; /* Prompt the user for parameter values */ for (i = 0; i < parmcnt; I++) { printf("Enter employee number: "); scanf("%ld", &(parm_value[i])); parmvar = parmda -> sqlvar + I; parmvar->sqltype = 496; parmvar->sqllen = 4; parmvar->sqldata = &(parm_value[i]); parmvar->sqlind = 0; } /* Open the cursor to start the query, passing parameters */ exec sql open qrycursor using descriptor :parmda; . . .
FIGURE 18-14 OPEN statement with SQLDA parameter processing
NotecarefullythattheSQLDAusedintheOPENstatementhasabsolutelynothingtodo withtheSQLDAusedintheDESCRIBEandFETCHstatements: • TheSQLDAintheOPENstatementisusedtopassparametervaluestotheDBMSfor dynamicqueryexecution.TheelementsofitsSQLVARarraycorrespondtothe parametermarkersinthedynamicstatementtext. • TheSQLDAintheDESCRIBEandFETCHstatementsreceivesdescriptionsofthequery resultscolumnsfromtheDBMSandtellstheDBMSwheretoplacetheretrievedquery results.TheelementsofitsSQLVARarraycorrespondtothecolumnsofqueryresults producedbythedynamicquery.
Chapter 18:
Dynamic SQL*
503
The Dynamic FETCH Statement ThedynamicFETCHstatement,showninFigure18-15,isavariationofthestaticFETCH statement.Itadvancesthecursortothenextavailablerowofqueryresults(ortherequested rowifthecursorisscrollableandoneofthescrollkeywordsisused)andretrievesthe valuesofitscolumnsintotheprogram’sdataareas.RecallfromChapter17thatthestatic FETCHstatementincludesanINTOclausewithalistofhostvariablesthatreceivethe retrievedcolumnvalues.InthedynamicFETCHstatement,thelistofhostvariablesis replacedbyaSQLDA. BeforeusingthedynamicFETCHstatement,itistheapplicationprogram’s responsibilitytoprovidedataareastoreceivetheretrieveddataandindicatorvariablefor eachcolumn.TheapplicationprogrammustalsofillintheSQLDATA,SQLIND,andSQLLEN fieldsintheSQLVARstructureforeachcolumn,asfollows: • TheSQLDATAfieldmustpointtothedataareafortheretrieveddata. • TheSQLLENfieldmustspecifythelengthofthedataareapointedtobythe SQLDATAfield.ThisvaluemustbecorrectlyspecifiedtomakesuretheDBMSdoes notcopyretrieveddatabeyondtheendofthedataarea. • TheSQLINDfieldmustpointtoanindicatorvariableforthecolumn(a2-byte integer).Ifnoindicatorvariableisusedforaparticularcolumn,theSQLINDfield forthecorrespondingSQLVARstructureshouldbesettozero. Normally,theapplicationprogramallocatesaSQLDA,usestheDESCRIBEstatement togetadescriptionofthequeryresults,allocatesstorageforeachcolumnofquery results,andsetstheSQLDATAandSQLINDvalues,allbeforeopeningthecursor.This sameSQLDAisthenpassedtotheFETCHstatement.However,thereisnorequirement thatthesameSQLDAbeusedorthattheSQLDAspecifythesamedataareasforeach FETCHstatement.Itisperfectlyacceptablefortheapplicationprogramtochangethe SQLDATAandSQLINDpointersbetweenFETCHstatements,retrievingtwosuccessive rowsintodifferentlocations.
FROM
PRIOR FIRST LAST ABSOLUTE value RELATIVE value
The dynamic FETCH statement syntax diagram
SQL
PART V
NEXT
FIGURE 18-15
DESCRIPTOR descriptor-name
cursor-name INTO
FETCH
504
Part V:
Programming with SQL
The Dynamic CLOSE Statement ThedynamicformoftheCLOSEstatementisidenticalinsyntaxandfunctiontothestatic CLOSEstatementshowninFigure17-28.Inbothcases,theCLOSEstatementendsaccessto thequeryresults.Whenaprogramclosesacursorforadynamicquery,theprogram normallyshouldalsodeallocatetheresourcesassociatedwiththedynamicquery,including • TheSQLDAallocatedforthedynamicqueryandusedintheDESCRIBEandFETCH statements • ApossiblesecondSQLDA,usedtopassparametervaluestotheOPENstatement • Thedataareasallocatedtoreceiveeachcolumnofqueryresultsretrievedbya FETCHstatement • Thedataareasallocatedasindicatorvariablesforthecolumnsofqueryresults Itmaynotbenecessarytodeallocatethesedataareasiftheprogramwillterminate immediatelyaftertheCLOSEstatement.
Dynamic SQL Dialects LiketheotherpartsoftheSQLlanguage,dynamicSQLvariesfromonebrandofDBMSto another.Infact,thedifferencesindynamicSQLsupportaremoreseriousthanforstatic SQL,becausedynamicSQLexposesmoreofthenutsandboltsoftheunderlyingDBMS— datatypes,dataformats,andsoon.Asapracticalmatter,thesedifferencesmakeit impossibletowriteasingle,general-purposedatabasefront-endthatisportableacross differentDBMSbrandsusingdynamicSQL.Instead,databasefront-endprogramsmust includeatranslationlayer,oftencalledadriver,foreachbrandofDBMSthattheysupport, toaccommodatethedifferences. Theearlyfront-endproductsusuallyshippedwithaseparatedriverforeachofthe popularDBMSbrands.TheintroductionofODBCasauniformSQLAPIlayermadethisjob simpler,sinceanODBCdrivercouldbewrittenonceforeachDBMSbrand,andthefrontendprogramcouldbewrittentosolelyusetheODBCinterface.Inpractice,however, ODBC’sleast-common-denominatorapproachmeantthatthefront-endprogramscouldn’t takeadvantageoftheuniquecapabilitiesofthevarioussupportedDBMSsystems,andit limitedtheperformanceoftheapplication.Asaresult,mostmodernfront-endprograms andtoolsstillincludeaseparate,explicitdriverforeachofthepopularDBMSbrands.An ODBCdriverisusuallyincludedtoprovideaccesstotheothers. AdetaileddescriptionofthedynamicSQLfeaturessupportedbyallofthemajorDBMS brandsisbeyondthescopeofthisbook.However,itisinstructivetoexaminethedynamic SQLsupportprovidedbySQL/DSandbyOracleasexamplesofthekindsofdifferences andextensionstodynamicSQLthatyoumayfindinyourparticularDBMS.
Dynamic SQL in Oracle* TheOracleDBMSprecededDB2intothemarketandbaseditsdynamicSQLsupporton IBM’sSystem/Rprototype.(Actually,theentireoriginalOracleDBMSwasindependently developedfromthepubliclyavailablespecificationsforSystem/R.)Forthisreason,the OraclesupportfordynamicSQLdifferssomewhatfromtheIBMSQLstandard.Although OracleandDB2arebroadlycompatible,theydiffersubstantiallyatthedetaillevel.
Chapter 18:
Dynamic SQL*
505
ThesedifferencesincludeOracle’suseofparametermarkers,itsuseoftheSQLDA,theformat ofitsSQLDA,anditssupportfordatatypeconversion.TheOracledifferencesfromDB2are similartothoseyoumayencounterinotherDBMSbrands.Forthatreason,itisinstructiveto brieflyexamineOracle’sdynamicSQLsupportanditspointsofdifferencefromDB2.
Named Parameters
RecallthatDB2doesnotallowhostvariablereferencesinadynamicallypreparedstatement. Instead,parametersinthestatementareidentifiedbyquestionmarks(parametermarkers), andvaluesfortheparametersarespecifiedintheEXECUTEorOPENstatement.Oracleallows youtospecifyparametersinadynamicallypreparedstatementusingthesyntaxforhost variables.Forexample,thissequenceofembeddedSQLstatementsislegalforOracle: execsqlbegindeclaresection; charstmtbuf[1001]; intemployee_number; execsqlenddeclaresection; . . . strcpy(stmtbuf,"deletefromsalesreps whereempl_num=:rep_number;"); execsqlpreparedelstmtfrom:stmtbuf; execsqlexecutedelstmtusing:employee_number;
Althoughrep_numberappearstobeahostvariableinthedynamicDELETEstatement, itisinfactanamedparameter.Asshownintheexample,thenamedparameterbehaves exactlyliketheparametermarkersinDB2.Avaluefortheparameterissuppliedfromareal hostvariableintheEXECUTEstatement.Namedparametersarearealconveniencewhen youusedynamicstatementswithavariablenumberofparameters.
The DESCRIBE Statement
execsqldescribeselectlistforqrystmtintoqry_sqlda;
ItcorrespondstotheDB2statement: execsqldescribeqrystmtintoqry_sqlda;
ThisOracleDESCRIBEstatementrequestsadescriptionofthenamedparametersina previouslyprepareddynamicstatement.ThestatementmightbeaqueryorsomeotherSQL statement: execsqldescribebindvariablesforthestmtintothe_sqlda;
PART V
TheOracleDESCRIBEstatementisused,liketheDB2DESCRIBEstatement,todescribethe queryresultsofadynamicquery.LikeDB2,OraclereturnsthedescriptionsinaSQLDA.The OracleDESCRIBEstatementcanalsobeusedtorequestadescriptionofthenamed parametersinadynamicallypreparedstatement.Oraclealsoreturnstheseparameter descriptionsinaSQLDA. ThisOracleDESCRIBEstatementrequestsadescriptionofthecolumnsofqueryresults fromapreviouslyprepareddynamicquery:
506
Part V:
Programming with SQL
ThisOraclestatementhasnoDB2equivalent.FollowingthisDESCRIBEstatement,your programwouldtypicallyexaminetheinformationintheSQLDA,fillinthepointersinthe SQLDAtopointtotheparametervaluestheprogramwantstosupply,andthenexecutethe statementusingtheSQLDAformoftheOPENorEXECUTEstatement: execsqlexecutethestmtusingdescriptorthe_sqlda; execsqlopenqrycursorusingdescriptorthe_sqlda;
TheinformationreturnedbybothformsoftheOracleDESCRIBEstatementisthesame andisdescribedinthenextsection.
The Oracle SQLDA
TheOracleSQLDAperformsthesamefunctionsastheDB2SQLDA,butitsformat,shownin Figure18-16,differssubstantiallyfromthatofDB2.ThetwoimportantfieldsintheDB2 SQLDAheaderbothhavecounterpartsintheOracleSQLDA: • TheNfieldintheOracleSQLDAspecifiesthesizeofthearraysusedtoholdcolumn definitions.ItcorrespondstotheSQLNfieldintheDB2SQLDA. • TheFfieldintheOracleSQLDAindicateshowmanycolumnsarecurrentlydescribed inthearraysoftheSQLDA.ItcorrespondstotheSQLDfieldintheDB2SQLDA. InsteadofDB2’ssinglearrayofSQLVARstructuresthatcontaincolumndescriptions, theOracleSQLDAcontainspointerstoaseriesofarrays,eachofwhichdescribesoneaspect ofacolumn: • TheTfieldpointstoanarrayofintegersthatspecifythedatatypeforeachquery resultscolumnornamedparameter.Theintegersinthisarraycorrespondtothe SQLTYPEfieldineachDB2SQLVARstructure. • TheVfieldpointstoanarrayofpointersthatspecifythebufferforeachcolumnof queryresultsoreachpassedparametervalue.Thepointersinthisarraycorrespond totheSQLDATAfieldineachDB2SQLVARstructure.
struct sqlda { long N; char **V; long *L; short *T; short **I; long F; char **S; short *M; short *C; char **X; short *Y; short *Z; } ;
/* /* /* /* /* /* /* /* /* /* /* /*
number of entries in the SQLDA arrays */ pointer to array of pointers to data areas */ pointer to array of buffer lengths */ pointer to array of data type codes */ pointer to array of pointers to indicator variables */ number of active entries in the SQLDA arrays */ pointer to array of pointers to column/parameter names */ pointer to array of name buffer lengths */ pointer to array of current lengths of names */ pointer to array of pointers to indicator parameter names */ pointer to array of indicator name buffer lengths */ pointer to array of current lengths of indicator names */
FIGURE 18-16 The Oracle SQLDA
Chapter 18:
Dynamic SQL*
507
• TheLfieldpointstoanarrayofintegersthatspecifythelengthofeachbuffer pointedtobytheVarray.TheintegersinthisarraycorrespondtotheSQLLENfield ineachDB2SQLVARstructure. • TheIfieldpointstoanarrayofdatapointersthatspecifytheindicatorvariablefor eachqueryresultscolumnornamedparameter.Thepointersinthisarray correspondtotheSQLINDfieldineachDB2SQLVARstructure. • TheSfieldpointstoanarrayofstringpointersthatspecifythebufferswhereOracle istoreturnthenameofeachqueryresultscolumnornamedparameter.Thebuffers pointedtobythisarraycorrespondtotheSQLNAMEstructureineachDB2SQLVAR structure. • TheMfieldpointstoanarrayofintegersthatspecifythemaximumlengthofthe variablenames.ForDB2,theSQLNAMEstructurehasafixed-lengthbuffer,sothere isnoequivalenttotheMfield. • TheCfieldpointstoanarrayofintegersthatspecifytheactuallengthsofthenames pointedtobytheSarray.WhenOraclereturnsthecolumnorparameternames,it setstheintegersinthisarraytoindicatetheiractuallengths.ForDB2,theSQLNAME structurehasafixed-lengthbuffer,sothereisnoequivalenttotheCfield. • TheXfieldpointstoanarrayofstringpointersthatspecifythebufferswhereOracle istoreturnthenameofeachnamedindicatorparameter.Thesebuffersareused onlybytheOracleDESCRIBEBLINDLISTstatement;theyhavenoDB2equivalent. • TheYfieldpointstoanarrayofintegersspecifyingthesizeofeachbufferpointedto bytheXarray.ThereisnoDB2equivalent. • TheZfieldpointstoanarrayofintegersspecifyingactuallengthsoftheindicator parameternamespointedtobytheXarray.WhenOraclereturnstheindicator parameternames,itsetstheintegersinthisarraytoindicatetheiractuallengths. ThereisnoDB2equivalent.
Data Type Conversions
PART V
ThedatatypeformatsthatDB2usestoreceiveparametervaluesandreturnqueryresults arethosesupportedbytheIBMS/370architecturemainframesthatrunDB2.Becauseitwas designedasaportableDBMS,Oracleusesitsowninternaldatatypeformats.Oracle automaticallyconvertsbetweenitsinternaldataformatsandthoseofthecomputersystem onwhichitisrunningwhenitreceivesparametervaluesfromyourprogramandwhenit returnsqueryresultstoyourprogram. YourprogramcanusetheOracleSQLDAtocontrolthedatatypeconversionperformed byOracle.Forexample,supposeyourprogramusestheDESCRIBEstatementtodescribethe resultsofadynamicqueryanddiscovers(fromthedatatypecodeintheSQLDA)thatthefirst columncontainsnumericdata.Yourprogramcanrequestconversionofthenumericdataby changingthedatatypecodeintheSQLDAbeforeitfetchesthedata.Iftheprogramplacesthe datatypecodeforacharacterstringintotheSQLDA,forexample,Oraclewillconvertthefirst columnofqueryresultsandreturnittoyourprogramasastringofdigits. ThedatatypeconversionfeatureoftheOracleSQLDAprovidesexcellentportability,both acrossdifferentcomputersystemsandacrossdifferentprogramminglanguages.Asimilar featureissupportedbyseveralotherDBMSbrands,butnotbytheIBMSQLproducts.
508
Part V:
Programming with SQL
Dynamic SQL and the SQL Standard TheSQL1standarddidnotaddressdynamicSQL,sothedefactostandardfordynamicSQL, asdescribedintheprecedingsections,wassetbyIBM’simplementationinDB2.TheSQL2 standardexplicitlyincludedastandardfordynamicSQL,specifiedinaseparatechapter (Part3)ofthestandardthatwasnearly50pageslong.Part3grewtoover400pageswhenlast updatedin2003.InthesimplestareasofdynamicSQL,theSQLstandardcloselyfollowsthe dynamicSQLcurrentlyusedbycommercialDBMSproducts.Butinotherareas,including eventhemostbasicdynamicSQLqueries,thestandardintroducesincompatibilitieswith existingDBMSproducts,whichwillrequiretherewritingofapplications.Thenextseveral sectionsdescribetheSQLstandardfordynamicSQLindetail,withanemphasisonthe differencesfromtheDB2-styledynamicSQLdescribedintheprecedingsections. Inpractice,supportforSQLstandarddynamicSQLhasbeenslowtoappearin commercialDBMSproducts,andmostdynamicSQLprogrammingstillrequirestheuseof theold,DB2-styledynamicSQL.EvenwhenanewversionofaDBMSproductsupportsthe newSQLstatements,theDBMSvendoralwaysprovidesaprecompileroptionthataccepts theolddynamicSQLstructureusedbytheparticularDBMS.Often,thisisthedefault optionfortheprecompiler,becausewiththousandsandthousandsofSQLprograms alreadyinexistence,theDBMSvendorhasanabsoluterequirementthatnewDBMS versionsdonotbreakoldprograms.Thus,themigrationtoportionsoftheSQLstandard thatrepresentincompatibilitieswithcurrentpracticewillbeaslowandevolutionaryone.
Basic Dynamic SQL Statements TheSQLstatementsintheANSI/ISOSQLstandardthatimplementbasicdynamicSQL statementexecution(thatis,dynamicSQLthatdoesnotinvolvedatabasequeries)are showninFigure18-17.ThesestatementscloselyfollowtheDB2structureandlanguage. Thisincludesthesingle-stepandtwo-stepmethodsofexecutingdynamicSQLstatements. ThestandardEXECUTEIMMEDIATEstatementhasanidenticalsyntaxandoperationto thatofitsDB2counterpart.ItimmediatelyexecutestheSQLstatementpassedtotheDBMS asacharacterstring.Thus,theEXECUTEIMMEDIATEstatementinFigure18-3conformsto theSQLstandard. ThestandardPREPAREandEXECUTEstatementsalsooperateidenticallytotheirDB2stylecounterparts.ThePREPAREstatementpassesatextstringcontainingaSQLstatement totheDBMSandcausestheDBMStoanalyzethestatement,optimizeit,andbuildan applicationplanforit.TheEXECUTEstatementcausestheDBMStoactuallyexecutea previouslypreparedstatement.LiketheDB2version,theSQLstandardEXECUTEstatement optionallyacceptshostvariablesthatpassthespecificvaluestobeusedwhenexecutingthe SQLstatement.ThePREPAREandEXECUTEstatementsinFigure18-4(labeledasitems2 and3,respectively)thusconformtotheSQLstandard. TwousefulextensionstothePREPARE/EXECUTEstructureareapartoftheFullcompliance levelSQLstandardspecification(neitherispartoftheEntryorIntermediatecompliancelevels). ThefirstisausefulcompaniontothePREPAREstatementthatunpreparesapreviously compileddynamicSQLstatement.TheDEALLOCATEPREPAREstatementprovidesthis capability.WhentheDBMSprocessesthisstatement,itcanfreetheresourcesassociatedwith thecompiledstatement,whichwillusuallyincludesomeinternalrepresentationofthe applicationplanforthestatement.ThestatementnamedintheDEALLOCATEPREPARE statementmustmatchthenamespecifiedinapreviouslyexecutedPREPAREstatement.
Chapter 18:
Dynamic SQL*
509
EXECUTE IMMEDIATE host-variable PREPARE statement-name FROM host-variable
EXECUTE statement-name USING
host-variable ,
USING SQL DESCRIPTOR descriptor-name
INTO
host-variable ,
INTO SQL DESCRIPTOR descriptor-name DEALLOCATE PREPARE statement-name
FIGURE 18-17 SQL standard dynamic SQL statements
PART V
IntheabsenceofacapabilitylikethatprovidedbyDEALLOCATEPREPARE,theDBMS hasnowayofknowingwhetherapreviouslypreparedstatementwillbeexecutedagainor not,andsomustretainalloftheinformationassociatedwiththestatement.Inpractice, someDBMSbrandsmaintainthecompiledversionofthestatementonlyuntiltheendof atransaction;inthesesystems,astatementmustberepreparedforeachsubsequent transactionwhereitisused.Becauseoftheoverheadinvolvedinthisprocess,otherDBMS brandsmaintainthecompiledstatementinformationindefinitely.TheDEALLOCATE PREPAREcanplayamoreimportantroleinthesesystems,whereadatabasesessionmight lastforhours.Note,however,thattheSQLstandardexplicitlysaysthatwhetheraprepared statementisvalidoutsideofthetransactioninwhichitispreparedisimplementationdependent. TheSQLstandardextensiontotheDB2-styleEXECUTEstatementmaybeevenmore usefulinpractice.ItallowstheEXECUTEstatementtobeusedtoprocesssimplesingleton SELECTstatementsthatreturnasinglerowofqueryresults.LiketheDB2EXECUTE statement,theSQLstandardstatementincludesaUSINGclausethatnamesthehost variablesthatsupplythevaluesforparametersinthestatementbeingexecuted.Butthe SQLstandardstatementalsopermitsanoptionalINTOclausethatnamesthehostvariables thatreceivethevaluesreturnedbyasingle-rowquery. Supposeyouhavewrittenaprogramthatdynamicallygeneratesaquerystatementthat retrievesthenameandquotaofasalesperson,withthesalesperson’semployeenumberas aninputparameter.UsingDB2-styledynamicSQL,eventhissimplequeryinvolvestheuse
510
Part V:
Programming with SQL
ofaSQLDA,cursors,aFETCHstatementloop,andsoon.UsingstandarddynamicSQL,the statementcanbeexecutedusingthesimpletwo-statementsequence: PREPAREqrystmtFROM:statement_buffer; EXECUTEqrystmtUSING:emplnumINTO:name,:quota;
Aswithanypreparedstatement,thissingle-rowquerycouldbeexecutedrepeatedly afterbeingpreparedonce.Itstillsuffersfromtherestrictionthatthenumberofreturned columns,andtheirdatatypes,mustknowwhentheprogramiswritten,sincetheymust matchexactlythenumberanddatatypesofthehostvariablesintheINTOclause.This restrictionisremovedbyallowingtheuseofaSQLDA-styledescriptorareainsteadofalist ofhostvariables,asdescribedinthenextsection.
The Standard SQLDA AlthoughitssupportforPREPARE/EXECUTEprocessingcloselyparallelsthatofDB2 dynamicSQL,theSQLstandarddivergessubstantiallyfromDB2styleintheareaof dynamicqueryprocessing.Inparticular,theSQLstandardincludesmajorchangestothe DB2SQLDataArea(SQLDA),whichisattheheartofdynamicmultirowqueries.Recallthat aSQLDataArea(SQLDA)providestwoimportantfunctions: • AflexiblewaytopassparameterstobeusedintheexecutionofadynamicSQL statement(passingdatafromthehostprogramtotheDBMS),asdescribedearlierin thesection“EXECUTEwithSQLDA” • Thewaythatthequeryresultsarereturnedtotheprogramintheexecutionofa dynamicSQLquery(passingdatafromtheDBMSbacktothehostprogram),as describedearlierinthesection“TheDynamicFETCHStatement” TheDB2-styleSQLDAhandlesthesefunctionswithflexibility,butithassomeserious disadvantages.Itisaverylow-leveldatastructure,whichtendstobespecifictoaparticular programminglanguage.Forexample,thevariable-lengthstructureofaDB2-styleSQLDA makesitverydifficulttorepresentintheFORTRANlanguage.TheSQLDAstructurealso implicitlymakesassumptionsaboutthememoryofthecomputersystemonwhichthe dynamicSQLprogramisrunning,howdataitemsinastructurearealignedonsucha system,andsoon.ForthewritersoftheSQLstandard,theselow-leveldependencieswere unacceptablebarrierstoportability.Therefore,theyreplacedtheDB2SQLDAstructurewitha setofstatementsformanipulatingamoreabstractstructurecalledadynamicSQLdescriptor. ThestructureofaSQLdescriptorisshowninFigure18-18.Conceptually,theSQL descriptorisparallelto,andplaysexactlythesameroleas,theDB2-styleSQLDAshownin Figure18-7.ThefixedpartoftheSQLdescriptorspecifiesacountofthenumberofitemsin thevariablepartofthedescriptor.Eachiteminthevariablepartcontainsinformationabout asingleparameterbeingpassed,suchasitsdatatype,itslength,anindicatortelling whetheraNULLvalueisbeingpassed,andsoon. ButunliketheDB2SQLDA,theSQLdescriptorisnotanactualdatastructurewithinthe hostprogram.Instead,itisacollectionofdataitemsownedbytheDBMSsoftware.The hostprogrammanipulatesSQLdescriptors—creatingthem,destroyingthem,placingdata itemsintothem,extractingdatafromthem—viaanewsetofdynamicSQLstatements speciallydesignedforthatpurpose.Figure18-19summarizestheseSQLdescriptor managementstatements.
Chapter 18:
FIGURE 18-18 SQL standard descriptor structure
Dynamic SQL*
511
Fixed part
number of items described
COUNT
Variable part—one occurrence per item (parameter or query results column): data type of item TYPE LENGTH
length of item
OCTET_LENGTH
length of item (in 8-bit octets)
RETURNED_LENGTH
length of returned data item
RETURNED_OCTET_LENGTH
length of returned data (in 8-bit octets)
PRECISION
precision of data item
SCALE
scale of data item
DATETIME_INTERVAL_CODE
type of date/time interval data
DATETIME_INTERVAL_PRECISION
precision of date/time interval data
NULLABLE
can item be NULL?
INDICATOR
is data item NULL? (indicator value)
DATA
data item itself
NAME
name of data item
UNNAMED
is data item unnamed?
TounderstandhowtheSQLdescriptormanagementstatementswork,it’sinstructiveto reexaminethedynamicSQLupdateprograminFigure18-8.Thisprogramillustratesthe useofaDB2-styleSQLDAinanEXECUTEstatement.Theflowoftheprogramremains identicalifaSQLdescriptorisusedinstead,butthespecificschangequitealot. ALLOCATE DESCRIPTOR descriptor-name WITH MAX number-of-items
DEALLOCATE DESCRIPTOR descriptor-name
PART V
SET DESCRIPTOR COUNT = host variable VALUE item number
item-name = host variable ,
GET DESCRIPTOR
host variable = COUNT VALUE item number
host variable = item-name ,
FIGURE 18-19 SQL standard descriptor management statements
512
Part V:
Programming with SQL
Beforeusingthedescriptor,theprogrammustcreateit,usingthestatement: ALLOCATEDESCRIPTORparmdescWITHMAX:parmcnt;
Thisstatementreplacestheallocationofstoragefortheparmdadatastructureatcallout 1inFigure18-8.Thedescriptor(namedparmdesc)willperformthesamefunctionsasthe parmda.NotethattheprograminFigure18-8hadtocalculatehowmuchstoragewouldbe requiredfortheparmdastructurebeforeallocatingit.WiththeSQLdescriptor,that calculationiseliminated,andthehostprogramsimplytellstheDBMShowmanyitemsthe variablepartofthedescriptormustbeabletohold. Thenextstepintheprogramistosetupthedescriptorsothatitdescribesthe parameterstobepassed—theirdatatypes,lengths,andsoon.Theloopatcallout2ofthe programremainsintact,butagain,thedetailsofhowthedescriptorisinitializeddifferfrom thosefortheSQLDA.Atcallout3andcallout4,thedatatypeandlengthfortheparameter arespecifiedwithaformoftheSETDESCRIPTORstatement,withthiscodeexcerpt: typecode=columns[i].typecode; length=columns[i].buflen; SETDESCRIPTORparmdescVALUE(:i+l)TYPE=:typecode SETDESCRIPTORparmdescVALUE(:i+l)LENGTH=:length;
ThedifferencesfromFigure18-8areinstructive.Becausethedescriptorismaintained bytheDBMS,thedatatypeandlengthmustbepassedtotheDBMS,throughtheSET DESCRIPTORstatement,usinghostvariables.Inthisparticularexample,thesimple variablestypecodeandlengthareused.Additionally,thedatatypecodesinFigure18-8 werespecifictoDB2.ThefactthateachDBMSvendoruseddifferentcodestorepresent differentSQLdatatypeswasamajorsourceofportabilityproblemsindynamicSQL. TheSQLstandardspecifiesintegerdatatypecodesforallofthedatatypesspecifiedinthe standard,eliminatingthisissue.TheSQLstandarddatatypecodesaresummarizedin Table18-2.So,inadditiontotheotherchanges,thedatatypecodesinthecolumnsstructure ofFigure18-8wouldneedtobemodifiedtousetheseSQLstandarddatatypecodes. Thestatementsatcallouts5and6inFigure18-8wereusedtobindtheSQLDAstructure totheprogrambuffersusedtocontaintheparameterdataandthecorrespondingindicator variable.Effectively,theyputpointerstotheseprogrambuffersintotheSQLDAfortheuseof theDBMS.WithSQLdescriptors,thistypeofbindingisnotpossible.Instead,thedatavalue andindicatorvaluearespecificallypassedashostvariableslaterintheprogram.Thus,the statementsatcallouts5and6wouldbeeliminatedintheconversiontostandardSQL. Thestatementatcallout7inFigure18-8setstheSQLDAtoindicatehowmany parametervaluesareactuallybeingpassedtotheDBMS.TheSQLdescriptormustsimilarly besettoindicatethenumberofpassedparameters.ThisisdonewithaformoftheSET DESCRIPTORstatement: SETDESCRIPTORparmdescCOUNT=:parmcnt;
Strictlyspeaking,thisSETDESCRIPTORstatementshouldprobablybeplacedearlierin theprogramandshouldbeexecutedbeforethosefortheindividualitems.TheSQL standardspecifiesacompletesetofrulesthatdescribehowsettingvaluesinsomepartsof thedescriptorcausesvaluesinotherpartsofthedescriptortobereset.Forthemostpart, theserulessimplyspecifythenaturalhierarchyofinformation.
Chapter 18:
Data Type
Dynamic SQL*
513
Code
Data Type Codes (TYPE) INTEGER
4
SMALLINT
5
NUMERIC
2
DECIMAL
3
FLOAT
6
REAL
7
DOUBLEPRECISION
8
CHARACTER
1
CHARACTERVARYING
12
BIT
14
BITVARYING
15
DATE/TIME/TIMESTAMP
9
INTERVAL
10
Date/Time Subcodes (Interval_Code) DATE
1
TIME
2
TIMEWITHTIMEZONE
4
TIMESTAMP
3
TIMESTAMPWITHTIMEZONE
5
Date/Time Subcodes (Interval_Precision) 1
MONTH
2
DAY
3
HOUR
4
MINUTE
5
SECOND
6
YEAR–MONTH
7
DAY–HOUR
8
DAY–MINUTE
9
DAY–SECOND
10
HOUR–MINUTE
11
HOUR–SECOND
12
MINUTE–SECOND
13
TABLE 18-2
SQL Standard Data Type Codes
PART V
YEAR
514
Part V:
Programming with SQL
Forexample,ifyousetthedatatypeforaparticularitemtoindicateaninteger,the standardsaysthatthecorrespondinginformationinthedescriptorthattellsthelengthof thesameitemwillberesettosomeimplementation-dependentvalue.Normallythis doesn’timpactyourprogramming;however,youcan’tassumethatjustbecauseyouset somevaluewithinthedescriptorpreviously,itstillretainsthesamevalue.It’sbesttofill thedescriptorhierarchically,startingwithhigher-levelinformation(forexample,the numberofitemsandtheirdatatypes)andthenproceedingtolower-levelinformation (datatypelengths,subtypes,whetherNULLvaluesareallowed,andsoon). TheflowoftheprograminFigure18-8cannowcontinueunmodified.ThePREPARE statementcompilesthedynamicUPDATEstatement,anditsformdoesnotchangefor standardSQL.Theprogramthenenterstheforloop,promptingtheuserforparameters. Hereagain,theconceptsarethesame,butthedetailsofmanipulatingtheSQLDAstructure andtheSQLdescriptordiffer. IftheuserindicatesthataNULLvalueistobeassigned(bytypinganasteriskin responsetotheprompt),theprograminFigure18-8setstheparameterindicatorbuffer appropriatelywiththestatement: *(parmvar->sqlind)=-1;
andifthevalueisnotNULL,theprogramagainsetstheindicatorbufferwiththestatement: *(parmvar->sqlind)=0;
FortheSQLdescriptor,thesestatementswouldagainbeconvertedtoapairofSET DESCRIPTORstatements: SETDESCRIPTORparmdescVALUE(:j+l)INDICATOR=-1; SETDESCRIPTORparmdescVALUE(:j+1)INDICATOR=0;
Noteagaintheuseoftheloopcontrolvariabletospecifywhichiteminthedescriptoris beingset,andthedirectpassingofdata(inthiscase,constants)ratherthantheuseof pointerstobuffersintheSQLDAstructure. Finally,theprograminFigure18-8passestheactualparametervaluetypedbytheuser totheDBMS,viatheSQLDA.Thestatementsatcallout8accomplishthisfordataofdifferent types,byfirstconvertingthetypedcharactersintobinaryrepresentationsofthedataand placingthebinarydataintothedatabufferspointedtobytheSQLDA.Again,theconversion tostandardSQLinvolvesreplacingthesepointersanddirectSQLDAmanipulationwitha SETDESCRIPTORstatement.Forexample,thesestatementspassthedataanditslengthfor avariable-lengthcharacterstring: length=strlen(inbuf); SETDESCRIPTORparmdescVALUE(:j+1)DATA=:inbuf; SETDESCRIPTORparmdescVALUE(:j+1)LENGTH=:length;
Fordataitemsthatdonotrequirealengthspecification,passingthedataiseveneasier, sinceonlytheDATAformoftheSETDESCRIPTORstatementisrequired.It’salsousefultonote thattheSQLstandardspecifiesimplicitdatatypeconversionsbetweenhostvariables(suchas inbuf)andSQLdatatypes.FollowingtheSQLstandard,itwouldbenecessaryforthe programinFigure18-8toperformallofthedatatypeconversioninthesscanf()functions.
Chapter 18:
Dynamic SQL*
515
Instead,thedatacouldbepassedtotheDBMSascharacterdata,forautomaticconversion anderrordetection. WiththeSQLDAfinallysetupasrequired,theprograminFigure18-8executesthe dynamicUPDATEstatementwiththepassedparametersatcallout9,usinganEXECUTE statementthatspecifiesaSQLDA.TheconversionofthisstatementtoaSQLdescriptoris straightforward;itbecomes EXECUTEupdatestmtUSINGSQLDESCRIPTORparmdesc;
ThekeywordsintheEXECUTEstatementchangeslightly,andthenameofthedescriptor isspecifiedinsteadofthenameoftheSQLDA. Finally,theprograminFigure18-8shouldbemodifiedlikethistotelltheDBMS todeallocatetheSQLdescriptor.Thestatementthatdoesthisis DEALLOCATEDESCRIPTORparmdesc;
Inasimpleprogramlikethisone,theDEALLOCATEisnotnecessary,butinamore complexreal-worldprogramwithmultipledescriptors,it’saverygoodideatodeallocate thedescriptorswhentheprogramnolongerrequiresthem.
The SQL Standard and Dynamic SQL Queries
ALLOCATEDESCRIPTORqrydescWITHMAX:colcount; DESCRIBEquerystmtUSINGSQLDESCRIPTORqrydesc;
ThestandardSQLformoftheDESCRIBEstatementhasaparalleleffectontheoneit replaces.Descriptionsofthequeryresultcolumnsarereturned,columnbycolumn,intothe SQLdescriptor,insteadofintotheSQLDA.BecausethedescriptorisaDBMSstructure,rather thananactualdatastructureintheprogram,thehostprogrammustretrievetheinformation fromthedescriptor,piecebypiece,asrequired.TheGETDESCRIPTORstatementperforms thisfunction,justastheSETDESCRIPTORfunctionperformstheoppositefunctionofputting
PART V
InthedynamicSQLstatementsoftheprecedingsections,theSQLdescriptor,liketheSQLDA itreplaces,isusedtopassparameterinformationfromthehostprogramtotheDBMS,for useindynamicstatementexecution.TheSQLstandardalsousestheSQLdescriptorin dynamicquerystatementswhere,liketheSQLDAitreplaces,itcontrolsthepassingofquery resultfromtheDBMSbacktothehostprogram.Figure18-9listsaDB2-styledynamicSQL queryprogram.It’susefultoexaminehowtheprograminFigure18-9wouldchangeto conformtotheSQLstandard.Again,theflowoftheprogramremainsidenticalunder standardSQL,butthespecificschangequitealot.ThestandardSQLformsofthedynamic SQLquery-processingstatementsareshowninFigure18-20. Thedeclarationofthecursorforthedynamicquery,incallout1ofFigure18-9,remains unchangedundertheSQLstandard.TheconstructionofthedynamicSELECTstatementin callout2isalsounchanged,asisthePREPAREstatementofcallout3.Thechangestothe programbeginatcallout4,wheretheprogramusestheDESCRIBEstatementtoobtaina descriptionofthequeryresults,whichisreturnedinaSQLDA-namedqry_da.Forstandard SQL,thisDESCRIBEstatementmustbemodifiedtorefertoaSQLdescriptor,whichmust havebeenpreviouslyallocated.Assumingthedescriptorisnamedqrydesc,thestatements wouldbe
516
Part V:
Programming with SQL
statement-name USING SQL DESCRIPTOR descriptor-name
DESCRIBE OUTPUT INPUT DECLARE cursor-name
CURSOR FOR statement-name SCROLL
INSENSITIVE ALLOCATE cursor-name
CURSOR FOR statement-name SCROLL
INSENSITIVE OPEN cursor-name USING
host-variable ,
USING SQL DESCRIPTOR descriptor-name FETCH cursor-name INTO
host-variable ,
INTO SQL DESCRIPTOR descriptor-name CLOSE cursor-name
FIGURE 18-20 Dynamic query-processing statements
informationintotheSQLdescriptor.IntheprogramofFigure18-9,thestatementsatcallout5, whichobtainsthelengthofaparticularcolumnofqueryresultsfromaSQLDA,wouldbe replacedwiththisstatement: GETDESCRIPTORqrydescVALUE(:i+1):length=LENGTH; qry_var->sqldat=malloc(length);
Thestatementatcallout5thatallocatesbuffersforeachitemofqueryresultsisstill needed,butthemethodfortellingtheDBMSwheretoputtheresultschangesforstandard SQL.InsteadofplacingtheaddressoftheprogramdestinationforeachitemintotheSQLDA, theprogrammustplacetheseaddressesintotheSQLdescriptor,usingtheSETDESCRIPTOR statement.ThebuffersfortheindicatorvariablesarenotneededwiththeSQLdescriptor. Instead,theinformationaboutwhetheracolumncontainsaNULLvaluecanbeobtained fromthedescriptorforeachrowasitisfetched,asseenlaterintheprogramexample. Inthisparticularexample,thenumberofcolumnsinthequeryresultsarecalculatedby theprogramasitbuildsthequery.Theprogramcouldalsoobtainthenumberofcolumns fromtheSQLdescriptorwiththisformoftheGETDESCRIPTORstatement: GETDESCRIPTORqrydesc:colcount=COUNT;
Chapter 18:
Dynamic SQL*
517
Havingobtainedthedescriptionofthequeryresults,theprogramperformsthequery byopeningthecursoratcallout6.ThesimpleformoftheOPENstatement,withoutany inputparameters,conformstotheSQLstandard.Ifthedynamicqueryspecified parameters,theycouldbepassedtotheDBMSeitherasaseriesofhostvariablesorviaa SQLdescriptor.ThestandardSQLOPENstatementusinghostvariablesisidenticaltothe DB2style,shownintheprograminFigure18-13.ThestandardSQLOPENstatementusinga descriptorisparalleltothestandardSQLEXECUTEstatementusingadescriptor,anddiffers fromtheDB2style.Forexample,theOPENstatementofFigure18-14: OPENqrycursorUSINGDESCRIPTOR:parmda;
ischangedforstandardSQLintothisOPENstatement: OPENqrycursorUSINGSQLDESCRIPTORparmdesc;
ThetechniqueforpassinginputparameterstotheOPENstatementviatheSQL descriptorisexactlythesameasthatdescribedearlierfortheEXECUTEstatement. LiketheOracleimplementationofdynamicSQL,theSQLstandardprovidesawayfor thehostprogramtoobtainadescriptionoftheparametersinadynamicqueryaswellasa descriptionofthequeryresults.FortheprogramfragmentinFigure18-14,thisDESCRIBE statement: DESCRIBEINPUTquerystmtUSINGSQLDESCRIPTORparmdesc;
willreturn,intheSQLdescriptornamedparmdesc,adescriptionofeachoftheparameters thatappearinthedynamicquery.ThenumberofparameterscanbeobtainedwiththeGET DESCRIPTORstatement,retrievingtheCOUNTitemfromthedescriptor.AswiththeOracle implementation,theSQLstandardcanhavetwodescriptorsassociatedwithadynamic query.Theinputdescriptor,obtainedwiththeDESCRIBEINPUTstatement,contains descriptionsoftheparameters.Theoutputdescriptorcontainsdescriptionsofthequery resultscolumns.Thestandardallowsyoutoexplicitlyaskfortheoutputdescription: DESCRIBEOUTPUTquerystmtUSINGSQLDESCRIPTORqrydesc;
FETCHsqlcursUSINGSQLDESCRIPTORqrydesc;
TheFETCHstatementadvancesthecursortothenextrowofqueryresultsandbrings thevaluesforthatrowintotheprogrambuffers,asspecifiedwithinthedescriptorstructure. Theprogrammuststillusethedescriptortodetermineinformationabouteachcolumnof returnedresults,suchasitslengthorwhetheritcontainsaNULLvalue.Forexample,to determinethereturnedlengthofacolumnofcharacterdata,theprogrammightusethe statement: GETDESCRIPTORqrydescVALUE(:i+1):length=RETURNED_LENGTH;
PART V
buttheDESCRIBEOUTPUTformofthestatementisthedefault,andthemostcommon practiceistoomitthekeywordOUTPUT. ReturningtothedynamicqueryexampleofFigure18-9,thecursorhasbeenopenedat callout6,andit’stimetofetchrowsofqueryresultsatcallout7.Again,thestandardSQL formoftheFETCHstatementisslightlymodifiedtousethestandardSQLdescriptor:
518
Part V:
Programming with SQL
TodeterminewhetherthevalueinthecolumnwasNULL,theprogramcanusethe statement: GETDESCRIPTORqrydescVALUE(:i+1):indbuf=INDICATOR;
Andsimilarlytodeterminethedatatypeofthecolumn,theprogramcanusethestatement: GETDESCRIPTORqrydescVALUE(:i+1):type=TYPE;
Asyoucansee,thedetailsofrow-by-rowqueryprocessingwithintheforloopofthe programwilldifferdramaticallyfromthoseinFigure18-9. Havingprocessedallrowsofqueryresults,theprogramclosesthecursoratcallout8. TheCLOSEstatementremainsunchangedunderstandardSQL.Followingtheclosingofthe cursor,itwouldbegoodpracticetodeallocatetheSQLdescriptor(s),whichwouldhave beenallocatedattheverybeginningoftheprogram. ThechangesrequiredtothedynamicSQLprogramsinFigures18-8,18-9,and18-14to makethemconformtotheSQLstandardillustrate,indetail,thenewfeaturesspecifiedby thestandardandthedegreetowhichtheydifferfromcommondynamicSQLusagetoday. Insummary,thechangesfromDB2-styledynamicSQLare • TheSQLDAstructureisreplacedwithanamedSQLdescriptor. • TheALLOCATEDESCRIPTORandDEALLOCATEDESCRIPTORstatementsareusedto createanddestroydescriptors,replacingallocationanddeallocationofhostprogram SQLDAdatastructures. • InsteadofdirectlymanipulatingelementsoftheSQLDA,theprogramspecifies parametervaluesandinformationthroughtheSETDESCRIPTORstatement. • InsteadofdirectlymanipulatingelementsoftheSQLDA,theprogramobtains informationaboutqueryresultsandobtainsthequeryresultdataitselfthroughthe GETDESCRIPTORstatement. • TheDESCRIBEstatementisusedbothtoobtaindescriptionsofqueryresults (DESCRIBEOUTPUT)andtoobtaindescriptionsofparameters(DESCRIBEINPUT). • TheEXECUTE,OPEN,andFETCHstatementsareslightlymodifiedtospecifytheSQL descriptorbynameinsteadoftheSQLDA.
Summary ThischapterdescribeddynamicSQL,anadvancedformofembeddedSQL.DynamicSQLis rarelyneededtowritesimpledataprocessingapplications,butitiscrucialforbuilding general-purposedatabasefront-ends.StaticSQLanddynamicSQLpresentaclassictradeoffbetweenefficiencyandflexibility,whichcanbesummarizedasfollows: • Simplicity StaticSQLisrelativelysimple;evenitsmostcomplexfeature,cursors, canbeeasilyunderstoodintermsoffamiliarfileinput/outputconcepts.Dynamic SQLiscomplex,requiringdynamicstatementgeneration,variable-lengthdata structures,andmemorymanagement,withmemoryallocation/deallocation,data typealignment,pointermanagement,andassociatedissues.
Chapter 18:
Dynamic SQL*
519
• Performance StaticSQLiscompiledintoanapplicationplanatcompile-time; dynamicSQLmustbecompiledatruntime.Asaresult,staticSQLperformanceis generallymuchbetterthanthatofdynamicSQL.TheperformanceofdynamicSQL isdramaticallyimpactedbythequalityoftheapplicationdesign;adesignthat minimizestheamountofcompilationoverheadcanapproachstaticSQLperformance. • Flexibility DynamicSQLallowsaprogramtodecideatruntimewhichspecific SQLstatementsitwillexecute.StaticSQLrequiresthatallSQLstatementsbecoded inadvance,whentheprogramiswritten,limitingtheflexibilityoftheprogram. DynamicSQLusesasetofextendedembeddedSQLstatementstosupportitsdynamic features: • TheEXECUTEIMMEDIATEstatementpassesthetextofadynamicSQLstatementto theDBMS,whichexecutesitimmediately. • ThePREPAREstatementpassesthetextofadynamicSQLstatementtotheDBMS, whichcompilesitintoanapplicationplanbutdoesnotexecuteit.Thedynamic statementmayincludeparametermarkerswhosevaluesarespecifiedwhenthe statementisexecuted. • TheEXECUTEstatementaskstheDBMStoexecuteadynamicstatementpreviously compiledbyaPREPAREstatement.Italsosuppliesparametervaluesforthe statementthatistobeexecuted. • TheDESCRIBEstatementreturnsadescriptionofapreviouslyprepareddynamic statementintoaSQLDA.Ifthedynamicstatementisaquery,thedescription includesadescriptionofeachcolumnofqueryresults. • TheDECLARECURSORstatementforadynamicqueryspecifiesthequerybythe statementnameassignedtoitwhenitwascompiledbythePREPAREstatement. • TheOPENstatementforadynamicquerypassesparametervaluesforthedynamic SELECTstatementandrequestsqueryexecution. • TheFETCHstatementforadynamicqueryfetchesarowofqueryresultsinto programdataareasspecifiedbyaSQLDAstructure. • TheCLOSEstatementforadynamicqueryendsaccesstothequeryresults.
PART V
This page intentionally left blank
19
CHAPTER
SQL APIs
T
heearlyIBMrelationaldatabaseprototypespioneeredtheembeddedSQLtechnique forprogrammaticaccesstoSQL-baseddatabases,whichwaswidelyadoptedby mainstreamSQLproducts.However,severalmajorDBMSproducts,ledbySybase’s firstSQLServerimplementation,tookaverydifferentapproach.Insteadoftryingtoblend SQLwithanotherprogramminglanguage,theseproductsprovidealibraryoffunctioncalls asanapplicationprogramminginterface(API)fortheDBMS.TopassSQLstatementstothe DBMS,anapplicationprogramcallsfunctionsintheAPI,anditcallsotherfunctionsto retrievequeryresultsandstatusinformationfromtheDBMS. Formanyprogrammers,aSQLAPIisaverystraightforwardwaytouseSQL.Most programmershavesomeexperienceinusingfunctionlibrariesforotherpurposes,suchas stringmanipulation,mathematicalfunctions,fileinput/output,andscreenforms management.Modernoperatingsystems,suchasUNIXandWindows,extensivelyuseAPI suitestoextendthecorecapabilitiesprovidedbytheOSitself.TheSQLAPIthusbecomes justanotherlibraryfortheprogrammertolearn. Overthelastdecadeorso,SQLAPIshavebecomeverypopular,equalingifnot surpassingthepopularityoftheembeddedSQLapproachfornewapplications development.ThischapterdescribesthegeneralconceptsusedbyallSQLAPIinterfaces.It alsodescribesspecificfeaturesofsomeoftheproprietaryAPIsusedbypopularSQL-based DBMSsystems,andboththeANSI/ISOSQLCall-LevelInterface(CLI)standardand Microsoft’sOpenDatabaseConnectivity(ODBC)standardonwhichtheANSI/ISOCLIis based.Finally,thischapterdescribesJDBC,whichistheAPIstandardforSQLaccessfrom programswritteninJava,andisusedbymostofthepopularInternetapplicationservers.
521
522
Part V:
Programming with SQL
API Concepts WhenaDBMSsupportsafunctioncallinterface,anapplicationprogramcommunicates withtheDBMSexclusivelythroughasetofcallsthatarecollectivelyknownasanapplication programminginterface,orAPI.ThebasicoperationofatypicalDBMSAPIisillustratedin Figure19-1. • TheprogrambeginsitsdatabaseaccesswithoneormoreAPIcallsthatconnectthe programtotheDBMSandoftentoaspecificdatabaseorschema. • TosendaSQLstatementtotheDBMS,theprogrambuildsthestatementasatext stringinabuffer(oftenstoredasahostlanguagevariable)andthenmakesanAPI calltopassthebuffercontentstotheDBMS. • TheprogrammakesAPIcallstocheckthestatusofitsDBMSrequestandtohandle errors. • Iftherequestisaquery,theprogramusesAPIcallstoretrievethequeryresultsinto theprogram’sbuffers.Typically,thecallsreturndataarowatatimeoracolumnat atime. • TheprogramendsitsdatabaseaccesswithanAPIcallthatdisconnectsitfrom theDBMS.
FIGURE 19-1
Using a SQL API for DBMS access
Chapter 19:
SQL APIs
523
FIGURE 19-2 An SQL API in a client/server architecture
ASQLAPIisoftenusedwhentheapplicationprogramandthedatabaseareontwo differentsystemsinaclient/serverarchitecture,asshowninFigure19-2.Inthis configuration,thecodefortheAPIfunctionsislocatedontheclientsystem,wherethe applicationprogramexecutes.TheDBMSsoftwareislocatedontheserversystem,where thedatabaseresides.CallsfromtheapplicationprogramtotheAPItakeplacelocallywithin theclientsystem,andtheAPIcodetranslatesthecallsintomessagesthatitsendstoand receivesfromtheDBMSoveranetwork.ASQLAPIoffersparticularadvantagesfora client/serverarchitecturebecauseitcanminimizetheamountofnetworktrafficbetween theAPIandtheDBMS. TheearlyAPIsofferedbyvariousDBMSproductsdifferedsubstantiallyfromone another.LikemanypartsofSQL,proprietarySQLAPIsproliferatedlongbeforetherewas anattempttostandardizethem.Inaddition,SQLAPIstendtoexposetheunderlying capabilitiesoftheDBMSmorethantheembeddedSQLapproach,leadingtoevenmore differences.Nonetheless,alloftheSQLAPIsavailableincommercialSQLproductsare basedonthesamefundamentalconceptsillustratedinFigures19-1and19-2.These conceptsalsoapplytotheODBCAPIandtomorerecentANSI/ISOstandardsbasedonit.
The dblib API (SQL Server)
PART V
ThefirstmajorDBMSproducttoemphasizeitscallableAPIwasSQLServer,inversions frombothSybaseandMicrosoft.Formanyyears,theSQLServercallableAPIwastheonly interfaceofferedbytheseproducts.BothMicrosoftandSybasenowofferembeddedSQL capabilitiesandhaveaddednewerorhigher-levelcallableAPIs,buttheoriginalSQLServer APIremainsaverypopularwaytoaccesstheseDBMSbrands.TheSQLServerAPIalso providedthemodelformuchofMicrosoft’sODBCAPI.SQLServeranditsAPIarealsoan excellentexampleofaDBMSdesignedfromthegrounduparoundaclient/server architecture.Forallofthesereasons,it’susefultobeginourexplorationofSQLAPIsby examiningthebasicSQLServerAPI. TheoriginalSQLServerAPI,whichiscalledthedatabaselibraryordblib,consistsof about100functionsavailabletoanapplicationprogram.TheAPIisverycomprehensive, butatypicalprogramusesonlyaboutadozenofthefunctioncalls,whicharesummarizedin Table19-1.Theothercallsprovideadvancedfeatures,alternativemethodsofinteractingwith theDBMS,orsingle-callversionsoffeaturesthatotherwisewouldrequiremultiplecalls.
524
Part V:
Programming with SQL
Function
Description
Database connection/disconnection dblogin()
Provides a data structure for login information
dbopen()
Opens a connection to SQL Server
dbuse()
Establishes the default database
dbexit()
Closes a connection to SQL Server
Basic statement processing dbcmd()
Passes SQL statement text to dblib
dbsqlexec()
Requests execution of a statement batch
dbresults()
Obtains results of next SQL statement in a batch
dbcancel()
Cancels the remainder of a statement batch
Error handling dbmsghandle()
Establishes a user-written message-handler procedure
dberrhandle()
Establishes a user-written error-handler procedure
Query results processing dbbind()
Binds a query results column to a program variable
dbnextrow()
Fetches the next row of query results
dbnumcols()
Obtains the number of columns of query results
dbcolname()
Obtains the name of a query results column
dbcoltype()
Obtains the data type of a query results column
dbcollen()
Obtains the maximum length of a query results column
dbdata()
Obtains a pointer to a retrieved data value
dbdatlen()
Obtains the actual length of a retrieved data value
dbcanquery()
Cancels a query before all rows are fetched
TABLE 19-1 Basic dblib API Functions
Basic SQL Server Techniques AsimpleSQLServerprogramthatupdatesadatabasecanuseaverysmallsetofdblibcalls todoitswork.TheprograminFigure19-3implementsasimplequotaupdateapplicationfor theSALESREPStableinthesampledatabase.ItisidenticaltotheprograminFigure17-17 (reproducedhereasFigure19-4),butusestheSQLServerAPIinsteadofembeddedSQL.The figureillustratesthebasicinteractionbetweenaprogramandSQLServer:
1. Theprogrampreparesaloginrecord,fillingintheusername,password,andany otherinformationrequiredtoconnecttotheDBMS.
2. Theprogramcallsdbopen()toestablishaconnectiontotheDBMS.Aconnection mustexistbeforetheprogramcansendSQLstatementstoSQLServer.
Chapter 19:
SQL APIs
525
main() { LOGINREC
*loginrec;
/* data structure for login information */
DBPROCESS *dbproc;
/* data structure for connection */
char
amount_str[31];
/* amount entered by user (as a string) */
int
status;
/* dblib call return status */
/* Get a login structure and set user name & password */ loginrec = dblogin(); DBSETLUSER(loginrec, "scott");
1
DBSETLPWD (loginrec, "tiger"); /* Connect to SQL Server */ dbproc = dbopen(loginrec, "");
2
/* Prompt the user for the amount of quota increase/decrease */ printf("Raise/lower by how much: "); gets(amount_str); /* Pass SQL statement to dblib */ dbcmd(dbproc, "update salesreps set quota = quota +");
3
dbcmd(dbproc, amount_str); /* Ask SQL Server to execute the statement */ dbsqlexec(dbproc);
4
/* Get results of statement execution */ status = dbresults(dbproc);
5
if (status != SUCCEED) printf("Error during update.\n");
PART V
else printf("Update successful.\n"); /* Break connection to SQL Server */ dbexit(dbproc); exit();
FIGURE 19-3 A simple program using dblib
6
526
Part V:
Programming with SQL
main() { exec sql include sqlca; exec sql begin declare section; float amount;
/* amount (from user) */
exec sql end declare section; /* Prompt the user for the amount of quota increase/decrease */ printf("Raise/lower quotas by how much:"); scanf("%f", &amount); /* Update the QUOTA column in the SALESREPS table */ exec sql update salesreps set quota = quota + :amount; /* Check results of statement execution */ if (sqlqa.sqlcode != 0) printf("Error during update.\n"); else printf("Update successful.\n"); exit(); }
FIGURE 19-4 The same program in Figure 19-3 using embedded SQL (from Figure 17-17)
3. TheprogrambuildsaSQLstatementinabufferandcallsdbcmd()topasstheSQL texttodblib.Successivecallstodbcmd()addtothepreviouslypassedtext;there isnorequirementthatacompleteSQLstatementbesentinasingledbcmd()call.
4. Theprogramcallsdbsqlexec(),instructingSQLServertoexecutethestatement previouslypassedwithdbcmd().
5. Theprogramcallsdbresults()todeterminethesuccessorfailureofthe statement.
6. Theprogramcallsdbexit()toclosedowntheconnectiontoSQLServer.
Chapter 19:
SQL APIs
527
It’sinstructivetocomparetheprogramsinFigure19-3andFigure19-4toseethe differencesbetweenthedblibapproachandtheembeddedSQL: • TheembeddedSQLprogrameitherimplicitlyconnectstotheonlyavailable database(asinDB2),oritincludesanembeddedSQLstatementforconnection (suchastheCONNECTstatementspecifiedbytheSQLstandard).Thedblib programconnectstoaparticularSQLServerwiththedbopen()call. • TheactualSQLUPDATEstatementprocessedbytheDBMSisidenticalinboth programs.WithembeddedSQL,thestatementispartoftheprogram’ssourcecode. Withdblib,thestatementispassedtotheAPIasasequenceofoneormore characterstrings.Infact,thedblibapproachmorecloselyresemblesthedynamic SQLEXECUTEIMMEDIATEstatementthanitdoesstaticSQL. • IntheembeddedSQLprogram,hostvariablesprovidethelinkbetweentheSQL statementsandthevaluesofprogramvariables.Withdblib,theprogrampasses variablevaluestotheDBMSinthesamewaythatitpassesprogramtext—aspartof aSQLstatementstring. • WithembeddedSQL,errorsarereturnedintheSQLCODEorSQLSTATEfieldofthe SQLCAstructure.Withdblib,thedbresults()callretrievesthestatusofeach SQLstatement. Overall,theembeddedSQLprograminFigure19-4isshorterandprobablyeasierto read.However,theprogramisneitherpurelyCnorpurelySQL,andaprogrammermustbe trainedintheuseofembeddedSQLtounderstandit.Theuseofhostvariablesmeansthat theinteractiveandembeddedformsoftheSQLstatementaredifferent.Inaddition,the embeddedSQLprogrammustbeprocessedbothbytheSQLprecompilerandbytheC compiler,lengtheningthecompilationcycle.Incontrast,theSQLServerprogramisaplainvanillaCprogram,directlyacceptabletotheCcompiler,anddoesnotrequirespecial codingtechniques.
Statement Batches
PART V
TheprograminFigure19-3sendsasingleSQLstatementtoSQLServerandchecksitsstatus. IfanapplicationprogrammustexecuteseveralSQLstatements,itcanrepeatthedbcmd()/ dbsqlexec()/dbresults()cycleforeachstatement.Alternatively,theprogramcan sendseveralstatementsasasinglestatementbatchtobeexecutedbySQLServer. Figure19-5showsaprogramthatusesabatchofthreeSQLstatements.AsinFigure19-3, theprogramcallsdbcmd()topassSQLtexttodblib.TheAPIsimplyconcatenatesthetext fromeachcall.Notethatit’stheprogram’sresponsibilitytoincludeanyrequiredspacesor punctuationinthepassedtext.SQLServerdoesnotbeginexecutingthestatementsuntilthe programcallsdbsqlexec().Inthisexample,threestatementshavebeensenttoSQLServer, sotheprogramcallsdbresults()threetimesinsuccession.Eachcalltodbresults() advancestheAPItotheresultsofthenextstatementinthebatchandtellstheprogramwhether thestatementsucceededorfailed. IntheprogramshowninFigure19-5,theprogrammerknowsinadvancethatthree statementsareinthebatch,andtheprogrammercancodethreecorrespondingcallsto dbresults().Ifthenumberofstatementsinthebatchisnotknowninadvance,the programcancalldbresults()repeatedlyuntilitreceivestheerrorcodeNO_MORE_ RESULTS.TheprogramexcerptinFigure19-6illustratesthistechnique.
528
Part V:
Programming with SQL
main() { LOGINREC
*loginrec;
/* data structure for login information */
DBPROCESS
*dbproc;
/* data structure for connection */
. . . /* Delete salespeople with low sales */ dbcmd(dbproc, "delete from salesreps where sales < 10000.00"); /* Increase quota for salespeople with moderate sales */ dbcmd(dbproc, "update salesreps set quota = quota + 10000.00"); dbcmd(dbproc, "where sales 150000.00"); /* Ask SQL Server to execute the statement batch */ dbsqlexec(dbproc); /* Check results of each of the three statements */ if (dbresults(dbproc) != SUCCEED) goto do_error; if (dbresults(dbproc) != SUCCEED) goto do_error; if (dbresults(dbproc) != SUCCEED) goto do_error; . . . }
FIGURE 19-5 Using a dblib statement batch
Error Handling
Thevaluereturnedbythedbresults()functiontellstheprogramwhetherthe correspondingstatementinthestatementbatchsucceededorfailed.Togetmoredetailed informationaboutafailure,yourprogrammustprovideitsownmessage-handlingfunction. Thedblibsoftwareautomaticallycallsthemessage-handlingfunctionwhenSQLServer encountersanerrorwhileexecutingSQLstatements.Notethatdblibcallsthemessagehandlingfunctionduringitsprocessingofthedbsqlexec()ordbresults()function calls,beforeitreturnstoyourprogram(i.e.,itisacallbackfunction,calledbackbytheSQL Serversoftware).Thisallowsthemessage-handlingfunctiontodoitsownerrorprocessing.
Chapter 19:
SQL APIs
529
.
FIGURE 19-6 Processing the results of a dblib statement batch
. . /* Execute statements previously with dbcmd() calls */ dbsqlexec(dbproc); /* Loop checking results of each statement in the batch */ while (status = dbresults(dbproc) != NO_MORE_RESULTS) { if (status == FAIL) goto handle_error; else printf("Statement succeeded.\n"); } /* Done with loop; batch completed successfully */ printf("Batch complete.\n"); exit(); . . .
Figure19-7showsanexcerptfromaSQLServerprogramthatincludesamessagehandlingfunctioncalledmsg_rtn().Whentheprogrambegins,itactivatesthemessagehandlingfunctionbycallingdberrhandle().Supposeanerroroccurslater,whileSQL ServerisprocessingtheDELETEstatement.Whentheprogramcallsdbsqlexec()or dbresults(),anddblibreceivestheerrormessagefromSQLServer,itcallsthemsg_ rtn()routineintheprogram,passingitfiveparameters: • dbproc Theconnectiononwhichtheerroroccurred
• severity Anumberindicatingtheseriousnessoftheerror • msgtext Anerrormessagecorrespondingtomsgno Themsg_rtn()functioninthisprogramhandlesthemessagebyprintingitandsaving theerrornumberinaprogramvariableforuselaterintheprogram.Whenthemessagehandlingfunctionreturnstodblib(whichcalledit),dblibcompletesitsownprocessing andthenreturnstotheprogramwithaFAILstatus.Theprogramcandetectthisreturn valueandperformfurthererrorprocessing,ifappropriate.
PART V
• msgno TheSQLServererrornumberidentifyingtheerror • msgstate Aparameterprovidinginformationabouttheerrorcontext
530
Part V:
Programming with SQL
. . . /* External variables to hold error information */ int errcode; /* saved error code */ char errmsg[256]; /* saved error message */ /* Define our own message-handling function */ int msg_rtn(dbproc, msgno, msgstate, severity, msgtext) DBPROCESS *dbproc; DBINT msgno; int msgstate; int severity; char *msgtext; extern int errcode; extern char *errmsg; { /* Print out the error number and message */ printf("*** Error: %d Message: %s\n", msgno, msgtext); /* Save the error information for the application program */ errcode = msgno; strcpy(errmsg, msgtext); /* Return to dlib to complete the API call */ return(0); } main() { DBPROCESS *dbproc; /* data structure for connection */ . . . /* Install our own error handling function */ dberrhandle(msg_rtn) . . . /* Execute a DELETE statement */ dbcmd(dbproc, "delete from salesreps where quota < 100000.00"); dbsqlexec(dbproc); dbresults(dbproc); . . .
FIGURE 19-7 Error handling in a dblib program
Chapter 19:
SQL APIs
531
TheprogramexcerptinthefigureactuallypresentsasimplifiedviewofSQLServer errorhandling.InadditiontoSQLstatementerrorsdetectedbySQLServer,errorscanalso occurwithinthedblibAPIitself.Forexample,ifthenetworkconnectiontotheSQLServer islost,adblibcallmaytimeoutwaitingforaresponsefromSQLServer,resultinginan error.TheAPIhandlestheseerrorsbycallingaseparateerror-handlingfunction,which operatesmuchlikethemessage-handlingfunctiondescribedhere. AcomparisonofFigure19-7withFigures17-10and17-14,reproducedhereas Figures19-8and19-9respectively,illustratesthedifferencesinerror-handlingtechniques betweendblibandembeddedSQL: • InembeddedSQL,theSQLCAstructureisusedtosignalerrorsandwarningstothe program.SQLServercommunicateserrorsandwarningsbycallingspecial functionswithintheapplicationprogramandreturningafailurestatusfortheAPI functionthatencounteredtheerror. • InembeddedSQL,errorprocessingissynchronous.TheembeddedSQLstatement fails,controlreturnstotheprogram,andtheSQLCODEorSQLSTATEvalueistested. SQLServererrorprocessingisasynchronous.WhenanAPIcallfails,SQLServer callstheapplicationprogram’serror-handlingormessage-handlingfunctionduring theAPIcall.Itreturnstotheapplicationprogramwithanerrorstatuslater. • EmbeddedSQLhasonlyasingletypeoferrorandasinglemechanismforreporting it.TheSQLServerschemehastwotypesoferrorsandtwoparallelmechanisms. Insummary,errorhandlinginembeddedSQLissimpleandstraightforward,butthe applicationprogramcanmakeonlyalimitednumberofresponseswhenanerroroccurs.A SQLServerprogramhasmoreflexibilityinhandlingerrors.However,thecallschemeused bydblibismoresophisticated,andwhileitisfamiliartosystemsprogrammers,itmaybe unfamiliartoapplicationprogrammers. FIGURE 19-8 A C embedded SQL program excerpt with SQLCODE error checking (from Figure 17-10)
. . . exec sql delete from salesreps where quota < 150000; goto error_routine; . . . error_routine: printf("SQL error: %ld\n, sqlca.sqlcode); exit(); . . .
PART V
if (sqlca.sqlcode < 0)
532
Part V:
Programming with SQL
FIGURE 19-9 A C embedded SQL program excerpt with GET DIAGNOSTICS error checking (from Figure 17-14)
. . . /* execute the DELETE statement & check for errors */ exec sql delete from salesreps where quota < 150000; if (strcmp(sqlca.sqlstate,"00000")) goto error_routine; /* DELETE successful; check how many rows deleted */ exec sql get diagnostics :numrows = ROW_COUNT; printf("%ld rows deleted\n",numrows); . . . error_routine: /* Determine how many errors reported */ exec sql get diagnostics :count = NUMBER; for (i=1; i quota order by name; /* Set up error processing */ whenever sqlerror goto error; whenever not found goto done; /* Open the cursor to start the query */ exec sql open repcurs;
2
/* Loop through each row of query results */ for (;;) { /* Fetch the next row of query results */ exec sql fetch repcurs
3
into :repname, :repquota, :repquota_ind, :repsales; /* Display the retrieved data */ printf("Name: %s\n", repname); if (repquota_ind < 0) printf("Quota is NULL\n"); else printf("Quota: %f\n", repquota); printf("Sales: %f\n", repsales); } error: printf("SQL error: %ld\n", sqlca.sqlcode); exit(); done: /* Query complete; close the cursor */ exec sql close repcurs; exit(); }
4
Chapter 19:
SQL APIs
537
IntheprogramshowninFigure19-10,ifoneofthesalesrepshadaNULLvalueinhisor herQUOTAcolumn,thedbnextrow()callforthatsalesrepwouldretrieveazerointothe repquotavariable.Notethattheprogramcannottellfromtheretrieveddatawhetherthe QUOTAcolumnfortherowreallyhasazerovalue,orwhetheritisNULL.Insome applications,theuseofsubstitutionvaluesisacceptable,butinothers,itisimportanttobe abletodetectNULLvalues.Theselatterapplicationsmustuseanalternativeschemefor retrievingqueryresults,describedinthenextsection.
Retrieval Using Pointers
WiththebasicSQLServerdataretrievaltechnique,thedbnextrow()callcopiesthedata valueforeachcolumnintooneofyourprogram’svariables.Iftherearemanyrowsofquery resultsormanylongcolumnsoftextdata,copyingthedataintoyourprogram’sdataareas cancreatesignificantoverhead.Inaddition,thedbnextrow()calllacksamechanismfor returningNULLvaluestoyourprogram. Tosolvethesetwoproblems,dbliboffersanalternatemethodofretrievingquery results.Figure19-13showstheprogramexcerptfromFigure19-10,rewrittentousethis alternatemethod:
1. TheprogramsendsthequerytoSQLServerandusesdbresults()toaccessthe results,asitdoesforanySQLstatement.However,theprogramdoesnotcall dbbind()tobindthecolumnsofqueryresultstoprogramvariables.
2. Theprogramcallsdbnextrow()toadvance,rowbyrow,throughthequery results.
3. Foreachcolumnofeachrow,theprogramcallsdbdata()toobtainapointertothe datavalueforthecolumn.Thepointerpointstoalocationwithindblib’sinternal buffers.
4. Ifacolumncontainsvariable-lengthdata,suchasaVARCHARdataitem,the programcallsdbdatlen()tofindthelengthofthedataitem.
5. IfacolumnhasaNULLvalue,thedbdata()functionreturnsanullpointer(0),and dbdatlen()returns0asthelengthoftheitem.Thesereturnvaluesgivethe programawaytodetectandrespondtoNULLvaluesinthequeryresults.
Random Row Retrieval
AprogramnormallyprocessesSQLServerqueryresultsbymovingthroughthem sequentiallyusingthedbnextrow()call.Forbrowsingapplications,dblibalsoprovides limitedrandomaccesstotherowsofqueryresults.Yourprogrammustexplicitlyenable randomrowaccessbyturningonadbliboption.Thedbgetrow()callcanthenbeused toretrievearowbyitsrownumber. Tosupportrandomrowretrieval,dblibstorestherowsofqueryresultsinaninternal buffer.Ifthequeryresultsfitentirelywithinthedblibbuffer,dbgetrow()supports randomretrievalofanyrow.Ifthequeryresultsexceedthesizeofthebuffer,onlytheinitial rowsofqueryresultsarestored.Theprogramcanrandomlyretrievetheserows,buta
PART V
TheprograminFigure19-13ismorecumbersomethantheoneinFigure19-10.In general,it’seasiertousethedbbind()functionthanthedbdata()approach,unlessyour programneedstohandleNULLvaluesorwillbehandlingalargevolumeofqueryresults.
538
Part V:
Programming with SQL
FIGURE 19-13 Retrieval using the dbdata() function
main() { LOGINREC *loginrec; /* data structure for login information */ char *namep; /* pointer to NAME column data */ int namelen; /* length of NAME column data */ float *quotap; /* pointer to QUOTA column data */ float *salesp; /* pointer to SALES column data */ char *namebuf; /* buffer to hold name */ /* Open a connection to SQL Server */ loginrec = dblogin(); DBSETLUSER(loginrec, "scott"); DBSETLPWD (loginrec, "tiger"); dbproc = dbopen(loginrec, ""); /* Pass query to dblib and ask SQL Server to execute it */ dbcmd(dbproc, "select name, quota, sales from salesreps "); dbcmd(dbproc, "where sales > quota order by name "); dbsqlexec(dbproc); /* Get to first statement in the batch */ dbresults(dbproc);
1
/* Retrieve the single row of query results */ while (status = dbnextrow(dbproc) == SUCCEED) {
2
/* Get the address of each data item in this row */ namep = dbdata(dbproc, 1); quotap = dbdata(dbproc, 2);
3
salesp = dbdata(dbproc, 3); namelen = dbdatlen(dbproc, 1);
4
/* Copy NAME value into our own buffer & null-terminate it */ strncpy(namebuf, namep, namelen); *(namebuf + namelen) = (char) 0; /* Print data for this salesperson */ printf("Name: %s\n", namebuf); if (quotap == 0) printf("Quota is NULL.\n"); else printf("Quota: %f\n", *quotap); printf("Sales: %f\n", *salesp); } /* Check for successful completion */ if (status == FAIL) printf("SQL error.\n"); dbexit(dbproc); exit(); }
5
Chapter 19:
SQL APIs
539
FIGURE 19-14 Random row retrieval dblib
dbnextrow()callthatattemptstoretrievearowpasttheendofthebufferreturnsthe specialBUF_FULLerrorcondition.Theprogrammustthendiscardsomeofthesavedrows fromthebuffer,usingthedbclrbuf()call,tomakeroomforthenewrow.Oncetherows arediscarded,theycannotbere-retrievedwiththedbgetrow()function.Thus,dblib supportsrandomretrievalofqueryresultswithinalimitedwindow,dictatedbythesizeof therowbuffer,asshowninFigure19-14.Yourprogramcanspecifythesizeofthedblib rowbufferbycallingthedblibroutinedbsetopt(). Therandomaccessprovidedbydbgetrow()issimilartothescrollcursorssupported byseveralDBMSproductsandspecifiedbytheSQLstandard.Inbothcases,random retrievalbyrownumberissupported.However,ascrollcursorisatruepointerintothe entiresetofqueryresults;itcanrangefromthefirsttothelastrow,evenifthequeryresults containthousandsofrows.Bycontrast,thedbgetrow()functionprovidesrandomaccess onlywithinalimitedwindow.Thisisadequateforlimitedbrowsingapplications,but cannoteasilybeextendedtolargequeries.
Positioned Updates
PART V
InanembeddedSQLprogram,acursorprovidesadirect,intimatelinkbetweenthe programandtheDBMSqueryprocessing.TheprogramcommunicateswiththeDBMS rowbyrowasitusestheFETCHstatementtoretrievequeryresults.Ifthequeryisasimple single-tablequery,theDBMScanmaintainadirectcorrespondencebetweenthecurrentrow ofqueryresultsandthecorrespondingrowwithinthedatabase.Usingthiscorrespondence, theprogramcanusethepositionedupdatestatements(UPDATE…WHERECURRENTOFand DELETE…WHERECURRENTOF)tomodifyordeletethecurrentrowofqueryresults. SQLServerqueryprocessingusesamuchmoredetached,asynchronousconnection betweentheprogramandtheDBMS.Inresponsetoastatementbatchcontainingoneor moreSELECTstatements,SQLServersendsthequeryresultsbacktothedblibsoftware, whichmanagesthem.Row-by-rowretrievalishandledbythedblibAPIcalls,notbySQL statements.Asaresult,earlyversionsofSQLServercouldnotsupportpositionedupdates, becauseitsnotionofacurrentrowappliedtoqueryresultswithinthedblibAPI,notto rowsoftheactualdatabasetables.
540
Part V:
Programming with SQL
LaterversionsofSQLServer(andSybase)addedcompletesupportforstandardSQL cursors,withtheirassociatedDECLARE/OPEN/FETCH/CLOSESQLstatements.SQLServer andSybasecursorsactuallyoperatewithinTransact-SQLstoredprocedures,andtheaction oftheFETCHstatementistofetchdatafromthedatabaseintothestoredprocedurefor processing—nottoactuallyretrieveitintotheapplicationprogramthatcalledthestored procedure.StoredproceduresandtheiroperationwithinvariouspopularSQLDBMS productsarediscussedinChapter20.
Dynamic Queries Intheprogramexamplesthusfarinthischapter,thequeriestobeperformedwereknown inadvance.Thecolumnsofqueryresultscouldbeboundtoprogramvariablesbyexplicit dbbind()callshard-codedintheprogram.MostprogramsthatuseSQLServercanbe writtenusingthistechnique.(Thisstaticcolumnbindingcorrespondstothefixedlistof hostvariablesusedinthestaticSQLFETCHstatementinstandardembeddedSQL, describedinChapter17.) Ifthequerytobecarriedoutbyaprogramisnotknownatthetimetheprogramis written,theprogramcannotincludehard-codeddbbind()calls.Instead,theprogrammust askdblibforadescriptionofeachcolumnofqueryresults,usingspecialAPIfunctions. Theprogramcanthenbindthecolumnsontheflytodataareasthatitallocatesatruntime. (ThisdynamiccolumnbindingcorrespondstotheuseofthedynamicSQLDBNUMCOLS() statementandSQLDA,indynamicembeddedSQL,asdescribedinChapter18.) Figure19-15showsaninteractivequeryprogramthatillustratesthedblibtechnique forhandlingdynamicqueries.Theprogramacceptsatablenameenteredbytheuserand thenpromptstheusertochoosewhichcolumnsaretoberetrievedfromthetable.Asthe userselectsthecolumns,theprogramconstructsaSELECTstatementandthenusesthese stepstoexecutetheSELECTstatementanddisplaythedatafromtheselectedcolumns:
1. TheprogrampassesthegeneratedSELECTstatementtoSQLServerusingthe dbcmd()call,requestsitsexecutionwiththedbsqlexec()call,andcalls dbresults()toadvancetheAPItothequeryresults,asitdoesforallqueries.
2. Theprogramcallsdbnumcols()tofindouthowmanycolumnsofqueryresults wereproducedbytheSELECTstatement.
3. Foreachcolumn,theprogramcallsdbcolname()tofindoutthenameofthe column,andcallsdbcoltype()tofindoutitsdatatype.
4. Theprogramallocatesabuffertoreceiveeachcolumnofqueryresultsandcalls dbbind()tobindeachcolumntoitsbuffer.
5. Whenallcolumnshavebeenbound,theprogramcallsdbnextrow()repeatedlyto retrieveeachrowofqueryresults.
Chapter 19:
SQL APIs
541
main() { /* This is a simple general-purpose query program. It prompts the user for a table name and then asks the user which columns of the table are to be included in the query. After the user's selections are complete, the program runs the requested query and displays the results. */ LOGINREC
*loginrec;
/* data structure for login information */
DBPROCESS *dbproc;
/* data structure for connection */
char
stmbuf[2001];
/* SQL text to be executed */
char
querytbl[32];
/* user-specified table */
char
querycol[32];
/* user-specified column */
int
status;
/* dblib return status */
int
first_col = 0;
/* is this the first column chosen? */
int
colcount;
/* number of columns of query results */
int
i;
/* index for columns */
char
inbuf[101];
/* input entered by user */
char
*item_name[100];
/* array to track column names */
char
*item_data[100];
/* array to track column buffers */
int char int
item_type[100];
/* array to track column data types */
*address;
/* address of buffer for current column */
length;
/* length of buffer for current column */
/* Open a connection to SQL Server */ loginrec = dblogin(); DBSETLUSER(loginrec, "scott"); DBSETLPWD (loginrec, "tiger"); dbproc = dbopen(loginrec, "");
printf("*** Mini-Query Program ***\n"); printf("Enter name of table for query: "); gets(querytbl); /* Start the SELECT statement in the buffer */ strcpy(stmbuf, "select ");
FIGURE 19-15
Using dblib for a dynamic query (continued)
PART V
/* Prompt the user for which table to query */
542
Part V:
Programming with SQL
/* Query the SQL Server system catalog to get column names */ dbcmd(dbproc, "select name from syscolumns "); dbcmd(dbproc, "where id = (select id from sysobjects "); dbcmd(dbproc, "where type = 'U' and name = "); dbcmd(dbproc, querytbl); dbcmd(dbproc, ")"); dbsqlexec(dbproc); /* Process the results of the query */ dbresults(dbproc); dbbind(dbproc, querycol); while (status = dbnextrow(dbproc) == SUCCEED) { printf("Include column %s (y/n)? ", querycol); gets(inbuf); if (inbuf[0] == 'y') { /* User wants the column; add it to the select list */ if (first_col++ > 0) strcat(stmbuf, ", "); strcat(stmbuf, querycol); } } /* Finish the SELECT statement with a FROM clause */ strcat(stmbuf, "from "); strcat(stmbuf, querytbl); /* Execute the query and advance to the query results */ dbcmd(dbproc, stmbuf); dbsqlexec(dbproc);
1
dbresults(dbproc); /* Ask dblib to describe each column, allocate memory, and bind it */ colcount = dbnumcols(dbproc);
2
for (i = 0; i < colcount; i++) { item_name[i] = dbcolname(dbproc, i); type = dbcoltype(dbproc, i); switch(type) {
FIGURE 19-15
Using dblib for a dynamic query
3
Chapter 19:
SQL APIs
543
case SQLCHAR: case SQLTEXT: case SQLDATETIME: length = dbcollen(dbproc, i) + 1; item_data[i] = address = malloc(length);
4
item_type[i] = NTBSTRINGBIND; dbbind(dbproc, i, NTBSTRINGBIND, length, address); break; case SQLINT1: case SQLINT2: case SQLINT4: item_data[i] = address = malloc(sizeof(long)): item_type[i] = INTBIND; dbbind(dbproc, i, INTBIND, sizeof(long), address); break; case SQLFLT8: case SQLMONEY: item_data[i] = address = malloc(sizeof(double)); item_type[i] = FLT8BIND; dbbind(dbproc, i, FLT8BIND, sizeof(double), address); break; } } /* Fetch and display the rows of query results */ while (status = dbnextrow(dbproc) == SUCCEED) {
5
/* Loop, printing data for each column of the row */ printf("\n");
/* Find the SQLVAR for this column; print column label */ printf("Column # %d (%s): ", i+1, item_name[i]; /* Handle each data type separately */ switch(item_type[i]) {
FIGURE 19-15
Using dblib for a dynamic query (continued)
PART V
for (i = 0; i < colcount; i++) {
544
Part V:
Programming with SQL
case NTBSTRINGBIND: /* Text data — just display it */ puts(item_data[i]); break; case INTBIND: /* Four-byte integer data — convert & display it */ printf("%lf", *((double *) (item_data[i]))); break; case FLT8BIND: /* Floating-point data — convert & display it */ printf("%lf", *((double *) (item_data[i]))); break; } } } printf("\nEnd of data.\n"); /* Clean up allocated storage */ for (i = 0; i < colcount; i++) { free(item_data[i]); } dbexit(dbproc); exit(); }
FIGURE 19-15
Using dblib for a dynamic query (continued)
Thedblib-basedprograminFigure19-15performsexactlythesamefunctionasthe dynamicembeddedSQLprograminFigure18-9,reproducedhereasFigure19-16.It’s instructivetocomparethetwoprogramsandthetechniquestheyuse: • ForbothembeddedSQLanddblib,theprogrambuildsaSELECTstatementinits buffersandsubmitsittotheDBMSforprocessing.WithdynamicSQL,thespecial PREPAREstatementhandlesthistask;withtheSQLServerAPI,thestandard dbcmd()anddbsqlexec()functionsareused. • Forbothinterfaces,theprogrammustrequestadescriptionofthecolumnsofquery resultsfromtheDBMS.WithdynamicSQL,thespecialDBNUMCOLS()statement handlesthistask,andthedescriptionisreturnedinaSQLDAdatastructure.With dblib,thedescriptionisobtainedbycallingAPIfunctions.Notethattheprogram inFigure19-15maintainsitsownarraystokeeptrackofthecolumninformation.
Chapter 19:
SQL APIs
545
main() { /* This is a simple general-purpose query program. It prompts the user for a table name, and then asks the user which columns of the table are to be included in the query. After the user's selections are complete, the program runs the requested query and displays the results. */ exec sql include sqlca; exec sql include sqlda; exec sql begin declare section; char stmtbuf[2001];
/* SQL text to be executed */
char querytbl[32];
/* user-specified table */
char querycol[32];
/* user-specified column */
exec sql end declare section; /* Cursor for system catalog query that retrieves column names */ exec sql declare tblcurs cursor for select colname from system.syscolumns where tblname = :querytbl and owner = user; exec sql declare qrycurs cursor for querystmt;
1
/* Data structures for the program */ colcount = 0;
int struct sqlda
*qry_da;
struct sqlvar *qry_var; int
i;
char
inbuf[101];
/* number of columns chosen */ /* allocated SQLDA for query */ /* SQLVAR for current column */ /* index for SQLVAR array in SQLDA */ /* input entered by user */
printf("*** Mini-Query Program ***\n\n") printf("Enter name of table for query: "); gets(querytbl);
FIGURE 19-16
Using embedded SQL EXECUTE with a SQLDA(from Figure 18-9) (continued)
PART V
/* Prompt the user for which table to query */
546
Part V:
Programming with SQL
/* Start the SELECT statement in the buffer */ strcpy(stmtbuf, "select "); /* Set up error processing */ exec sql whenever sqlerror goto handle_error; exec sql whenever not found goto no_more_columns; /* Query the system catalog to get column names for the table */ exec sql open tblcurs; for ( ; ; ) { 2 /* Get name of next column and prompt the user */ exec sql fetch tblcurs into :querycol; printf("Include column %s (y/n)? ", querycol); gets(inbuf); if (inbuf[0] == 'y') { /* User wants the column; add it to the select list */ if (colcount++ > 0) strcat(stmtbuf, ", "); strcat(stmtbuf, querycol); } } no_more_columns: exec sql close tblcurs; /* Finish the SELECT statement with a FROM clause */ strcat(stmtbuf, "from "); strcat(stmtbuf, querytbl); /* Allocate SQLDA for the dynamic query */ query_da = (SQLDA *)malloc(sizeof(SQLDA) + colcount * sizeof(SQLVAR)); query_da->sqln = colcount; /* Prepare the query and ask the DBMS to describe it */ exec sql prepare querystmt from :stmtbuf;
3
exec sql describe querystmt into qry_da;
4
FIGURE 19-16
Using embedded SQL EXECUTE with a SQLDA(from Figure 18-9)
Chapter 19:
SQL APIs
547
/* Loop through SQLVARs, allocating memory for each column */ for (i = 0; i < colcount; I++) { qry_var = qry_da->sqlvar + I; qry_var->sqldat = malloc(qry_var->sqllen);
5
qry_var->sqlind = malloc(sizeof(short)); } /* SQLDA is all set; do the query and retrieve the results! */ exec sql open qrycurs;
6
exec sql whenever not found goto no_more_data; for ( ; ; ) { /* Fetch the row of data into our buffers */ exec sql fetch sqlcurs using descriptor qry_da;
7
printf("\n"); /* Loop printing data for each column of the row */ for (i = 0; i < colcount; I++) { /* Find the SQLVAR for this column; print column label */ qry_var = qry_da->sqlvar + I; printf(" Column # %d (%s): ", i+1, qry_var->sqlname); /* Check indicator variable for NULL indication */ if (*(qry_var -> sqlind)) != 0) { puts("is NULL!\n"); continue; } /* Actual data returned; handle each type separately */
case 448: case 449: /* VARCHAR data -– just display it */ puts(qry_var -> sqldata); break; case 496: case 497:
FIGURE 19-16
Using embedded SQL EXECUTE with a SQLDA(from Figure 18-9) (continued)
PART V
switch (qry_var -> sqltype) {
548
Part V:
Programming with SQL
/* Four-byte integer data -– convert & display it */ printf("%ld", *((int *) (qry_var->sqldata))); break; case 500: case 501: /* Two-byte integer data -– convert & display it */ printf("%d", *((short *)(qry_var->sqldata))); break; case 480: case 481: /* Floating-point data -– convert & display it */ printf("%lf", *((double *)(qry_var->sqldat))); break; } } } no_more_data: printf("\nEnd of data.\n"); /* Clean up allocated storage */ for (i = 0; i < colcount; I++) { qry_var = qry_da->sqlvar + I; free(qry_var->sqldata); free(qry_var->sqlind); } free(qry_da); close qrycurs; exit(); }
FIGURE 19-16
Using embedded SQL EXECUTE with a SQLDA(from Figure 18-9) (continued)
8
Chapter 19:
SQL APIs
549
• Forbothinterfaces,theprogrammustallocatebufferstoreceivethequeryresults andmustbindindividualcolumnstothosebufferlocations.WithdynamicSQL,the programbindscolumnsbyplacingthebufferaddressesintotheSQLVARstructures intheSQLDA.WithSQLServer,theprogramusesthedbbind()functiontobindthe columns. • Forbothinterfaces,thequeryresultsarereturnedintotheprogram’sbuffers,row byrow.WithdynamicSQL,theprogramretrievesarowofqueryresultsusinga specialversionoftheFETCHstatementthatspecifiestheSQLDA.WithSQLServer, theprogramcallsdbnextrow()toretrievearow. Overall,thestrategyusedtohandledynamicqueriesisverysimilarforbothinterfaces. ThedynamicSQLtechniqueusesspecialstatementsanddatastructuresthatareuniqueto dynamicSQL;theyarequitedifferentfromthetechniquesusedforstaticSQLqueries.In contrast,thedblibtechniquesfordynamicqueriesarebasicallythesameasthoseusedfor allotherqueries.Theonlyaddedfeaturesarethedblibfunctionsthatreturninformation aboutthecolumnsofqueryresults.ThistendstomakethecallableAPIapproacheasierto understandfortheless-experiencedSQLprogrammer.
ODBC and the SQL/CLI Standard OpenDatabaseConnectivity(ODBC)isadatabase-independentcallableAPIsuiteoriginally developedbyMicrosoft.AlthoughMicrosoftplaysanimportantroleasadatabasesoftware vendor,itsdevelopmentofODBCwasmotivatedevenmorebyitsroleasamajoroperating systemdeveloper.MicrosoftwantedtomakeiteasierfordevelopersofWindowsapplications toincorporatedatabaseaccess.Butthelargedifferencesbetweenthevariousdatabasesystems andtheirAPIsmadethisverydifficult.Ifanapplicationdeveloperwantedaprogramtowork withseveraldifferentDBMSbrands,ithadtoprovideaseparate,speciallywrittendatabase interfacemodule(usuallycalledadriver)foreachone.Eachapplicationprogramthatwanted toprovideaccesstomultipledatabaseshadtoprovideasetofdrivers. Microsoft’ssolutiontothisproblemwastocreateODBCasauniform,standardized databaseaccessinterface,andtoincorporateitintotheWindowsoperatingsystem.For applicationdevelopers,ODBCeliminatedtheneedtowritecustomdatabasedrivers.For databasevendors,ODBCprovidedawaytogainsupportfromabroaderrangeof applicationprograms.
ODBCwouldhavebeenimportantevenasaMicrosoft-onlystandard.However,Microsoft workedtomakeitavendor-independentstandardaswell.Adatabasevendorassociation calledtheSQLAccessGroupwasworkingonstandardizingclient/serverprotocolsforremote databaseaccessataboutthesametimeasMicrosoft’soriginaldevelopmentofODBC. MicrosoftpersuadedtheSQLAccessGrouptoexpandtheirfocusandadoptODBCastheir standardforvendor-independentdatabaseaccess.ManagementoftheSQLAccessGroup standardwaseventuallyturnedovertotheEuropeanX/OPENconsortium,anotherstandards organization,aspartofitsoverallstandardsforaCommonApplicationEnvironment(CAE).
PART V
The Call-Level Interface Standardization
550
Part V:
Programming with SQL
Withthegrowingpopularityofcall-levelAPIsfordatabaseaccess,theofficialSQL standardsgroupseventuallyturnedtheirattentiontostandardizationofthisaspectofSQL. TheX/OPENstandard(basedonMicrosoft’searlierODBCwork)wastakenasastarting pointandslightlymodifiedtocreateanofficialANSI/ISOstandard.TheresultingSQL/CallLevelInterface(SQL/CLI)standardwaspublishedin1995asANSI/ISO/IEC9075-3-1995. Withafewmodifications,SQL/CLIbecamePart3oftheSQL:1999standardandhasbeen carriedforwardwithupdatestoallthesubsequentversionsoftheANSI/ISOstandard. MicrosofthasevolvedODBCtoconformtotheofficialSQL/CLIstandard.TheCLI standardroughlyformsthecorelevelofMicrosoft’sODBC3revision.Other,higher-level capabilitiesofODBC3gobeyondtheCLIspecificationtoprovidemoreAPIcapabilityand todealwiththespecificproblemsofmanagingODBCaspartoftheWindowsoperating system.Inpractice,thecore-levelODBCcapabilitiesandtheSQL/CLIspecificationform theeffectivecallableAPIstandard. Becauseofitssubstantialadvantagesforbothapplicationdevelopersanddatabase vendors,ODBC/CLIhasbecomeaverywidelysupportedstandard.VirtuallyallSQLbaseddatabasesystemsprovideanODBC/CLIinterfaceasoneoftheirsupported interfaces.SomeDBMSbrandshaveevenadoptedODBC/CLIastheirstandarddatabase API.ThousandsofapplicationprogramssupportODBC/CLI,includingalloftheleading programmingtoolspackages,query-andforms-processingtoolsandreportwriters,and popularproductivitysoftwaresuchasspreadsheetsandgraphicsprograms. TheSQL/CLIstandardincludesabout40differentAPIcalls,summarizedinTable19-2. Thecallsprovideacomprehensivefacilityforestablishingconnectionstoadatabaseserver, executingSQLstatements,retrievingandprocessingqueryresults,andhandlingerrorsin databaseprocessing.Theyprovideallofthecapabilitiesavailablethroughthestandard’s embeddedSQLinterface,includingbothstaticSQLanddynamicSQLcapabilities. ThesimpleCLIprograminFigure19-17repeatstheprograminFigure19-3and19-9, butitusestheCLIfunctions.ItfollowsthesequenceofstepsusedbymostCLI-based applications:
1. TheprogramconnectstotheCLIandallocatesdatastructuresforitsuse.
2. Itconnectstoaspecificdatabaseserver.
3. TheprogrambuildsSQLstatementsinitsmemorybuffers.
4. ItmakesCLIcallstorequeststatementexecutionandcheckstatus.
5. Uponsuccessfulcompletion,itmakesaCLIcalltocommitthedatabasetransaction.
6. Itdisconnectsfromthedatabaseandreleasesitsdatastructures.
AlloftheCLIroutinesreturnastatuscodeindicatingeithersuccessfulcompletionof theroutineorsometypeoferrororwarningaboutitsexecution.ThevaluesfortheCLI returnstatuscodesaresummarizedinTable19-3.Someoftheprogramexamplesinthis bookomitthecheckingofreturnstatuscodestoshortentheexampleandfocusonthe specificfeaturesbeingillustrated.However,productionprogramsthatcallCLIfunctions shouldalwayscheckthereturnvaluetoensurethatthefunctionwascompleted successfully.Symbolicconstantnamesforthereturnstatuscodesaswellasmanyother values,suchasdatatypecodesandstatement-idcodes,aretypicallydefinedinaheaderfile thatisincludedatthebeginningofaprogramthatusestheCLI.
Chapter 19:
Function
SQL APIs
551
Description
Resource and connection management SQLAllocHandle()
Allocates resources for environment, connection, descriptor, or statement
SQLFreeHandle()
Frees previously allocated resources
SQLAllocEnv()
Allocates resources for a SQL environment
SQLFreeEnv()
Frees resources for a SQL environment
SQLAllocConnect()
Allocates resources for a database connection
SQLFreeConnect()
Frees resources for a database connection
SQLAllocStmt()
Allocates resources for a SQL statement
SQLFreeStmt()
Frees resources for a SQL statement
SQLConnect()
Establishes a database connection
SQLDisconnect()
Ends an established database connection
Statement execution SQLExecDirect()
Directly executes a SQL statement
SQLPrepare()
Prepares a SQL statement for subsequent execution
SQLExecute()
Executes a previously prepared SQL statement
SQLRowCount()
Gets number of rows affected by last SQL statement
Transaction management SQLEndTran()
Ends a SQL transaction
SQLCancel()
Cancels execution of a SQL statement
Parameter handling SQLBindParam()
Binds program location to a parameter value
SQLParamData()
Processes deferred parameter values
SQLPutData()
Provides deferred parameter value or a portion of a character string value
Query results processing Sets the name of a cursor
SQLGetCursorName()
Obtains the name of a cursor
SQLFetch()
Fetches a row of query results
SQLFetchScroll()
Fetches a row of query results with scrolling
SQLCloseCursor()
Closes an open cursor
SQLGetData()
Obtains the value of a query results column
Query results description SQLNumResultCols()
Determines the number of query results columns
SQLDescribeCol()
Describes a single query results column
TABLE 19-2 SQL/CLI API Functions (continued)
PART V
SQLSetCursorName()
552
Part V:
Programming with SQL
Function
Description
SQLColAttribute()
Gets attribute of a query results column
SQLGetDescField()
Gets value of a descriptor field
SQLSetDescField()
Sets value of a descriptor field
SQLGetDescRec()
Gets values from a descriptor record
SQLSetDescRec()
Sets values in a descriptor record
SQLCopyDesc()
Copies descriptor area values
Error handling SQLError()
Obtains error information
SQLGetDiagField()
Gets value of a diagnostic record field
SQLGetDiagRec()
Gets value of the diagnostic record
Attribute management SQLSetEnvAttr()
Sets attribute value for a SQL environment
SQLGetEnvAttr()
Retrieves attribute value for a SQL environment
SQLSetStmtAttr()
Sets descriptor area to be used for a SQL statement
SQLGetStmtAttr()
Gets descriptor area for a SQL statement
Driver management SQLDataSources()
Gets a list of available SQL servers
SQLGetFunctions()
Gets information about supported features of a SQL implementation
SQLGetInfo()
Gets information about supported features of a SQL implementation
TABLE 19-2 SQL/CLI API Functions (continued)
CLI Structures TheCLImanagesinteractionsbetweenanapplicationprogramandasupporteddatabase throughahierarchyofconcepts,reflectedinahierarchyofCLIdatastructures: • SQL-environment Thehighest-levelenvironmentwithinwhichdatabaseaccess takesplace.TheCLIusesthedatastructureassociatedwithaSQL-environmentto keeptrackofthevariousapplicationprogramsthatareusingit. • SQL-connection Alogicalconnectiontoaspecificdatabaseserver.Conceptually, theCLIallowsasingleapplicationprogramtoconnecttoseveraldifferentdatabase serversconcurrently.Eachconnectionhasitsowndatastructure,whichtheCLIuses totrackconnectionstatus. • SQL-statement AnindividualSQLstatementtobeprocessedbyadatabaseserver. Astatementmaymovethroughseveralstagesofprocessing,astheDBMSprepares (compiles)it,executesit,processesanyerrors,andinthecaseofqueries,returnsthe resultstotheapplicationprogram.Conceptually,anapplicationprogrammayhave multipleSQLstatementsmovingthroughtheseprocessingstagesinparallel.Each statementhasitsowndatastructure,whichtheCLIusestotrackitsprogress.
Chapter 19:
SQL APIs
553
/* Program to raise all quotas by a user-specified amount */ #include
/* header file with CLI definitions */
main() { SQLHENV
env_hdl;
/* SQL-environment handle */
SQLHDBC
conn_hdl;
/* connection handle */
SQLHSTMT
stmt_hdl;
/* statement handle */
SQLRETURN
status;
/* CLI routine return status */
char
*svr_name
= "demo";
/* server name */
char
*user_name = "joe";
/* user name for connection */
char
*user_pswd = "xyz";
/* user password for connection */
char
amount_str[31];
/* amount entered by user */
char
stmt_buf[128];
/* buffer for SQL statement */
/* Allocate handles for SQL environment, connection, statement */ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env_hdl); SQLAllocHandle(SQL_HANDLE_DBC, env_hdl, &conn_hdl);
1
SQLAllocHandle(SQL_HANDLE_STMT, conn_hdl, &stmt_hdl); /* Connect to the database, passing server name, user, password */ /* SQL_NTS says NULL-terminated string instead of passing length */ SQLConnect(conn_hdl, svr_name, SQL_NTS,
2
user_name, SQL_NTS, user_pswd, SQL_NTS); /* Prompt the user for the amount of quota increase/decrease */ printf("Raise/lower quotas by how much: "); gets(amount_str); /* Assemble UPDATE statement and ask DBMS to execute it */ strcpy(stmt_buf, "update salesreps set quota = quota + "); strcat(stmt_buf, amount_str); status = SQLExecDirect(stmt_hdl, stmt_buf, SQL_NTS);
3 4
/* Commit if successful; rollback if not */ if (status) { SQLEndTran(SQL_HANDLE_ENV, env_hdl, SQL_ROLLBACK); printf("Error during update\n"); } else {
5
printf("Update successful.\n"); } /* Disconnect from database server */ SQLDisconnect(conn_hdl); /* Deallocate handles and exit */ SQLFreeHandle(SQL_HANDLE_STMT, stmt_hdl); SQLFreeHandle(SQL_HANDLE_DBC, conn_hdl); SQLFreeHandle(SQL_HANDLE_ENV, env_hdl); exit(); }
FIGURE 19-17
A simple program using SQL/CLI
6
PART V
SQLEndTran(SQL_HANDLE_ENV, env_hdl, SQL_COMMIT);
554
Part V:
Programming with SQL
CLI Return Value
Meaning
0
Statement completed successfully
1
Successful completion with warning
100
No data found (when retrieving query results)
99
Data needed (required dynamic parameter missing)
–1
Error during SQL statement execution
–2
Error—invalid handle supplied in call
TABLE 19-3 CLI Return Status Codes
TheCLIusesatechniquecommonlyusedbymodernoperatingsystemsandlibrary packagestomanagetheseconceptualentities.Asymbolicpointercalledahandleis associatedwiththeoverallSQLenvironment,withaSQLconnectiontoaspecificdatabase server,andwiththeexecutionofaSQLstatement.Thehandleidentifiesanareaofmemory managedbytheCLIitself.Sometypeofhandleispassedasoneoftheparametersinevery CLIcall.TheCLIroutinesthatmanagehandlesareshowninFigure19-18. Ahandleiscreated(allocated)usingtheCLISQLAllocHandle()routine.Oneofthe parametersoftheroutinetellstheCLIwhichtypeofhandleistobeallocated.Another parameterreturnsthehandlevaluetotheapplicationprogram.Onceallocated,ahandleis passedtosubsequentCLIroutinestomaintainacontextfortheCLIcalls.Inthisway, differentthreadsofexecutionwithinaprogramordifferentconcurrentlyrunningprograms (processes)caneachestablishtheirownconnectiontotheCLIandcanmaintaintheirown contexts,independentofoneanother.Handlesalsoallowasingleprogramtohavemultiple CLIconnectionstodifferentdatabaseservers,andtoprocessmorethanoneSQLstatement inparallel.Whenahandleisnolongerneeded,theapplicationcallsSQLFreeHandle()to telltheCLItoreleasetheresourcesitisusing. Inadditiontothegeneral-purposehandlemanagementroutines,SQLAllocHandle() andSQLFreeHandle(),theCLIspecificationincludesseparateroutinestocreateandfree anenvironment,connection,orstatementhandle.Theseroutines(SQLAllocEnv(), SQLAllocStmt(),andsoon)wereapartoftheoriginalODBCAPIandarestillsupported incurrentODBCimplementationsforbackwardcompatibility.However,Microsofthas indicatedthatthegeneralhandle-managementroutinesarenowthepreferredODBC functions,andthespecificroutinesmaybedroppedinfutureODBCreleases.Formaximum cross-platformportability,it’sbesttousethegeneral-purposeroutines.
SQL-Environment
TheSQL-environmentisthehighest-levelcontextusedbyanapplicationprograminits callstotheCLI.Asingle-threadedapplicationtypicallyhasoneSQL-environmentforthe entireprogram.AmultithreadedapplicationmayhaveoneSQL-environmentperthreador oneoverallSQL-environment,dependingonthearchitectureoftheprogram.TheCLI conceptuallypermitsmultipleconnections,possiblytoseveraldifferentdatabaseservers, fromwithinoneSQL-environment.AspecificCLIimplementationforaspecificDBMSmay ormaynotactuallysupportmultipleconnections.
Chapter 19:
SQL APIs
555
/* Allocate a handle for use in subsequent CLI calls */ short SQLAllocHandle ( SQLSMALLINT
HdlType,
/* IN:
integer handle type code */
SQLINTEGER
inHdl,
/* IN:
environment or conn handle */
SQLINTEGER
*rtnHdl)
/* OUT: returned handle */
/* Free a handle previously allocated by SQLAllocHandle() */ SQLSMALLINT SQLFreeHandle ( SQLSMALLINT
HdlType,
/* IN:
integer handle type code */
SQLINTEGER
inHdl)
/* IN:
handle to be freed */
/* Allocate a handle for a new SQL-environment */ SQLSMALLINT SQLAllocEnv ( SQLINTEGER
*envHdl)
/* OUT: returned environment handle */
/* Free an environment handle previously allocated by SQLAllocEnv() */ SQLSMALLINT SQLFreeEnv ( SQLINTEGER
envHdl)
/* IN:
environment handle */
/* Allocate a handle for a new SQL-connection */ SQLSMALLINT SQLAllocConnect ( SQLINTEGER
envHdl,
SQLINTEGER
*connHdl)
/* IN:
environment handle */
/* OUT: returned handle */
/* Free a connection handle previously allocated */ SQLSMALLINT SQLFreeConnect ( SQLINTEGER
connHdl)
/* IN:
connection handle */
/* Allocate resources for an SQL statement */ SQLSMALLINT SQLAllocStmt ( envHdl,
SQLINTEGER
*stmtHdl)
/* IN:
environment handle */
/* OUT: statement handle */
/* Free a connection handle previously allocated */ SQLSMALLINT SQLFreeStmt ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLINTEGER
option)
/* IN:
cursor and unbind options */
FIGURE 19-18
SQL/CLI handle management routines
PART V
SQLINTEGER
556
Part V:
Programming with SQL
SQL-Connections
WithinaSQL-environment,anapplicationprogrammayestablishoneormoreSQLconnections.ASQL-connectionisalinkagebetweentheprogramandaspecificSQLserver (databaseserver)overwhichSQLstatementsareprocessed.Inpractice,aSQL-connection oftenisactuallyavirtualnetworkconnectiontoadatabaseserverlocatedonanother computersystem.However,aSQL-connectionmayalsobealogicalconnectionbetweena programandaDBMSlocatedonthesamecomputersystem. Figure19-19showstheCLIroutinesthatareusedtomanageSQL-connections.To establishaconnection,anapplicationprogramfirstallocatesaconnectionhandlebycalling SQLAllocHandle()withtheappropriatehandletype.Itthenattemptstoconnecttothe targetSQLserverwithaSQLConnect()call.SQLstatementscansubsequentlybe processedovertheconnection.Theconnectionhandleispassedasaparametertoallofthe statement-processingcallstoindicatewhichconnectionisbeingused.Whentheconnection isnolongerneeded,acalltoSQLDisconnect()terminatesit,andacallto SQLFreeHandle()releasestheassociatedconnectionhandleintheCLI.
/* Initiate a connection to a SQL-server */ SQLSMALLINT SQLConnect( SQLINTEGER SQLCHAR
connHdl,
*svrName,
SQLSMALLINT SQLINTEGER SQLSMALLINT SQLINTEGER SQLSMALLINT
svrnamlen, *userName, usrnamlen,
/* IN:
connection handle */
/* IN:
name of target SQL-server */
/* IN:
length of SQL-server name */
/* IN:
user name for connection */
/* IN:
length of user name */
*passwd,
/* IN:
connection password */
pswlen)
/* IN:
password length */
/* Disconnect from a SQL-server */ SQLSMALLINT SQLDisconnect( SQLINTEGER
connHdl)
/* IN:
connection handle */
/* Get the name(s) of accessible SQL-servers for connection */ SQLSMALLINT SQLDataSources ( SQLINTEGER
envHdl,
SQLSMALLINT
direction,
SQLINTEGER SQLSMALLINT
*svrname, buflen,
SQLSMALLINT *namlen, SQLINTEGER SQLSMALLINT
*descrip, buf2len,
SQLSMALLINT *dsclen)
/* IN: /* IN:
environment handle */
indicates first/next request */
/* OUT: buffer for server name */ /* IN:
length of server name buffer */
/* OUT: actual length of server name */ /* OUT: buffer for description */ /* IN:
length of description buffer */
/* OUT: actual length of description */
FIGURE 19-19 SQL/CLI connection management routines
Chapter 19:
SQL APIs
557
Normally,anapplicationprogramknowsthenameofthespecificdatabaseserver(in termsofthestandard,the“SQLserver”)thatitneedstoaccess.Incertainapplications(such asgeneral-purposequeryordataentrytools),itmaybedesirabletolettheuserchoose whichdatabaseserveristobeused.TheCLISQLDataSources()callreturnsthenamesof theSQLserversthatareknowntotheCLI—thatis,thedatasourcesthatcanbelegally specifiedasservernamesinSQLConnect()calls.Toobtainthelistofservernames,the applicationrepeatedlycallsSQLDataSources().Eachcallreturnsasingleserver description,untilthecallreturnsanerrorindicatingnomoredata.Aparametertothecall canbeoptionallyusedtoalterthissequentialretrievalofservernames.
CLI Statement Processing TheCLIprocessesSQLstatementsusingatechniqueverysimilartothatdescribedfor dynamicembeddedSQLinChapter18.TheSQLstatementispassedtotheCLIintextform, asacharacterstring.Itcanbeexecutedinaone-ortwo-stepprocess. Figure19-20showsthebasicSQLstatement-processingcalls.Theapplicationprogram mustfirstcallSQLAllocHandle()toobtainastatementhandle,whichidentifiesthe statementtotheprogramandtheCLI.AllsubsequentSQLExecDirect(), SQLPrepare(),andSQLExecute()callsreferencethisstatementhandle.Whenthe handleisnolongerneeded,itisfreedwithaSQLFreeHandle()call. Forone-stepexecution,theapplicationprogramcallsSQLSQLExecDirect(),passing theSQLstatementtextasoneoftheparameterstothecall.TheDBMSprocessesthestatement asaresultofthecallandreturnsthecompletionstatusofthestatement.Thisone-stepprocess wasusedinthesimpleexampleprograminFigure19-17.Itcorrespondstotheone-step EXECUTEIMMEDIATEstatementinembeddeddynamicSQL,describedinChapter18. Fortwo-stepexecution,theapplicationprogramcallsSQLPrepare(),passingtheSQL statementtextasoneoftheparameterstothecall.TheDBMSanalyzesthestatement, determineshowtocarryitout,andretainsthisinformation.Itdoesnotimmediatelycarry outthestatement.Instead,subsequentcallstotheSQLExecute()routineactuallycause thestatementtobeexecuted.Thistwo-stepprocesscorrespondsexactlytothePREPARE andEXECUTEembeddeddynamicSQLstatementsdescribedinChapter18.Youshould alwaysuseitforanySQLoperationsthatwillbecarriedoutrepeatedly,becauseitcauses theDBMStogothroughtheoverheadofstatementanalysisandoptimizationonlyonce,in responsetotheSQLPrepare()call.ParameterscanbepassedthroughtheCLItotailorthe operationofthemultipleSQLExecute()callsthatfollow. Inmanycases,aSQLstatementmustberepeatedlyexecutedwithchangesonlyinsomeof thevaluesthatitspecifies.Forexample,anINSERTstatementtoaddanordertothesample databaseisidenticalforeveryorderexceptforthespecificinformationaboutthecustomer number,productandmanufacturer,andquantityordered.AsdescribedinChapter18,for dynamicembeddedSQL,suchstatementscanbeprocessedefficientlybyspecifyingthe variablepartsofthestatementasinputparameters.Thestatementtextpassedtothe SQLPrepare()callhasaparametermarker—aquestionmark(?)—initstextateach positionwhereaparametervalueistobeinserted.Whenthestatementislaterexecuted, valuesmustbesuppliedforeachofitsinputparameters.
PART V
Statement Execution with Parameters
558
Part V:
Programming with SQL
/* Directly execute a SQL statement */ SQLSMALLINT SQLExecDirect ( SQLINTEGER SQLCHAR
stmtHdl,
*stmttext,
SQLSMALLINT
textlen)
/* IN:
statement handle */
/* IN:
SQL statement text */
/* IN:
statement text length */
/* Prepare a SQL statement */ SQLSMALLINT SQLPrepare ( SQLINTEGER SQLCHAR
stmtHdl,
*stmttext,
SQLSMALLINT
textlen)
/* IN:
statement handle */
/* IN:
SQL statement text */
/* IN:
statement text length */
/* Execute a previously prepared SQL statement */ SQLSMALLINT SQLExecute ( SQLINTEGER
stmtHdl)
/* IN:
statement handle */
/* Bind a SQL statement parameter to a program data area */ SQLSMALLINT SQLBindParam ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLSMALLINT
parmnr,
/* IN:
parameter number (1,2,3...) */
SQLSMALLINT
valtype,
/* IN:
data type of value supplied */
SQLSMALLINT
parmtype,
/* IN:
data type of parameter */
SQLSMALLINT
colsize,
/* IN:
column size */
SQLSMALLINT
decdigits, /* IN:
void
*value,
SQLINTEGER
*lenind)
number of decimal digits */
/* IN:
pointer to parameter value buf */
/* IN:
pointer to length/indicator buf */
/* Get parameter-tag for next required dynamic parameter */ SQLSMALLINT SQLParamData ( SQLINTEGER void
stmtHdl,
*prmtag)
/* IN:
stmt handle w/dynamic parms */
/* OUT: returned parameter-tag value */
/* Obtain detailed info about an item described by a CLI descriptor */ SQLSMALLINT SQLPutData ( SQLINTEGER void
stmtHdl,
*prmdata,
SQLSMALLINT
/* IN:
stmt handle w/dynamic parms */
/* IN:
buffer with data for parameter */
prmlenind) /* IN:
FIGURE 19-20 CLI statement-processing routines
parameter length or NULL ind */
Chapter 19:
SQL APIs
PART V
Themoststraightforwardwaytosupplyinputparametervaluesiswiththe SQLBindParam()call.EachcalltoSQLBindParam()establishesalinkagebetweenoneof theparametermarkersintheSQLstatement(identifiedbynumber)andavariableinthe applicationprogram(identifiedbyitsmemoryaddress).Inaddition,anassociationis optionallyestablishedwithasecondapplicationprogramvariable(aninteger)thatprovides thelengthofvariable-lengthinputparameters.IftheparameterisaNULL-terminatedstring likethoseusedinCprograms,aspecialnegativecodevalue,definedintheheaderfileas thesymbolicconstantSQL_NTS,canbepassed,indicatingthatthestringlengthcanbe obtainedfromthedataitselfbytheCLIroutines.Similarly,anegativecodeisusedto indicateaNULLvalueforaninputparameter.Ifthreeinputparametermarkersareinthe statement,threecallswillbemadetoSQLBindParam(),oneforeachinputparameter. Oncetheassociationbetweenapplicationprogramvariables(moreaccurately,program storagelocations)andthestatementparametersisestablished,thestatementcanbe executedwithacalltoSQLExecute().Tochangetheparametervaluesforsubsequent statements,itisonlynecessarytoplacenewvaluesintheapplicationprogrambufferareas beforethenextcalltoSQLExecute().Alternatively,theparameterscanbereboundto differentdataareaswithintheapplicationprogrambysubsequentcallsto SQLBindParam().Figure19-21showsaprogramthatincludesaSQLstatementwithtwo inputparameters.Theprogramrepeatedlypromptstheuserforacustomernumberanda newcreditlimitforthecustomer.Thevaluesprovidedbytheuserbecometheinput parameterstoanUPDATEstatementfortheCUSTOMERStable. TheSQLParamData()andSQLPutData()functionsprovideanalternativemethodof passingparameterdataatruntime,calleddeferredparameterpassing.Theselectionofthis techniqueforaparticularstatementparameterisindicatedinthecorrespondingcallto SQLBindParam().Insteadofactuallysupplyingaprogramdatalocationtowhichthe parameterisbound,theSQLBindParam()callindicatesthatdeferredparameterpassing willbeusedandprovidesavaluethatwilllaterbeusedtoidentifytheparticularparameter beingprocessedinthisway. Afterstatementexecutionisrequested(byaSQLExecute()orSQLExecDirect() call),theprogramcallsSQLParamData()todeterminewhetherdeferredparameterdatais requiredbythestatement.Ifso,theCLIreturnsastatuscode(SQL_NEED_DATA)alongwith anindicatorofwhichparameterneedsavalue.TheprogramthencallsSQLPutData()to actuallyprovidethevaluefortheparameter.Typically,theprogramthencalls SQLParamData()againtodetermineifanotherparameterrequiresdynamicdata.The cyclerepeatsuntilallrequireddynamicdatahasbeensupplied,andSQLstatement executionthencontinuesnormally. Thisalternativeparameter-passingmethodisconsiderablymorecomplexthanthe straightforwardprocessofbindingparameterstoapplicationprogramlocations.Ithastwo advantages.Thefirstisthattheactualpassingofdatavalues(andtheallocationofstorageto containthosevalues)canbedelayeduntilthelastpossiblemomentwhenthedataisactually needed.Thesecondadvantageisthatthetechniquecanbeusedtopassverylongparameter valuespiecebypiece.Forselectedlongdatatypes,theCLIallowsrepeatedcallsto SQLPutData()forthesameparameter,witheachcallpassingthenextpartofthedata.For example,thetextofadocumentthatissuppliedasaparameterfortheVALUESclauseofan INSERTstatementmightbepassedin1000-characterpiecesthroughrepeatedSQLPutData() callsuntilallofthedocumenthasbeenpassed.Thisavoidstheneedtoallocateasinglevery largememorybufferwithintheapplicationprogramtoholdtheentireparametervalue.
559
560
Part V:
Programming with SQL
/* Program to raise selected user-specified customer credit limits */ #include
/* header file with CLI defs */
main() { SQLHENV
env_hdl;
/* SQL-environment handle */
SQLHDBC
conn_hdl;
/* connection handle */
SQLHSTMT
stmt_hdl;
/* statement handle */
SQLRETURN
status;
/* CLI routine return status */
SQLCHAR
*svr_name
SQLCHAR
*user_name = "joe";
/* user name for connection */
SQLCHAR
*user_pswd = "xyz";
/* user password for connection */
char
amt_buf[31];
= "demo";
SQLINTEGER amt_ind = SQL_NTS; char
cust_buf[31];
/* server name */
/* amount entered by user */ /* amount ind (NULL-term string) */ /* cust # entered by user */
SQLINTEGER cust_ind = SQL_NTS;
/* cust # ind (NULL-term string) */
char
/* buffer for SQL statement */
stmt_buf[128];
/* Allocate handles for SQL environment, connection, statement */ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env_hdl); SQLAllocHandle(SQL_HANDLE_DBC, env_hdl, &conn_hdl); SQLAllocHandle(SQL_HANDLE_STMT, conn_hdl, &stmt_hdl); /* Connect to the database, passing server name, user, password */ /* SQL_NTS says NULL-terminated string instead of passing length */ SQLConnect(conn_hdl, svr_name, SQL_NTS, user_name, SQL_NTS, user_pswd, SQL_NTS); /* Prepare an UPDATE statement with parameter markers */ strcpy(stmt_buf, "update customers set credit_limit = ? "); strcat(stmt_buf, "where cust_num = ?"); SQLPrepare(stmt_hdl, stmt_buf, SQL_NTS); / * Bind parameters to the program's buffers */ SQLBindParam(stmt_hdl,1,SQL_C_CHAR,SQL_DECIMAL,9,2,&amt_buf,&amt_ind); SQLBindParam(stmt_hdl,2,SQL_C_CHAR,SQL_INTEGER,0,0,&cust_buf,&cust_ind);
FIGURE 19-21 CLI program using input parameters
Chapter 19:
SQL APIs
561
/ * Loop to process each credit limit change */ for ( ; ; ) { /* Prompt the user for the customer and new credit limit */ printf("Enter customer number: "); gets(cust_buf); if (strlen(cust_buf) == 0) break; printf("Enter new credit limit: "); gets(amt_buf); / * Execute the statement with the parameters */ status = SQLExecute(stmt_hdl); if (status) printf("Error during update\n"); else printf("Credit limit change successful.\n"); /* Commit the update */ SQLEndTran(SQL_HANDLE_ENV, env_hdl, SQL_COMMIT); } / * Disconnect, deallocate handles and exit */ SQLDisconnect(conn_hdl); SQLFreeHandle(SQL_HANDLE_STMT, stmt_hdl); SQLFreeHandle(SQL_HANDLE_DBC, conn_hdl); SQLFreeHandle(SQL_HANDLE_ENV, env_hdl); exit();
FIGURE 19-21 CLI program using input parameters (continued)
TheCOMMITandROLLBACKfunctionsforSQLtransactionprocessingalsoapplytoSQL operationviatheCLI.However,becausetheCLIitselfmustbeawarethatatransactionis beingcompleted,theCOMMITandROLLBACKSQLstatementsarereplacedbytheCLI SQLEndTran()call,showninFigure19-22.Thiscallwasusedtocommitthetransactions intheprogramexamplesofFigures19-17and19-21.ThesameCLIroutineisusedto executeeitheraCOMMIToraROLLBACKoperation;theparticularoperationtobeperformed isspecifiedbythecompletiontypeparametertothecall. TheCLISQLCancel()call,alsoshowninFigure19-22,doesnotactuallyprovidea transactionmanagementfunction,butinpracticeitisalmostalwaysusedinconjunctionwitha ROLLBACKoperation.ItisusedtocanceltheexecutionofaSQLstatementthatwaspreviously initiatedbyaSQLExecDirect()orSQLExecute()call.Thiswouldbeappropriateina programthatisusingdeferredparameterprocessing,asdescribedintheprevioussection.
PART V
CLI Transaction Management
562
Part V:
Programming with SQL
/* COMMIT or ROLLBACK a SQL transaction */ SQLSMALLINT SQLEndTran ( SQLSMALLINT
hdltype,
/* IN:
type of handle */
SQLINTEGER
txnHdl,
/* IN:
env, conn, or stmt handle */
SQLSMALLINT
compltype)
/* IN:
txn typ (COMMIT/ROLLBACK) */
/* Cancel a currently executing SQL statement */ SQLSMALLINT SQLCancel ( SQLSMALLINT
stmtHdl)
/* IN:
statement handle */
FIGURE 19-22 CLI transaction management routines
Iftheprogramdeterminesthatitshouldcancelthestatementexecutioninsteadofsupplying avalueforadeferredparameter,theprogramcancallSQLCancel()toachievethisresult. TheSQLCancel()callcanalsobeusedinamultithreadedapplicationtocancelthe effectofaSQLExecute()orSQLExecDirect()callthathasnotyetcompleted.Inthis situation,thethreadmakingtheoriginalexecutecallwillstillbewaitingforthecallto complete,butanotherconcurrentlyexecutingthreadmaycallSQLCancel()usingthe samestatementhandle.Thespecificsofthistechnique,andhowinterruptibleaCLIcallis, tendtobeveryimplementationdependent.
Processing Query Results with CLI
TheCLIroutinesdescribedthusfarcanbeusedtoprocessSQLdatadefinitionstatements orSQLdatamanipulationstatementsotherthanqueries(thatis,UPDATE,DELETE,and INSERTstatements).Forqueryprocessing,someadditionalCLIcalls,showninFigure19-23, arerequired.ThesimplestwaytoprocessqueryresultsiswiththeSQLBindCol()and SQLFetch()calls.Tocarryoutaqueryusingthesecalls,theapplicationprogramgoes throughthefollowingsteps(assumingaconnectionhasalreadybeenestablished):
1. TheprogramallocatesastatementhandleusingSQLAllocHandle().
2. TheprogramcallsSQLExecDirect()topassthetextoftheSQLSELECT statementandtocarryoutthequery.
3. TheprogramcallsSQLBindCol()onceforeachcolumnofqueryresultsthatwillbe returned.Eachcallassociatesaprogrambufferareawithareturneddatacolumn.
4. TheprogramcallsSQLFetch()tofetcharowofqueryresults.Thedatavaluefor eachcolumninthenewlyfetchedrowisplacedintotheappropriateprogrambuffer asindicatedinthepreviousSQLBindCol()calls.
5. Ifthequeryproducesmultiplerows,theprogramrepeatsStep4untilthe SQLFetch()callreturnsavalueindicatingthattherearenomorerows.
6. Whenallqueryresultshavebeenprocessed,theprogramcallsSQLDisconnect() toendthedatabasesession.
TheprogramexcerptinFigure19-24showsasimplequerycarriedoutusingthis technique.Theprogramisidenticalinfunctiontothedblib-basedprogramexamplein Figure19-10.It’sinstructivetocomparethetwoprograms.Thespecificsofthecallsand theirparametersarequitedifferent,buttheflowoftheprogramsandthelogicalsequence ofcallsthattheymakearethesame.
Chapter 19:
SQL APIs
563
/* Bind a query results column to a program data area */ SQLSMALLINT SQLBindCol ( SQLINTEGER
stmtHdl,
/* IN:
SQLSMALLINT
colnr,
/* IN:
statement handle */ column number to be bound */
SQLSMALLINT
tgttype,
/* IN:
data type of program data area */
void
value,
/* IN:
ptr to program data area */
SQLINTEGER
buflen,
/* IN:
length of program buffer */
SQLINTEGER
lenind)
/* IN:
ptr to length/indicator buffer */
/* Advance the cursor to the next row of query results */ SQLSMALLINT SQLFetch ( SQLINTEGER
stmtHdl)
/* IN:
statement handle */
/* Scroll the cursor up or down through the query results */ SQLSMALLINT SQLFetchScroll ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLSMALLINT
fetchdir,
/* IN:
direction (first/next/prev) */
SQLINTEGER
offset)
/* IN:
offset (number of rows) */
/* Get the data for a single column of query results */ SQLSMALLINT SQLGetData ( SQLINTEGER
stmtHdl,
/* IN:
SQLSMALLINT
colnr,
/* IN:
statement handle */ column number to be retrieved */
SQLSMALLINT tgttype, void *value,
/* IN: /* IN:
data type to return to program */ ptr to buffer for column data */
SQLINTEGER
buflen,
/* IN:
length of program buffer */
SQLINTEGER
*lenind)
/* OUT: actual length and/or NULL ind */
/* Close a cursor to end access to query results */ SQLSMALLINT SQLCloseCursor ( SQLINTEGER
stmtHdl)
/* IN:
statement handle */
/* Establish a cursor name for an open cursor */ SQLSMALLINT SQLSetCursorName ( stmtHdl,
/* IN:
statement handle */
SQLCHAR
cursname,
/* IN:
name for cursor */
SQLSMALLINT
namelen)
/* IN:
length of cursor name */
/* Retrieve the name of an open cursor */ SQLSMALLINT SQLGetCursorName ( SQLINTEGER SQLCHAR
stmtHdl, cursname,
SQLSMALLINT
buflen,
SQLSMALLINT *namlen)
/* IN: statement handle */ /* OUT: buffer for returned name */ /* IN:
length of buffer */
/* OUT: actual length of returned name */[
FIGURE 19-23 CLI query results processing routines
PART V
SQLINTEGER
564
Part V:
Programming with SQL
/* Program to display a report of sales reps over quota */ #include
/* header file with CLI definitions */
main() { SQLHENV
env_hdl;
/* SQL-environment handle */
SQLHDBC
conn_hdl;
/* connection handle */
SQLHSTMT
stmt_hdl;
/* statement handle */
SQLRETURN
status;
/* CLI routine return status */
SQLCHAR
*svr_name =
"demo";
SQLCHAR
*user_name = "joe";
SQLCHAR
*user_pswd = "xyz";
/* server name */ /* user name for connection */ /* user password for connection */
char
repname[16];
/* retrieved salesperson's name */
float
repquota;
/* retrieved quota */
float
repsales;
/* retrieved sales */
SQLSMALLINT repquota_ind;
/* NULL quota indicator */
char
/* buffer for SQL statement */
stmt_buf[128];
/* Allocate handles and connect to the database */ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env_hdl); SQLAllocHandle(SQL_HANDLE_DBC, env_hdl, &conn_hdl); SQLAllocHandle(SQL_HANDLE_STMT, conn_hdl, &stmt_hdl); SQLConnect(conn_hdl, svr_name, SQL_NTS, user_name, SQL_NTS, user_pswd, SQL_NTS); /* Request execution of the query */ strcpy(stmt_buf, "select name, quota, sales from salesreps "); strcat(stmt_buf, "where sales > quota order by name"); SQLExecDirect(stmt_hdl, stmt_buf, SQL_NTS); / * Bind retrieved columns to the program's buffers */ SQLBindCol(stmt_hdl,1,SQL_C_CHAR,repname,15,NULL); SQLBindCol(stmt_hdl,2,SQL_C_FLOAT,&repquota,0,"a_ind); SQLBindCol(stmt_hdl,3,SQL_C_FLOAT,&repsales,0,NULL); / * Loop through each row of query results */ for ( ; ; ) {
FIGURE 19-24 Retrieving CLI query results
Chapter 19:
SQL APIs
565
/* Fetch the next row of query results */ if (SQLFetch(stmt_hdl) != SQL_SUCCESS) break; /* Display the retrieved data */ printf("Name: %s\n", repname); if (repquota_ind < 0) printf("Quota is NULL\n"); else printf("Quota: %f\n", repquota); printf("Sales: %f\n", repsales); } / * Disconnect, deallocate handles and exit */ SQLDisconnect(conn_hdl); SQLFreeHandle(SQL_HANDLE_STMT, stmt_hdl); SQLFreeHandle(SQL_HANDLE_DBC, conn_hdl); SQLFreeHandle(SQL_HANDLE_ENV, env_hdl); exit();
FIGURE 19-24 Retrieving CLI query results (continued)
PART V
EachcalltoSQLBindCol()establishesanassociationbetweenonecolumnofquery results(identifiedbycolumnnumber)andanapplicationprogrambuffer(identifiedbyits address).WitheachcalltoSQLFetch(),theCLIusesthisbindingtocopytheappropriate datavalueforthecolumnintotheprogram’sbufferarea.Whenappropriate,asecond programdataareaisspecifiedastheindicator-variablebufferforthecolumn.Eachcallto SQLFetch()setsthisprogramvariabletoindicatetheactuallengthofthereturneddata value(forvariable-lengthdata)andtoindicatewhenaNULLvalueisreturned. TheCLIroutinesinFigure19-23canalsobeusedtoimplementanalternativemethodof processingqueryresults.Inthistechnique,thecolumnsofqueryresultsarenotboundto locationsintheapplicationprograminadvance.Instead,eachcalltoSQLFetch()only advancesthecursortothenextrowofqueryresults.Itdoesnotactuallycauseretrievalof dataintohostprogramdataareas.Instead,acalltoSQLGetData()ismadetoactually retrievethedata.OneoftheparametersofSQLGetData()specifieswhichcolumnofquery resultsistoberetrieved.Theotherparametersspecifythedatatypetobereturnedandthe locationofthebuffertoreceivethedataandanassociatedindicatorvariablevalue. Atthebasiclevel,theSQLGetData()callissimplyanalternativetothehost-variable bindingapproachprovidedbySQLBindCol(),butSQLGetData()providesanimportant advantagewhenprocessingverylargedataitems.Somedatabasessupportlongbinaryor character-valuedcolumnsthatcancontainthousandsormillionsofbytesofdata.It’s usuallyimpracticaltoallocateaprogrambuffertoholdallofthedatainsuchacolumn. UsingSQLGetData(),theprogramcanallocateabufferofreasonablesizeandworkits waythroughthedataafewthousandbytesatatime.
566
Part V:
Programming with SQL
It’spossibletointermixtheSQLBindCol()andSQLGetData()stylestoprocessthe queryresultsofasinglestatement.Inthiscase,theSQLFetch()callactuallyretrievesthedata valuesfortheboundcolumns(thoseforwhichaSQLBindCol()callhasbeenmade),butthe programmustexplicitlycallSQLGetData()toprocesstheothercolumns.Thistechniquemay beespeciallyappropriateifaqueryretrievesseveralcolumnsoftypicalSQLdata(names,dates, moneyamounts)andacolumnortwooflongdata,suchasthetextofacontract.Notethat someCLIimplementationsseverelyrestricttheabilitytointermixthetwostylesofprocessing. Inparticular,someimplementationsrequirethatalloftheboundcolumnsappearfirstinthe left-to-rightorderofqueryresults,beforeanycolumnsretrievedusingSQLGetData().
Scrolling Cursors
TheSQL/CLIstandardspecifiesCLIsupportforscrollingcursorsthatparallelsthe scrolling-cursorsupportoriginallyincludedintheSQLstandardforembeddedSQL.The SQLFetchScroll()call,showninFigure19-23,providestheextendedFETCHfunctions neededforforward/backwardandrandomretrievalofqueryresults.Oneofitsparameters specifiesthestatementhandleforthequery,justasforthesimpleSQLFetch()call.The othertwoparametersspecifythedirectionofFETCHmotion(PREVIOUS,NEXT,andsoon) andtheoffsetforFETCHmotionsthatrequireit(absoluteandrelativerandomrow retrieval).TheoperationofSQLBindCol()andSQLGetData()forprocessingreturned valuesisidenticaltothatdescribedfortheSQLFetch()call.
Named Cursors
NotethattheCLIdoesn’tincludeanexplicitcursordeclarationcalltoparallelthe embeddedSQLDECLARECURSORstatement.Instead,SQLquerytext(thatis,aSELECT statement)ispassedtotheCLIforexecutioninthesamemannerasanyotherSQL statement,usingeitheraSQLExecDirect()callorSQLPrepare()/SQLExecute() callsequence.Theresultsofthequeryareidentifiedbythestatementhandleinsubsequent SQLFetch(),SQLBindCol(),andsimilarcalls.Forthesepurposes,thestatementhandle takestheplaceofthecursornameusedinembeddedSQL. Aproblemwiththisschemearisesinthecaseofpositioned(cursor-based)updatesand positioneddeletes.AsdescribedinChapter17,apositioneddatabaseUPDATEorDELETE statement(UPDATE…WHERECURRENTOForDELETE…WHERECURRENTOF)canbeusedto modifyordeletethecurrent(thatis,justfetched)rowofqueryresults.Theseembedded SQLstatementsusethecursornametoidentifytheparticularrowtobeprocessed,sincean applicationprogrammayhavemorethanonecursoropenatatimetoprocessmorethan onesetofqueryresults. Tosupportpositionedupdates,theCLIprovidestheSQLSetCursorName()callshownin Figure19-23.Thecallisusedtoassignacursorname,specifiedasoneofitsparameters,toaset ofqueryresults,identifiedbythestatementhandlethatproducedthem.Oncethecallhasbeen made,thecursornamecanbeusedinsubsequentpositionedUPDATEorDELETEstatements, whichcanbepassedtotheCLIforexecution.Acompanioncall,SQLGetCursorName(),can beusedtoobtainapreviouslyassignedcursorname,givenitsstatementhandle.
Dynamic Query Processing with CLI
IfthecolumnstoberetrievedbyaSQLqueryarenotknowninadvancewhenaprogram isdeveloped,theprogramcanusethequery-processingcallsinFigure19-25todetermine thecharacteristicsofthequeryresultsatruntime.Thesecallsimplementthesametypeof dynamicSQLquery-processingcapabilitythatwasdescribedfordynamicembeddedSQL inChapter18.
Chapter 19:
SQL APIs
567
/* Determine the number of result columns in a query */ SQLSMALLINT SQLNumResultCols ( SQLINTEGER
stmtHdl,
SQLSMALLINT *colcount)
/* IN:
statement handle */
/* OUT: returned number of columns */
/* Determine the characteristics of a column of query results */ SQLSMALLINT SQLDescribeCol ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLSMALLINT
colnr,
/* IN:
number of column to describe */
SQLCHAR SQLSMALLINT
*colname, buflen,
/* OUT: name of query results column */ /* IN:
length of column name buffer */
SQLSMALLINT *namlen,
/* OUT: actual column name length */
SQLSMALLINT *coltype,
/* OUT: returned column data type code */
SQLSMALLINT *colsize,
/* OUT: returned column data length */
SQLSMALLINT *decdigits,
/* OUT: returned # of digits in column */
/* Obtain detailed info about a column of query results */ SQLSMALLINT SQLColAttribute ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLSMALLINT
colnr,
/* IN:
number of column to describe */
SQLSMALLINT
attrcode,
/* IN:
code of attribute to retrieve */
SQLCHAR
*attrinfo,
/* OUT: buffer for string attr. info */
SQLSMALLINT *buflen,
/* IN:
SQLSMALLINT *actlen,
/* OUT: actual attribute info length */
SQLINTEGER
/* OUT: returned integer attr. info */
*numattr)
length of column attribute buffer */
/* Retrieve frequently used info from a CLI descriptor */ short SQLGetDescRec ( SQLINTEGER SQLCHAR SQLSMALLINT
recnr, *name, buflen,
/* IN:
descriptor handle */
/* IN:
descriptor record number */
/* OUT: name of item being described */ /* IN:
length of name buffer */
SQLSMALLINT *namlen,
/* OUT: actual length of returned name */
SQLSMALLINT *datatype,
/* OUT: data type code for item */
SQLSMALLINT *subtype,
/* OUT: data type subcode for item */
SQLSMALLINT *length,
/* OUT: length of item */
SQLSMALLINT *precis,
/* OUT: precision of item, if numeric */
SQLSMALLINT *scale,
/* OUT: scale of item, if numeric */
SQLSMALLINT *nullable)
/* OUT: can item have NULL values */
FIGURE 19-25 CLI dynamic query-processing calls (continued)
PART V
SQLSMALLINT
descHdl,
568
Part V:
Programming with SQL
/* Set frequently used info in a CLI descriptor */ SQLSMALLINT SQLSetDescRec ( SQLINTEGER
descHdl,
/* IN:
descriptor handle */
SQLSMALLINT
recnr,
/* IN:
descriptor record number */
SQLSMALLINT
datatype,
/* IN:
data type code for item */
SQLSMALLINT
subtype,
/* IN:
data type subcode for item */
SQLSMALLINT
length,
/* IN:
length of item */
SQLSMALLINT
precis,
/* IN:
precision of item, if numeric */
SQLSMALLINT void SQLSMALLINT
scale,
/* IN:
scale of item, if numeric */
*databuf,
/* IN:
data buffer address for item */
buflen,
/* IN:
data buffer length */
SQLSMALLINT *indbuf)
/* IN:
indicator buffer addr for item */
/* Get detailed info about an item described by a CLI descriptor */ SQLSMALLINT SQLGetDescField ( SQLINTEGER
descHdl,
/* IN:
descriptor handle */
SQLSMALLINT
recnr,
/* IN:
descriptor record number */
SQLSMALLINT
attrcode,
/* IN:
code of attribute to describe */
*attrinfo,
/* IN:
buffer for attribute info */
/* IN:
length of attribute info */
void SQLSMALLINT
buflen,
SQLSMALLINT *actlen)
/* OUT: actual length of returned info */
/* Set value of an item described by a CLI descriptor */ SQLSMALLINT SQLSetDescField ( SQLINTEGER
descHdl,
/* IN:
descriptor handle */
SQLSMALLINT
recnr,
/* IN:
descriptor record number */
SQLSMALLINT
attrcode,
/* IN:
code of attribute to describe */
*attrinfo,
/* IN:
buffer with attribute value */
buflen)
/* IN:
length of attribute info */
void SQLSMALLINT
/* Copy a CLI descriptor contents into another descriptor */ SQLSMALLINT SQLCopyDesc ( SQLINTEGER
indscHdl,
/* IN:
source descriptor handle */
SQLINTEGER
outdscHdl)
/* IN:
destination descriptor handle
*/
FIGURE 19-25 CLI dynamic query-processing calls (continued)
Chapter 19:
SQL APIs
569
HerearethestepsfordynamicqueryprocessingusingCLI:
1. TheprogramallocatesastatementhandleusingSQLAllocHandle().
2. TheprogramcallsSQLPrepare(),passingthetextoftheSQLSELECTstatement forthequery.
3. TheprogramcallsSQLExecute()tocarryoutthequery.
4. TheprogramcallsSQLNumResultCols()todeterminethenumberofcolumnsof queryresults.
5. TheprogramcallsSQLDescribeCol()onceforeachcolumnofreturnedquery resultstodetermineitsdatatype,size,whetheritmaycontainNULLvalues,and soon.
6. Theprogramallocatesmemorytoreceivethereturnedqueryresultsandbinds thesememorylocationstothecolumnsbycallingSQLBindCol()onceforeach column.
7. TheprogramcallsSQLFetch()tofetcharowofqueryresults.TheSQLFetch() calladvancesthecursortothenextrowofqueryresultsandreturnseachcolumnof resultsintotheappropriateareaintheapplicationprogram,asspecifiedinthe SQLBindCol()calls.
8. Ifthequeryproducesmultiplerows,theprogramrepeatsStep7untilthe SQLFetch()callreturnsavalueindicatingthattherearenomorerows.
9. Whenallqueryresultshavebeenprocessed,theprogramcallsSQLCloseCursor() toendaccesstothequeryresults.
PART V
Figure19-26showsaprogramthatusesthesetechniquestoprocessadynamicquery. TheprogramisidenticalinitsconceptandpurposetotheembeddeddynamicSQLquery programshowninFigure19-16andthedblib-baseddynamicSQLqueryprogramshown inFigure19-15.Onceagain,it’sinstructivetocomparetheprogramexamplestoenhance yourunderstandingofdynamicqueryprocessing.TheAPIcallshavequitedifferentnames, butthesequenceoffunctionscallsforthedblibprogram(Figure19-15)andtheCLI program(Figure19-26)arenearlyidentical.Thedbcmd()/dbsqlexec()/dbresults() callsequenceisreplacedbySQLExecDirect().(Inthiscase,thequerywillbeexecuted onlyonce,sothere’snoadvantagetousingSQLPrepare()andSQLExecute() separately.)Thedbnumcols()callbecomesSQLNumResultCols().Thecallstoobtain columninformation(dbcolname(),dbcoltype(),dbcollen())becomeasinglecallto SQLDescribeCol().Thedbnextrow()callbecomesSQLFetch().Alloftheother changesintheprogramaremadetosupportthesechangesintheAPIfunctions. IfyoucomparetheprograminFigure19-26withthecorrespondingembeddeddynamic SQLprograminFigure19-16,oneofthemajordifferencesisembeddedSQL’suseofthe specialSQLDataArea(SQLDA)forcolumnbindingandcolumndescription.TheCLIsplits thesefunctionsbetweentheSQLNumResultCols(),SQLDescribeCol(),and SQLBindCol()functions,andmostprogrammersfindtheCLIstructureeasiertouseand understand.However,theCLIprovidesanalternative,lower-levelmethodthatoffers capabilitieslikethoseprovidedbytheembeddedSQLDA.
570
Part V:
Programming with SQL
main() { /* This is a simple general-purpose query program.
It prompts
the user for a table name, and then asks the user which columns of the table are to be included in the query.
After
the user's selections are complete, the program runs the requested query and displays the results. */ SQLHENV
env_hdl;
/* SQL-environment handle */
SQLHDBC
conn_hdl;
/* connection handle */
SQLHSTMT
stmt1_hdl;
/* statement handle for main query */
SQLHSTMT
stmt2_hdl;
/* statement handle for col name query */
SQLRETURN
status;
/* CLI routine return status */
SQLCHAR
*svr_name = "demo";
/* server name */
SQLCHAR
*user_name = "joe";
/* user name for connection */
SQLCHAR
*user_pswd = "xyz";
/* user password for connection */
char
stmtbuf[2001];
/* main SQL query text to be executed */
char
stmt2buf[2001];
/* SQL text for column name query */
char
querytbl[32];
/* user-specified query table */
char
querycol[32];
/* user-specified column */
int
first_col = 0;
/* is this the first column chosen? */
SQLSMALLINT colcount; SQLCHAR
*nameptr;
/* number of columns of query results */ /* address for CLI to return column name */
SQLSMALLINT namelen;
/* returned CLI column name length */
SQLSMALLINT type;
/* CLI data type code for column */
SQLSMALLINT size;
/* returned CLI column size */
SQLSMALLINT digits;
/* returned CLI column # digits */
SQLSMALLINT nullable;
/* returned CLI nullability */
short
/* index for columns */
char
i; inbuf[101];
/* inp
ut entered by user */
char
*item_name[100];
/* array to track column names */
char
*item_data[100];
/* array to track column buffers */
int
item_ind[100];
/* array of indicator variables */
item_type[100];
/* array to track column data types */
short SQLCHAR
*dataptr;
/* address of buffer for current column */
/* Open a connection to the demo database via CLI */ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env_hdl);
FIGURE 19-26 Using CLI for a dynamic query
Chapter 19:
SQL APIs
571
SQLAllocHandle(SQL_HANDLE_DBC, env_hdl, &conn_hdl); SQLAllocHandle(SQL_HANDLE_STMT, conn_hdl, &stmt1_hdl); SQLAllocHandle(SQL_HANDLE_STMT, conn_hdl, &stmt2_hdl); SQLConnect(conn_hdl, svr_name, SQL_NTS, user_name, SQL_NTS, user_name, SQL_NTS, /* Prompt the user for which table to query * / printf("*** Mini-Query Program ***\n"); printf("Enter name of table for query: "); gets(querytbl); /* Start the SELECT statement in the buffer */ strcpy(stmtbuf, "select "); /* Query the Information Schema to get column names */ strcpy(stmt2buf, "select column_name from columns where table_name = "); strcat(stmt2buf, querytbl); SQLExecDirect(stmt2_hdl, stmt2buf, SQL_NTS);
/* Process the results of the query */ SQLBindCol(stmt2_hdl, 1, SQL_C_CHAR, querycol, 31, (int *)0); while (status = SQLFetch(stmt2_hdl) == SQL_SUCCESS) { printf("Include column %s (y/n)? ", querycol); gets(inbuf); if (inbuf[0] == 'y') { /* User wants the column, add it to the select list */ if (first_col++ > 0) strcat(stmtbuf,", "); strcat(stmtbuf, querycol);
/* Finish the SELECT statement with a FROM clause */ strcat(stmtbuf, "from "); strcat(stmtbuf, querytbl); /* Execute the query and get ready to fetch query results */ SQLExecDirect(stmt1_hdl, stmtbuf, SQL_NTS);
FIGURE 19-26 Using CLI for a dynamic query (continued)
PART V
} }
572
Part V:
Programming with SQL
/* Ask CLI to describe each column, allocate memory & bind it */ SQLNumResultCols(stmt1_hdl, &colcount); for (i =0; i < colcount; i++) { item_name[i] = nameptr = malloc(32); indptr = &item_ind[i]; SQLDescribeCol(stmt1_hdl, i, nameptr, 32, &namelen, &type, &size, &digits, &nullable); switch(type) { case SQL_CHAR: case SQL_VARCHAR: /* Allocate buffer for string & bind the column to it */ item_data[i] = dataptr = malloc(size+1); item_type[i] = SQL_C_CHAR; SQLBindCol(stmt1_hdl, i, SQL_C_CHAR, dataptr, size+1, indptr); break; case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TYPE_TIME_WITH_TIMEZONE: case SQL_TYPE_TIMESTAMP: case SQL_TYPE TIMESTAMP_WITH_TIMEZONE: case SQL_INTERVAL_DAY: case SQL_INTERVAL_DAY_TO_HOUR: case SQL_INTERVAL_DAY_TO_MINUTE: case SQL_INTERVAL_DAY_TO_SECOND: case SQL_INTERVAL_HOUR: case SQL_INTERVAL_HOUR_TO_MINUTE: case SQL_INTERVAL_HOUR_TO_SECOND: case SQL_INTERVAL_MINUTE: case SQL_INTERVAL_MINUTE_TO_SECOND: case SQL_INTERVAL_MONTH: case SQL_INTERVAL_SECOND: case SQL_INTERVAL_YEAR: case SQL_INTERVAL_YEAR_TO_MONTH: /* Request ODBC/CLI conversion of these types to C-strings */ item_data[i] = dataptr = malloc(31); item_type[i] = SQL_C_CHAR; SQLBindCol(stmt1_hdl, i, SQL_C_CHAR, dataptr, 31, indptr); break;
FIGURE 19-26 Using CLI for a dynamic query
Chapter 19:
SQL APIs
573
case SQL_INTEGER: case SQL_SMALLINT: /* Convert these types to C long integers */ item_data[i] = dataptr = malloc(sizeof(integer)); item_type[i] = SQL_C_SLONG; SQLBindCol(stmt1_hdl, i, SQL_C_SLONG, dataptr, sizeof(integer), indptr); break; case SQL_NUMERIC: case SQL_DECIMAL: case SQL_FLOAT: case SQL_REAL: case SQL_DOUBLE: /* For illustration, convert these types to C double floats */ item_data[i] = dataptr = malloc(sizeof(long)); item_type[i] = SQL_C_DOUBLE; SQLBindCol(stmt1_hdl, i, SQL_C_DOUBLE, dataptr, sizeof(double), indptr); break; default: /* For simplicity, we don't handle bit strings, etc. */ printf("Cannot handle data type %d\n", (integer)type); exit(); } } /* Fetch and display the rows of query results */ while (status = SQLFetch(stmt1_hdl) == SQL_SUCCESS) { /* Loop, printing data for each column of the row / for(i = 0; i < colcount; i++) { /* Print column label */ printf("Column # %d (%s): ", i+1, item_name[i]); /* Check indicator variable for NULL indication */ if (item_ind[i] == SQL_NULL_DATA){ puts("is NULL!\n"); continue; }
FIGURE 19-26 Using CLI for a dynamic query (continued)
PART V
printf("\n");
574
Part V:
Programming with SQL
/* Handle each returned (maybe converted) data type separately / switch(item_type[i]) { case SQL_C_CHAR: /* Returned as text data - just display it */ puts(item_data[i]); break; case SQL_C_SLONG: /* Four-byte integer data - convert & display it */ printf("%ld", *((int *)(item_data[i]))); break; case SQL_C_DOUBLE: /* Floating-point data
convert & display it */
printf("%lf", *((double *)(item_data[i]))); break; } } } printf("\nEnd of data.\n"): /* Clean up allocated storage */ for (i = 0; i < colcount; i++) { free(item_data[i]); free(item_name[i]); } SQLDisconnect(conn_hdl); SQLFreeHandle(SQL_HANDLE_STMT, stmt1_hdl); SQLFreeHandle(SQL_HANDLE_STMT, stmt2_hdl); SQLFreeHandle(SQL_HANDLE_DBC, conn_hdl); SQLFreeHandle(SQL_HANDLE_ENV, env_hdl); exit(); }
FIGURE 19-26 Using CLI for a dynamic query (continued)
Chapter 19:
SQL APIs
575
ThealternativeCLImethodfordynamicqueryprocessinginvolvesCLIdescriptors.ACLI descriptorcontainslow-levelinformationaboutastatementparameter(aparameter descriptor)orthecolumnsofarowofqueryresults(arowdescriptor).Theinformationinthe descriptorislikethatcontainedinthevariableareaoftheSQLDA—thecolumnorparameter’s name,datatypeandsubtype,length,databufferlocation,NULLindicatorlocation,andsoon. Theparameterdescriptorsandrowdescriptorsthuscorrespondtotheinputandoutput SQLDAsprovidedbysomeDBMSbrandsintheirembeddeddynamicSQLimplementations. CLIdescriptorsareidentifiedbydescriptorhandles.TheCLIprovidesadefaultsetof descriptorsforparametersandqueryresultscolumnswhenastatementisprepared. Alternatively,theprogramcanallocateitsowndescriptorsandusethem.Thehandlesofthe descriptorsforastatementareconsideredstatementattributes,andtheyareassociatedwith aparticularstatementhandle.Thedescriptorhandlevaluescanberetrievedandsetbythe applicationprogramusingtheattributemanagementroutines,describedlaterinthesection “CLIAttributes.” Twocallsareusedtoretrieveinformationfromadescriptor,givenitshandle.The SQLGetDescField()callretrievesaparticularfieldofadescriptor,whichisidentifiedby acodevalue.Itistypicallyusedtoobtainthedatatypeorlengthofaqueryresultscolumn, forexample.TheSQLGetDescRec()callretrievesmanypiecesofinformationinonecall, includingthecolumnorparametername,datatypeandsubtype,length,precisionand scale,andwhetheritmaycontainNULLvalues.Acorrespondingsetofcallsisusedtoplace informationintoadescriptor.TheSQLSetDescField()callsetsthevalueofasinglepiece ofinformationwithinadescriptor.TheSQLSetDescRec()setsmultiplevaluesinasingle call,includingthedatatypeandsubtype,length,precisionandscale,andnullability.For convenience,theCLIprovidesaSQLCopyDesc()callthatcopiesallofthevaluesfromone descriptortoanother.
CLI Errors and Diagnostic Information
PART V
EachCLIfunctionreturnsashortintegervaluethatindicatesitscompletionstatus.Ifthe completionstatusindicatesanerror,theerror-handlingCLIcallsshowninFigure19-27can beusedtoobtainmoreinformationabouttheerroranddiagnoseit.ThemostbasicerrorhandlingcallisSQLError().Theapplicationprogrampassestheenvironment,connection, andstatementhandlesandisreturnedtheSQLSTATEresultcode,thenativeerrorcodeof thesubsystemproducingtheerror,andanerrormessageintextform. TheSQLError()routineactuallyretrievesspecific,frequentlyusedinformationfrom theCLIdiagnosticsarea.Theothererror-handlingroutinesprovidemorecomplete informationthroughdirectaccesstothediagnosticrecordscreatedandmaintainedbythe CLI.Ingeneral,aCLIcallcanproducemultipleerrors,whichresultinmultiplediagnostic records.TheSQLGetDiagRec()callretrievesanindividualdiagnosticrecord,byrecord number.Throughrepeatedcalls,theapplicationprogramcanretrievecompleteinformation aboutallerrorrecordsproducedbyaCLIcall.Evenmorecompleteinformationcanbe obtainedbyinterrogatingindividualdiagnosticfieldswithintherecord.Thiscapabilityis providedbytheSQLGetDiagField()call. Althoughnotstrictlyanerror-processingfunction,theSQLRowCount()function,like theerror-handlingfunctions,iscalledafterapreviousCLISQLExecute()call.Itisused todeterminetheimpactofthepreviousstatementwhenitwassuccessful.Areturned valueindicatesthenumberofrowsofdataaffectedbythepreviouslyexecutedstatement. (Forexample,thevalue4wouldbereturnedforasearchedUPDATEstatementthatupdates fourrows.)
576
Part V:
Programming with SQL
/* Retrieve error information associated with a previous CLI call */ SQLSMALLINT SQLError ( SQLINTEGER
envHdl,
/* IN:
environment handle */
SQLSMALLINT
connHdl,
/* IN:
connection handle */
SQLSMALLINT
stmtHdl,
/* IN:
statement handle */
SQLCHAR
*sqlstate,
/* OUT: five-character SQLSTATE value */
SQLSMALLINT *nativeerr,
/* OUT: returned native error code */
SQLCHAR
/* OUT: buffer for err message text */
SQLSMALLINT
*msgbuf, buflen,
/* IN:
SQLSMALLINT *msglen)
length of err msg text buffer */
/* OUT: returned actual msg length */
/* Determine number of rows affected by previous SQL statement */ SQLSMALLINT SQLRowCount ( SQLSMALLINT
stmtHdl,
/* IN:
SQLSMALLINT
*rowcnt)
/* OUT: number of rows */
statement handle */
/* Retrieve info from one of the CLI diagnostic error records */ SQLSMALLINT SQLGetDiagRec ( SQLSMALLINT
hdltype,
/* IN:
handle type code */
SQLSMALLINT
inHdl,
/* IN:
CLI handle */
/* IN:
requested err record number */
SQLSMALLINT SQLCHAR
recnr, *sqlstate,
/* OUT: returned 5-char SQLSTATE code */
SQLSMALLINT *nativeerr,
/* OUT: returned native error code */
SQLCHAR
/* OUT: buffer for err message text */
SQLSMALLINT
*msgbuf, buflen,
/* IN:
SQLSMALLINT *msglen)
length of err msg text buffer */
/* OUT: returned actual msg length */
/* Retrieve a field from one of the CLI diagnostic error records */ SQLSMALLINT SQLGetDiagField ( SQLSMALLINT
hdltype,
/* IN:
handle type code */
SQLSMALLINT
inHdl,
/* IN:
CLI handle */
SQLSMALLINT
recnr,
/* IN:
requested err record number */
SQLSMALLINT
diagid,
/* IN:
diagnostic field id */
void SQLSMALLINT
*diaginfo, buflen,
SQLSMALLINT *actlen)
FIGURE 19-27 CLI error-handling routines
/* OUT: returned diagnostic info */ /* IN:
length of diagonal info buffer */
/* OUT: returned actual info length */
Chapter 19:
SQL APIs
577
CLI Attributes TheCLIprovidesanumberofoptionsthatcontrolsomeofthedetailsofitsprocessing. Someofthesecontrolrelativelyminorbutcriticaldetails,suchaswhethertheCLIshould automaticallyassumethatparameterspassedasstringvaluesareNULL-terminated.Others controlbroaderaspectsofCLIoperation,suchasthescrollabilityofcursors. TheCLIgivesapplicationprogramsthecapabilitytocontroltheseprocessingoptions throughasetofCLIattributes.Theattributesarestructuredinahierarchy,parallelingthe environment/connection/statementhierarchyoftheCLIhandlestructure.Environment attributescontroloveralloperationaloptions.Connectionoptionsapplytoaparticular connectioncreatedbytheSQLConnect()call,butmayvaryfromoneconnectionto another.Statementattributesapplytotheprocessingofanindividualstatement,identified byaCLIstatementhandle. AsetofCLIcalls,showninFigure19-28,isusedbyanapplicationprogramtocontrol attributes.Thegetcalls(SQLGetEnvAttr(),SQLGetConnectAttr(),and SQLGetStmtAttr())obtaincurrentattributevalues.Thesetcalls(SQLSetEnvAttr(), SQLSetConnectAttr(),andSQLSetStmtAttr())modifythecurrentattributevalues. Inallofthecalls,theparticularattributebeingprocessedisindicatedbyacodevalue. AlthoughtheCLIstandardprovidesthiselaborateattributestructure,itactually specifiesrelativelyfewattributes.ThesingleenvironmentattributespecifiedisNULL TERMINATION;itcontrolsnull-terminatedstrings.Thesingleconnectionattributespecified controlswhethertheCLIautomaticallypopulatesaparameterdescriptorwhenastatement ispreparedorexecuted.Statement-levelattributescontrolthescrollabilityandsensitivityof cursors.PerhapsthemostimportantoftheCLI-specifiedattributesarethehandlesofthe fourCLIdescriptorsthatmaybeassociatedwithastatement(twoparameterdescriptors andtworowdescriptors).ThecallsinFigure19-28areusedtoobtainandsetthese descriptorhandleswhenusingdescriptor-basedstatementprocessing. TheODBCAPI,onwhichtheSQL/CLIstandardwasoriginallybased,includesmany moreattributes.Forexample,ODBCconnectionattributescanbeusedtospecifyareadonlyconnection,toenableasynchronousstatementprocessing,tospecifythetimeoutfora connectionrequest,andsoon.ODBCenvironmentattributescontrolautomatictranslation ofODBCcallsfromearlierversionsoftheODBCstandard.ODBCstatementattributes controltransactionisolationlevels,specifywhetheracursorisscrollable,andlimitthe numberofrowsofqueryresultsthatmightbegeneratedbyarunawayquery.
TheCLIincludesthreespecificcallsthatcanbeusedtoobtaininformationaboutthe particularCLIimplementation.Ingeneral,thesecallswillnotbeusedbyanapplication programwrittenforaspecificpurpose.Theyareneededbygeneral-purposeprograms (suchasaqueryorreportwritingprogram)thatneedtodeterminethespecific characteristicsoftheCLItheyareusing.ThecallsareshowninFigure19-29. TheSQLGetInfo()callisusedtoobtaindetailedinformationaboutaCLI implementation,suchasthemaximumlengthsoftableandusernames,whethertheDBMS supportsouterjoinsortransactions,andwhetherSQLidentifiersarecase-sensitive.The SQLGetFunctions()callisusedtodeterminewhetheraspecificimplementationsupports aparticularCLIfunctioncall.Itiscalledwithafunctioncodevaluecorrespondingtooneof theCLIfunctionsandreturnsaparameterindicatingwhetherthefunctionissupported.
PART V
CLI Information Calls
578
Part V:
Programming with SQL
/* Obtain the value of a SQL-environment attribute */ SQLSMALLINT SQLGetEnvAttr( SQLINTEGER
envHdl,
/* IN:
environment handle */
SQLINTEGER
attrCode,
/* IN:
integer attribute code */
void
*rtnVal,
SQLINTEGER
bufLen,
SQLINTEGER
*strLen)
/* OUT: return value */ /* IN:
length of rtnVal buffer */
/* OUT: length of actual data */
/* Set the value of a SQL-environment attribute */ SQLSMALLINT SQLSetEnvAttr( SQLINTEGER
envHdl,
/* IN:
SQLINTEGER
attrCode,
/* IN:
environment handle */ integer attribute code */
void
*attrVal,
/* IN:
new attribute value */
SQLINTEGER
*strLen)
/* IN:
length of data */
/* Obtain the value of a SQL-connection attribute */ SQLSMALLINT SQLGetConnectAttr( SQLINTEGER
connHdl,
/* IN:
connection handle */
SQLINTEGER
attrCode,
/* IN:
integer attribute code */
void
*rtnVal,
SQLINTEGER
bufLen,
SQLINTEGER
*strLen)
/* OUT: return value */ /* IN:
length of rtnVal buffer */
/* OUT: length of actual data
/* Set the value of a SQL-connection attribute */ SQLSMALLINT SQLSetConnectAttr( SQLINTEGER
connHdl,
/* IN:
SQLINTEGER
attrCode,
/* IN:
connection handle */ integer attribute code */
void
*attrVal,
/* IN:
new attribute value */
SQLINTEGER
*strLen)
/* IN:
length of data */
/* Obtain the value of a SQL-statement attribute */ SQLSMALLINT SQLGetStmtAttr( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLINTEGER
attrCode,
/* IN:
integer attribute code */
void
*rtnVal,
SQLINTEGER
bufLen,
SQLINTEGER
*strLen)
/* OUT: return value */ /* IN:
length of rtnVal buffer */
/* OUT: length of actual data */
/* Set the value of a SQL-statement attribute */ SQLSMALLINT SQLSetStmtAttr( SQLINTEGER
stmtHdl,
/* IN:
SQLINTEGER
attrCode,
/* IN:
statement handle */ integer attribute code */
void
*attrVal,
/* IN:
new attribute value */
SQLINTEGER
*strLen)
/* IN:
length of data */
FIGURE 19-28 CLI attribute management routines
Chapter 19:
SQL APIs
579
/* Retrieve detailed info about capabilities of a CLI implementation */ SQLSMALLINT SQLGetInfo ( SQLINTEGER
connHdl,
/* IN:
connection handle */
SQLSMALLINT
infotype,
/* IN:
type of info requested */
void SQLSMALLINT
*infoval, buflen,
/* OUT: buffer for retrieved info */ /* IN:
SQLSMALLINT *infolen)
length of info buffer */
/* OUT: returned info actual length */
/* Determine number of rows affected by previous SQL statement */ SQLSMALLINT SQLGetFunctions ( SQLINTEGER
connHdl,
/* IN:
connection handle */
SQLSMALLINT
functid,
/* IN:
function id code */
SQLSMALLINT *supported)
/* OUT: whether function supported */
/* Determine information about supported data types */ SQLSMALLINT SQLGetTypeInfo ( SQLINTEGER
stmtHdl,
/* IN:
statement handle */
SQLSMALLINT
datatype)
/* IN:
ALL TYPES or type requested */
FIGURE 19-29 CLI implementation information routines
TheSQLGetTypeInfo()callisusedtoobtaininformationaboutaparticular supporteddatatypeoraboutalltypessupportedviatheCLIinterface.Thecallactually behavesasifitwereaqueryagainstasystemcatalogofdatatypeinformation.Itproducesa setofqueryresultrows,eachrowcontaininginformationaboutonespecificsupported type.Thesuppliedinformationindicatesthenameofthetype,itssize,whetheritis nullable,whetheritissearchable,andsoon.
The ODBC API
PART V
MicrosoftoriginallydevelopedtheOpenDatabaseConnectivity(ODBC)APItoprovidea database-brand–independentAPIfordatabaseaccessonitsWindowsoperatingsystems.The earlyODBCAPIbecamethefoundationfortheSQL/CLIstandard,whichisnowtheofficial ANSI/ISOstandardforaSQLCall-LevelInterface.TheoriginalODBCAPIwasextendedand modifiedduringthestandardizationprocesstocreatetheSQL/CLIspecification.Withthe introductionofODBCrelease3.0,MicrosoftbroughtODBCintoconformancewiththeSQL/ CLIstandard.Withthisrevision,ODBCbecomesasupersetoftheSQL/CLIspecification. ODBCgoesbeyondtheSQL/CLIcapabilitiesinseveralareas,inpartbecause Microsoft’sgoalsforODBCwerebroaderthansimplycreatingastandardizeddatabase accessAPI.MicrosoftalsowantedtoallowasingleWindowsapplicationprogramtobeable toconcurrentlyaccessseveraldifferentdatabasesusingtheODBCAPI.Italsowantedto provideastructurewheredatabasevendorscouldsupportODBCwithoutgivinguptheir proprietaryAPIs,andwherethesoftwarethatprovidedODBCsupportforaparticular brandofDBMScouldbedistributedbythedatabasevendorandinstalledonWindowsbasedclientsystemsasneeded.ThelayeredstructureofODBCandofspecialODBC managementcallsprovidesthesecapabilities.
580
Part V:
Programming with SQL
The Structure of ODBC ThestructureofODBCasitisprovidedonWindows-basedorotheroperatingsystemsis showninFigure19-30.TherearethreebasiclayerstotheODBCsoftware: • CallableAPI Atthetoplayer,ODBCprovidesasinglecallabledatabaseaccessAPI thatcanbeusedbyallapplicationprograms.TheAPIispackagedasadynamic-linked library(DLL),whichisanintegralpartofthevariousWindowsoperatingsystems. • ODBCdrivers AtthebottomlayeroftheODBCstructureisacollectionofODBC drivers.EachoftheDBMSbrandshasaseparatedriver.Thepurposeofthedriveris totranslatethestandardizedODBCcallsintotheappropriatecall(s)forthespecific DBMSthatitsupports.Eachdrivercanbeindependentlyinstalledonaparticular computersystem.ThisallowstheDBMSvendorstoprovideanODBCdriverfor theirparticularbrandofDBMSandtodistributethedriverindependentlyofthe Windowsoperatingsystemsoftware.Ifthedatabaseresidesonthesamesystemas theODBCdriver,thedriverisusuallylinkeddirectlytothedatabase’snativeAPI code.Ifthedatabaseistobeaccessedoveranetwork,thedrivermaycallanative DBMSclienttohandletheclient/serverconnection,orthedrivermighthandlethe networkconnectionitself. • Drivermanager InthemiddlelayeroftheODBCstructureistheODBCdriver manager.ItsroleistoloadandunloadthevariousODBCdrivers,onrequestfrom applicationprograms.ThedrivermanagerisalsoresponsibleforroutingtheAPI callsmadebyapplicationprogramstotheappropriatedriverforexecution.
FIGURE 19-30 ODBC architecture
Chapter 19:
SQL APIs
581
WhenanapplicationprogramwantstoaccessadatabaseviaODBC,itgoesthroughthe sameinitiationsequencespecifiedbytheSQL/CLIstandard.Theprogramallocatesan environmenthandle,thenaconnectionhandle,andthencallsSQLConnect(),specifying theparticulardatasourcetobeaccessed.WhenitreceivestheSQLConnect()call,the ODBCdrivermanagerexaminestheconnectioninformationprovidedanddeterminesthe appropriateODBCdriverthatisneeded.Thedrivermanagerloadsthedriverintomemory ifit’snotalreadybeingusedbyanotherapplicationprogram. SubsequentcallsbytheapplicationprogramonthisparticularCLI/ODBCconnectionare routedtothisdriver.Theapplicationprogramcan,ifappropriate,makeotherSQLConnect() callsforotherdatasourcesthatwillcausethedrivermanagertoconcurrentlyloadother driversforotherDBMSbrands.TheapplicationprogramcanthenuseODBCtocommunicate withtwoormoredifferentdatabases,ofdifferentbrands,byusingauniformAPI.
ODBC and DBMS Independence ByprovidingauniformAPIanditsdrivermanagerarchitecture,ODBCgoesalongway towardprovidingacross-vendorAPIfordatabaseaccess,butit’simpossibletoprovide fullytransparentaccess.TheODBCdriversforthevariousdatabasesystemscaneasily maskcosmeticdifferencesintheirSQLdialectsandAPIsuites,butmorefundamental differencesaredifficultorimpossibletomask.ODBCprovidesapartialsolutiontothis problembyprovidingseveraldifferentlevelsofODBCcapability,andbymakingeach ODBCdriverself-describingthroughtheODBC/CLIcallsthatreturninformationabout generalfunctionality,supportedfunctions,andsupporteddatatypes.However,the existenceofdifferentcapabilitylevelsandprofileseffectivelypushestheDBMSdifferences rightbackintotheapplicationprogram,whichmustdealwiththisnonuniformityofODBC drivers.Inpractice,thevastmajorityofapplicationprogramsrelyononlythebasic,coreset ofODBCfunctionalityanddon’tbotherwithmoreadvancedfeaturesorprofiles.
ODBC Catalog Functions
PART V
OneoftheareaswhereODBCofferscapabilitybeyondtheSQL/CLIstandardisthe retrievalofinformationaboutthestructureofadatabasefromitssystemcatalog.Asapart oftheANSI/ISOSQLstandard,theCLIassumesthatthisinformation(abouttables, columns,privileges,andsoforth)isavailablethroughtheSQLInformationSchema,as describedinChapter16.ODBCdoesn’tassumethepresenceofanInformationSchema. Instead,itprovidesasetofspecializedfunctions,showninTable19-4,thatprovide informationaboutthestructureofadatasource.Bycallingthesefunctionsandprocessing theirresults,anapplicationprogramcandetermine,atruntime,informationaboutthe tables,columns,privileges,primarykeys,foreignkeys,andstoredproceduresthatformthe structureofadatasource.However,topreservesecurity,thesefunctionsreturninformation onlyaboutobjectstowhichtheuserhasspecificaccess. TheODBCcatalogfunctionstypicallyaren’tneededbyanapplicationprogramthatis writtenforaspecificpurpose.However,theyareessentialforageneral-purposeprogram, suchasaqueryprogram,reportgenerator,ordataanalysistool.Thecatalogfunctionscan becalledanytimeafteraconnectiontoadatasourcehasbeenmade.Forexample,areportwritingprogrammightcallSQLConnect()andthenimmediatelycallSQLTables()to determinewhichtablesareavailableinthetargetdatasource.Thetablescouldthenbe presentedinalistonthescreen,allowingtheusertoselectwhichtableshouldbeusedto generateareport.
582
Part V:
Programming with SQL
Function
Description
SQLTables
Returns a list of catalogs, schemas, tables, or table types in the data source
SQLColumns
Returns a list of columns in one or more tables
SQLStatistics
Returns a list of statistics about a single table along with a list of indexes associated with that table
SQLSpecialColumns
Returns a list of columns that uniquely identifies a row in a single table; also returns a list of columns in that table that are automatically updated
SQLPrimaryKeys
Returns a list of columns that compose the primary key of a single table
SQLForeignKeys
Returns a list of foreign keys in a single table or a list of foreign keys in other tables that refer to a single table
SQLTablePrivileges
Returns a list of privileges associated with one or more tables
SQLColumnPrivileges
Returns a list of privileges associated with one or more columns in a single table
SQLProcedures
Returns a list of procedures in the data source
SQLProcedureColumns
Returns a list of input and output parameters, the return value, and the columns in the result set of a single procedure
SQLGetTypeInfo
Returns a list of the SQL data types supported by the data source
TABLE 19-4 ODBC Catalog Functions
Allofthecatalogfunctionsreturntheirinformationasiftheywereasetofqueryresults. TheapplicationprogramusesthetechniquesalreadydescribedforCLIqueryprocessingto bindthecolumnsofreturnedinformationtoprogramvariableareas.Theprogramthencalls SQLFetch()toworkitswaythroughthereturnedinformation.Forexample,intheresults returnedbytheSQLTables()call,eachSQLFetch()retrievesinformationaboutonetable inthedatasource.
Extended ODBC Capabilities ODBCprovidesasetofextendedcapabilitiesbeyondthosespecifiedintheSQL/CLI standard.ManyofthecapabilitiesaredesignedtoimprovetheperformanceofODBC-based applicationsbyminimizingthenumberofODBCfunctioncallsanapplicationprogram mustmakeand/ortheamountofnetworktrafficgeneratedbytheODBCcalls.Other capabilitiesprovideusefulfeaturesformaintainingdatabaseindependenceoraidan applicationprograminthedatabaseconnectionprocess.Someofthecapabilitiesare providedthroughtheadditionalsetofODBCfunctioncallsshowninTable19-5.Othersare providedthroughstatementorconnectionattributes.Manyoftheseadditionalcapabilities wereintroducedinthe3.0revisionofODBCandarenotyetsupportedbymostODBC driversorODBC-basedapplications.
Chapter 19:
SQL APIs
Function
Description
SQLBrowseConnect()
Supplies information about available ODBC data sources and the attributes required to connect to each
SQLDrivers()
Returns a list of the available drivers and driver attribute names
SQLDriverConnect()
Works as an extended form of the SQLConnect() call for passing additional connection information
SQLNumParams()
Returns the number of parameters in a previously prepared SQL statement
SQLBindParameter()
Provides extended functionality beyond the SQL/CLI SQLBindParam() call
SQLDescribeParam()
Returns information about a parameter
SQLBulkOperations()
Performs bulk insertion and bookmark operations
SQLMoreResults()
Determines whether more results are available for a statement
SQLSetPos()
Sets the cursor position within a retrieved set of query results for positioned operations
SQLNativeSQL()
Returns the native SQL translation of a supplied ODBC-compliant SQL statement text
583
TABLE 19-5 Additional ODBC Functions
Extended Connection Capabilities
SQL Dialect Translation
ODBCspecifiesnotjustasetofAPIcalls,butalsoastandardSQLlanguagedialectthat isasubsetoftheSQLstandard.ItistheresponsibilityofODBCdriverstotranslatethe ODBCdialectintostatementsappropriateforthetargetdatasource(forexample,modifying
PART V
TwooftheextendedODBCfeaturesarefocusedontheconnectionprocess.Connection browsingisdesignedtosimplifythedatasourceconnectionprocessandmakeitmore databaseindependent.SQLBrowseConnect()supportsaniterativestyleofconnectionfor accesstoODBCdatasources.Anapplicationprogramfirstcallsthefunctionwithbasic informationaboutthetargetdatasource,andthefunctionreturnsadditionalconnection attributesneeded(suchasausernameorpassword).Theapplicationprogramcanobtainthis information(forexample,bypromptingtheuser)andthencanrecallSQLBrowseConnect() withtheadditionalinformation.Thecyclecontinuesuntiltheapplicationhasdeterminedall oftheinformationrequiredforasuccessfulSQLConnect()call. TheconnectionpoolingcapabilityisdesignedtoimprovetheefficiencyofODBC connect/disconnectprocessinginaclient/serverenvironment.Whenconnectionpoolingis activated,ODBCdoesnotactuallyterminatenetworkconnectionsuponreceivinga SQLDisconnect()call.Instead,theconnectionsareheldopeninanidlestateforsome periodandreusedifaSQLConnect()callismadeforthesamedatasource.Thisreuseof connectionscansignificantlycutdownthenetworkandlogin/logoutoverheadinclient/ serverapplicationsthatinvolveshorttransactionsandhightransactionrates.
584
Part V:
Programming with SQL
date/timeliterals,quoteconventions,keywords,andsoon).TheSQLNativeSQL()call allowstheapplicationprogramtoseetheeffectofthistranslation.ODBCalsosupports escapesequencesthatallowanapplicationprogramtomoreexplicitlydirectthetranslation ofSQLfeaturesthattendtobelessconsistentacrossSQLdialects,suchasouterjoinsand pattern-matchingsearchconditions.
Asynchronous Execution
AnODBCdrivermaysupportasynchronousexecutionofODBCfunctions.Whenan applicationprogrammakesanasynchronousmodeODBCcall,ODBCinitiatestherequired processing(usuallystatementpreparationorexecution)andthenimmediatelyreturns controltotheapplicationprogram.Theapplicationprogramcanproceedwithotherwork andlaterresynchronizewiththeODBCfunctiontodetermineitscompletionstatus. Asynchronousexecutioncanberequestedonaper-connectionoraper-statementbasis.In somecases,asynchronouslyexecutingfunctionscanbeterminatedwithaSQLCancel() call,givingtheapplicationprogramamethodforabortinglong-runningODBCoperations.
Statement-Processing Efficiency
EachODBCcalltoexecuteaSQLstatementcaninvolveasignificantamountofoverhead, especiallyifthedatasourceinvolvesaclient/servernetworkconnection.Toreducethis overhead,anODBCdrivermaysupportstatementbatches.Withthiscapability,anapplication programcanpassasequenceoftwoormoreSQLstatementsasabatchtobeexecutedina singleSQLExecDirect()orSQLExecute()call.Forexample,aseriesofadozenINSERT orUPDATEstatementscouldbeexecutedasabatchinthisway.Itcansignificantlyreduce networktrafficinaclient/serverenvironment,butitcomplicateserrordetectionand recovery,whichtendtobecomedriver-specificwhenstatementbatchesareused. ManyDBMSproductsaddresstheefficiencyofmultistatementtransactionsina differentway.Theysupportstoredprocedureswithinthedatabaseitself,whichcancollect asequenceofSQLoperations,togetherwiththeassociatedflow-controllogic,andallow thestatementstobeinvokedwithasinglecalltotheprocedure.ODBCprovidesasetof capabilitiesthatallowanapplicationprogramtodirectlycallastoredprocedureinthe targetdatasource.Fordatabasesthatallowstoredprocedureparameterstobepassedby name,ODBCallowsparameterstobeboundbynameinsteadofbyposition.Fordata sourcesthatprovidemetadatainformationaboutstoredprocedureparameters,the SQLDescribeParam()callallowstheapplicationprogramtodetermine,atruntime,the requiredparameterdatatype.Outputparametersofastoredprocedurearesupported eitherthroughSQLBindParam()(inwhichcase,theapplicationprogram’sdatabufferis modifieduponreturnfromtheSQLExecute()orSQLExecDirect()call)orthrough SQLGetData(),whichallowsretrievaloflongerrowsofreturneddata. TwootherextendedODBCcapabilitiesprovideefficiencywhenasingleSQLstatement (suchasanINSERTorUPDATEstatement)istobeexecutedrepeatedly.Bothaddressthe bindingofparametersforthissituation.Withthebindingoffsetfeature,onceastatement parameterhasbeenboundandthestatementhasbeenexecuted,ODBCallowsthe applicationprogramtochangeitsbindingforthenextstatementexecutionbyspecifyinga newmemorylocationasanoffsetfromtheoriginallocation.Thisisaneffectivewayof bindingaparametertoindividualitemsinanarrayforrepeatedstatementexecution.In general,modifyinganoffsetvalueismuchmoreefficientthanrebindingtheparameterwith repeatedcallstoSQLBindParam().
Chapter 19:
SQL APIs
585
ODBCparameterarraysprovideanalternativemechanismforanapplicationprogramto passmultiplesetsofparametervaluesinasinglecall.Forexample,ifanapplication programneedstoinsertmultiplerowsintoatable,itcanrequestexecutionofa parameterizedINSERTstatementandbindtheparameterstoarraysofdatavalues.The effectiveresultisasifmultipleINSERTstatementsareperformed—oneforeachsetof parametervalues.ODBCsupportsbothrow-wiseparameterarrays(eacharrayelement holdsonesetofparametervalues)orcolumn-wiseparameterarrays(eachparametervalue isboundtoitsownindividualarray,whichholdsitsvalues).
Query-Processing Efficiency
PART V
Inaclient/serverenvironment,thenetworkoverheadinvolvedinfetchingmanyrowsof queryresultscanbequitesubstantial.Tocutthisoverhead,anODBCdrivermaysupport multirowfetchesthroughtheODBCblockcursorcapability.Withablockcursor,each SQLFetch()orSQLFetchScroll()callretrievesmultiplerows(termedthecurrent rowsetofthecursor)fromthedatasource.Theapplicationmustbindthereturnedcolumns toarraystoholdthemultiplerowsoffetcheddata.Eitherrow-wiseorcolumn-wisebinding oftherowsetdataissupported,usingthesametechniquesasthoseusedforparameter arrays.Inaddition,theSQLSetPos()functionmaybeusedtoestablishoneoftherowsof therowsetasthecurrentrowforpositionedupdateanddeleteoperations. ODBCbookmarksprovideadifferentefficiencyboostforanapplicationprogramthat needstooperateonretrievedrowsofdata.AnODBCbookmarkisadatabase-independent uniquerow-idforSQLoperations.(AdrivermayactuallyuseprimarykeysorDBMSspecificrow-idsorothermethodstosupportbookmarks,butitistransparenttothe applicationprogram.)Whenbookmarksareenabled,thebookmark(row-id)isreturnedfor eachrowofqueryresults.Thebookmarkcanbeusedwithscrollingcursorstoreturntoa particularrow.Additionally,itcanbeusedtoperformapositionedupdateordeletebased onabookmark. Bookmarkscanalsobeusedtodetermineifaparticularrowretrievedbytwodifferent queriesis,infact,thesameroworadifferentrowwiththesamedatavalues.Bookmarks canmakesomeoperationsmuchmoreefficient(forexample,performingpositioned updatesviaabookmarkratherthanrespecifyingacomplexsearchconditiontoidentify therow).However,therecanbesubstantialoverheadforsomeDBMSbrandsandODBC driversinmaintainingthebookmarkinformation,sothistrade-offmustbeconsidered carefully. ODBCbookmarksformthebasisforODBCbulkoperations,anotherefficiency-related feature.TheSQLBulkOperations()callallowsanapplicationprogramtoefficiently update,insert,delete,orrefetchmultiplerowsbasedontheirbookmarks.Itoperatesin conjunctionwithblockcursorsandworksontherowsinthecurrentrowset.Theapplication programplacesthebookmarksfortherowstobeaffectedintoanarrayandplacesintoother arraysthevaluestobeinsertedordeleted.ItthencallsSQLBulkOperations()witha functioncodeindicatingwhethertheidentifiedrowsaretobeupdated,deleted,orrefetched, orwhetherasetofnewrowsistobeadded.Thiscallcompletelybypassesthenormal SQLstatementsyntaxfortheseoperations,andbecauseitcanoperateonmultiplerows inasinglecall,canbeaveryefficientmechanismforbulkinsertion,deletion,orupdate ofdata.
586
Part V:
Programming with SQL
The Oracle Call Interface (OCI) ThemostpopularprogrammaticinterfacetoOracleisembeddedSQL.However,Oracle alsoprovidesanalternativecallableAPI,knownastheOracleCallInterface,orOCI.OCIhas beenavailableformanyyearsandremainedfairlystablethroughanumberofmajorOracle upgradecycles,includingalloftheOracle7versions.WiththeintroductionofOracle8,OCI underwentamajorrevision,andmanyoftheoriginalOCIcallswerereplacedbynew, improvedversions.MovingforwardthroughOracle9i,10g,11g,andbeyond,this“new OCI”(theOracle8version)iseffectivelytheOracleCallInterfacefornewprograms. The“oldOCI”(fromOracle7andbefore)isrelevantonlyforlegacyprogramsthatwere originallydevelopedusingit.Forreference,selected“oldOCI”routinesaresummarizedin Table19-6,sothatyoucanrecognizeaprogramthatmaybeusingthisoldversion.Conceptually, theroutinescloselyparalleltheembeddeddynamicSQLinterface,describedinChapter18. ThenewOCIusesmanyofthesameconceptsastheSQL/CLIstandardandODBC, includingtheuseofhandlestoidentifyinterfaceobjects.Severalhundredroutinesare definedintheAPI,andacompletedescriptionofthemisbeyondthescopeofthisbook. Thefollowingsectionsidentifythemajorroutinesthatwillbeusedbymostapplication programsandtheirfunctions.
OCI Handles ThenewOCIusesahierarchyofhandlestomanageinteractionwithanOracledatabase, likethehandlehierarchyoftheSQL/CLIdescribedearlierinthesection“CLIStructures.” Thehandlesare • Environmenthandle Thetop-levelhandleassociatedwithanOCIinteraction • Servicecontexthandle IdentifiesanOracleserverconnectionforstatement processing • Serverhandle IdentifiesanOracledatabaseserver(formultisessionapplications) • Sessionhandle Identifiesanactiveusersession(formultisessionapplications) • Statementhandle IdentifiesanOracle-SQLstatementbeingprocessed • Bindhandle IdentifiesanOraclestatementinputparameter • Definehandle IdentifiesanOraclequeryresultscolumn • Transactionhandle IdentifiesaSQLtransactioninprogress • Complexobjecthandle RetrievesdatafromanOracleobject • Errorhandle ReportsandprocessesOCIerrors AnapplicationprogrammanagesOCIhandlesusingtheroutinesshowninTable19-7. Theallocate(Alloc)andFreeroutinesfunctionliketheirSQL/CLIcounterparts.TheGet attributeandSetattributefunctionsoperatelikethesimilarlynamedSQL/CLIroutines thatgetandsetenvironment,connection,andstatementattributes. AnerrorhandleisusedtopassinformationbackfromOCItotheapplication.Theerror handletobeusedforerrorreportingistypicallypassedasaparametertoOCIcalls.Ifthe returnstatusindicatesanerror,informationabouttheerrorcanberetrievedfromtheerror handleusingOCIErrorGet().
Chapter 19:
Function
SQL APIs
587
Description
Database connection/disconnection olon()
Logs onto an Oracle database
oopen()
Opens a cursor (connection) for SQL statement processing
oclose()
Closes an open cursor (connection)
ologof()
Logs off from an Oracle database
Basic statement processing osql3()
Prepares (compiles) a SQL statement string
oexec()
Executes a previously compiled statement
oexn()
Executes with an array of bind variables
obreak()
Aborts the current Oracle call interface function
oermsg()
Obtains error message text
Statement parameters obndrv()
Binds a parameter to a program variable (by name)
obndrn()
Binds a parameter to a program variable (by number)
Transaction processing ocom()
Commits the current transaction
orol()
Rolls back the current transaction
ocon()
Turns on autocommit mode
ocof()
Turns off autocommit mode
Query results processing Obtains a description of a query results column
oname()
Obtains the name of a query results column
odefin()
Binds a query results column to a program variable
ofetch()
Fetches the next row of query results
ofen()
Fetches multiple rows of query results into an array
ocan()
Cancels a query before all rows are fetched
TABLE 19-6 Old Oracle Call Interface Functions (Oracle 7 and Earlier)
Routine
Function
OCIHandleAlloc()
Allocates a handle for use
OCIHandleFree()
Frees a handle previously allocated
OCIAttrGet()
Retrieves a particular attribute of a handle
OCIAttrSet()
Sets the value of a particular handle attribute
TABLE 19-7 OCI Handle Management Routines
PART V
odsc()
588
Part V:
Programming with SQL
Oracle Server Connection TheinitializationandconnectionsequenceforOCIparallelsthosealreadyillustratedfor CLI/ODBCanddblib.TheOCIroutinesassociatedwithconnectionmanagementare showninTable19-8.AnapplicationprogramfirstcallsOCIInitialize()toinitializethe OracleCallInterface.ThiscallalsoindicateswhetherOCIwillbeusedinmultithreaded mode,whethertheapplicationprogramwilluseOCIobject-modefunctions,andother options.Afterinitialization,theapplicationprogramcallsOCIEnvInit()toinitializean environmenthandle.AswithCLI/ODBC,allOCIinteractionstakeplacewithinthecontext oftheenvironmentdefinedbythishandle. Aftertheseinitialsteps,mostapplicationscallOCILogon()toestablishasessionwith anOracledatabaseserver.SubsequentOCIcallstakeplacewithinthecontextofthissession andusethesupplieduser-idtodeterminetheirprivilegeswithintheOracledatabase.Acall toOCILogoff()terminatesthesession.Theothercallsprovidemoreadvancedsession managementformultithreadedandmulticonnectionapplications.TheOCIServerVersion() callcanbeusedtodeterminetheversionoftheOracleserversoftware.The OCIPasswordChange()callcanbeusedtochangeanexpiredpassword.Whenconnection poolingisused,theapplicationcancallOCIConnectionPoolCreate()toestablisha connectionpool,followedbyOCILogon2()tocreatesessionswithintheconnectionpool. Whentheconnectionpoolisnolongerneeded,OCIConnectionPoolDestroy()canbe usedtodestroyit.
Routine
Function
OCIInitialize()
Initializes the Oracle Call Interface for use
OCIEnvInit()
Establishes an environment handle for OCI interaction
OCIConnectionPoolCreate()
Initializes the connection pool
OCIConnectionPoolDestroy()
Destroys the connection pool
OCILogon()
Connects to an Oracle database server for an OCI session
OCILogon2()
Gets a session—either a new session or a virtual one— from an existing session pool or connection pool
OCILogoff()
Terminates a previous logon connection
OCIServerAttach()
Attaches to an Oracle server for multisession operations
OCIServerDetach()
Detaches from an Oracle server
OCIServerVersion()
Returns server version information
OCISessionBegin()
Begins a user session on a previously attached server
OCIPasswordChange()
Changes a user’s password on the server
OCISessionEnd()
Ends a previously begun user session
TABLE 19-8 OCI Initialization and Connection Management Routines
Chapter 19:
SQL APIs
589
Statement Execution TheOCIfunctionsshowninTable19-9implementSQLstatementexecution. OCIStmtPrepare()andOCIStmtExecute()supportthetwo-stepprepare/execute process.TheOCIStmtExecute()functioncanalsobeusedtodescribequeryresults (similartotheembeddedSQLDESCRIBEstatement)withoutactuallyexecutingthequery bypassingaspecificflag.OCIautomaticallyprovidesadescriptionofqueryresultswhen OCIStmtExecute()iscalledinthenormalstatementexecutionmode.Thedescription isavailableasanattributeofthestatementhandlefortheexecutedquery. TheOCIBindbyPos()andOCIBindbyName()functionsareusedtobindapplication programlocationstostatementparameters,usingeitherparameterpositionsorparameter names.Thesecallsautomaticallyallocatebindhandlesfortheparameterswhentheyare called,ortheymaybecalledwithexplicitlyallocatedbindhandles.Theothercalls implementmoreadvancedbindingtechniques,includingbindingofmultipleparameter values(arrays)andbindingofcomplexobjectdatatypes.Theyalsoprovideexecute-time parameter(andqueryresults)processing,correspondingtothedeferredparametermode supportedbyCLI/ODBCanddescribedearlierinthe“CLIStatementProcessing”section. Thepieceinfocallssupportthismodeofoperation.
Function
OCIStmtPrepare()
Prepares a statement for execution
OCIStmtExecute()
Executes a previously prepared statement
OCIBreak()
Aborts current OCI operation on a server
OCIBindbyPos()
Binds a parameter based on its position
OCIBindbyName()
Binds a parameter based on its name
OCIStmtGetBindInfo()
Obtains the names of bind and indicator variables
OCIBindArrayOfStruct()
Sets up array binding for passing multiple parameter values
OCIBindDynamic()
Registers a callback routine for a previously bound parameter that will use runtime binding
OCIBindObject()
Provides additional information for a previously bound parameter with a complex object data type
OCIStmtGetPieceInfo()
Obtains information about a dynamic piecewise parameter value needed at execute-time by OCI (or a dynamic piecewise query results column being returned)
OCIStmtSetPieceInfo()
Sets information (buffer, length, indicator, etc.) for a dynamic piecewise parameter value being supplied at execute-time to OCI (or a dynamic piecewise query results column being accepted at runtime)
TABLE 19-9 OCI Statement-Processing and Parameter-Handling Routines
PART V
Routine
590
Part V:
Programming with SQL
Routine
Function
OCIStmtFetch()
Fetches a row or rows of query results
OCIDefineByPos()
Binds a query results column
OCIDefineArrayofStruct()
Sets up array binding for multirow results retrieval
OCIDefineDynamic()
Registers a callback routine for dynamic processing of query results column
OCIDefineObject()
Provides additional information for a previously bound query results column with a complex object type
TABLE 19-10 OCI Query Results–Processing Routines
Query Results Processing TheOCIfunctionsshowninTable19-10areusedtoprocessqueryresults.The OCIDefineByPos()functionisusedtobindaqueryresultscolumn(identifiedbycolumn number)toanapplicationprogramstoragelocation.(TheOCIterminologyreferstothisas thedefineprocess;thetermbindingisreservedforinputparameters.)Theotherdefinecalls supportdynamic(execute-time)binding,arraybinding(formultirowfetchoperations),and bindingofcomplexobjectdatatypes.TheOCIStmtFetch()callretrievesarowofquery resultsandprovidestheSQLFETCHstatementfunctionality.
Descriptor Handling OCIusesdescriptorstoprovideinformationaboutparameters,Oracledatabaseobjects (tables,views,storedprocedures,etc.),largeobjects,complexobjects,row-ids,andother OCIobjects.Adescriptorprovidesinformationtotheapplicationprogramandisusedin somecasestomanagethedetailsoftheprocessingoftheseobjects.Theroutinesshownin Table19-11areusedtomanagedescriptors.Theyallocateandfreethedescriptorsand retrieveandsetindividualdatavalueswithinthedescriptors.
Transaction Management ApplicationprogramsusethefunctionsshowninTable19-12toimplementSQLtransaction management.TheOCITransCommit()andOCITransRollback()callsprovidethe basiccapabilitytocommitandrollbacktransactions,andcorrespondtotheusualSQL
Routine
Function
OCIDescriptorAlloc()
Allocates a descriptor or LOB locator
OCIDescriptorFree()
Frees a previously allocated descriptor
OCIParamGet()
Gets a descriptor for a parameter
OCIParamSet()
Sets a parameter descriptor in a complex object-retrieval handle
TABLE 19-11 OCI Descriptor-Management Routines
Chapter 19:
SQL APIs
Routine
Function
OCITransCommit()
Commits a transaction
OCITransRollback()
Rolls back a transaction
OCITransStart()
Initiates or reattaches a special transaction
OCITransPrepare()
Prepares a transaction to be committed in a distributed environment
OCITransMultiPrepare()
Prepares a transaction with multiple branches in a single call
OCITransForget()
Forgets a previously prepared transaction
OCITransDetach()
Detaches a distributed transaction
591
TABLE 19-12 OCI Transaction Management Routines
COMMITandROLLBACKstatements.Theotherfunctionsprovideaveryrichandcomplex transactionscheme,includingthespecificationofread-only,serializable,andlooselyor tightlycoupledtransactions,andcontroloverdistributedtransactions.Thetransaction managementroutinestakeaservicecontexthandlethatidentifiesacurrentconnectionas aninputparameter.
Error Handling
TheOCIfunctionsreturnastatuscodeindicatingwhethertheycompletedsuccessfully. Inaddition,mostOCIfunctionsacceptanerrorhandleasaninputparameter.Ifanerror occursduringprocessing,errorinformationisassociatedwiththishandle.Uponreturn fromthefunction,theapplicationprogramcancallOCIErrorGet()ontheerrorhandleto obtainfurtherinformationabouttheerror,includingtheerrornumberanderrormessage.
Catalog Information
Large Object Manipulation
OCIincludesalargegroupofroutines,someofwhichareshowninTable19-13,for processingOraclelargeobject(LOB)datatypesandlargeobjectsstoredinfilesreferenced inOraclecolumns.Becauselargeobjectsmaybetensofthousandstomillionsofbytesin length,theytypicallycannotbebounddirectlytoapplicationprogrambuffersintheir entirety.Instead,OCIusesaLOBlocator,whichfunctionslikeahandlefortheLOBdataitem. ThelocatorisreturnedforLOBdatainqueryresultsandusedasaninputparameterfor LOBdatabeinginsertedorupdated.TheLOBhandlingroutinessupportpiece-by-piece processingofLOBdata,allowingittobetransferredbetweenanOracledatabaseandan applicationprogram.TheroutinesacceptoneormoreLOBlocatorsasparameters.
PART V
TheOCIDescribeAny()callprovidesaccesstoOraclesystemcataloginformation.An applicationprogramcallsthisroutinewiththenameofatable,view,synonym,stored procedure,datatype,orotherOracleschemaobject.Theroutinepopulatesadescriptor (identifiedbyadescriptorhandle)withinformationabouttheattributesoftheobject. SubsequentcallstoOCIAttrGet()onthedescriptorhandlecanbeusedtoobtain completedataabouttheobjectatruntime.
592
Part V:
Programming with SQL
Routine
Function
OCILobRead()
Reads a piece of a LOB into application program data area
OCILobWrite()
Writes data from an application program data area into a LOB
OCILobAppend()
Appends data to the end of a LOB
OCILobErase()
Erases data within a LOB
OCILobTrim()
Truncates data from the end of a LOB
OCILobGetLength()
Obtains the length of a LOB
OCILobLocatorIsInit()
Checks whether a LOB locator is valid
OCILobCopy()
Copies data from one LOB to another
OCILobAssign()
Assigns one LOB locator to another
OCILobIsEqual()
Compares two LOB locators
OCILobFileOpen()
Opens a file containing LOB data
OCILobFileClose()
Closes a previously opened LOB file
OCILobFileCloseAll()
Closes all previously opened LOB files
OCILobFileIsOpen()
Checks whether a LOB file is open
OCILobFileGetName()
Obtains the name of a LOB file, given a LOB locator
OCILobFileSetName()
Sets the name of a LOB file in a LOB locator
OCILobFileExists()
Checks if a LOB file exists
OCILobLoadFromFile()
Loads a LOB from a LOB file
TABLE 19-13 OCI Large Object (LOB) Processing Routines
Java Database Connectivity (JDBC) JDBCisacallableSQLAPIfortheJavaprogramminglanguage.JDBCisboththeofficial anddefactostandardforSQLdatabaseaccessfromJava.FortheCprogramminglanguage, theDBMSvendorsdevelopedtheirownproprietaryAPIswellbeforethedevelopmentof ODBCorSQL/CLIAPI.ForJava,theJDBCAPIwasdevelopedbySunMicrosystemsas partofasuiteofJavaAPIs,embodiedinvariousJavaeditions.Asaresult,allofthemajor DBMSproductsprovideJavasupportviaJDBC;therearenoimportantcompetingAPIs.
JDBC History and Versions TheJDBCAPIhasbeenthroughseveralmajorrevisionssinceitsoriginalintroduction. JDBC1.0providedthebasiccoreofdataaccessfunctionality,includingadrivermanagerto arbitrateconnectionstomultipleDBMSs,connectionmanagementtoaccessindividual databases,statementmanagementtosendSQLcommandstotheDBMS,andresultset managementtoprovideJavaaccesstothequeryresults.
Chapter 19:
SQL APIs
593
TheJDBC2.0APIanditsincrementalversionsextendedJDBC1.0,anddividedthe functionalityintoaCoreAPIandExtensionsAPI.The2.0versionadded • Batchoperations AJavaprogramcanpassmanyrowsofdatatobeinsertedor updatedviaasingleAPIcall,improvingperformanceandefficiencyofbulk operations. • Scrollableresultsets LikethescrollablecursorsprovidedinotherAPIs,thisnew capabilitypermittedbothforwardandbackwardmotionthroughqueryresults. • Updateableresultsets AJavaprogramcanupdatethedatabasebyupdatinga specificrowofqueryresultsorinsertinganewrowthroughtheresults. • Connectionpooling ConnectionstothedatabasecanbesharedacrossJava programs,reducingtheoverheadoffrequentconnectinganddisconnecting. • Distributedtransactions TheAPIprovidesthecapabilitytosynchronizeupdates acrossmultipledatabases,withall-or-nothingtransactionsthatspandatabase boundaries. • Datasources Anewtypeofobjectthatencapsulatesthedetailsofadatabase connection,reducingtheneedforanapplicationprogrammertounderstand connectionspecifics. • Rowsets Anabstractionofqueryresults,rowsetsallowquery-resultsprocessing evenwhenaprogramisdisconnectedfromthesourcedatabaseandlater resynchronization. • JavaNaming&DirectoryInterface(JNDI)support Databasesanddriverscan benamedandcatalogedinanetworkdirectory,andaccessedviathosedirectory entries. TheJDBC3.0APIwasfinalizedandformallyannouncedbySuninFebruary2002,and packagedaspartofJava2StandardEdition(J2SE)1.4.Newcapabilitiesintroducedinthe3.0 versioninclude • Object-relationalSQLextensions TheAPIaddssupportforabstractdatatypes andtheassociatedcapabilitiesthatwereaddedtotheSQLstandardin1999.
• Cursorpreservation APIoptionsallowcursorstoremainopenacrosstransactions. • Preparedstatementmetadata Programscandetermineinformationaboutprepared statements,suchasthenumberanddatatypesofparametersandofqueryresults columns.
JDBC Implementations and Driver Types JDBCassumesadriverarchitecturelikethatprovidedbytheODBCstandard,onwhichitis broadlybased.Figure19-31showsthemainbuildingblocks.AJavaprogramconnectsto theJDBCdrivermanagerviatheJDBCAPI.TheJDBCsystemsoftwareisresponsiblefor loadingoneormoreJDBCdrivers,typicallyondemandfromJavaprogramsthatrequest them.Conceptually,eachdriverprovidesaccesstooneparticularDBMSbrand,making
PART V
• Savepoints TheAPIallowsapartialrollbacktoaspecificallymarkedsavepoint partwaythroughatransaction.
594
Part V:
Programming with SQL
FIGURE 19-31 JDBC architecture building blocks
whateverbrand-specificAPIcallsandsendingtheSQLstatementsneededtocarryoutthe JDBCrequest.TheJDBCsoftwareisdeliveredasaJavapackage,whichisimportedintoa JavaprogramthatwantstouseJDBC. TheJDBCspecificationdoesnotdealwiththespecificdetailsofhowaJDBCdriveris implemented.However,sincetheintroductionofJDBC,developershavetendedto characterizeJDBCdriversintofourdrivertypes.Thetypedescriptionsassumeaclient/ serverconnectionfromtheJDBCAPI(ontheclientsystem)toadatabaseserver.Whilethis isacommonenterprisedeploymentarchitecture,it’sworthnotingthatJDBCisusedto accesslocaldatabasesonsystemsassmallashandhelddevices;inthiscontext,thedriver typeshavelessmeaning.ThedrivertypesdifferinhowtheytranslateJDBCcalls(method invocations)intospecificactionsagainsttheDBMS. AType1driver,alsocalledaJDBC/ODBCbridge,isshowninFigure19-32.Thedriver translatesJDBCcallsintoavendor-neutralAPI,whichinpracticeisalwaysODBC.The requestpassestoaspecificODBCdriverforthetargetDBMS.(Optionally,theODBCdriver managermaybeeliminated,sincetheODBCAPItothedrivermanageristhesameasthe APItothedriveritself.)Ultimately,theODBCdrivercallstheDBMS’proprietaryAPI.Ifthe databaseisonalocalsystem,theDBMScarriesouttherequest.Ifit’sonaremote(server) system,theDBMScodeontheclientisanetworkaccessstub,whichtranslatestherequest intoanetworkmessage(proprietarytotheDBMS)andsendsittotheDBMSserver. AType1driverhasonesignificantadvantage.BecausenearlyallpopularDBMS productssupportODBC,asingleType1drivercanprovideaccesstodozensofdifferent DBMSbrands.Type1driversarewidelyavailable,includingonethatisdistributedbySun.
Chapter 19:
SQL APIs
595
FIGURE 19-32 A JDBC Type 1 driver
PART V
AType1driveralsohasseveraldisadvantages.EachJDBCrequestpassesthroughmany layersonitswaytoandfromtheDBMS,soaType1drivertypicallycarriesalotof computingoverhead,anditsperformancesuffersasaresult.TheuseofODBCasan intermediatestagealsomaylimitthefunctionalityprovidedbythedriver—featuresofthe underlyingDBMSthatmightbeabletobedeliveredviatheJDBCinterfacedirectlymaynot beaccessibleviaODBC.Finally,theODBCdriverrequiredbyaType1driverwillbe deliveredinbinaryform,notasaJavaexecutable.Thus,anygivenType1driverisspecificto theclientcomputer’shardwareandoperatingsystem,andwilllacktheportabilityofJava. AType2driverisalsocalledaNativeAPIdriver.ThedrivertranslatesJDBCrequests directlyintothenativeAPIoftheDBMS,asshowninFigure19-33.UnlikewiththeType1 driver,noODBCorothervendor-neutrallayerisinvolved.Ifthedatabaseislocatedonthe samesystemastheJavaprogram,theType2driver’scallstothenativeAPIwillgodirectly
596
Part V:
Programming with SQL
FIGURE 19-33 A JDBC Type 2 driver
totheDBMS.Inaclient/servernetwork,theDBMScodeontheclientisagainanetwork accessstub,andtherequestsflowoverthenetworkinaDBMS-proprietaryprotocol,asin theType1driver. Type2driverspresentadifferentsetoftrade-offsthanType1drivers.AType2driver hasfewerlayers,soperformanceistypicallyhigher.Itstillhasthedisadvantageof requiringbinarycodetobeinstalledontheclientsystem,soeachType2driverwillstillbe specifictoahardwarearchitectureandoperatingsystem.UnlikeaType1driver,aType2 driverisalsospecifictoaDBMSbrand.Ifyouwanttocommunicatewithseveraldifferent DBMSs,youwillneedmultipledrivers.Finally,it’sworthnotingthattheType1/Type2 distinctionassumesthatthenativeDBMSAPIisnotODBC.IfaDBMSpresentsanative ODBCinterface,thentheuseofODBCdoesnotimplyanadditionallayer,anditsType2 driverwill,infact,useODBCtoaccesstheDBMS. AType3driverisaNetwork-Neutraldriver.ThedrivertranslatesJDBCrequestsinto networkmessagesinavendor-neutralformatandsendsthemacrossthenetworktothe server,asshowninFigure19-34.Ontheserver,amiddlewarelayerreceivesthenetwork requestsandtranslatesthemintocallstotheDBMS’nativeAPI.Queryresultsarepassed backacrossthenetwork,againinavendor-neutralformat.
Chapter 19:
SQL APIs
597
FIGURE 19-34 A JDBC Type 3 driver
PART V
Type3driversonceagainpresentadifferentsetoftrade-offs.Onemajoradvantage claimedfortheType3architectureisthattheclient-sidecodecanbewritteninJava,using thenetworkinterfacesprovidedbyotherJavaAPIs.Noticealsothattheclient-sidecodeis DBMSneutral;itdoesthesameworknomatterwhatthetargetDBMSontheserver.This meansthattheclient-sidecodeisveryportable,abletorunonanysystemthatsupportsa JavaVirtualMachine(JVM)andJavanetworkAPIs.Type3driversshareonedisadvantage withType1drivers:theuseofavendor-neutralnetworklayer,justliketheuseofavendorneutralODBClayer,meansthatsomecapabilitiesoftheunderlyingDBMSmaybe inaccessiblethroughtheintermediatelayer.AType3architecturealsoinvolvesadouble translationofeachJDBCrequest,justasinType1;however,oneofthetranslationstakes placeontheserversystem,minimizingtheclient-sideimpact. AType4driverisaNetwork-Proprietarydriver.ThedrivertranslatesJDBCrequestsinto networkmessages,butthistimeinaDBMS-proprietaryformat,asshowninFigure19-35. ThedriveriswritteninJavaandimplementsanetworkclientfortheDBMS’networking software,suchasOracle’sSQL*Net.Ontheserver,thereisnoneedforamiddlewarelayer, sincetheDBMSserveralreadyprovidessupportfortheDBMSvendor’sownclient/server networking.Queryresultsflowbackacrossthenetwork,againinvendor-proprietary format,andsuppliedbacktotherequestingprogram.
598
Part V:
Programming with SQL
FIGURE 19-35 A JDBC Type 4 driver
Type4driverspreserveoneoftheimportantadvantagesofType3drivers.Theycanbe implementedinpureJava,solikeType3,theyareportableacrosscomputerhardwareand operatingsystems.However,unlikeType3drivers,theyareDBMS-specific,sodifferent client-sidecodeisrequiredforeachDBMSbrandyouwanttoaccess.AType4architecture involveslessoverheadontheserversystemandmaythereforedeliverslightlybetter performance.Inpractice,theoverheadofthenetworkmessagingwillalmostalwaysswamp thisadvantage,exceptinveryhightransactionrateapplications. Figure19-36summarizesthefourJDBCdrivertypesandshowshowtheyrelatetoone another.Thetwocolumnsdividethedrivertypesbasedonwhethertheyuseavendor-neutral intermediatelayer(leftcolumn)ortranslatedirectlyfromtheJDBCAPItoaDBMSproprietaryinterface.Thetworowsdividethedrivertypesbasedonwhetherthetranslation toaspecificDBMSAPIoccursontheclientside(upperrow)orontheserverside(lowerrow). Asthefigureshows,thesetwodecisionsresultinfour(2×2)drivertypes.
The JDBC API Javaisanobject-orientedlanguage,soit’sprobablynosurprisethatJDBCorganizesitsAPI functionsaroundacollectionofdatabase-relatedobjectsandthemethodsthattheyprovide: • DriverManagerobject Theentry-pointtoJDBC • Connectionobjects Representindividualactiveconnectionstotargetdatabases • Statementobjects RepresentSQLstatementstobeexecuted
Chapter 19:
SQL APIs
599
FIGURE 19-36 JDBC driver types and trade-offs
• ResultSetobjects RepresenttheresultsofaSQLquery • MetaDataobjects Representmetadataaboutdatabases,queryresults,andstatements • Exceptionobjects RepresenterrorsinSQLstatementexecution TheseobjectshavethelogicalrelationshipshowninFigure19-37,basedonwhich objectsprovidemethodstocreateotherobjects.Thefollowingsectionsdescribeeachof theseobjects,andhowtheirmethodsareusedtoconnecttodatabases,executeSQL statements,andprocessqueryresults.AcompleteexplanationoftheJDBCAPIisbeyond thescopeofthisbook,buttheconceptsdescribedshouldallowyoutomakeeffectiveuseof JDBCandtounderstandthedocumentationthatisdeliveredwiththepackage. TheDriverManagerobjectisthemaininterfacetotheJDBCpackage.Someofthe mostimportantmethodsthatitprovidesareshowninTable19-14.AfterloadingtheJDBC driverclassthatyouwanttouse(typicallyusingtheClass.forName()method),your programwillasktheDriverManagerobjecttoconnectyoutothatspecificdriveranda specificdatabasewiththegetConnection()method:
ThegetConnection()methodreturnsanobject,theConnectionobject,which embodiestheconnectionthathasjustbeencreatedandthedatabaseontheotherendofthat connection.OtherDriverManagermethodsprovideprogrammaticcontroloverconnection timeouts,switchonJDBCcallloggingfordebugging,andperformotherutilityfunctions.If itencountersanerrorwhileattemptingtomaketheconnection,theDriverManagerobject willthrowanexception.Errorhandlingisdescribedinthe“ErrorHandlinginJDBC”section laterinthischapter.
PART V
//CreateaconnectiontotheOracleJDBCdriver Stringurl="…willvarydependingonOS,etc." Stringuser="Scott"; Stringpswd="Tiger"; Connectiondbconn= DriverManager.getConnection(url,user,pswd);
600
Part V:
Programming with SQL
Method
Description
getConnection()
Creates and returns a database connection object, given a URL for the datasource, and optionally a user name and password, and connection properties
registerDriver()
Registers a driver with JDBC driver manager
setLoginTimeout()
Sets timeout for connection login
getLoginTimeout()
Obtains login timeout value
setLogWriter()
Enables tracing of JDBC calls
TABLE 19-14
DriverManager Object Methods
FIGURE 19-37 Key objects used by the JDBC API
Chapter 19:
SQL APIs
Method
Description
close()
Closes the connection to the datasource
createStatement()
Creates a Statement object for the connection
prepareStatement()
Prepares a parameterized SQL statement into a PreparedStatement for execution
prepareCall()
Prepares a parameterized call to a stored procedure or function into a CallableStatement for execution
commit()
Commits the current transaction on the connection
rollback()
Rolls back the current transaction on the connection
setAutoCommit()
Sets/resets autocommit mode on the connection
getWarnings()
Retrieves SQL warning(s) associated with a connection
getMetaData
Returns a DatabaseMetaData object with info about database
TABLE 19-15
601
JDBC Connection Object Methods
JDBC Basic Statement Processing
//Theconnectionobjectandstringswewilluse Connectiondbconn;//thedatabaseconnection Stringstr1="UPDATEOFFICESSETTARGET=0"; Stringstr2="DELETEFROMSALESREPSWHEREEMPL_NUM=106"; //CreateastatementobjectforexecutingSQL Statementstmt=dbconn.createStatement();
PART V
ThemajorfunctionsoftheJDBCConnectionobjectaretomanagetheconnectiontothe database,tocreateSQLstatementsforprocessingbythatdatabase,andtomanage transactionsovertheconnection.Table19-15showstheConnectionobjectmethodsthat providethesefunctions.InmostsimpleJDBCprograms,thenextstepafteraconnectionhas beenestablishedwillbetocalltheConnectionobject’screateStatement()methodto createaStatementobject. ThemajorfunctionofaStatementobjectistoactuallyexecuteSQLstatements. Table19-16showstheStatementobjectmethodsthatyouusetocontrolstatement execution.Thereareseveraldifferentexecute()methods,dependingonthespecific typeofSQLstatement.Simplestatementsthatdonotproducequeryresults(e.g.,UPDATE, DELETE,INSERT,CREATETABLE)canusetheexecuteUpdatemethod.Queriesusethe executeQuery()method,becauseitprovidesamechanismforreturningthequery results.Otherexecute()methodssupportpreparedSQLstatements,statement parameters,andstoredprocedures. ToillustratethebasicuseofConnectionandStatementobjects,hereisasimpleJava programexcerptthatcreatesaconnectiontoadatabase,performstwodatabaseupdates, commitsthechanges,andthenclosestheconnection:
602
Part V:
Programming with SQL
//UpdatetheOFFICEStablewiththestatementobject stmt.executeUpdate(str1); //UpdatetheSALESREPStablewiththestatementobject stmt.executeUpdate(str2); //Committhechangestothedatabase dbconn.commit(); //UpdatetheSALESREPStableusingthesamestatementobject stmt.executeUpdate(str2); //Finally,closetheconnection dbconn.close();
Astheexampleshows,theSQLtransaction-processingoperations(commitand rollback)arehandledbymethodcallstotheConnectionobject,ratherthanbyexecuting COMMITandROLLBACKstatements.ThisallowstheJDBCdrivertoknowthestatusofthe transactionsthatitisprocessingwithoutexaminingthespecificSQLbeingexecuted.JDBC alsosupportsanautocommitmode,inwhicheverystatementistreatedasanindividual transaction.AConnectionobjectmethodalsocontrolsthisoption. Method
Description
Basic statement execution executeUpdate()
Executes a nonquery SQL statement and returns the number of rows affected
executeQuery()
Executes a single SQL query and returns a result set
execute()
General-purpose execution of one or more SQL statements
Statement batch execution addBatch()
Stores previously supplied parameter values as part of a batch of values for execution
executeBatch()
Executes a sequence of SQL statements; returns an array of integers indicating the number of rows impacted by each one
Query results limitation setMaxRows()
Limits number of rows retrieved by a query
getMaxRows()
Retrieves current maximum row limit setting
setMaxFieldSize()
Limits maximum size of any retrieved column
getMaxFieldSize()
Retrieves current maximum field size limit
setQueryTimeout()
Limits maximum time of query execution
getQueryTimeout()
Retrieves current maximum query time limit
Error handling getWarnings() TABLE 19-16
Retrieves SQL warning(s) associated with statement execution
JDBC Statement Object Methods
Chapter 19:
SQL APIs
603
NotethattheConnectionandStatementmethodscalledinthisprogramexcerptcan causeerrors,andtheexcerptdoesnotshowanyerror-handlingcode.Ifanerroroccurs,the JDBCdriverwillthrowaSQLExceptionexception.Normally,anexcerptliketheprevious one(orpartsofit)willappearwithinatry/catchstructuretohandlethepossible exception.Forsimplicity,theenclosingtry/catchstructureissuppressedinthisandthe nextseveralexamples.Error-handlingtechniquesaredescribedinthe“ErrorHandlingin JDBC”sectionlaterinthischapter.
Simple Query Processing
AswiththeotherSQLAPIsandembeddedSQL,queryprocessingrequiresanadditional mechanismbeyondthoseusedfordatabaseupdatestohandlethereturnedqueryresults. InJDBC,theResultSetobjectprovidesthatadditionalmechanism.Toexecuteasimple query,aJavaprograminvokestheexecuteQuery()methodofaStatementobject, passingthetextofthequeryinthemethodcall.TheexecuteQuery()methodreturnsa ResultSetobjectthatembodiesthequeryresults.TheJavaprogramtheninvokesthe methodsofthisResultSetobjecttoaccessthequeryresults,rowbyrowandcolumnby column.Table19-17showssomeofthemethodsprovidedbytheResultSetobject. HereisaverysimpleJavaprogramexcerptthatshowshowtheobjectsandmethods youhaveseensofarcombinetoperformsimplequeryprocessing.Itretrievesandprints theofficenumber,city,andregionforeachofficeintheOFFICEStable:
PART V
//Theconnectionobject,strings,andvariables Connectiondbconn;//thedatabaseconnection Intnum;//returnedofficenumber Stringcity;//returnedcity Stringreg;//returnedregion Stringstr1="SELECTOFFICE,CITY,REGIONFROMOFFICES"; //Createastatementobjectforexecutingthequery Statementstmt=dbconn.createStatement(); //Carryoutquery–methodreturnsaResultSetobject ResultSetanswer=stmt.executeQuery(str1); //LoopthroughResultSetarowatatime while(answer.next()){ //Retrieveeachcolumnofdata num=answer.getInt("OFFICE"); city=answer.getString("CITY"); reg=answer.getString(3); //Printtherowofresults System.out.println(city+""+num+""+reg); } //Explicitlyclosethecursorandconnection answer.close(); dbconn.close();
604
Part V:
Programming with SQL
Method
Description
Cursor motion next()
Moves cursor to next row of query results
close()
Ends query processing; closes the cursor
Basic column-value retrieval getInt()
Retrieves integer value from specified column
getShort()
Retrieves short integer value from specified column
getLong()
Retrieves long integer value from specified column
getFloat()
Retrieves floating point numeric value from specified column
getDouble()
Retrieves double-precision floating point value from specified column
getString()
Retrieves character string value from specified column
getBoolean()
Retrieves true/false value from specified column
getDate()
Retrieves date value from specified column
getTime()
Retrieves time value from specified column
getTimestamp()
Retrieves timestamp value from specified column
getByte()
Retrieves byte value from specified column
getBytes()
Retrieves fixed-length or variable-length BINARY data from specified column
getObject()
Retrieves any type of data from specified column
Large object retrieval getAsciiStream()
Gets input stream object for processing a character large object (CLOB) column
GetBinaryStream()
Gets input stream object for processing a binary large object (BLOB) column
Other functions getMetaData()
Returns a ResultSetMetaData object with metadata for query
getWarnings()
Retrieves SQL warnings associated with the ResultSet
TABLE 19-17
JDBC ResultSet Object Methods
Themethodsusedarestraightforwardandtheyparallelthequery-processingsteps alreadyseenforembeddedSQLandC/C++APIs.TheResultSetobjectmaintainsacursor tonoteitscurrentpositionwithinthequeryresults.Itsnextmethodadvancesthecursor,row byrow,throughthem.ThereisanexplicitJDBCgetmethodcalltoretrieveeachcolumnof dataforeachrow.Java’sstrongtypingandmemory-protectionschemesmakethisapproacha requirement,butitcarriessignificantlyhigheroverheadthantheC/C++approachofbinding programvariablesandhavingthedatabaseAPIautomaticallypopulatethosevariableswhen thenextrowisfetched.Finally,theclose()methodcallendsqueryprocessing.
Chapter 19:
SQL APIs
605
Theexamplealsoshowsthetwoalternativemethodsforspecifyingwhichcolumn’s valueshouldberetrievedbyeachgetmethodcall.Youcanspecifythenameofthecolumn toberetrieved(usedfortheOFFICEandCITYcolumns),oritsordinalpositionwithinthe columnsofresults(usedfortheREGIONcolumn).JDBCdeliversthiscapabilityby overloadingeachofthegetmethods—oneversiontakesastring(columnname)argument; theothertakesaninteger(columnnumber)argument.
Using Prepared Statements in JDBC
1. TheJavaprogramestablishesaconnectiontotheDBMSintheusualway.
2. TheprogramcallstheprepareStatement()methodwiththetextofthestatement tobeprepared,includingparametermarkers.TheDBMSanalyzesthestatementand createsaninternal,optimizedrepresentationofthestatementtobeexecuted.
3. Later,whenit’stimetoexecutetheparameterstatement,theprogramcallsoneofthe setmethodsinTable19-18foreachparameter,supplyingavaluefortheparameter.
PART V
TheexecuteQuery()andexecuteUpdate()methodsoftheStatementobjectprovide adynamicSQLcapability.TheyparalleltheSQLExecDirect()callintheCLIstandard. ThedatabaseontheotherendoftheJDBCconnectiondoesn’tknowinadvancewhichSQL textwillbepresentedwhentheexecutemethodiscalled.Itmustparsethestatementonthe flyanddeterminehowtoexecuteit.ThedynamicSQLapproachmakesthispartofthe JDBCinterfacequiteeasytouse,butitcreatesthehighoverheadusuallyassociatedwith dynamicSQLfortheunderlyingDBMS.Forhightransactionrateapplicationswhere performanceisimportant,analternativepreparedstatementinterfaceismoreappropriate. ThepreparedstatementapproachusesthesameconceptsasthePREPARE/EXECUTE statementsofembeddeddynamicSQLandtheSQLPrepare()andSQLExecute()calls oftheCLIstandard.ASQLstatementthatistobeexecutedrepeatedly(suchasanUPDATE statementthatwillbeusedonmanyrows,oraquerythatwillbeexecutedhundredsof timesduringaprogram)isfirstpreparedbypassingittotheDBMSforparsingandanalysis. Later,thestatementmaybeexecutedrepeatedlywithverylittleoverhead.Youcanvarythe specificvaluesusedbythestatementduringeachexecutionbypassingparametervaluesfor theexecution.Forexample,youcanchangethevaluestobeusedforeachUPDATEoperation, orchangethevaluetobematchedintheWHEREclauseofaqueryusingparameters. TouseapreparedstatementwithJDBC,yourprograminvokestheprepareStatement() methodonaconnectioninsteadofthecreateStatement()method.Unlike createStatement(),theprepareStatement()methodtakesanargument—astring containingtheSQLstatementthatistobeprepared.Withinthestatementstring,parameters tobesuppliedatstatementexecutionareindicatedbyaquestionmark(?),whichservesasa parametermarker.Aparametercanbeusedwithinthestatementanywherethataconstant couldlegallyappearinthestatement.TheprepareStatement()methodreturnsa PreparedStatementobject,whichincludessomeadditionalmethodsbeyondthose providedbyaStatementobject.Table19-18showssomeoftheseadditionalmethods, nearlyallofwhichareforparameterprocessing. Theadditionalset()methodsofthePreparedStatementobjecttaketwo parameters.Oneindicatestheparameternumberforwhichavalueisbeingsupplied.The otherprovidestheparametervalueitself.Withthesemethods,thetypicalsequencefor JDBCpreparedstatementprocessingcanbesummarizedasfollows:
606
Part V:
Programming with SQL
Method
Description
setInt()
Sets value of an integer parameter
setShort()
Sets value of a short integer parameter
setLong()
Sets value of a long integer parameter
setFloat()
Sets value of a floating point parameter
setDouble()
Sets value of a double-precision floating point parameter
setString()
Sets value of a string parameter
setBoolean()
Sets value of a BOOLEAN parameter
setDate()
Sets value of a DATE parameter
setTime()
Sets value of a TIME parameter
setTimestamp()
Sets value of a TIMESTAMP parameter
setByte()
Sets value of a BYTE parameter
setBytes()
Sets value of a BINARY or VARBINARY parameter
setBigDecimal()
Sets value of a DECIMAL or NUMERIC parameter
setNull()
Sets a NULL value for a parameter
setObject()
Sets value of an arbitrary parameter
clearParameters
Clears all parameter values
getParameterMetaData()
Returns ParameterMetaData object for a prepared statement (JDBC 3.0 only)
TABLE 19-18
Additional Methods of a JDBC PreparedStatement Object
4. Whenallparametervalueshavebeensupplied,theprogramcallsexecuteQuery orexecuteUpdatetoexecutethestatement.
5. TheprogramrepeatsSteps3and4overandover(typicallydozensorhundredsof timesormore),varyingtheparametervalues.Ifaparticularparameter’svaluedoes notchangefromoneexecutiontothenext,thesetmethoddoesnotneedtobe recalled. Hereisaprogramexcerptthatillustratesthetechnique:
//Theconnectionobject,strings,andvariables Connectiondbconn;//thedatabaseconnection Stringcity;//returnedcity Stringstr1="UPDATEOFFICESSETREGION=?WHEREMGR=?"; Stringstr2="SELECTCITYFROMOFFICESWHEREREGION=?";
Chapter 19:
SQL APIs
Using Callable Statements in JDBC
ThelastseveralsectionsdescribedhowJDBCsupportsdynamicSQLstatementexecution (viatheStatementobjectcreatedbythecreateStatement()method)andprepared SQLstatements(viathePreparedStatementobjectcreatedbythe prepareStatement()method).JDBCalsosupportstheexecutionofstoredprocedures andstoredfunctionsthroughathirdtypeofstatementobject,theCallableStatement objectcreatedbytheprepareCall()method.
PART V
//PreparetheUPDATEstatement PreparedStatementpstmt1=dbconn.prepareStatement(str1); //Preparethequery PreparedStatementpstmt2=dbconn.prepareStatement(str2); //SetparametersforUPDATEstatement&executeit pstmt1.setString(1,"Central"); pstmt1.setInt(2,108); pstmt1.executeUpdate(); //Resetoneoftheparametersandexecuteagain,thencommit pstmt1.setInt(2,104); pstmt1.executeUpdate(); dbconn.commit() //Setparameterforquery&executeit pstmt2.setString(1,"Central"); ResultSetanswer=pstmt2.executeQuery(); //LoopthroughResultSetarowatatime while(answer.next()){ //Retrieveeachcolumnofdata city=answer.getString(1); //Printtherowofresults System.out.println("Centralcityis"+city); } answer.close(); //Setadifferentparameterforquery&executeit pstmt2.setString(1,"Eastern"); ResultSetanswer=pstmt2.executeQuery(); //LoopthroughResultSetarowatatime while(answer.next()){ //Retrieveeachcolumnofdata city=answer.getString(1); //Printtherowofresults System.out.println("Easterncityis"+city); } answer.close(); //Done–closetheconnection dbconn.close();
607
608
Part V:
Programming with SQL
HereishowaJavaprograminvokesastoredfunctionorstoredprocedureusingJDBC:
1. TheJavaprograminvokestheprepareCall()method,passingitaSQLstatement thatinvokesthestoredroutine.Parameterstothecallareindicatedbyparameter markerswithinthestatementstring,justastheyareforapreparedstatement.
2. ThemethodreturnsaCallableStatementobject.
3. TheJavaprogramusestheset()methodsoftheCallableStatementobjectto specifyparametervaluesfortheprocedureorfunctioncall.
4. TheJavaprogramusesanothermethodoftheCallableStatementobjectto specifythedatatypesofreturnedvaluesfromthestoredprocedureorfunction.
5. TheJavaprograminvokesoneoftheCallableStatementobject’sexecute() methodstoactuallymakethecalltothestoredprocedure.
6. Finally,theJavaprograminvokesoneormoreoftheCallableStatementobject’s get()methodstoretrievethevaluesreturnedbythestoredprocedure(ifany)or thereturnvalueofthestoredfunction.
ACallableStatementobjectprovidesallofthemethodsofaPreparedStatement, listedinTables19-16and19-18.Theadditionalmethodsthatitprovidesforregisteringthe datatypesofoutputorinput/outputparameters,andforretrievingthereturnedvaluesof thoseparametersafterthecall,areshowninTable19-19. Function
Description
registerOutParameter()
Registers data type for output (or input/output) parameter
getInt()
Retrieves integer returned value
getShort()
Retrieves short integer value from specified column
getLong()
Retrieves long integer value from specified column
getFloat()
Retrieves floating point numeric value from specified column
getDouble()
Retrieves double-precision floating point value from specified column
getString()
Retrieves character string value from specified column
getBoolean()
Retrieves true/false value from specified column
getDate()
Retrieves single date value from specified column
getTime()
Retrieves single time value from specified column
getTimestamp()
Retrieves single timestamp value from specified column
getByte()
Retrieves single byte value from specified column
getBytes()
Retrieves fixed-length or variable-length BINARY data
getBigDecimal()
Retrieves DECIMAL or NUMERIC data
getObject()
Retrieves any type of data
TABLE 19-19 Additional Methods of the CallableStatement Object
Chapter 19:
SQL APIs
609
Ashortexampleisthebestwaytoillustratethetechniqueforcallingastoredprocedure andstoredfunction.(Thebodyoftheprocedureandfunctionareomittedfromthisexample becausethepointishowtheyarecalledratherthanwhattheydo.)Supposethesample databasecontainsastoredproceduredefinedlikethis: CREATEPROCEDURECHANGE_REGION (INOFFICEINTEGER, OUTOLD_REGVARCHAR(10), INNEW_REGVARCHAR(10));
thatchangestheregionofanoffice,asrequestedbythetwoinputparameters,andreturns theoldregionasanoutputparameterandastoredfunction,definedlikethis: CREATEFUNCTIONGET_REGION (INOFFICEINTEGER) RETURNSVARCHAR(10);
thatreturnstheregionofanoffice,givenitsofficenumber.ThisJavaprogramexcerpt showshowtoinvokethestoredprocedureandstoredfunctionusingJDBC:
PART V
//Theconnectionobject,strings,andvariables Connectiondbconn;//thedatabaseconnection Stringstr1="{CALLCHANGE_REGION(?,?,?)}"; Stringstr2="{?=CALLGET_REGION(?)}"; Stringoldreg;//returnedformerregion Stringansreg;//returnedcurrentregion //Preparethetwostatements CallableStatementcstmt1=dbconn.prepareCall(str1); CallableStatementcstmt2=dbconn.prepareCall(str2); //Specifyparamvalues&returneddatatypesforstoredprocedurecall cstmt1.setInt(1,12);//callwithofficenumber12(Chicago) cstmt1.setString(3,"Central");//andnewCentralregion cstmt1.registerOutParameter(2,Types.VARCHAR);//returnsavarcharparam //Goaheadandexecutethecalltothestoredprocedure cstmt1.executeUpdate(); oldreg=cstmt.getString(2);//returned(2nd)paramisastring //Specifyparamvalues&returneddatatypeforstoredfunctioncall cstmt2.setInt(1,12);//callwithofficenumber12(Chicago) cstmt2.registerOutParameter(1,Types.VARCHAR);//fcnreturnsavarchar //Goaheadandexecutethecalltothestoredfunction cstmt2.executeUpdate(); ansreg=cstmt.getString(1);//returnedvalue(1stparam)isastring //Done–closetheconnection dbconn.close();
610
Part V:
Programming with SQL
Notethatthecallinvocationsofthestoredprocedureorfunctioninthestatement stringsareenclosedincurlybrackets.Theinputparameterspassedtoastoredprocedureor functionarehandledexactlythesamewayasparametersforapreparedstatement.Output parametersfromastoredprocedurerequiresomenewmachinery:the registerOutParameter()methodcalltospecifytheirdatatypes,andcallstotheget() methodstoretrievetheirvaluesafterthecalliscomplete.ThesearesummarizedinTable 19-19.Input/outputparametersforastoredprocedurerequireboththatvaluesbepassed intotheprocedurecall,usingtheset()methods,andthattheoutputdatatypebe specifiedwithregisterOutParameter()andthatthereturneddataberetrievedwith theget()methods. Forastoredfunction,thereareonlyinputparameters,andtheset()methodsareonce againused.Thereturnvalueofthefunctionisspecifiedwithaparametermarkerinthe preparedstatementstring.Itsdatatypeisregistered,anditsvalueisretrieved,justasifit werearegularoutputparameter.
Error Handling in JDBC
WhenanerroroccursduringJDBCoperation,theJDBCinterfacethrowsaJavaexception. MostSQLstatementexecutionerrorsthrowaSQLException.Theerrorcanbehandledvia thestandardJavatry/catchmechanism.WhenaSQLExceptionerroroccurs,the catch()methodiscalledwithaSQLExceptionobject,someofwhosemethodsare summarizedinTable19-20. TheSQLExceptionmethodsallowyoutoretrievetheerrormessage,SQLSTATEerror code,andDBMS-specificerrorcodeassociatedwiththeerror.AsingleJDBCoperationcan createmorethanoneerror.Inthiscase,theerrorsareavailabletoyourprogramin sequence.CallinggetNextException()onthefirstreportederrorreturnsa SQLExceptionforthesecondexception,andsoon,untilnomoreexceptionsaretobe handled.
Scrollable and Updateable Cursors in JDBC
JustasscrollablecursorshavebeenaddedtotheANSI/ISOSQLstandards,scrollable cursorshavebeenaddedtoJDBCresultsetsinlaterversionsofthespecification.You indicatethatyouwantaquerytoproduceresultsthatarescrollablethroughaparameterto theexecuteQuerymethod.Ifyouspecifyscrollability,theResultSetreturnedbythe executeQuerycallofferssomeadditionalmethodsforcursorcontrol.Theimportant methodsarelistedinTable19-21.
Method
Description
getMessage()
Retrieves error message describing the exception
getSQLState()
Retrieves SQLSTATE value (5-char string, as described in Chapter 17)
getErrorCode()
Retrieves driver-specific or DBMS-specific error code
getNextException()
Moves to next SQL exception in a series
TABLE 19-20 JDBC SQLException Methods
Chapter 19:
Function
SQL APIs
611
Description
Scrollable cursor motion previous()
Moves cursor to previous row of query results
beforeFirst()
Moves cursor before the start of the results
first()
Moves cursor to first row of query results
last()
Moves cursor to last row of query results
afterLast()
Moves cursor past end of the results
absolute()
Moves cursor to absolute row number indicated
relative()
Moves cursor to relative row number indicated
Cursor position sensing isFirst()
Determines whether the current row is the first row of the result set
isLast()
Determines whether the current row is the last row of the result set
isBeforeFirst()
Determines whether the cursor is positioned before the beginning of the result set
isAfterLast()
Determines whether the cursor is positioned past the end of the result set
moveToInsertRow()
Moves cursor to “empty” row for inserting new data
moveToCurrentRow()
Moves cursor back to the current row before an insertion
Update a column of current row (via cursor) Updates an integer column value
updateShort()
Updates a short integer column value
updateLong()
Updates a long integer column value
updateFloat()
Updates a floating point column value
updateDouble()
Updates a double-precision floating point column value
updateString()
Updates a string column value
updateBoolean()
Updates a true/false column value
updateDate()
Updates a date column value
updateTime()
Updates a time column value
updateTimestamp()
Updates a timestamp column value
updateByte()
Updates a byte column value
updateBytes()
Updates a fixed-length or variable-length column value
updateBigDecimal()
Updates a DECIMAL or NUMERIC column value
updateNull()
Updates a column to a NULL value
updateObject()
Updates an arbitrary column value
TABLE 19-21 JDBC ResultSet Object Extended Cursor Methods
PART V
updateInt()
612
Part V:
Programming with SQL
Function
Description
getTables()
Returns result set of table information of tables in database
getColumns()
Returns result set of column names and type info, given table name
getPrimaryKeys()
Returns result set of primary key info, given table name
getProcedures()
Returns result set of stored procedure info
getProcedureColumns()
Returns result set of info about parameters for a specific stored procedure
TABLE 19-22 DatabaseMetaData Methods for Database Information Retrieval
Inadditiontoscrollableresultsets,laterversionsoftheJDBCspecificationadded supportforupdateableresultsets.ThiscapabilitycorrespondstotheUPDATE…WHERE CURRENTOFcapabilityinembeddedSQL.Itallowsanupdatetospecificcolumnsofthis row,whichisindicatedbythecurrentpositionofacursor.Updateableresultsetsalsoallow newrowsofdatatobeinsertedintoatableviaaresultset.
Retrieving Metadata with JDBC
TheJDBCinterfaceprovidesobjectsandmethodsforretrievingmetadataaboutdatabases, queryresults,andparameterizedstatements.AJDBCConnectionobjectprovidesaccess tometadataaboutthedatabasethatitrepresents.InvokingitsgetMetaData()method returnsaDatabaseMetaDataobject,describedinTable19-22.Eachmethodlistedinthe tablereturnsaresultsetcontaininginformationaboutatypeofdatabaseentity:tables, columns,primarykeys,andsoon.TheresultsetcanbeprocessedusingthenormalJDBC queryresultsprocessingroutines.Othermetadataaccessmethodsprovideinformation aboutthedatabaseproductnamesupportedonthisconnection,itsversionnumber,and similarinformation. Metadatainformationaboutqueryresultscanalsobeveryuseful.AResultSetobject providesagetMetaDatamethodthatcanbeinvokedtoobtainadescriptionofitsquery results.ThemethodreturnsaResultSetMetaDataobject,describedinTable19-23.The methodsletyoudeterminehowmanycolumnsareinthequeryresults,andthenameand datatypeofeachcolumn,identifiedbytheirordinalpositionwithinthequeryresults.
Function
Description
getColumnCount()
Returns number of query results columns
getColumnName()
Retrieves name of specified results column
getColumnType()
Retrieves data type of specified results column
TABLE 19-23 ResultSetMetaData Methods
Chapter 19:
SQL APIs
Function
Description
getParameterClassName()
Returns name of the class (data type) for specified parameter
getParameterCount()
Returns number of parameters in the statement
getParameterMode()
Returns mode (IN, OUT, INOUT) of parameter
getParameterType()
Returns SQL data type of specified parameter
getParameterTypeName()
Returns DBMS data type of specified parameter
getPrecision()
Returns precision of specified parameter
getScale()
Returns scale of specified parameter
isNullable()
Determines whether the specified parameter is nullable
isSigned()
Determines whether the specified parameter is a signed number
613
TABLE 19-24 JDBC ParameterMetaData Methods
Finally,metadatainformationabouttheparametersusedinapreparedSQLstatement orapreparedcalltoastoredprocedurecanalsobeuseful.ThegetParameterMetaData() methodthatretrievesthisinformationisinheritedfromtheCallableStatementobjectsince itextendsthePreparedStatementobject.ThemethodreturnsaParameterMetaData object,describedinTable19-24.Invokingthemethodsofthisobjectprovidesinformation abouthowmanyparametersareusedinthestatement,theirdatatypes,whethereach parameterisaninput,output,orinput/outputparameter,andsimilarinformation.
Advanced JDBC Capabilities
PART V
JDBC2.0andJDBC3.0introducedseveralcapabilitiesthatextendthebasicdatabaseaccess functionalityofJDBC.JDBCdatasources,firstintroducedinJDBC2.0,provideahigher-level methodforfindingavailabledriversanddatabasesandconnectingtothem.Theymaskthe detailsofmakingaconnectionfromtheJavaapplicationprogrammer.Basically,adata sourceisidentifiedwithsomeexternaldirectoryorcatalogthatisabletotranslatelogical entitynamesintospecificdetails.Usingadatasource,theapplicationprogrammercan specifyatargetdatabasebyanabstractname,andhavethedirectoryinconjunctionwith theJDBCsoftwarehandlethedetailsofconnections. JDBCrowsetsareanotheradvancedconceptenhancedandextendedintheJDBCrevisions. ArowsetextendstheconceptofaJDBCresultset,whichyouwillrecallrepresentsasetof queryresults.Beyondthequeryresultsthemselves,arowsetencapsulatesinformationabout theunderlyingsourcedatabase,theconnectiontothedatabase,itsusernameandpassword, andsoon.Therowsetretainsitsidentityindependentofanactiveconnectiontothedatabase. Thus,arowsetmayexistinadisconnectedstate,anditcanbeusedtoreestablishaconnection tothedatabase.Whenconnectedtothedatabase,therowsetcancontainqueryresultslike aresultset. Rowsetshaveseveralothercharacteristicsandcapabilities.Arowsetmeetstherequirement foraJavaBeanscomponent,andwhenconnectedtoadatabase,providesawaytomakearesult setlooklikeanEnterpriseJavaBean(EJB).Rowsetsholdtabularrow/columnqueryresults,
614
Part V:
Programming with SQL
andthoseresultscanberetrieved,navigated,andevenupdatedwhethertherowsetiscurrently connectedtothesourcedatabaseornot.Ifdisconnectedupdatesaremade,resynchronization isimpliedwhentherowsetonceagainisconnectedtothesourcedatabase.Finally,theconcept ofarowsetisnotnecessarilytiedtoSQLandrelationaldatabases.Thedatainarowsetcan conceptuallycomefromanytabulardatasource,suchasapersonalcomputerspreadsheetor evenatablewithinawordprocessingdocument.AcompletediscussionofJDBCrowsetsis beyondthescopeofthisbook;seetheJDBCdocumentationathttp://java.sun.com/javase/ technologies/database/index.jspformoreinformationaboutthisandotherJDBCcapabilities. (ClicktheJDBCDocumentationlinkfortheversionyouwant.)
Summary ManySQL-basedDBMSproductsprovideacallableAPIforprogrammaticdatabaseaccess: • DependingontheparticularDBMSbrandanditshistory,thecallableAPImaybe analternativetoanembeddedSQLapproach,oritmaybetheprimarymethodby whichanapplicationprogramaccessesthedatabase. • Acallableinterfaceputsqueryprocessing,parameterpassing,statementcompilation, statementexecution,andsimilartasksintothecallinterface,keepingtheprogrammatic SQLlanguageidenticaltointeractiveSQL.WithembeddedSQL,thesetasksare handledbyspecialSQLstatements(OPEN,FETCH,CLOSE,PREPARE,EXECUTE, andsoon)thatareuniquetoprogrammaticSQL. • Microsoft’sODBCisawidelysupported,callableAPIthatprovidesaneffective wayforanapplicationprogramtoachieveindependencefromaparticularDBMS. However,differencesbetweenDBMSbrandsarereflectedinvaryingsupportfor ODBCfunctionsandcapabilities. • TheSQL/Call-LevelInterface(SQL/CLI)standardisbasedonODBCandis compatiblewithitatthecorelevel.SQL/CLIprovidesacallableAPItocomplement theembeddedSQLinterfacespecifiedintheSQLstandard.ManyDBMSvendors supporttheSQL/CLIbecauseoftheirhistoricalsupportforODBC. • ForJavaprograms,theJDBCinterfaceisthedefactoindustrystandardcallableAPI, supportedbyallofthemajorDBMSproductsanddefinedasthedatabase managementAPIwithintheJava2EnterpriseEdition(J2EE)standardimplemented byallofthemajorapplicationserverproducts. • TheproprietarycallableAPIsofthedifferentDBMSbrandsremainimportantinthe market(especiallyOracle’sOCI).Allofthemofferthesamebasicfeatures,butthey varydramaticallyintheextendedfeaturesthattheyofferandinthedetailsofthe callsanddatastructuresthattheyuse. • Ingeneral,DBMSvendorsputconsiderableperformance-tuningworkintotheir proprietaryAPIsandtendtoofferODBCand/orSQL/CLIsupportasacheck-off feature.Thus,applicationswithhigherperformancerequirementstendtousethe proprietaryAPIsandarelockedintoaparticularDBMSbrandwhentheydo.
VI
PART
SQL Today and Tomorrow
T
heinfluenceofSQLcontinuestoexpandasnewSQL capabilitiesandextensionstoSQLaddressnewtypesofdata managementrequirements.Chapters20through27describe severaloftheseexpandingareas.Chapter20describesstored proceduralSQL,whichprovidesprocessingcapabilitieswithinthe DBMSitselfforimplementingbusinessrulesandcreatingwell-defined databaseinteractions.Chapter21describesSQL’sroleinanalyzing dataandthetrendtocreateSQL-baseddatawarehouses.Chapter22 describestheroleofSQLincreatinginteractivewebsites,and especiallyitsrelationshiptoapplicationservertechnology.Chapter23 discusseshowSQLisusedtocreatedistributeddatabasesthattap thepowerofcomputernetworks.Chapter24discussesoneofthe mostimportantareasofSQLevolution—theinterplaybetweenSQL andobject-orientedtechnologiesandthenewgenerationofobjectrelationaldatabases.Chapter25focusesontherelationshipbetween SQLandoneofthemostimportantofthesetechnologies,XML,along withtheemergingInternetwebservicesarchitecturebasedonXML. Chapter26exploresdatabasesintendedforspecialpurposes, includingmobileandembeddeddatabases.Finally,Chapter27 highlightsthekeytrendsthatwilldrivetheevolutionofSQLforthe comingdecade.
CHAPTER 20 DatabaseProcessingand StoredProceduralSQL CHAPTER 21 SQLandDataWarehousing CHAPTER 22 SQLandApplicationServers CHAPTER 23 SQLNetworkingand DistributedDatabases CHAPTER 24 SQLandObjects CHAPTER 25 SQLandXML CHAPTER 26 SpecialtyDatabases CHAPTER 27 TheFutureofSQL
This page intentionally left blank
20
CHAPTER
Database Processing and Stored Procedural SQL
T
helong-termtrendinthedatabasemarketisfordatabasestotakeonaprogressively largerroleintheoveralldataprocessingarchitecture.Thepre-relationaldatabase systemsbasicallyhandledonlydatastorageandretrieval;applicationprogramswere responsiblefornavigatingtheirwaythroughthedatabase,sortingandselectingdata,and handlingallprocessingofthedata.WiththeadventofrelationaldatabasesandSQL,the DBMStookonexpandedresponsibilities.Databasesearchingandsortingwereembodiedin SQLlanguageclausesandprovidedbytheDBMS,alongwiththecapabilitytosummarize data.Explicitnavigationthroughthedatabasebecameunnecessary.SubsequentSQL enhancementssuchasprimarykey,foreignkey(referential),andcheckconstraintscontinued thetrend,takingoverdatavalidationanddataintegrityfunctionsthathadremainedthesole responsibilityofapplicationprogramswithearlierSQLimplementations.Ateachstep,having theDBMStakeonmoreresponsibilityprovidedmorecentralizedcontrolandreducedthe possibilityofdatacorruptionduetoapplicationprogrammingerrors. Inmanyinformationtechnology(IT)departmentswithinlargecompaniesand organizations,thisDBMStrendparalleledanorganizationaltrend.Thecorporatedatabase andthedataitcontainscametobeviewedasamajorcorporateasset,andinmanyIT departments,adedicateddatabaseadministration(DBA)groupemerged,withresponsibility formaintainingthedatabase,defining(andinsomecasesupdating)thedataitcontained, andprovidingstructuredaccesstoit.OthergroupswithintheITdepartment,orelsewhere withinthecompany,coulddevelopapplicationprograms,reports,queries,orotherlogicthat accessedthedatabase.Inmostorganizations,applicationprograms,andthebusinesspeople usingthem,havehadprimaryresponsibilityforupdatingthedatawithinthedatabase. However,theDBAgroupsometimeshashadresponsibilityforupdatingreference(lookup) tabledataandforassistingwithscriptsandutilitiestoperformtaskssuchasthebulk loadingofnewlyacquireddata.Butthesecurityofthedatabase,thepermittedformsof access,andingeneral,everythingwithintherealmofthedatabase,becametheprovince oftheDBA.
617
618
Part VI:
SQL Today and Tomorrow
Threeimportantfeaturesofmodernenterprise-scalerelationaldatabases—stored procedures,functions,andtriggers—havebeenapartofthistrend.Storedprocedurescan performdatabase-relatedapplicationprocessingwithinthedatabaseitself.Forexample, astoredproceduremightimplementtheapplication’slogictoacceptacustomerorderorto transfermoneyfromonebankaccounttoanother.FunctionsarestoredSQLprogramsthat returnonlyasinglevalueforeachrowofdata.Unlikestoredprocedures,functionsare invokedbyreferencingtheminSQLstatementsinalmostanyclausewhereacolumnname canbeused.Thismakesthemidealforperformingcalculationsanddatatransformations ondatatobedisplayedinqueryresultsorusedinsearchconditions.Nearlyallrelational DBMSproductscomewithasetofvendor-suppliedfunctionsforgeneraluse,andtherefore functionsaddedbylocaldatabaseusersareoftencalleduser-definedfunctions.Triggersare usedtoautomaticallyinvoketheprocessingcapabilityofastoredprocedurebasedon conditionsthatarisewithinthedatabase.Forexample,atriggermightautomatically transferfundsfromasavingsaccounttoacheckingaccountifthecheckingaccount becomesoverdrawn.Thischapterdescribesthecoreconceptsbehindstoredprocedures, functions,andtriggers,andtheirimplementationinseveralpopularDBMSbrands. ThestoredproceduralSQLcapabilitiesofthepopularDBMSproductshavebeen significantlyexpandedintheirmajorrevisionsduringthelate1990sand2000s.Acomplete treatmentofstoredprocedure,function,andtriggerprogrammingiswellbeyondthe scopeofthisbook,buttheconceptsandcomparisonsherewillgiveyouanunderstanding ofthecorecapabilitiesandafoundationforbeginningtousethespecificcapabilitiesof yourDBMSsoftware.Storedprocedures,functions,andtriggersbasicallyextendSQLinto amorecompleteprogramminglanguage,andthischapterassumesthatyouarefamiliar withbasicprogrammingconcepts.
Procedural SQL Concepts Initsoriginalform,SQLwasnotenvisionedasacompleteprogramminglanguage.Itwas designedandimplementedasalanguageforexpressingdatabaseoperations—creating databasestructures,enteringdataintothedatabase,updatingdatabasedata—andespecially forexpressingdatabasequeriesandretrievingtheanswers.SQLcouldbeusedinteractively bytypingSQLstatementsatakeyboard,onebyone.Inthiscase,thesequenceofdatabase operationswasdeterminedbythehumanuser.SQLcouldalsobeembeddedwithinanother programminglanguage,suchasCOBOLorC.Inthiscase,thesequenceofdatabase operationswasdeterminedbytheflowofcontrolwithintheCOBOLorCprogram. WithstoredproceduralSQL,theSQLlanguageisextendedwithseveralcapabilities normallyassociatedwithprogramminglanguages.SequencesofextendedSQLstatements aregroupedtogethertoformSQLprogramsorprocedures.(Forsimplicity,wereferto storedprocedures,functions,andtriggerscollectivelyasSQLprocedures.)Thespecifics varyfromoneimplementationtoanother,butgenerally,thesecapabilitiesareprovided: • Conditionalexecution AnIF…THEN…ELSEstructureallowsaSQLprocedureto testaconditionandtocarryoutdifferentoperationsdependingontheresult. • Looping AWHILEorFORlooporsimilarstructureallowsasequenceofSQL operationstobeperformedrepeatedly,untilsometerminatingconditionismet. Someimplementationsprovideaspecialcursor-basedloopingstructuretoprocess eachrowofqueryresults.
Chapter 20:
Database Processing and Stored Procedural SQL
619
• Blockstructure AsequenceofSQLstatementscanbegroupedintoasingleblock andusedinotherflow-of-controlconstructsasifthestatementblockwereasingle statement. • Namedvariables ASQLproceduremaystoreavaluethatithascalculated,retrieved fromthedatabase,orderivedinsomeotherwayintoaprogramvariable,andlater retrievethestoredvalueforuseinsubsequentcalculations. • Namedprocedures AsequenceofSQLstatementsmaybegroupedtogether, givenaname,andassignedformalinputandoutputparameters,likeasubroutine orfunctioninaconventionalprogramminglanguage.Oncedefinedinthisway, theproceduremaybecalledbyname,passingitappropriatevaluesforitsinput parameters.Iftheprocedureisafunctionreturningavalue,itmaybeusedinSQL valueexpressions. Collectively,thestructuresthatimplementthesecapabilitiesformastoredprocedural language(SPL). StoredprocedureswerefirstintroducedbySybaseintheoriginalSybaseSQLServer product.(Functionsandtriggersevolvedabitlater,andthusarediscussedlaterinthis chapter.)Muchoftheoriginalenthusiasmforstoredprocedureswasbecauseoftheir performanceadvantagesinaclient/serverdatabasearchitecture.Withoutstoredprocedures, everySQLoperationrequestedbyanapplicationprogram(runningontheclientcomputer system)wouldbesentacrossthenetworktothedatabaseserverandwouldwaitforareply messagetobereturnedacrossthenetwork.IfalogicaltransactionrequiredsixSQLoperations, sixnetworkroundtripswererequired.Withstoredprocedures,thesequenceofsixSQL operationscouldbeprogrammedintoaprocedureandstoredinthedatabase.Theapplication programwouldsimplyrequesttheexecutionofthestoredprocedureandawaittheresults. Inthisway,sixnetworkroundtripscouldbecuttooneroundtrip—therequestandreplyfor executingthestoredprocedure. Storedproceduresprovedtobeanaturalfitfortheclient/servermodel,andSybase usedthemtoestablishanearlyleadwiththisarchitecture.Acompetitiveresponsequickly followedfrommanyoftheotherDBMSvendors.Today,mostenterpriseDBMSproducts provideastoredprocedurecapability,andthebenefitsofstoredproceduresincorporate databaseshasexpandedconsiderablybeyondtheearlyfocusonnetworkperformance. StoredproceduresarelessrelevantforothertypesofspecializedDBMSsystems,suchas datawarehousingsystemsorin-memorydatabases.SomeDBMSproductshavemodeled theirSPLstructuresonCorPascallanguageconstructs.Othershavetriedtomatchthestyle oftheSQLDataManipulationLanguage(DML)andDataDefinitionLanguage(DDL) statements.Oracle,ontheotherhand,baseditsSPL(PL/SQL)ontheAdaprogramming language,becauseitwasthestandardlanguageofitslargeU.S.governmentcustomers. WhilestoredprocedureconceptsareverysimilarfromoneSQLdialecttoanother,the specificsyntaxvariesconsiderably.
PART VI
620
Part VI:
SQL Today and Tomorrow
A Basic Example It’seasiesttoexplainthebasicsofstoredproceduresthroughanexample.Considerthe processofaddingacustomertothesampledatabase.Herearethestepsthatmaybe involved:
1. Obtainthecustomernumber,name,creditlimit,andtargetsalesamountforthe customer,aswellastheassignedsalespersonandoffice.
2. Addarowtothecustomertablecontainingthecustomer’sdata.
3. Updatetherowfortheassignedsalesperson,raisingthequotatargetbythe specifiedamount.
4. Updatetherowfortheoffice,raisingthesalestargetbythespecifiedamount.
5. Committhechangestothedatabase,ifallpreviousstatementsweresuccessful.
Withoutastoredprocedurecapability,hereisaSQLstatementsequencethatdoesthis workforXYZCorporation,newcustomernumber2137,withacreditlimitof$30,000and first-yeartargetsalesof$50,000tobeassignedtoPaulCruz(employee#103)oftheChicago office: INSERTINTOCUSTOMERS(CUST_NUM,COMPANY,CUST_REP,CREDIT_LIMIT) VALUES(2137,'XYZCorporation',103,30000.00); UPDATESALESREPS SETQUOTA=QUOTA+50000.00 WHEREEMPL_NUM=103; UPDATEOFFICES SETTARGET=TARGET+50000.00 WHERECITY='Chicago'; COMMIT;
Withastoredprocedure,allofthisworkcanbeembeddedintoasingledefinedSQL routine.Figure20-1showsastoredprocedureforthistask,expressedinOracle’sPL/SQL storedproceduredialect.TheprocedureisnamedADD_CUST,anditacceptssix parameters—thecustomername,number,creditlimit,andtargetsales,theemployee numberoftheassignedsalesperson,andthecitywheretheassignedsalesofficeislocated. Oncethisprocedurehasbeencreatedinthedatabase,astatementlikethisone: ADD_CUST('XYZCorporation',2137,30000.00,50000.00,103,'Chicago');
callsthestoredprocedureandpassesitthesixspecifiedvaluesasitsparameters.TheDBMS executesthestoredprocedure,carryingouteachSQLstatementintheproceduredefinition onebyone.IftheADD_CUSTprocedurecompletesitsexecutionsuccessfully,acommitted transactionhasbeencarriedoutwithintheDBMS.Ifnot,thereturnederrorcodeand messageindicateswhatwentwrong.
Chapter 20:
Database Processing and Stored Procedural SQL
621
/* Add a customer procedure */ create procedure add_cust ( c_name
in varchar2,
c_num
in integer,
/* input customer name */ /* input customer number */
cred_lim in number,
/* input credit limit */
tgt_sls
in number,
/* input target sales */
c_rep
in integer,
/* input salesrep emp # */
c_offc
in varchar2)
/* input office city */
as begin /* Insert new row of CUSTOMERS table */ insert into customers (cust_num, company, cust_rep, credit_limit) values (c_num, c_name, c_rep, cred_lim); /* Update row of SALESREPS table */ update salesreps set quota = quota + tgt_sls where empl_num = c_rep; /* Update row of OFFICES table */ update offices set target = target + tgt_sls where city = c_offc; /* Commit transaction and we are done */ commit; end;
FIGURE 20-1 A basic stored procedure in PL/SQL
Using Stored Procedures TheproceduredefinedinFigure20-1illustratesseveralofthebasicstructurescommontoall SPLdialects.NearlyalldialectsuseaCREATEPROCEDUREstatementtoinitiallydefinea storedprocedure.AcorrespondingDROPPROCEDUREstatementisusedtodiscardprocedures thatarenolongerneeded.TheCREATEPROCEDUREstatementdefinesthefollowing: • Thenumberanddatatypesofitsparameters • Thenamesanddatatypesofanylocalvariablesusedbytheprocedure • Thesequenceofstatementsexecutedwhentheprocedureiscalled
PART VI
• Thenameofthestoredprocedure
622
Part VI:
SQL Today and Tomorrow
ThefollowingsectionsdescribetheseelementsandthespecialSQLstatementsthatare usedtocontroltheflowofexecutionwithinthebodyofastoredprocedure.
Creating a Stored Procedure InmanycommonSPLdialects,theCREATEPROCEDUREstatementisusedtocreateastored procedureandtospecifyhowitoperates.TheCREATEPROCEDUREstatementassignsthe newlydefinedprocedureaname,whichisusedtocallit.Thenamemusttypicallyfollow therulesforSQLidentifiers.(TheprocedureinFigure20-1isnamedADD_CUST.)Astored procedureacceptszeroormoreparametersasitsarguments.(Thisonehassixparameters: C_NAME,C_NUM,CRED_LIM,TGT_SLS,C_REP,andC_OFFC.)InallofthecommonSPL dialects,thevaluesfortheparametersappearinacomma-separatedlist,enclosedin parentheses,followingtheprocedurenamewhentheprocedureiscalled.Theheaderofthe storedproceduredefinitionspecifiesthenamesoftheparametersandtheirdatatypes.The sameSQLdatatypessupportedbytheDBMSforcolumnswithinthedatabasecanbeused asparameterdatatypes. InFigure20-1,alloftheparametersareinputparameters(signifiedbytheINkeyword intheprocedureheaderintheOraclePL/SQLdialect).Whentheprocedureiscalled,the parametersareassignedthevaluesspecifiedintheprocedurecall,andthestatementsinthe procedurebodybegintoexecute.Theparameternamesmayappearwithintheprocedure body(andparticularlywithinstandardSQLstatementsintheprocedurebody)anywhere thataconstantmayappear.Whenaparameternameappears,theDBMSusesitscurrent value.InFigure20-1,theparametersareusedintheINSERTstatementandtheUPDATE statement,bothasdatavaluestobeusedincolumncalculationsandassearchconditions. Inadditiontoinputparameters,someSPLdialectsalsosupportoutputparameters. Theseallowastoredproceduretopassbackvaluesthatitcalculatesduringitsexecution. Outputparametersprovideanimportantcapabilityforpassingbackinformationfromone storedproceduretoanotherstoredprocedurethatcallsit,andcanalsobeusefulfor debuggingstoredproceduresusinginteractiveSQL.SomeSPLdialectssupportparameters thatoperateasbothinputandoutputparameters.Inthiscase,theparameterpassesavalue tothestoredprocedure,andanychangestothevalueduringtheprocedureexecutionare reflectedinthecallingprocedure. Figure20-2showsthesameADD_CUSTproceduredefinition,expressedintheSybase Transact-SQLdialect.(TheTransact-SQLdialectisalsousedbyMicrosoftSQLServer;its basicsarelargelyunchangedsincetheoriginalSybaseSQLServerversion,whichwasthe foundationforboththeMicrosoftandSybaseproductlines.)Notethedifferencesfromthe Oracledialect: • ThekeywordPROCEDUREcanbeabbreviatedtoPROC. • Noparenthesizedlistofparametersfollowstheprocedurename.Instead,the parameterdeclarationsimmediatelyfollowthenameofthestoredprocedure. • Theparameternamesallbeginwithan“at”sign(@),bothwhentheyaredeclaredat thebeginningoftheprocedureandwhentheyappearwithinSQLstatementsinthe procedurebody. • Thereisnoformalend-of-procedurebodymarker.Instead,theprocedurebodyisa singleTransact-SQLstatement.Ifmorethanonestatementisneeded,theTransactSQLblockstructureisusedtogroupthestatements.
Chapter 20:
Database Processing and Stored Procedural SQL
623
/* Add a customer procedure */ create proc add_cust @c_name
varchar(20),
@c_num integer, @cred_lim decimal(9,2),
/* input customer name */ /* input customer number */ /* input credit limit */
@tgt_sls
decimal(9,2),
/* input target sales */
@c_rep
integer,
/* input salesrep emp # */
@c_offc
varchar(15)
/* input office city */
as begin /* Insert new row of CUSTOMERS table */ insert into customers (cust_num, company, cust_rep, credit_limit) values (@c_num, @c_name, @c_rep, @cred_lim) /* Update row of SALESREPS table */ update salesreps set quota = quota + quota + @tgt_sls where empl_num = @c_rep /* Update row of OFFICES table */ update offices set target = target + @tgt_sls where city = @c_offc /* Commit transaction and we are done */ commit trans end
FIGURE 20-2 The ADD_CUST stored procedure in Transact-SQL
Figure20-3showstheADD_CUSTprocedureagain,thistimeexpressedintheInformix storedproceduredialect.Thedeclarationoftheprocedureheaditselfandtheparameters morecloselyfollowtheOracledialect.UnliketheTransact-SQLexample,thelocalvariables andparametersuseordinarySQLidentifiersastheirnames,withoutanyspecialidentifying symbols.TheproceduredefinitionisformallyendedwithanENDPROCEDUREclause,which makesthesyntaxlesserror-prone. InalldialectsthatusetheCREATEPROCEDUREstatement,theprocedurecanbedropped whennolongerneededbyusingacorrespondingDROPPROCEDUREstatement:
PART VI
DROPPROCEDUREADD_CUST;
624
Part VI:
SQL Today and Tomorrow
/* Add a customer procedure */ create procedure add_cust ( c_name
varchar(20),
c_num
integer,
/* input customer name */ /* input customer number */
cred_lim numeric(16,2),
/* input credit limit */
tgt_sls
numeric(16,2),
/* input target sales */
c_rep
integer,
/* input salesrep emp # */
c_offc
varchar(15))
/* input office city */
/* Insert new row of CUSTOMERS table */ insert into customers (cust_num, company, cust_rep, credit_limit) values (c_num, c_name, c_rep, cred_lim); /* Update row of SALESREPS table */ update salesreps set quota = quota + quota + tgt_sls where empl_num = c_rep; /* Update row of OFFICES table */ update offices set target = target + tgt_sls where city = c_offc; /* Commit transaction and we are done */ commit work; end procedure;
FIGURE 20-3 The ADD_CUST stored procedure in Informix SPL
Calling a Stored Procedure OncedefinedbytheCREATEPROCEDUREstatement,astoredprocedurecanbeused.An applicationprogrammayrequestexecutionofthestoredprocedure,usingtheappropriate SQLstatement.Anotherstoredproceduremaycallittoperformaspecificfunction.The storedproceduremayalsobeinvokedthroughaninteractiveSQLinterface. ThevariousSQLdialectsdifferinthespecificsyntaxusedtocallastoredprocedure. HereisacalltotheADD_CUSTprocedureinthePL/SQLdialect: EXECUTEADD_CUST('XYZCorporation',2137,30000.00,50000.00,103, 'Chicago');
Thevaluestobeusedfortheprocedure’sparametersarespecified,inorder,inalistthat isenclosedbyparentheses.Whencalledfromwithinanotherprocedureoratrigger,the EXECUTEstatementmaybeomitted,andthecallbecomessimply: ADD_CUST('XYZCorporation',2137,30000.00,50000.00,103,'Chicago');
Chapter 20:
Database Processing and Stored Procedural SQL
625
Theproceduremayalsobecalledusingnamedparameters,inwhichcasetheparameter valuescanbespecifiedinanysequence.Hereisanexample: EXECUTEADD_CUST(c_name='XYZCorporation', c_num=2137, cred_lim=30000.00, c_offc='Chicago', c_rep=103, tgt_sales=50000.00);
IntheTransact-SQLdialect,thecalltothestoredprocedurebecomes EXECUTEADD_CUST'XYZCorporation',2137,30000.00,50000.00,103,'Chicago';
Theparenthesesaren’trequired,andthevaluestobeusedforparametersagainforma comma-separatedlist.ThekeywordEXECUTEcanbeabbreviatedtoEXEC,andthe parameternamescanbeexplicitlyspecifiedinthecall,allowingyoutospecifythe parametervaluesinanyorderyouwish.Hereisanalternative,equivalentTransact-SQLcall totheADD_CUSTstoredprocedure: EXECADD_CUST@C_NAME='XYZCorporation', @C_NUM=2137, @CRED_LIM=30000.00, @C_OFFC='Chicago', @C_REP=103, @TGT_SLS=50000.00;
TheInformixSPLformofthesameEXECUTEcommandis EXECUTEPROCEDUREADD_CUST('XYZCorporation',2137,30000.00,50000.00, 103,'Chicago');
Again,theparametersareenclosedinacomma-separated,parenthesizedlist.Thisform oftheEXECUTEstatementmaybeusedinanycontext.Forexample,itmaybeusedbyan embeddedSQLapplicationprogramtoinvokeastoredprocedure.Withinastored procedureitself,anotherstoredprocedurecanbecalledusingthisequivalentstatement: CALLADD_CUST('XYZCorporation',2137,30000.00,50000.00,103,'Chicago');
Stored Procedure Variables
PART VI
Inadditiontotheparameterspassedintoastoredprocedure,it’softenconvenientor necessarytodefineothervariablestoholdintermediatevaluesduringtheprocedure’s execution.Allstoredproceduredialectsprovidethiscapability.Usually,thevariablesare declaredatthebeginningoftheprocedurebody,justaftertheprocedureheaderandbefore thelistofSQLstatements.ThedatatypesofthevariablescanbeanyoftheSQLdatatypes supportedascolumndatatypesbytheDBMS. Figure20-4showsasimpleTransact-SQLstoredprocedurefragmentthatcomputes thetotaloutstandingorderamountforaspecificcustomernumber,andsetsuponeof twomessagesdependingonwhetherthetotalorderamountisunder$30,000.Notethat Transact-SQLlocalvariablenames,likeparameternames,beginwithan“@”sign.
626
Part VI:
SQL Today and Tomorrow
/* Check order total for a customer */ create proc chk_tot @c_num integer as
/* one input parameter */
/* Declare two local variables */ declare @tot_ord money, @msg_text varchar(30) begin /* Calculate total orders for customer */ select @tot_ord = sum(amount) from orders where cust = @c_num /* Load appropriate message, based on total */ if tot_ord < 30000.00 select @msg_text = "high order total" else select @msg_text = "low order total" /* Do other processing for message text */ . . . end
FIGURE 20-4 Using local variables in Transact-SQL
TheDECLAREstatementdeclaresthelocalvariablesforthisprocedure.Inthiscase,there aretwovariables:onewiththeMONEYdatatypeandoneVARCHAR. InTransact-SQL,theSELECTstatementassumestheadditionalfunctionofassigning valuestovariables.AsimpleformofthisuseofSELECTistheassignmentofthemessagetext: SELECT@MSG_TEXT="highordertotal";
Theassignmentofthetotalorderamountatthebeginningoftheprocedurebodyisa morecomplexexample,wheretheSELECTisusedbothtoassignavalueandasthe introducerofthequerythatgeneratesthevaluetobeassigned. Figure20-5showstheInformixSPLversionofthesamestoredprocedure.Thereare severaldifferencesfromtheTransact-SQLversion: • LocalvariablesaredeclaredusingtheDEFINEstatement.Thisexampleshowsonly averylimitedsubsetoftheoptionsthatareavailable. • VariablenamesareordinarySQLidentifiers;thereisnospecialfirstcharacter. • AspecializedSELECT…INTOstatementisusedwithinSPLtoassigntheresultsofa singletonSELECTstatementintoalocalvariable. • TheLETstatementprovidessimpleassignmentofvariablevalues.
Chapter 20:
Database Processing and Stored Procedural SQL
627
/* Check order total for a customer */ create procedure chk_tot (c_num integer) /* Declare two local variables */ define tot_ord numeric(16,2); define msg_text varchar(30); /* Calculate total orders for requested customer */ select sum(amount) into tot_ord from orders where cust = c_num; /* Load appropriate message, based on total */ if tot_ord < 30000.00 let msg_text = "high order total" else let msg_text = "low order total" /* Do other processing for message text */ . . . end procedure;
FIGURE 20-5 Using local variables in Informix SPL
Figure20-6showstheOraclePL/SQLversionofthesamestoredprocedure.Again, thereareseveraldifferencestonotefromtheTransact-SQLandInformixSPLexamples: • TheSELECT...INTOstatementhasthesameformastheInformixprocedure;itis usedtoselectvaluesfromasingle-rowquerydirectlyintolocalvariables. • TheassignmentstatementsusePascal-style(:=)notationinsteadofaseparateLET statement. LocalvariableswithinastoredprocedurecanbeusedasasourceofdatawithinSQL expressionsanywherethataconstantmayappear.Thecurrentvalueofthevariableisused intheexecutionofthestatement.Inaddition,localvariablesmaybedestinationsfordata derivedfromSQLexpressionsorqueries,asshownintheprecedingexamples.
Statement Blocks
PART VI
Inallbuttheverysimpleststoredprocedures,itisoftennecessarytogroupasequenceof SQLstatementstogethersothattheywillbetreatedasiftheywereasinglestatement.For example,intheIF…THEN…ELSEstructuretypicallyusedtocontroltheflowofexecution withinastoredprocedure,moststoredproceduredialectsexpectasinglestatement followingtheTHENkeyword.IfaprocedureneedstoperformasequenceofseveralSQL statementswhenthetestedconditionistrue,itmustgroupthestatementstogetherasa statementblock,andthisblockwillappearafterTHEN.
628
Part VI:
SQL Today and Tomorrow
/* Check order total for a customer */ create procedure chk_tot (c_num in number) as /* Declare two local variables */ tot_ord
number(16,2);
msg_text varchar(30); begin /* Calculate total orders for requested customer */ select sum(amount) into tot_ord from orders where cust = c_num; /* Load appropriate message, based on total */ if tot_ord < 30000.00 then msg_text := 'high order total'; else msg_text := 'low order total'; end if; /* Do other processing for message text */ . . . end;
FIGURE 20-6
Using local variables in Oracle PL/SQL
InTransact-SQL,astatementblockhasthissimplestructure: /*Transact-SQLblockofstatements*/ begin /*SequenceofSQLstatementsappearshere*/ ... end
ThesolefunctionoftheBEGIN…ENDpairistocreateastatementblock;theydonot impactthescopeoflocalvariablesorotherdatabaseobjects.TheTransact-SQLprocedure definition,conditionalexecution,andloopingconstructs,andothers,arealldesignedto operatewithsingleSQLstatements,sostatementblocksarefrequentlyusedineachofthese contextstogroupstatementstogetherasasingleunit.
Chapter 20:
Database Processing and Stored Procedural SQL
629
InInformixSPL,astatementblockincludesnotonlyastatementsequence,butalsomay optionallydeclarelocalvariablesforusewithintheblockandexceptionhandlerstohandle errorsthatmayoccurwithintheblock.HereisthestructureofanInformixSQLstatement block: /*InformixSPLblockofstatements*/ /*Declarationofanylocalvariables*/ define... /*Declarehandlingforexceptions*/ onexception... /*DefinethesequenceofSQLstatements*/ begin... end
Thevariabledeclarationsectionisoptional;wehavealreadyseenanexampleofitinthe InformixstoredprocedurebodyinFigure20-5.Theexception-handlingsectionisalso optional;itsroleisdescribedlaterinthe“HandlingErrorConditions”section.TheBEGIN… ENDsequenceperformsthesamefunctionasitdoesforTransact-SQL.Informixalsoallows asinglestatementtoappearinthispositioniftheblockconsistsofjusttheothertwo componentsandasingleSQLorSPLstatement. TheInformixSQLstructuresdon’trequiretheuseofstatementblocksasoftenasthe Transact-SQLstructures.IntheInformixdialect,theloopingconditionalexecution statementseachincludeanexplicittermination(IF…ENDIF,WHILE…ENDWHILE,FOR… ENDFOR).Withinthestructure,asingleSQLstatementorasequenceofstatements(each endingwithasemicolon)mayappear.Asaresult,anexplicitblockstructureisnotalways neededsimplytogrouptogetherasequenceofSQLstatements. TheOraclePL/SQLblockstructurehasthesamecapabilitiesastheInformixstructure. Itoffersthecapabilitytodeclarevariablesandexceptionconditions,usingthisformat: /*OraclePL/SQLstatementblock*/ /*Declarationofanylocalvariables*/ declare... /*Specifythesequenceofstatements*/ begin... /*Declarehandlingforexceptions*/ exception... end;
PART VI
Allthreesectionsoftheblockstructureareoptional.It’scommontoseethestructure usedwithonlytheBEGIN…ENDsequencetodefineastatementsequence,orwitha DECLARE…BEGIN…ENDsequencetodeclarevariablesandasequenceofstatements.As withInformix,theOraclestructuresthatspecifyconditionalexecutionandloopinghavea self-definingend-of-statementmarker,sosequencesofstatementswithinthesestructures donotnecessarilyneedanexplicitBEGIN…ENDstatementblockstructure.
630
Part VI:
SQL Today and Tomorrow
Functions Inadditiontostoredprocedures,mostSPLdialectssupportastoredfunctioncapability.The distinctionisthatafunctionreturnsasinglething(suchasadatavalue,anobject,oran XMLdocument)eachtimeitisinvoked,whileastoredprocedurecanreturnmanythingsor nothingatall.SupportforreturnedvaluesvariesbySPLdialect.Functionsarecommonly usedascolumnexpressionsinSELECTstatements,andthusareinvokedonceperrowin theresultset,allowingthefunctiontoperformcalculations,dataconversion,andother processestoproducethereturnedvalueforthecolumn.Followingisasimpleexampleofa storedfunction.Assumeyouwanttodefineastoredprocedurethat,givenacustomer number,calculatesthetotalcurrentorderamountforthatcustomer.IfyoudefinetheSQL procedureasafunction,thetotalamountcanbereturnedasitsvalue. Figure20-7showsanOraclefunctionthatcalculatesthetotalamountofcurrentorders foracustomer,giventhecustomernumber.NotetheRETURNclauseintheprocedure definition,whichtellstheDBMSthedatatypeofthevaluebeingreturned.InmostDBMS products,ifyouenterafunctioncallviatheinteractiveSQLcapability,thefunctionvalueis displayedinresponse.Withinastoredprocedure,youcancallastoredfunctionanduseits returnvalueincalculationsorstoreitinavariable. ManySPLdialectsalsoallowyoutouseafunctionasauser-definedfunctionwithin SQLvalueexpressions.ThisistrueoftheOraclePL/SQLdialect,sothisuseofthefunction definedinFigure20-7withinasearchconditionislegal. SELECTCOMPANY,NAME FROMCUSTOMERS,SALESREPS WHERECUST_REP=EMPL_NUM ANDGET_TOT_ORDS(CUST_NUM)>10000.00;
/* Return total order amount for a customer */ create function get_tot_ords(c_num in number) return number as /* Declare one local variable to hold the total */ tot_ord number(16,2); begin /* Simple single-row query to get total */ select sum(amount) into tot_ord from orders where cust = c_num; /* return the retrieved value as fcn value */ return tot_ord; end;
FIGURE 20-7 An Oracle PL/SQL function
Chapter 20:
Database Processing and Stored Procedural SQL
631
AstheDBMSevaluatesthesearchconditionforeachrowofprospectivequeryresults,it usesthecustomernumberofthecurrentcandidaterowasanargumenttotheGET_TOT_ ORDSfunctionandcheckstoseeifitexceedsthe$10,000threshold.Thissamequerycould beexpressedasagroupedquery,withtheORDERStablealsoincludedintheFROMclause, andtheresultsgroupedbycustomerandsalesperson.Inmanyimplementations,theDBMS carriesoutthegroupedquerymoreefficientlythantheprecedingone,whichprobably forcestheDBMStoprocesstheorderstableonceforeachcustomer. Figure20-8showstheInformixSPLdefinitionforthesamestoredfunctionshownin Figure20-7.Exceptforstylisticvariations,itdiffersverylittlefromtheOracleversion. TheTransact-SQLdialectusedinMicrosoftSQLServerandSybaseAdaptiveServer Enterprise(ASE)hasastored(user-defined)functioncapabilitysimilartotheoneillustrated inFigures20-7and20-8.
Returning Values via Parameters Functionsprovideonlytheabilitytoreturnasinglethingfromastoredroutine.Several storedproceduredialectsprovideamethodforreturningmorethanonevalue(orother thing),bypassingthevaluesbacktothecallingroutinethroughoutputparameters.The outputparametersarelistedinthestoredprocedure’sparameterlist,justliketheinput parametersseeninthepreviousexamples.However,insteadofbeingusedtopassdata valuesintothestoredprocedurewhenitiscalled,theoutputparametersareusedtopass databackoutofthestoredproceduretothecallingprocedure. Figure20-9showsaPL/SQLstoredproceduretoretrievethenameofacustomer,his orhersalesperson,andthesalesofficetowhichthecustomerisassigned,givenasupplied customernumber.Theprocedurehasfourparameters.Thefirstone,CNUM,isaninput parameterandsuppliestherequestedcustomernumber.Theotherthreeparametersare outputparameters,usedtopasstheretrieveddatavaluesbacktothecallingprocedure.
/* Return total order amount for a customer */ create function get_tot_ords(c_num in integer) returning numeric(16,2) /* Declare one local variable to hold the total */ define tot_ord numeric(16,2); begin /* Simple single-row query to get total */ select sum(amount) into tot_ord from orders where cust = c_num;
return tot_ord; end function;
FIGURE 20-8 An Informix SPL function
PART VI
/* Return the retrieved value as fcn value */
632
Part VI:
SQL Today and Tomorrow
/* Get customer name, salesrep, and office */ create procedure get_cust_info(c_num
in
number,
c_name out varchar, r_name out varchar, c_offc out varchar) as begin /* Simple single-row query to get info */ select company, name, city into c_name, r_name, c_offc from customers, salesreps, offices where cust_num = c_num and empl_num = cust_rep and office = rep_office; end;
FIGURE 20-9 PL/SQL stored procedure with output parameters
Inthissimpleexample,theSELECT...INTOformofthequeryplacesthereturned variablesdirectlyintotheoutputparameters.Inamorecomplexstoredprocedure,the returnedvaluesmightbecalculatedandplacedintotheoutputparameterswithaPL/SQL assignmentstatement. Whenastoredprocedurewithoutputparametersiscalled,thevaluepassedforeach outputparametermustbeanacceptabletargetthatcanreceivethereturneddatavalue.The targetmaybealocalvariable,forexample,oraparameterofahigher-levelprocedurethat iscallingalower-levelproceduretodosomeworkforit.HereisanOraclePL/SQL anonymous(unnamed)blockthatmakesanappropriatecalltotheGET_CUST_INFO procedureinFigure20-9: /*Getthecustomerinfoforcustomer2111*/ declarethe_namevarchar(20); the_repvarchar(15); the_cityvarchar(15); executeget_cust_info(2111,the_name,the_rep,the_city);
Ofcourse,itwouldbeunusualtocallthisprocedurewithaliteralcustomernumber,but it’sperfectlylegalsincethatisaninputparameter.Theremainingthreeparametershave acceptabledataassignmenttargets(inthiscase,theyarePL/SQLvariables)passedtothemso thattheycanreceivethereturnedvalues.Thefollowingcalltothesameprocedureisillegal becausethesecondparameterisanoutputparameterandthuscannotreceivealiteralvalue: /*Getthecustomerinfoforcustomer2111*/ executeget_cust_info(2111,'XYZCo',the_rep,the_city)
Inadditiontoinputandoutputparameters,Oracleallowsyoutospecifyprocedureparameters thatarebothinputandoutput(INOUT)parameters.Theymustobeythesamepreviously citedrestrictionsforoutputparameters,butinaddition,theirvaluesareusedasinputby theprocedure.
Chapter 20:
Database Processing and Stored Procedural SQL
633
/* Get customer name, salesrep, and office */ create procedure get_cust_info(@c_num
integer, @c_name varchar(20) out, @r_name varchar(15) out, @c_offc varchar(15) out)
as begin /* Simple single-row query to get info */ select @c_name = company, @r_name = name, @c_offc = city from customers, salesreps, offices where cust_num = @c_num and empl_num = cust_rep and office = rep_office; end
FIGURE 20-10 Transact-SQL stored procedure with output parameters
Figure20-10showsaversionoftheGET_CUST_INFOproceduredefinedintheTransactSQLdialect.Thewayinwhichtheoutputparametersareidentifiedintheprocedureheader differsslightlyfromtheOracleversion,variablenamesbeginwiththe“@”sign,andthe single-rowSELECTstatementhasadifferentform.Otherwise,thestructureofthe procedureanditsoperationareidenticaltotheOracleexample. WhenthisprocedureiscalledfromanotherTransact-SQLprocedure,thefactthatthe second,third,andfourthparametersareoutputparametersmustbeindicatedinthecallto theprocedure,aswellasinitsdefinition.HereistheTransact-SQLsyntaxforcallingthe procedureinFigure20-10: /*Getthecustomerinfoforcustomer2111*/ declarethe_namevarchar(20); declarethe_repvarchar(15); declarethe_cityvarchar(15); execget_cust_info@c_num=2111, @c_name=the_nameoutput, @r_name=the_repoutput, @c_offc=the_cityoutput;
PART VI
Figure20-11showstheInformixSPLversionofthesamestoredprocedureexample. Informixtakesadifferentapproachtohandlingmultiplereturnvalues.Insteadofoutput parameters,Informixextendsthedefinitionofastoredfunctiontoallowmultiplereturn values.Thus,theGET_CUST_INFOprocedurebecomesafunctionfortheInformixdialect. ThemultiplereturnvaluesarespecifiedintheRETURNINGclauseoftheprocedureheader, andtheyareactuallyreturnedbytheRETURNstatement.
634
Part VI:
SQL Today and Tomorrow
FIGURE 20-11 Informix stored function with multiple return values
/* Get customer name, salesrep, and office */ create function get_cust_info(c_num integer) returning varchar(20), varchar(15), varchar(15) define c_name varchar(20); define r_name varchar(15); define r_name varchar(15); /* Simple single-row query to get info */ select company, name, city into cname, r_name, c_offc from customers, salesreps, offices where cust_num = c_num and empl_num = cust_rep and office = rep_office; /* Return the three values */ return cname, r_name, c_offc; end procedure;
TheInformixCALLstatementthatinvokesthestoredfunctionusesaspecial RETURNINGclausetoreceivethereturnedvalues: /*Getthecustomerinfoforcustomer2111*/ definethe_namevarchar(20); definethe_repvarchar(15); definethe_cityvarchar(15); callget_cust_info(2111) returningthe_name,the_rep,the_city;
AsintheTransact-SQLdialect,InformixalsoallowsaversionoftheCALLstatement thatpassestheparametersbyname: callget_cust_info(c_num=2111) returningthe_name,the_rep,the_city;
Conditional Execution OneofthemostbasicfeaturesofstoredproceduresisanIF…THEN…ELSEconstructfor decisionmakingwithintheprocedure.LookbackattheoriginalADD_CUSTprocedure definedinFigure20-1foraddinganewcustomer.Supposethattherulesforaddingnew customersaremodifiedsothatthereisacapontheamountbywhichasalesperson’squota shouldbeincreasedforanewcustomer.Ifthecustomer’santicipatedfirst-yearordersare $20,000orless,thatamountshouldbeaddedtothequota,butiftheyaremorethan$20,000, thequotashouldbeincreasedbyonly$20,000.Figure20-12showsamodifiedprocedure thatimplementsthisnewpolicy.TheIF…THEN…ELSElogicoperatesexactlyasitdoesin anyconventionalprogramminglanguage.
Chapter 20:
Database Processing and Stored Procedural SQL
635
/* Add a customer procedure */ create procedure add_cust ( c_name
in varchar2,
/* input customer name */
c_num
in number,
/* input customer number */
cred_lim
in number,
/* input credit limit */
tgt_sls
in number,
/* input target sales */
c_rep
in number,
/* input salesrep empl # */
c_offc
in varchar2)
/* input office city */
as begin /* Insert new row of CUSTOMERS table */ insert into customers (cust_num, company, cust_rep, credit_limit) values (c_num, c_name, c_rep, cred_lim); if tgt_sales