OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0 047)
User Manual: Pdf
Open the PDF directly: View PDF .
Page Count: 794
Download | |
Open PDF In Browser | View PDF |
® OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) This page intentionally left blank ® OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Steve O’Hearn McGraw-Hill is an independent entity from Oracle Corporation. This publication and CD may be used in assisting students to prepare for the Oracle Database SQL Expert exam. Neither Oracle Corporation nor The McGraw-Hill Companies warrant that use of this publication will ensure passing the relevant exam. New York Chicago San Francisco Lisbon London Madrid Mexico City Milan New Delhi San Juan Seoul Singapore Sydney Toronto Copyright © 2010 by The McGraw-Hill Companies, Inc. 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-161422-1 MHID: 0-07-161422-2 The material in this eBook also appears in the print version of this title: ISBN: 978-0-07-161421-4, MHID: 0-07-161421-4. 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 bulksales@mcgraw-hill.com. Information has been obtained by Publisher from sources believed to be reliable. However, because of the possibility of human or mechanical error by our sources, Publisher, or others, Publisher does not guarantee to the accuracy, adequacy, or completeness of any information included in this work and is not responsible for any errors or omissions or the results obtained from the use of such information. Oracle Corporation does not make any representations or warranties as to the accuracy, adequacy, or completeness of any information contained in this Work, and is not responsible for any errors or omissions. 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. Disclaimer: This eBook does not include the ancillary media that was packaged with the original printed version of the book. FREE SUBSCRIPTION TO oracle magazine GET YOUR oracle magazine is essential gear for today’s information technology professionals. Stay informed and increase your productivity with every issue of oracle magazine. Inside each free bimonthly issue you’ll get: • Up-to-date information on Oracle Database, Oracle Application Server, Web development, enterprise grid computing, database technology, and business trends • Third-party news and announcements • Technical articles on Oracle and partner products, technologies, and operating environments • Development and administration tips • Real-world customer stories If there are other Oracle users at your location who would like to receive their own subscription to Oracle Magazine, please photocopy this form and pass it along. Three easy ways to subscribe: 1 Web Visit our Web site at oracle.com/oraclemagazine You’ll find a subscription form there, plus much more 2 Fax Complete the questionnaire on the back of this card and fax the questionnaire side only to +1.847.763.9638 3 Mail Complete the questionnaire on the back of this card and mail it to P.O. Box 1263, Skokie, IL 60076-8263 Copyright © 2008, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Want your own FREE subscription? To receive a free subscription to Oracle Magazine, you must fill out the entire card, sign it, and date it (incomplete cards cannot be processed or acknowledged). You can also fax your application to +1.847.763.9638. Or subscribe at our Web site at oracle.com/oraclemagazine No. Yes, please send me a FREE subscription Oracle Magazine. From time to time, Oracle Publishing allows our partners exclusive access to our e-mail addresses for special promotions and announcements. To be included in this program, please check this circle. If you do not wish to be included, you will only receive notices about your subscription via e-mail. Oracle Publishing allows sharing of our postal mailing list with selected third parties. If you prefer your mailing address not to be included in this program, please check this circle. If at any time you would like to be removed from either mailing list, please contact Customer Service at +1.847.763.9635 or send an e-mail to oracle@halldata.com. If you opt in to the sharing of information, Oracle may also provide you with e-mail related to Oracle products, services, and events. If you want to completely unsubscribe from any e-mail communication from Oracle, please send an e-mail to: unsubscribe@oracle-mail.com with the following in the subject line: REMOVE [your e-mail address]. For complete information on Oracle Publishing’s privacy practices, please visit oracle.com/html/privacy/html x signature (required) date name title company e-mail address street/p.o. box city/state/zip or postal code telephone country fax Would you like to receive your free subscription in digital format instead of print if it becomes available? Yes No YOU MUST ANSWER ALL 10 QUESTIONS BELOW. 1 08014004 2 WHAT IS THE PRIMARY BUSINESS ACTIVITY OF YOUR FIRM AT THIS LOCATION? (check one only) o o o o o o o 01 02 03 04 05 06 07 o o o o o o o o o o o o o o o o o o 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 98 Aerospace and Defense Manufacturing Application Service Provider Automotive Manufacturing Chemicals Media and Entertainment Construction/Engineering Consumer Sector/Consumer Packaged Goods Education Financial Services/Insurance Health Care High Technology Manufacturing, OEM Industrial Manufacturing Independent Software Vendor Life Sciences (biotech, pharmaceuticals) Natural Resources Oil and Gas Professional Services Public Sector (government) Research Retail/Wholesale/Distribution Systems Integrator, VAR/VAD Telecommunications Travel and Transportation Utilities (electric, gas, sanitation, water) Other Business and Services _________ 3 o o o o o o o o o o o o o o o o o 99 4 99 5 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 98 o Digital Equipment Corp UNIX/VAX/VMS HP UNIX IBM AIX IBM UNIX Linux (Red Hat) Linux (SUSE) Linux (Oracle Enterprise) Linux (other) Macintosh MVS Netware Network Computing SCO UNIX Sun Solaris/SunOS Windows Other UNIX Other None of the Above 01 02 03 04 05 06 07 o Hardware Business Applications (ERP, CRM, etc.) Application Development Tools Database Products Internet or Intranet Products Other Software Middleware Products None of the Above 6 HARDWARE o 15 Macintosh o 16 Mainframe o 17 Massively Parallel Processing o o o o o o SERVICES o 24 Consulting o 25 Education/Training o 26 Maintenance o 27 Online Database o 28 Support o 29 Technology-Based Training o 30 Other 99 o None of the Above o o 7 More than 25,000 Employees 10,001 to 25,000 Employees 5,001 to 10,000 Employees 1,001 to 5,000 Employees 101 to 1,000 Employees Fewer than 100 Employees 01 02 03 04 05 06 Less than $10,000 $10,000 to $49,999 $50,000 to $99,999 $100,000 to $499,999 $500,000 to $999,999 $1,000,000 and Over WHAT IS YOUR COMPANY’S YEARLY SALES REVENUE? (check one only) o o o o o 9 01 02 03 04 05 06 DURING THE NEXT 12 MONTHS, HOW MUCH DO YOU ANTICIPATE YOUR ORGANIZATION WILL SPEND ON COMPUTER HARDWARE, SOFTWARE, PERIPHERALS, AND SERVICES FOR YOUR LOCATION? (check one only) o o o o o o 8 18 19 20 21 22 23 WHAT IS YOUR COMPANY’S SIZE? (check one only) o o o o o o IN YOUR JOB, DO YOU USE OR PLAN TO PURCHASE ANY OF THE FOLLOWING PRODUCTS? (check all that apply) SOFTWARE o 01 CAD/CAE/CAM o 02 Collaboration Software o 03 Communications o 04 Database Management o 05 File Management o 06 Finance o 07 Java o 08 Multimedia Authoring o 09 Networking o 10 Programming o 11 Project Management o 12 Scientific and Engineering o 13 Systems Management o 14 Workflow Minicomputer Intel x86(32) Intel x86(64) Network Computer Symmetric Multiprocessing Workstation Services o o o o o o DO YOU EVALUATE, SPECIFY, RECOMMEND, OR AUTHORIZE THE PURCHASE OF ANY OF THE FOLLOWING? (check all that apply) o o o o o o o WHICH OF THE FOLLOWING BEST DESCRIBES YOUR PRIMARY JOB FUNCTION? (check one only) CORPORATE MANAGEMENT/STAFF o 01 Executive Management (President, Chair, CEO, CFO, Owner, Partner, Principal) o 02 Finance/Administrative Management (VP/Director/ Manager/Controller, Purchasing, Administration) o 03 Sales/Marketing Management (VP/Director/Manager) o 04 Computer Systems/Operations Management (CIO/VP/Director/Manager MIS/IS/IT, Ops) IS/IT STAFF o 05 Application Development/Programming Management o 06 Application Development/Programming Staff o 07 Consulting o 08 DBA/Systems Administrator o 09 Education/Training o 10 Technical Support Director/Manager o 11 Other Technical Management/Staff o 98 Other WHAT IS YOUR CURRENT PRIMARY OPERATING PLATFORM (check all that apply) 01 02 03 04 05 $500, 000, 000 and above $100, 000, 000 to $500, 000, 000 $50, 000, 000 to $100, 000, 000 $5, 000, 000 to $50, 000, 000 $1, 000, 000 to $5, 000, 000 WHAT LANGUAGES AND FRAMEWORKS DO YOU USE? (check all that apply) o o o o 01 02 03 04 Ajax C C++ C# o o o o 13 14 15 16 Python Ruby/Rails Spring Struts 10 05 Hibernate 06 J++/J# 07 Java 08 JSP 09 .NET 10 Perl 11 PHP 12 PL/SQL o 17 SQL o 18 Visual Basic o 98 Other WHAT ORACLE PRODUCTS ARE IN USE AT YOUR SITE? (check all that apply) ORACLE DATABASE o 01 Oracle Database 11g o 02 Oracle Database 10 g o 03 Oracle9 i Database o 04 Oracle Embedded Database (Oracle Lite, Times Ten, Berkeley DB) o 05 Other Oracle Database Release ORACLE FUSION MIDDLEWARE o 06 Oracle Application Server o 07 Oracle Portal o 08 Oracle Enterprise Manager o 09 Oracle BPEL Process Manager o 10 Oracle Identity Management o 11 Oracle SOA Suite o 12 Oracle Data Hubs ORACLE DEVELOPMENT TOOLS o 13 Oracle JDeveloper o 14 Oracle Forms o 15 Oracle Reports o 16 Oracle Designer o 17 Oracle Discoverer o 18 Oracle BI Beans o 19 Oracle Warehouse Builder o 20 Oracle WebCenter o 21 Oracle Application Express ORACLE APPLICATIONS o 22 Oracle E-Business Suite o 23 PeopleSoft Enterprise o 24 JD Edwards EnterpriseOne o 25 JD Edwards World o 26 Oracle Fusion o 27 Hyperion o 28 Siebel CRM ORACLE SERVICES o 28 Oracle E-Business Suite On Demand o 29 Oracle Technology On Demand o 30 Siebel CRM On Demand o 31 Oracle Consulting o 32 Oracle Education o 33 Oracle Support o 98 Other 99 o None of the Above To my father Don, an outstanding professional and highly accomplished engineer, who always believed in me, and taught me the value of hard work and dedication. This page intentionally left blank About the Author Steve O’Hearn is a veteran technology consultant with over 20 years of experience in the design, development, and administration of various Oracle systems for such clients as the U.S. Defense Department, NASA HQ, the FAA, the World Bank, and many others. He first became an Oracle Certified Professional (OCP) in 2001 and is a certified Oracle Database SQL Expert. He has a degree in Business Administration with a specialization in Information Processing from The George Washington University, and his postgraduate work includes the completion of the Future of e-Government Executive Education training at Harvard University’s Kennedy School of Government in 2003. He is a member of MENSA. Mr. O’Hearn has been published in a variety of publications, including the Harvard Business Review, and contributed to Oracle Web Applications 101 from Oracle Press and Oracle8 Server Unleashed. He authored the critically acclaimed OCP Developer: PL/SQL Program Units Exam Guide from Oracle Press. Mr. O’Hearn is an officially recognized subject matter expert on the topic of database and information technology by the National Press Club, where he is an active member, and where he has chaired or vice-chaired the New Media, High Tech, Publications, and Online Journalism Committees, created the Club’s original social network and blog, and won several awards. He has been Vice President and conference coordinator for the Mid-Atlantic Association of Oracle Professionals, where he was also the first webmaster in 1997. Mr. O’Hearn provides Oracle technology training and tutoring online. He invites any and all inquiries at soh@corbinian.com. About the Technical Editor Alistair Grieve started his career as a Tandem NonStop COBOL programmer. Since then he has worked for more than 20 years as a software developer and database administrator, primarily in the financial services sector, in the UK, the U.S.A., and New Zealand. He is also a freelance technical editor. Mr. Grieve is an Engineering Science graduate of the University of Oxford. He is a Sun Certified Java Programmer (SCJP) and Web Component Developer (SCWCD), as well as an Oracle Certified Professional (OCP) database administrator. He can be contacted at techedit@gmx.com. vii viii OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) About LearnKey LearnKey provides self-paced learning content and multimedia delivery solutions to enhance personal skills and business productivity. LearnKey claims the largest library of rich streaming-media training content that engages learners in dynamic mediarich instruction complete with video clips, audio, full motion graphics, and animated illustrations. LearnKey can be found on the Web at www.LearnKey.com. Contents at A Glance 1 Introduction to SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 Using DDL Statements to Create and Manage Tables . . . . . . . . . . . 45 3 Manipulating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4 Retrieving Data Using the SQL S ELECT Statement . . . . . . . . . . . 137 5 Restricting and Sorting Data . . . . . . . . . . . . . . . . . . . . . . . . . 169 6 Using Single-Row Functions to C ustomize Output . . . . . . . . . . . . 209 7 Reporting A ggregated Data Using the Group Functions . . . . . . . . . . 275 8 Displaying Data from Multiple Tables . . . . . . . . . . . . . . . . . . . . 311 9 Retrieving Data Using Subqueries . . . . . . . . . . . . . . . . . . . . . . 345 10 Creating Other Schema Objects . . . . . . . . . . . . . . . . . . . . . . . 381 11 Managing Schema Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 423 12 Using the Set O perators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 13 Generating Reports by Grouping Related Data . . . . . . . . . . . . . . . . 511 14 Managing O bjects with Data D ictionary Views . . . . . . . . . . . . . . . 533 15 Manipulating Large Data Sets . . . . . . . . . . . . . . . . . . . . . . . . 559 16 Hierarchical R etrieval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 17 Regular Expression Support . . . . . . . . . . . . . . . . . . . . . . . . . . 639 18 Controlling User Access . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 A About the CD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729 ix This page intentionally left blank Contents 1 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii xxv xxix Introduction to SQL .. . . . . . . . . . . . . . . . . . . . . . . . . . . 1 The Exam: An Overview .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . “SQL Fundamentals I” Versus “SQL Expert” . . . . . . . . . . . . . . What to Expect .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Define and Understand the Basics of the RDBMS . . . . . . . . . . . . . . . . Relational Databases and Dr. E.F. Codd .. . . . . . . . . . . . . . . . . Database Normalization .. . . . . . . . . . . . . . . . . . . . . . . . . . . . Database Design Considerations .. . . . . . . . . . . . . . . . . . . . . . Define and Understand the Basics of SQL . . . . . . . . . . . . . . . . . . . . . . Understand the Oracle RDBMS and Oracle SQL .. . . . . . . . . . . . . . . . Oracle Is the Market Leader .. . . . . . . . . . . . . . . . . . . . . . . . . Certification: Oracle SQL Versus ANSI SQL . . . . . . . . . . . . . Certification: Oracle SQL Versus Oracle SQL*Plus .. . . . . . . . Oracle’s Tools for Working with SQL . . . . . . . . . . . . . . . . . . . Oracle’s Documentation for SQL . . . . . . . . . . . . . . . . . . . . . . Understand the Unique Role of SQL in Modern Software Systems . . . . SQL Is a 4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . SQL: Gateway to the RDBMS for All Other Languages .. . . . . Syntax Isn’t Enough .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Confirm Appropriate Materials for Study .. . . . . . . . . . . . . . . . . . . . . . Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Documentation .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 4 10 13 14 16 17 18 21 21 23 23 23 25 26 26 28 30 31 32 32 34 35 38 42 xi xii OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) 2 3 Using DDL Statements to Create and Manage Tables .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Categorize the Main Database Objects .. . . . . . . . . . . . . . . . . . . . . . . . What Are Database Objects? . . . . . . . . . . . . . . . . . . . . . . . . . Schemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create a Simple Table .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Naming a Table or Other Object . . . . . . . . . . . . . . . . . . . . . . The SQL Statement CREATE TABLE .. . . . . . . . . . . . . . . . . Review the Table Structure .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . List the Data Types That Are Available for Columns . . . . . . . . . . . . . . Character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Numeric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Date .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Large Objects (LOBs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Explain How Constraints Are Created at the Time of Table Creation . . . Creating CONSTRAINTS in the CREATE TABLE Statement .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Types of CONSTRAINTS . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 46 48 50 51 58 59 60 61 62 63 65 67 67 72 81 82 84 89 Manipulating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Describe Each Data Manipulation Language (DML) Statement . . . . . . SQL Statement Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . DML Statement Descriptions .. . . . . . . . . . . . . . . . . . . . . . . . Insert Rows into a Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Default Column List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Enumerated Column List .. . . . . . . . . . . . . . . . . . . . . . . . . . . Update Rows in a Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expressions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The WHERE Clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Delete Rows from a Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Control Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . COMMIT .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ROLLBACK .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 94 98 98 99 103 106 108 108 110 111 112 112 116 4 Contents xiii SAVEPOINT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ROLLBACK Revisited . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 121 122 125 128 133 Retrieving Data Using the SQL SELECT Statement . . . 137 Execute a Basic SELECT Statement . . . . . . . . . . . . . . . . . . . . . . . . . . The SELECT Statement—An Example . . . . . . . . . . . . . . . . . SELECT: Minimum Requirements . . . . . . . . . . . . . . . . . . . . . List the Capabilities of SQL SELECT Statements . . . . . . . . . . . . . . . . The SELECT Statement—An Overview . . . . . . . . . . . . . . . . Expressions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Additional SELECT Statement Clauses . . . . . . . . . . . . . . . . . The Capabilities of SELECT . . . . . . . . . . . . . . . . . . . . . . . . . Describe How Schema Objects Work . . . . . . . . . . . . . . . . . . . . . . . . . Tables .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Indexes .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sequences .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Synonyms .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 138 139 140 141 142 146 151 152 154 155 155 155 156 156 157 157 159 161 166 Restricting and Sorting Data .. . . . . . . . . . . . . . . . . . . . 169 Limit the Rows That Are Retrieved by a Query . . . . . . . . . . . . . . . . . . The WHERE Clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Boolean Logic .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Additional WHERE Clause Features .. . . . . . . . . . . . . . . . . . . Additional Concepts .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sort the Rows That Are Retrieved by a Query . . . . . . . . . . . . . . . . . . . Reference by Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expressions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 170 177 181 184 184 185 189 xiv OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Reference by Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Combinations .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ORDER BY and NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 192 193 194 194 196 198 204 Using Single-Row Functions to C ustomize Output . . . 209 Describe Various Types of Functions That Are Available in SQL .. . . . . Character Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Number Functions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Date Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Other Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Character, Number, and Date Functions in SELECT Statements . . . The DUAL Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Character Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mathematical Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . Working with Dates .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Other Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nesting Functions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Describe the Use of Conversion Functions .. . . . . . . . . . . . . . . . . . . . . Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Automatic Datatype Conversions .. . . . . . . . . . . . . . . . . . . . . Manage Data in Different Time Zones—Use Various Datetime Functions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Database Time Versus Session Time . . . . . . . . . . . . . . . . . . . . Coordinated Universal Time (UTC) . . . . . . . . . . . . . . . . . . . Time Zone Datatypes .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Time Zone Functions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Time Zone Conversion Functions .. . . . . . . . . . . . . . . . . . . . . AT TIME ZONE, AT LOCAL .. . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 212 212 212 213 213 214 214 215 223 225 230 234 235 236 246 247 249 250 250 253 257 261 263 265 267 271 Contents 7 Reporting Aggregated Data Using the Group Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 Identify the Available Group Functions .. . . . . . . . . . . . . . . . . . . . . . . Describe the Use of Group Functions .. . . . . . . . . . . . . . . . . . . . . . . . . COUNT .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . SUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MIN, MAX .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . AVG .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MEDIAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . RANK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . FIRST, LAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . GROUPING .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Others . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Group Data by Using the GROUP BY Clause . . . . . . . . . . . . . . . . . . . Multiple Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ORDER BY Revisited . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nesting Functions .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Include or Exclude Grouped Rows by Using the HAVING Clause .. . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 xv 276 277 277 280 280 281 282 283 284 284 285 285 291 292 292 296 298 299 301 307 Displaying Data from Multiple Tables . . . . . . . . . . . . . . 311 Write SELECT Statements to Access Data from More Than One Table Using Equijoins and Non-Equijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins .. . . . . . . . . . . . KEY Relationships .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Types of Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inner Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Outer Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using Table Aliases .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NATURAL Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . USING .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Multitable Joins .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Non-Equijoins .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Join a Table to Itself by Using a Self-Join .. . . . . . . . . . . . . . . . . . . . . . Self-Referencing Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . Self-Join Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 313 315 316 318 321 323 324 325 326 328 329 329 xvi OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Generate a Cartesian Product of All Rows from Two or More Tables . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 330 332 334 336 342 Retrieving Data Using Subqueries .. . . . . . . . . . . . . . . . 345 Define Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Describe the Types of Problems That Subqueries Can Solve . . . . . . . . . List the Types of Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Write Single-Row and Multiple-Row Subqueries . . . . . . . . . . . . . . . . . Single-Row Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Multiple-Row Subqueries .. . . . . . . . . . . . . . . . . . . . . . . . . . . Write a Multiple-Column Subquery . . . . . . . . . . . . . . . . . . . . . . . . . . Use Scalar Subqueries in SQL .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solve Problems with Correlated Subqueries .. . . . . . . . . . . . . . . . . . . . Update and Delete Rows Using Correlated Subqueries . . . . . . . . . . . . . UPDATE with a Correlated Subquery .. . . . . . . . . . . . . . . . . . DELETE with a Correlated Subquery . . . . . . . . . . . . . . . . . . . Use the EXISTS and NOT EXISTS Operators .. . . . . . . . . . . . . . . . . . Use the WITH Clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 347 348 349 350 354 356 358 360 362 362 364 365 366 367 369 372 378 10 Creating Other Schema Objects .. . . . . . . . . . . . . . . . . 381 Create and Use Simple and Complex Views .. . . . . . . . . . . . . . . . . . . . Creating Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Updatable Views .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inline Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Retrieving Data .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ALTER VIEW .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create, Maintain, and Use Sequences . . . . . . . . . . . . . . . . . . . . . . . . . Creating Sequences .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using Sequences .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create and Maintain Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implicit Index Creation .. . . . . . . . . . . . . . . . . . . . . . . . . . . . Single Column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 383 386 389 391 391 392 392 394 397 398 399 Contents Composite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Unique .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dropping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create Private and Public Synonyms .. . . . . . . . . . . . . . . . . . . . . . . . . Private . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Public .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Object Privileges .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Name Priority . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Replacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dropping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii 402 403 404 404 405 406 406 408 409 410 410 412 414 420 11 Managing Schema Objects .. . . . . . . . . . . . . . . . . . . . . . 423 Add and Modify Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Adding Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modifying Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Renaming Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Drop Columns and Set Column UNUSED . . . . . . . . . . . . . . . . . . . . . Dropping Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . UNUSED .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Add Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using ALTER TABLE to Add Constraints . . . . . . . . . . . . . . . Modifying Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Removing Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Disabling and Enabling Constraints . . . . . . . . . . . . . . . . . . . . DROP TABLE and CASCADE CONSTRAINTS . . . . . . . . . DELETE and ON DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . DEFERRABLE and DEFERRED .. . . . . . . . . . . . . . . . . . . . . . Renaming Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create Indexes Using the CREATE TABLE Statement .. . . . . . . . . . . . Automatic Index Creation .. . . . . . . . . . . . . . . . . . . . . . . . . . USING INDEX .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create Function-Based Indexes .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Perform FLASHBACK Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recover Dropped Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 424 427 430 431 431 434 436 436 440 440 442 449 450 451 452 454 454 455 457 458 458 459 xviii OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Recovering Tables in Time .. . . . . . . . . . . . . . . . . . . . . . . . . . Marking Time .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create and Use External Tables .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Benefits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Creating External Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 465 468 469 469 474 476 478 484 12 Using the Set Operators . . . . . . . . . . . . . . . . . . . . . . . . 487 Describe Set Operators .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use a Set Operator to Combine Multiple Queries into a Single Query . . . UNION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . UNION ALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . INTERSECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MINUS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Combinations .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Control the Order of Rows Returned .. . . . . . . . . . . . . . . . . . . . . . . . . ORDER BY—By Position . . . . . . . . . . . . . . . . . . . . . . . . . . . ORDER BY—By Reference . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 490 490 494 494 495 496 497 497 499 500 501 502 508 13 Generating Reports by G rouping Related Data . . . . . . . 511 Use the ROLLUP Operation to Produce S ubtotal Values . . . . . . . . . . . Use the CUBE Operation to Produce C rosstabulation Values . . . . . . . . Use the GROUPING Function to Identify the Row Values Created by ROLLUP or CUBE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use GROUPING SETS to Produce a Single R esult Set . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512 515 517 519 522 523 525 530 Contents xix 14 Managing Objects with Data D ictionary Views .. . . . . . 533 Use the Data Dictionary Views to Research Data on Your Objects .. . . . Structure .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dynamic Performance Views . . . . . . . . . . . . . . . . . . . . . . . . . Reading Comments .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Adding Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Query Various Data Dictionary Views . . . . . . . . . . . . . . . . . . . . . . . . . DICTIONARY .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Identifying a User’s Owned Objects . . . . . . . . . . . . . . . . . . . . Inspecting Tables and Columns . . . . . . . . . . . . . . . . . . . . . . . Compiling Views .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Checking Privileges .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inspecting Constraints .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Finding Columns .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 535 538 540 541 542 542 543 545 546 547 547 549 549 551 553 556 15 Manipulating Large Data Sets . . . . . . . . . . . . . . . . . . . . 559 Manipulate Data Using Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . CREATE TABLE and Subqueries .. . . . . . . . . . . . . . . . . . . . . INSERT and Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . UPDATE and Correlated Subqueries . . . . . . . . . . . . . . . . . . . Describe the Features of Multitable INSERTs .. . . . . . . . . . . . . . . . . . . Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Unconditional .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conditional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pivot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Merge Rows in a Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Track the Changes to Data over a Period of Time .. . . . . . . . . . . . . . . . Flashback Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Flashback Version Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . Flashback Transaction Query . . . . . . . . . . . . . . . . . . . . . . . . . 560 560 563 564 567 571 571 574 580 582 586 588 594 597 xx OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600 601 604 611 16 Hierarchical Retrieval . . . . . . . . . . . . . . . . . . . . . . . . . . 615 Interpret the Concept of a Hierarchical Query .. . . . . . . . . . . . . . . . . . Create and Format Hierarchical Data . . . . . . . . . . . . . . . . . . . . . . . . . Create a Tree-Structured Report .. . . . . . . . . . . . . . . . . . . . . . Choosing Direction .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ORDER SIBLINGS BY .. . . . . . . . . . . . . . . . . . . . . . . . . . . . SYS_CONNECT_BY_PATH .. . . . . . . . . . . . . . . . . . . . . . . . CONNECT_BY_ROOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exclude Branches from the Tree Structure . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 618 621 622 623 624 625 626 628 629 631 635 17 Regular Expression Support . . . . . . . . . . . . . . . . . . . . . 639 Using Metacharacters .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Regular Expression Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Replacing Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Regular Expressions and CHECK Constraints . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640 643 653 659 662 663 665 670 18 Controlling User Access .. . . . . . . . . . . . . . . . . . . . . . . . 673 Differentiate System Privileges from Object Privileges . . . . . . . . . . . . . System Privileges .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . GRANT and REVOKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ANY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ADMIN OPTION .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ALL PRIVILEGES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PUBLIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 675 677 679 682 683 684 685 A Contents xxi Grant Privileges on Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Schema Prefixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . WITH GRANT OPTION .. . . . . . . . . . . . . . . . . . . . . . . . . . REVOKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ALL PRIVILEGES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dependent Privileges .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . View Privileges in the Data Dictionary . . . . . . . . . . . . . . . . . . . . . . . . Grant Roles .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Distinguish Between Privileges and Roles . . . . . . . . . . . . . . . . . . . . . . Certification Summary .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Two-Minute Drill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q&A Self Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Self Test Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686 688 689 690 690 691 691 693 696 698 699 701 706 About the CD .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709 System Requirements .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Installing and Running MasterExam . . . . . . . . . . . . . . . . . . . . . . . . . . MasterExam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Electronic Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Removing Installation(s) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Technical Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . LearnKey Technical Support . . . . . . . . . . . . . . . . . . . . . . . . . 710 710 710 711 711 711 711 711 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713 Index .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729 This page intentionally left blank Acknowledgments A s with most large endeavors, this book was the product of many people! Tim Green, the acquisitions editor, is a man of vision, patience, persistence, and insight. McGraw-Hill is lucky to have him, and I was lucky to get to work with him and his excellent team on this project. Meghan Riley is the perfect combination of professionalism, grace, and delightfulness, and is a joy to work with. Molly Sharp of ContentWorks is focused, thorough, and pleasantly fun to work with as well—the whole team has just been fantastic. Also thanks to fellow Oracle Press author Kevin Loney for a key nugget or two of information along the way. A huge and very special thank you to my technical editor, Alistair Grieve, who was meticulous, quick, creative, and extremely knowledgeable—I can't think of enough superlatives to use for him here. Let me give you an idea of how detailed-oriented Alistair is: he caught a typo in Chapter 6 in the word “supercalifragilisticexpialidocious.” More than that, he was technically brilliant and contributed a great deal to making this book better. Kudos to Tim Green and the other good folks at McGraw-Hill for bringing Alistair on the team. Thanks to other great members of the team who have supported this effort: Robert Campbell, copy editor, Paul Tyler, proofreader, and Jack Lewis, indexer. To my very many friends and colleagues whom I’ve had the pleasure of working and/or serving with over the years at various locations and in various capacities, at such enterprises as Sysorex, ISC, MAOP, EOUG, Boeing, ORI, ARC, the NPC, and elsewhere, including some who are still at those places, and some who have gone on to other adventures—there is no way I could name everyone here who has been instrumental or contributed something important to my life and work. A partial list includes: Jeremy Judson, Salam Qureishi, Nadir Ali, Wendy Loundermon, Athar Javaid, Dan Doherty, Ed Wolfe, Ashley Rubeck, Cindy Shiflett, Phil Hasse, Dave Gagner, Jon Feld, Jay Nielsen, Steve Smith, Edgar Kline, Kathy Gardos, James Perry, Terri Buckler, Mark Tash, Adhil Shaikh, Monique Tribolet, Ed Spinella, Dino Merkezas, Bert Spencer, Steve Vandivier, Karen Owens, Mike Ault, Graham Seibert, Vince Adams, Bob Schnetter, Dave Salmen, Oscar Wood, Josh xxiii xxiv OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Parreco, Craig Kasold, Jennifer Blair, Dave Cooper, Ted Cohen, Steve Cummings, Jimmy Smith, Peter Dube, Ruthie Washburn, Kim Curl, Robin Ruth, Renee Battle, Danny Duong, Hung Nguyen, Drew Daffron, Ken O’Neal, Kim Miller, John Lauder, Mark O’Donnell, Bob Smout, Todd Stottlemeyer, Paul Leslie, David Wise, Dan Rutherford, Laura Taylor, Laura Setliff, Trin Tranh, Wilson Dizard, Lyle Beall, Paul Elliott, John Metelsky, Don Knight, Art Garrison, Marshall Cohen, Mark Wojno, Bill McCarren, Jonathan Salant, Tammy Lytle, Rick Dunham, John Cosgrove, Doug Harbrecht, Audrey Ford, Tim Aquilino, Debbie Beebe, Bill Simpson, Annette Taylor, Fred Wills, Carlesza Harris, Gardner McBride, Cindy McBride, Jim Flyzik, Bob Guerra, John Coffey, Lyle Beall, Bobbie Beall, and to three who are no longer with us: Aaron “Eppie” Epstein, Martin Kuhn, and Gordon Gustin. To Dan Hinkle, my business associate of many years, who opened up many doors and many opportunities—a special acknowledgment, and of course to Brenda. Thank you to Bianca Canales for being a great friend, and for providing some key insight at important points in my career; and to Marlene Theriault for special encouragement and very helpful suggestions years ago, which I still benefit from today. To my very many fantastic Oracle students over the years, too numerous to mention here—each of my classes has had a distinctly wonderful and rewarding personality, and each individual student brings a unique set of experiences and observations to the task of learning, all of which have been fun for me and rewarding to work with, and I’ve benefited from having met you all—as iron sharpens iron. A special thank you to my very dear friends Todd and Cindy Bauchspies, and also Mike and Kate Waters, and their gifted and talented sons James and Gavin, and to Phil and Charlotte Jones and Chester and Stephanie and Kenny and Karen, and Harriet Marin and Joe Motz, and of course to Bill Bryant—a huge thanks to all of you for being so patient with my occasional long periods of self-imposed exile while I work on projects such as this book—and still being my friends afterward! A special thank you to Jim Bauchspies, who is like a second father to me in many ways, both personally and professionally, and to Georgine, who gave me many a home-cooked meal and a warm welcome at just the right time. And to Roy Patterson for making my very first Oracle project a reality back in 1986. A very special thank you to Lisa, my sweetheart, for being wonderful and especially encouraging! To my mother, Joan, the best mother anyone could possibly have, and to whom I dedicated my first book. She’s always been there for me, through thick and thin, with a song in her voice and a smile in her heart—Mom, you’re the best! Thanks to my father, Don, an accomplished engineer, and a practitioner of project management, who taught me the value of hard work and dedication, both in word and in deed. A published author in his own right, a consummate professional with a great sense of humor, and the person to whom I’ve dedicated this book. Preface T he most powerful tool in the world today is information. The most powerful information tool in the world is the relational database. The leading relational database in the world is Oracle. And the core language at the foundation of all Oracle products is Oracle’s Structured Query Language, or SQL, a language that is common to all major relational databases of all vendors worldwide. This book is designed to prepare you to become a certified expert in that language by preparing you for the Oracle Database SQL Expert exam, 1Z0-047. The objective of this study guide is to prepare you for the 1Z0-047 exam by familiarizing you with the technology and body of knowledge tested on the exam. Because the primary focus of the book is to help you pass the test, we don’t always cover every aspect of the related technology. Some aspects of the technology are only covered to the extent necessary to help you understand what you need to know to pass the exam, but we hope this book will serve you as a valuable professional resource after your exam. In This Book This book is organized in such a way as to serve as an in-depth review for the Oracle Database SQL Expert exam for both experienced Oracle professionals and newcomers to SQL technologies. Each chapter covers a major aspect of the exam, with an emphasis on the “why” as well as the “how to” of working with and supporting relational database applications. On the CD For more information on the CD-ROM, please see the Appendix “About the CD-ROM” at the back of the book. Exam Readiness Checklist At the end of the Introduction you will find an Exam Readiness Checklist. This table has been constructed to allow you to cross-reference the official exam xxv xxvi OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) objectives with the objectives as they are presented and covered in this book. The checklist also allows you to gauge your level of expertise on each objective at the outset of your studies. This should allow you to check your progress and make sure you spend the time you need on more difficult or unfamiliar sections. References have been provided for the objective exactly as the vendor presents it, the section of the study guide that covers that objective, and a chapter and page reference. In Every Chapter We’ve created a set of chapter components that call your attention to important items, reinforce important points, and provide helpful exam-taking hints. Take a look at what you’ll find in every chapter: n Every chapter begins with Certification Objectives—what you need to know in order to pass the section on the exam dealing with the chapter topic. The Objective headings identify the objectives within the chapter, so you’ll always know an objective when you see it! n Exam Watch notes call attention to information about, and potential pitfalls in, the exam. These helpful hints are written by authors who have taken the exams and received their certificationwho better to tell you what to worry about? They know what you’re about to go through! n On the Job notes describe the issues that come up most often in real-world settings. They provide a valuable perspective on certification- and productrelated topics. They point out common mistakes and address questions that have arisen from on-the-job discussions and experience. n The Certification Summary is a succinct review of the chapter and a restatement of salient points regarding the exam. 3n Q&A The Two-Minute Drill at the end of every chapter is a checklist of the main points of the chapter. It can be used for last-minute review. n The Self Test offers questions intended to check your knowledge of each chapter. The answers to these questions, as well as explanations of the answers, can be found at the end of each chapter. By taking the Self Test after completing each chapter, you’ll reinforce what you’ve learned from that chapter. n The MasterExams offer questions similar to those found on the certification exam. One MasterExam is on the CD in the back of this book. A second Preface xxvii is available online for owners of this book who register. These exams most closely reflect the experience of taking the actual certification exam. As you read each chapter, you’ll obtain information about each certification objective topic. However, when you take the real exam, you won’t have topic headers to let you know what the question is testing. In addition, the real exam will combine various topics into one question. By taking the MasterExams after completing the book, you’ll reinforce what you’ve learned from the book while becoming familiar with the structure of the exam questions. Some Pointers Once you’ve finished reading this book, set aside some time to do a thorough review. You might want to return to the book several times and make use of all the methods it offers for reviewing the material: 1. Re-read all the Certification Summaries and Two-Minute Drills, or have someone quiz you. You also can use the drills as a way to do a quick cram before the exam. You might want to make some flash cards out of 3 × 5 index cards that have the Two-Minute Drill material on them. 2. Re-read all the Exam Watch notes. Remember that these notes are written by authors who have taken the exam and passed. They know what you should expect—and what you should be on the lookout for. 3. Re-take the Self Tests. Taking the Self Tests right after you’ve read the chapter is a good idea, because the questions help reinforce what you’ve just learned. However, it’s an even better idea to go back later and do all the questions in the book in one sitting. Pretend that you’re taking the live exam. When you go through the questions the first time, you should mark your answers on a separate piece of paper. That way, you can run through the questions as many times as you need to until you feel comfortable with the material. 4. Take one of the MasterExams, timed, and without your book, to see how you did. Make notes as you progress to keep a list of topics you think you need to study further before taking the real exam. This page intentionally left blank Introduction W elcome to a book that could change your career, and quite possibly change your life—and all for the better. You’re holding in your hands a study guide and roadmap to obtaining the Oracle Database SQL Expert certification. Possession of this book does not guarantee your success. But it increases your odds of success dramatically. You’re going to have to work at it. But you can do it—armed with the information contained in this book, you can achieve what few have accomplished: a certification that declares your expertise in the core language at the heart of all major database systems in use in the world today. You live in the Information Age, and SQL is the master language of all serious information that drives the businesses, governments, and organizations that run the world. Chapter 1 will provide you with some introductory information about the exam and the exam experience. After that, you’ll review the topics according to the certification objectives. These are the officially declared topics, published by Oracle Corporation and stated by the company to be the topics from which the exam draws its questions. This book will not—and cannot—reveal actual exam questions, or their corresponding answers. Those of us who have taken the exam are forbidden to reveal that information. But this book will focus on the topics that the exam addresses, and will teach you the information that, as of this writing, you need to know about the exam. A good Oracle professional will not limit his or her study to just one book. Oracle Corporation has made a number of manuals available online that describe the full functionality of their products. But those of us who have been in the business a while know that these great resources, valuable and voluminous as they are, can be overwhelming sometimes, cryptic at other times, and generally too difficult to navigate effectively within a person’s professional lifetime, without some sort of guide. This book is your guide, but it is much more than that—it is a self-contained study guide, complete with full descriptions, syntax details, sample code, self-tests, and master exams that simulate the real certification exam experience. In other words, you are holding a treasure map to the nuggets of wisdom you need to know to pass the exam and win your certification. It’s the product of years of experience, earned xxix xxx OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) through hard work, tested among veteran Oracle professionals from around the world and with many backgrounds and strengths, consolidated into one clearly organized format to empower you to prepare quickly and efficiently to become certified. The book is designed to serve the following audiences: n For the veteran who wishes only to zero in on particular topics on an à la carte basis, the book is categorized by certification objective. If you’ve already seen the published certification objectives and only wish to study up on a few areas, you can do that with this book—find the appropriate section and study those chapters. n For the reader who wishes a more comprehensive review, the objectives and chapters are sequentially ordered to begin with the fundamentals and work up into the more advanced topics. You can study the book straight through and experience a complete presentation of the knowledge you need to pass the exam. n For the seasoned practitioner who wants to jump straight to the exam experience—go straight for the back of the book and install the CD, take the exam. Each question is tied back to a section and topic in the book so that any questions you miss will quickly focus your study on the topics you need to brush up on. The 1Z0-047 exam has been tested against versions 10g and 11g of the Oracle database. For this book, I used Oracle Database 11g, release 1. Some of the screen shots of SQL statements were taken from SQL*Plus, others from SQL Developer. Note that in the SQL Developer’s Script Output display, numeric data displays left justified by default, as opposed to SQL*Plus, where numeric data displays right justified by default. Images of entity-relationship diagrams were taken from the brand new Oracle SQL Data Modeler. The product shipped during the writing of this book, and I took advantage of it on the first day it went live at oracle.com. Good reading, study well, and the best of luck to you. Your feedback is invited and welcome: soh@corbinian.com. Exam Readiness Checklist xxxi Chapter Page Retrieving Data Using the SQL SELECT Statement 4 137 List the capabilities of SQL SELECT statements 4 141 Execute a basic SELECT statement 4 138 Describe how schema objects work 4 154 Restricting and Sorting Data 5 169 Limit the rows that are retrieved by a query 5 170 Sort the rows that are retrieved by a query 5 184 Using Single-Row Functions to Customize Output 6 209 Describe various types of functions that are available in SQL 6 210 Use character, number, and date functions in SELECT statements 6 214 Describe the use of conversion functions 6 235 Reporting Aggregated Data Using the Group Functions 7 275 Identify the available group functions 7 276 Describe the use of group functions 7 277 Group data by using the GROUP BY clause 7 285 Include or exclude grouped rows by using the HAVING clause 7 296 Displaying Data from Multiple Tables 8 311 Write SELECT statements to access data from more than one table using equijoins and nonequijoins 8 312 Join a table to itself by using a self-join 8 328 View data that generally does not meet a join condition by using outer joins 8 312 Generate a Cartesian product of all rows from two or more tables 8 330 Using Subqueries to Solve Queries 9 345 Define subqueries 9 346 Describe the types of problems that subqueries can solve 9 347 List the types of subqueries 9 348 Expert Certification Objective Intermediate Exam Readiness Checklist Beginner Exam 1Z0-047 Certification Objective Chapter Page Write single-row and multiple-row subqueries 9 349 Using the Set Operators 12 487 Describe set operators 12 488 Use a set operator to combine multiple a single query 12 490 Control the order of rows returned 12 497 Manipulating Data 3 93 Describe each data manipulation language (DML) statement 3 94 Insert rows into a table 3 98 Update rows in a table 3 106 Delete rows from a table 3 111 Control transactions 3 112 Using DDL Statements to Create and Manage Tables 2 45 Categorize the main database objects 2 46 Review the table structure 2 59 List the data types that are available for columns 2 60 Create a simple table 2 50 Explain how constraints are created at the time of table creation 2 67 Creating Other Schema Objects 10 381 Create simple and complex views 10 382 Retrieve data from views 10 391 Create, maintain, and use sequences 10 392 Create and maintain indexes 10 397 Create private and public synonyms 10 404 Managing Objects with Data Dictionary Views 14 533 Use the data dictionary views to research data on your objects 14 534 Query various data dictionary views 14 542 Controlling User Access 18 673 Expert Exam Readiness Checklist Intermediate OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Beginner xxxii Chapter Page Differentiate system privileges from object privileges 18 674 Grant privileges on tables 18 686 View privileges in the data dictionary 18 691 Grant roles 18 693 Distinguish between privileges and roles 18 696 Managing Schema Objects 11 423 Add constraints 11 436 Create indexes 11 454 Create indexes using the CREATE TABLE statement 11 454 Creating function-based indexes 11 457 Drop columns and set column UNUSED 11 431 Perform FLASHBACK operations 11 458 Create and use external tables 11 468 Manipulating Large Data Sets 15 559 Manipulate data using subqueries 15 560 Describe the features of multitable INSERTs 15 567 Use the following types of multitable INSERTs (Unconditional, Conditional and Pivot) 15 571 Merge rows in a table 15 582 Track the changes to data over a period of time 15 586 Generating Reports by Grouping Related Data 13 511 Use the ROLLUP operation to produce subtotal values 13 512 Use the CUBE operation to produce crosstabulation values 13 515 Use the GROUPING function to identify the row values created by ROLLUP or CUBE 13 517 Use GROUPING SETS to produce a single result set 13 519 Managing Data in Different Time Zones 6 247 Use various datetime functions 6 247 Expert Certification Objective Intermediate Exam Readiness Checklist xxxiii Beginner Exam Readiness Checklist Certification Objective Chapter Page Retrieving Data Using Subqueries 9 345 Write a multiple-column subquery 9 356 Use scalar subqueries in SQL 9 358 Solve problems with correlated subqueries 9 360 Update and delete rows using correlated subqueries 9 362 Use the EXISTS and NOT EXISTS operators 9 365 Use the WITH clause 9 366 Hierarchical Retrieval 16 615 Interpret the concept of a hierarchical query 16 616 Create a tree-structured report 16 621 Format hierarchical data 16 618 Exclude branches from the tree structure 16 626 Regular Expression Support 17 639 Using Meta Characters 17 640 Regular Expression Functions 17 643 Replacing Patterns 17 653 Regular Expressions and Check Constraints 17 659 Expert Exam Readiness Checklist Intermediate OCA Oracle Database SQL Certified Expert Exam Guide (Exam 1Z0-047) Beginner xxxiv 1 Introduction to SQL Certification Objectives 1.01 The Exam: An Overview 1.05 1.02 Define and Understand the Basics of the RDBMS Understand the Unique Role of SQL in Modern Software Systems 1.06 Confirm Appropriate Materials for Study 1.03 Define and Understand the Basics of SQL 3 1.04 Understand the Oracle RDBMS and Oracle SQL Q&A Two-Minute Drill Self Test 2 Chapter 1: Introduction to SQL O racle Corporation’s implementation of the Structured Query Language, or SQL, is arguably the most powerful and most significant computer language used in the world of government and business today. This chapter begins the process of preparing you to successfully take and pass the Oracle 1Z0-047 exam, titled “Oracle Database SQL Expert”. First we’ll discuss a few particulars about the exam itself, how it’s different from other Oracle certification tests, and what you can expect when you take it. Then we’ll begin to address the SQL language; we’ll introduce some background information and prepare you to go through a comprehensive analysis and review of the language in order to successfully study for the test. We will explore the background of SQL and its role in the world of computer languages and software development. If you are a veteran Oracle professional and are taking a bare-bones approach to exam preparation, you might want to read the first section, which provides an overview of the exam, and then perhaps skim through the rest of the chapter, looking for the Exam Watch sections along the way. However, I encourage you to review all of this material, for it will help you to position your thinking with regard to the exam, as well as your career. If you aren’t absolutely crystal clear on how prominent SQL is in the marketplace, or how important it is that you have a comprehensive and thorough understanding of all of the capabilities of SQL, then read on. If nothing else, this chapter will help galvanize your career development by informing (or reminding) you of how increasingly crucial it is that you maintain your SQL skills at the highest level, as this is what organizations in the world today require—and this requirement grows with each day, as databases grow, and as the use and potential of the data they contain continue to increase in significance. Certification Objective 1.01 The Exam: An Overview A typical Oracle professional doesn’t generally begin his or her career by taking the advanced “1Z0-047 Oracle Database SQL Expert” exam. Since you’re reading this book, chances are you’ve probably taken some of Oracle’s other certification tests, such as “1Z0-051 SQL Fundamentals I”. The “SQL Expert” exam builds on The Exam: An Overview 3 the “SQL Fundamentals I” exam in terms of both subject matter and complexity. But “SQL Expert” is a very different and unique exam. It is demanding and asks questions that test the full breadth of your knowledge of SQL syntax and processing, and its application to business rules. A typical question on the SQL Expert exam might go something like this: n You’ll be asked to review an exhibit, which could be a set of data output in a half-dozen columns and perhaps 20 or 30 rows—or it might be an entityrelationship diagram (ERD) containing as many as a half-dozen entities or more. n Next you’ll need to review a set of SQL statements that are intended to operate on the exhibit you were just shown, with a number of SQL statements, in which there might be a series of nested scalar functions, aggregate functions, multitable indices, subqueries of various forms, and/ or the use of different statements and clauses showcasing features such as complex timezone usage, very large datatypes, complex join conditions, etc. n Some of the code may be correct—some may not, and you’ll need to recognize the difference. n With the sample exhibit and SQL code in front of you, you may be asked to identify the resulting status of the database after the SQL statements execute. n You may be asked to identify the internal workings of the Oracle database, in order, in accordance with the SQL statements you’ve been shown. n The list of possible answers may include more than one correct response, and you must identify each of them. Does that sound like a lot to do for a single question? Then consider this: for the entire exam, you are allowed 120 minutes to answer 70 questions. That’s an average of 1.71 minutes per question. Think you can handle it? Do you have what it takes to be a formally recognized and officially certified Oracle Database SQL Expert? Whether you do or not remains to be seen . . . but one thing is for certain. This book will prepare you, strengthen your knowledge, fill in the gaps, and dramatically increase your odds of success. So get ready for a fun and rewarding challenge and an important milestone in your career. Get ready to enter the world of the technical elite, to join the crème de la crème, to be ranked with the best of the best. 4 Chapter 1: Introduction to SQL Get ready, for here starts your path to become . . . a certified Oracle Database SQL Expert. Time’s a-wastin’ . . . let’s get started . . . first, we’ll take a detailed look at the official certification objectives of the SQL Expert exam and compare them with the SQL Fundamentals exam. “SQL Fundamentals I” Versus “SQL Expert” As I just mentioned, since you’re planning on obtaining your SQL Expert certification by taking the “1Z0-047 Oracle Database SQL Expert” exam, then chances are you may have already taken another exam, titled “1Z0-051, SQL Fundamentals I”. The two exams share some common objectives, but 047 goes far beyond 051. See Table 1-1 for a comparison of those objectives, and a detailed analysis of where the two exams are similar, and where they are different. Table 1-1 Comparison: 1Z0-051 and 1Z0-047 Exam Objectives 1Z0-051 SQL Fundamentals I 1Z0-047 SQL Expert Exam Objectives 1.0 1.0 Retrieving Data Using the SQL SELECT Statement 1.1 1.1 List the capabilities of SQL SELECT statements 1.2 1.2 Execute a basic SELECT statement — 1.3 Describe how schema objects work 2.0 2.0 2.1 2.1 Limit the rows that are retrieved by a query 2.2 2.2 Sort the rows that are retrieved by a query 2.3 — Use ampersand substitution to restrict and sort output at runtime 3.0 3.0 Using Single-Row Functions to Customize Output 3.1 3.1 Describe various types of functions that are available in SQL 3.2 3.2 Use character, number, and date functions in SELECT statements (*) 3.3 Describe the use of conversion functions Restricting and Sorting Data The Exam: An Overview Table 1-1 Comparison: 1Z0-051 and 1Z0-047 Exam Objectives (Continued) 5 1Z0-051 SQL Fundamentals I 1Z0-047 SQL Expert Exam Objectives 4.0 (*) Using Conversion Functions and Conditional Expressions 4.1 (*) Describe various types of conversion functions that are available in SQL 4.2 (*) Use the TO_CHAR, TO_NUMBER, and TO_DATE conversion functions 4.3 — Apply conditional expressions in a SELECT statement 5.0 4.0 Reporting Aggregated Data Using the Group Functions 5.1 4.1 Identify the available group functions 5.2 4.2 Describe the use of group functions 5.3 4.3 Group data by using the GROUP BY clause 5.4 4.4 Include or exclude grouped rows by using the HAVING clause 6.0 5.0 Displaying Data from Multiple Tables 6.1 5.1 Write SELECT statements to access data from more than one table using equijoins and nonequijoins 6.2 5.2 Join a table to itself by using a self-join 6.3 5.3 View data that generally does not meet a join condition by using outer joins 6.4 5.4 Generate a Cartesian product of all rows from two or more tables 7.0 6.0 Using Subqueries to Solve Queries 7.1 6.1 Define subqueries 7.2 6.2 Describe the types of problems that subqueries can solve 7.3 6.3 List the types of subqueries 7.4 6.4 Write single-row and multiple-row subqueries (Continued) 6 Chapter 1: Table 1-1 Comparison: 1Z0-051 and 1Z0-047 Exam Objectives (Continued) Introduction to SQL 1Z0-051 SQL Fundamentals I 1Z0-047 SQL Expert Exam Objectives 8.0 7.0 Using the Set Operators 8.1 7.1 Describe set operators 8.2 7.2 Use a set operator to combine multiple queries into a single query 8.3 7.3 Control the order of rows returned 9.0 8.0 Manipulating Data 9.1 8.1 Describe each data manipulation language (DML) statement 9.2 8.2 Insert rows into a table 9.3 8.3 Update rows in a table 9.4 8.4 Delete rows from a table 9.5 8.5 Control transactions 10.0 9.0 Using DDL Statements to Create and Manage Tables 10.1 9.1 Categorize the main database objects 10.2 9.2 Review the table structure 10.3 9.3 List the data types that are available for columns 10.4 9.4 Create a simple table 10.5 9.5 Explain how constraints are created at the time of table creation 10.6 (**) 1.3 (**) Describe how schema objects work 11.0 10.0 Creating Other Schema Objects 11.1 10.1 Create simple and complex views 11.2 10.2 Retrieve data from views 11.3 10.3 Create, maintain, and use sequences 11.4 10.4 Create and maintain indexes 11.5 10.5 Create private and public synonyms The Exam: An Overview Table 1-1 Comparison: 1Z0-051 and 1Z0-047 Exam Objectives (Continued) 1Z0-051 SQL Fundamentals I 1Z0-047 SQL Expert Exam Objectives — 11.0 Managing Objects with Data Dictionary Views — 11.1 Use the data dictionary views to research data on your objects — 11.2 Query various data dictionary views — 12.0 Controlling User Access — 12.1 Differentiate system privileges from object privileges — 12.2 Grant privileges on tables — 12.3 View privileges in the data dictionary — 12.4 Grant roles — 12.5 Distinguish between privileges and roles — 13.0 Managing Schema Objects — 13.1 Add constraints — 13.2 Create indexes — 13.3 Create indexes using the CREATE TABLE statement — 13.4 Creating function-based indexes — 13.5 Drop columns and set column UNUSED — 13.6 Perform FLASHBACK operations — 13.7 Create and use external tables — 14.0 Manipulating Large Data Sets — 14.1 Manipulate data using subqueries — 14.2 Describe the features of multitable INSERTs — 14.3 Use the following types of multitable INSERTs (Unconditional, Conditional and Pivot) — 14.4 Merge rows in a table — 14.5 Track the changes to data over a period of time 7 (Continued) 8 Chapter 1: Table 1-1 Comparison: 1Z0-051 and 1Z0-047 Exam Objectives (Continued) Introduction to SQL 1Z0-051 SQL Fundamentals I 1Z0-047 SQL Expert Exam Objectives — 15.0 Generating Reports by Grouping Related Data — 15.1 Use the ROLLUP operation to produce subtotal values — 15.2 Use the CUBE operation to produce crosstabulation values — 15.3 Use the GROUPING function to identify the row values created by ROLLUP or CUBE — 15.4 Use GROUPING SETS to produce a single result set — 16.0 Managing Data in Different Time Zones — 16.1 Use various datetime functions — 17.0 Retrieving Data Using Subqueries — 17.1 Write a multiple-column subquery — 17.2 Use scalar subqueries in SQL — 17.3 Solve problems with correlated subqueries — 17.4 Update and delete rows using correlated subqueries — 17.5 Use the EXISTS and NOT EXISTS operators — 17.6 Use the WITH clause — 18.0 Hierarchical Retrieval — 18.1 Interpret the concept of a hierarchical query — 18.2 Create a tree-structured report — 18.3 Format hierarchical data — 18.4 Exclude branches from the tree structure — 19.0 Regular Expression Support — 19.1 Using meta characters — 19.2 Regular expression functions — 19.3 Replacing patterns — 19.4 Regular expressions and check constraints * Note that conversion functions are addressed by both exams, but with more emphasis in 051 versus 047. ** This is a repeat of item 1.3. The Exam: An Overview 9 As you can see, both exams look at many of the same features, such as the SELECT statement and its ability to sort rows and convert datatypes, together with its use of functions and expressions; the GROUP BY clause; joining tables; subqueries; the set operators (such as UNION and INTERSECT); the INSERT, UPDATE, and DELETE statements; creating database objects, and more. All of those topics are on both exams. But SQL Expert goes far beyond this. The SQL Expert exam also addresses topics such as n The data dictionary n User access with roles and privileges n FLASHBACK operations n External tables n Function-based indexes n Constraints n Multitable INSERTs n Tracking changes over time n Conditional INSERTs with pivots n CUBE n ROLLUP operations n GROUPING SETS n Managing data across multiple time zones n EXISTS and NOT EXISTS n The WITH clause n Multi-column, scalar, and correlated subqueries n Hierarchical SELECT n Tree-structured output n Regular expressions in functions and check constraints n And more As you can see, the SQL Expert exam goes much further than the topics addressed by the SQL Fundamentals I exam. Both exams consist of 70 questions, and two hours are afforded the test taker of either exam. At the time of this writing, the passing scores are published differently at the Oracle.com web site: for “SQL Fundamentals I” it is 60 percent, while “SQL Expert” requires 66 percent. However, note that passing score requirements 10 Chapter 1: Introduction to SQL are subject to change without notice. Oracle Corporation reserves the right to substitute a particular version of the test with another version, and depending on the complexity of the specific questions included in a new version, the passing score may be adjusted accordingly. In fact, Oracle publishes this notice on its web site with regarding to the required passing score for any given exam: The passing scores provided on the Oracle Certification Program website are for informational purposes only. Oracle does not recommend an exam preparation strategy targeting the passing score, because passing scores are subject to change without notice. In other words: study well, and don’t plan on trying to achieve the minimal passing score requirement. Instead do the best you possibly can in order to increase your chances of victory. What to Expect I’ve taken the test. Let me share a little with you about what you can expect. Test Logistics In my case, I went to the Oracle Corporation web site (oracle.com), clicked the Certification link, and looked for the 1Z0-047 exam page. From there I clicked the link asking me to “register” for the exam. This took me to the Prometric web site (www.prometric.com) where I located a local university that was hosting proctored exams. I found an available time, provided my credit card information for the $125 payment, and a few days later arrived at the testing facility. When I arrived, I was asked to turn my mobile phone off and give it to the staff, who locked it into a small container. The staff retained the key but handed the container containing my mobile phone to me. I was told I would be able to take the container with me into the testing room, unable to access it inside the locked container. I was told I could recover my phone after the exam. After providing two forms of ID, I was shown into a large room filled with computers and taken to one that was already logged in to the Prometric automated testing system. I sat down and began. I stepped through a series of disclosures and agreements and finally was presented with the first of what I knew would be 70 questions. The 120-minute timer started with the first question. It clicked off each second in the upper-right corner, and I could monitor it throughout the exam. The Exam: An Overview 11 All of the questions were multiple-choice. Most of them required me to click a button to display an exhibit, which popped up in a separate window, sized just big enough to show whatever the exhibit was displaying. Generally the exhibit was an entity-relationship diagram, but sometimes it was a listing of data that could’ve been the contents of a table or the output of a report. The exhibit didn’t indicate what it was intended for, but the question would eventually get around to explaining how you were supposed to treat and interpret the exhibit for the question. Some questions will throw a lot of material at you. You won’t necessarily need to analyze every bit of it to answer the question. Be careful with your time—keep an eye on the clock, remember that you have less than two minutes per question on average, and don’t get distracted. Remember—your goal is to answer the question, not necessarily to evaluate every line of the code and data element that is presented to you. Some questions will be about one simple concept, and that concept will be shown in the context of a series of several SQL statements or data listings. When you’re asked to “look at the exhibit” and “evaluate the following SQL code”, you might want to temporarily ignore all of that and glance ahead at the actual question first, so that you know what you’ll be looking for in the exhibit and the code. Otherwise, you’ll waste time studying some ERD containing over a half-dozen entities with multiple relationships, plus a half-dozen lines of SQL code, when the question might really center on just one or two of those entities and how they should be joined in a multitable query. So don’t get distracted—stay focused on the question, and use your time judiciously. The questions were presented on the screen one at a time. I clicked Next to advance to the next question. I wasn’t required to answer each question before advancing. Stay focused on the Each of the questions had an optional check question. Don’t let a large example of box in the upper-left corner labeled “Mark”. SQL text distract you. I could “mark” any question for future reference, whether I had answered it or not. When I eventually reached the final question, answered it, and clicked Next, I found myself looking at a summary screen showing the number corresponding to every question of the exam in a singular tabular listing. The questions were identified by number only, and next to each was the letter—or letters—of the answers I had provided. Any question I had “marked” showed a highlighted M next to it. Any question I had not fully answered showed a highlighted I—for 12 Chapter 1: Introduction to SQL “incomplete”—next to it. I was easily able to review and complete the answers and review any questions, including those I had marked, before completing the exam. One factor worth noting regarding questions that require more than one correct answer to be identified: some of these questions will tell you exactly how many correct answers you must choose from the set presented to you. For example, one question may have a total of four possible answers, of which two are correct, and the question will tell you to choose two answers. In this example, if you were to choose a third answer, the automated testing system wouldn’t let you do it, but would pop up a small message window telling you to de-select another answer first. But let’s say you don’t catch the fact that there were two correct answers, and you only click one, and you move on. Nothing in the system will stop you from moving ahead and leaving the question incomplete with—in this example—only one of the two required answers. In fact you’re always allowed to advance and leave any question “incomplete”. But the good news is this: once you reach the summary screen at the end, any incomplete questions will be flagged clearly and you’ll be able to go back and review. So in case you think you answered everything, don’t be too sure and exit the test prematurely—be sure you take a good look at the summary screen at the end and check for any highlighted “I” markings next to your answers. If you see any and weren’t expecting to, it’s quite possible that you’re dealing with a question that had more correct answers than you thought. When I was done with my questions and was satisfied that I had answered everything, I clicked Exit on the summary screen, the test score was instantly evaluated, and I was shown my score and passing grade on the screen. In addition, a nearby printer produced a written summary of my performance as well. I picked up my papers and went to the front desk of the testing center, where a clerk made copies of my papers and kept a set. They unlocked the container containing my mobile phone, which I retrieved, and I left a happy and certified SQL Expert. Subject Areas The certification objectives for 1Z0-047 are shown in Table 1-1. They are taken directly from the Oracle Corporation web site as of this writing. They were the same certification objectives at the time that I took the exam. Warning: the emphasis on the exam is on those objectives not included in the 1Z0-051 exam. That makes sense, of course, but it’s not obvious from the published literature—until now. While all topic areas are addressed in some fashion, and Define and Understand the Basics of the RDBMS 13 Oracle Corporation reserves the right to change anything and everything about the exam with no warning at any time, be aware that I’ve taken this exam, and of the 19 stated certification objective categories for 047, my exam provided a greater emphasis on the nine certification objective categories that are not covered by 051. The test does include questions from all categories—including those categories that are included in 051. But the nine unique certification categories not included in 051 are emphasized in 047. In addition, you’ll need to have an ability to read entity-relationship diagrams in order to take this exam, something that’s not specifically mentioned in the list of certification objectives. A large number of questions will ask you to look at an “exhibit”, and more often than not the exhibit will be some sort of entityrelationship diagram. Many questions challenge your knowledge of several facts at once. For example, I encountered one question that presented several nested scalar functions in a series of SELECT statements. I had to understand clearly what each individual scalar function did, recognizing syntax issues, understand the data type transformations as one function passed on results to another, confirm whether the parameter positioning was accurate, and identify two facts about the process and end result, all within the concept of a given ERD. The moral to the story: study this book well, understand everything listed in the certification objectives, pay special attention to those areas that are not included in 051 but are unique to 047, and get all of your facts down cold. And on test day: show up rested and on time, and don’t get distracted. Pay attention to the real question and keep track of your time. You’ll be glad you did. Certification Objective 1.02 Define and Understand the Basics of the RDBMS Now that you’ve taken a look at the exam’s certification objectives, let’s get started with reviewing the subject of the Structured Query Language (SQL). This section isn’t specifically analyzed on the exam, but the information presented here is foundational to an understanding of everything else in the book. If you’re a veteran SQL developer, you might want to just skim the rest of this chapter, looking for the 14 Chapter 1: Introduction to SQL “Exam Watch” sections, and moving on to the next chapter. Otherwise, stay tuned and get your thinking well positioned to focus on the remainder of the book. We’ll start with a cursory review of the reason we have SQL: the relational database management system (RDBMS). This section reviews the history and fundamental principles of the RDBMS. Relational Databases and Dr. E.F. Codd Before the advent of the RDBMS, software developers found themselves frequently creating applications that used data. These applications needed features to store, change, and retrieve data in various forms. The data was different in every application, but the required functionality was the same—store it, change it, retrieve it. In spite of this common need for functionality, there was no common approach for getting the job done. There was no standard approach to database design, nor a standard set of logic for the storage, changing, and retrieval—each programmer recreated this logic in every application. The result was a slow development effort and proprietary data structures. Programmers found it difficult at best to share each other’s data. Even if they wanted to do it, it was often an arduous, time-consuming effort. Something better was needed. The concept of a relational database management system was first formally introduced in 1970 in a paper published by an IBM engineer named Dr. E.F. Codd. That paper was titled “A Relational Model of Data for Large Shared Data Banks”, and Codd’s work revolutionized the software industry. Codd envisioned a system within which programmers could build their own individual databases, using standard methods and functions, with built-in support for common functions to add, modify, and extract data from the database. In an RDBMS, data is stored in tables, each of which consists of one or more columns of information. Consider Figure 1-1, which shows a list of ships with the fictional Codd Cruise Lines. The database table has two columns, which are “Ship ID” and “Ship Name”. Each row of data includes a bit of information that serves as a unique identifier, which in this example is the “Ship ID” column. For example, the first row has a unique identifier of “1”, the second row has a unique identifier of “2”, and so on. This unique identifier is a key to identifying a particular ship’s record. The values found under the “Ship ID” column uniquely identify each ship. This column is considered to be a primary key column. Define and Understand the Basics of the RDBMS Figure 1-1 List of “Codd Cruise Lines” ships Ship ID Ship Name 1 Codd Crystal 2 Codd Elegance 3 Codd Champion 4 Codd Victorious 15 Next is Figure 1-2, which is a database table of employees. In this case, we have three columns of data, “Employee ID”, “Name”, and “Ship ID”. The unique identifier here is “Employee ID”. Now, if I were to ask you to identify the ship to which Mike West was assigned, what would you say? Naturally you would (or should) say it was the “Codd Victorious”, and you would determine this by looking in the employees table, finding the record for Mike West, then “relating” that record’s Ship ID value to the ship table, and finding that Ship ID 4 “relates” to the ship named “Codd Victorious”. This is an example of the sort of data that an RDBMS might contain, and the sort of processing it does to “relate” data in one table to another table. A typical database consists of any number of tables, many of which contain key information that is used to relate rows of one table to rows of another table. In the example you just saw, each ship record can theoretically relate to multiple records in the “employee” table. In other words, for every one ship, there might be many employees. These two tables are said to have a one-to-many relationship. A properly structured relational database system will consist of several tables, each of which contains data that uniquely identifies each record, and then “relates” records to each other, using those unique identifiers, according to the needs of the business rules that the database is intended to support. Figure 1-2 List of “Codd Cruise Lines” employees Employee ID Name Ship ID 1 Joe Smith 3 2 M ike West 4 3 Alice Lindon 3 16 Chapter 1: Introduction to SQL Database Normalization A full analysis of the concept of database normalization is beyond the task of this book, whose intent is to prepare you for the exam. But it’s worth noting the rules of normalization, which are a set of rules that drive the design of any set of tables that compose a relational database. The most common levels of normalization are summarized in Table 1-2. Normalization is a standard method used by database designers intended to reduce the risk of errors in the database. By eliminating, for example, the existence of unnecessary duplication of data and other design weaknesses, the process of normalization can help minimize the occurrence of conflicting data and improve the quality of the data contained within the database. A database adheres to the first normal form (1NF) when tables are structured in a one-to-many relationship. For example, in our earlier example of “ships” and “employees”, we would have been in violation of first normal form if we had instead placed all the ship names in the “employees” table and repeated them and any associated data, such as ship length, with each record of each employee that might happen to be assigned to that ship. By separating “ship” and “employee” data, we established the requirement to be, at a minimum, in first normal form. Table 1-2 Levels of Normalization Level of Normal Form Abbreviation Characterized by First Normal Form 1NF No repeating groups, all tables are two-dimensional. Second Normal Form 2NF 1NF plus each data element is identified by one corresponding unique identifier—a primary key— that is not a composite and therefore cannot be subdivided into smaller bits of data. Third Normal Form 3NF 2NF plus all tables contain no data other than that which describes the intent of the primary key— extraneous data is placed in separate tables. Boyce-Codd BCNF A slightly modified version of 3NF designed to eliminate structures that might allow some rare logical inconsistencies to appear in the data. Fourth Normal Form 4NF BCNF plus additional logic to ensure that every multivalued dependency is dependent on a superkey. Fifth Normal Form 5NF 4NF plus every join dependency for the table is a result of the candidate keys. Define and Understand the Basics of the RDBMS 17 Second normal form (2NF) exists when no non-key attribute is dependent upon a part of a composite key. Nothing in the exam Third normal form (3NF) is the most objectives, nor in my experience of having commonly used form of normalization for taken the exam, indicates that the test transaction-based database applications. In this involves anything other than typical third form, lookup data is moved to separate tables. normal form scenarios. These descriptions are merely a refresher and are not intended to be an exhaustive analysis of database normalization. For that, I refer you to other books in the Oracle Press line that deal with the fundamentals of database design. Database Design Considerations Databases may be used for different purposes, and not all purposes require the same sort of design. Furthermore, there are conflicting priorities that any database designer is forced to consider in the design of any database. For example, the ideal database shouldn’t store any data more than once. This way, errors are minimized considerably. After all, when you enter the current phone number for a customer, it should only be located in one place in the database, so you don’t end up with a database that requires the end users to update information in more than one location. What if the users forget? Then you’ll end up with conflicting information in the database, and that’s a bad situation. With only one location for the “customer’s current phone number”, any changes made to the customer’s current phone number will be done easily, and the results will be clear to future users of the database. Now—as you’ve already seen, any record in the database should have a unique identifier. So that would imply that the customer’s current phone number should have one unique identifier. That’s a reasonable requirement. But what happens if the database design becomes complex, and stores a great deal of information in many tables? And what happens if the complexity of the design requires that unique identifier to relate to many tables in order to finally extract the customer’s current phone number, buried down inside a set of tables? Depending on your computer hardware, you might experience slow performance if the database grows in size to tens of millions of records, with many interrelated tables. 18 Chapter 1: Introduction to SQL And now imagine that your database is required to reply instantly to any incoming phone call, in such a way that the office telephone system identifies the incoming phone number via caller ID and sends that phone number to the database. The customer’s name must appear immediately on the screen, so that your call center can answer “Hello, Mr. Codd, nice to hear from you again today, your order is on its way”. That means your database has to reply instantly to that particular query. That might require some special consideration, depending on the circumstances. Perhaps you’ll choose to copy the set of “customer current phone number” records in a second table to support speedy lookups if the overall system is too slow and cumbersome to handle it. There are purists out there who would argue this is bad design. But try to explain that to your boss when the hardware budget is tight and your incoming customer phone calls are being passed off anonymously to the call center in violation of corporate policy. The bottom line is that the database exists to serve the organization, not the other way around, and you’ll often find yourself in a situation where your design choices and trade-offs require you to bend the rules of what is considered good design. It’s important to note that there is not necessarily a single right or wrong way to model every system out there. Some design decisions involve trade-offs of performance (speed of response) versus reduction of duplicate data and complexity of the resulting application.These are the challenges to any data modeler and to any SQL developer. Now that you have a basic idea of how a database should be structured, how do you actually build it? To accomplish this, you need a tool. This is why the Structured Query Language was created. Certification Objective 1.03 Define and Understand the Basics of SQL The Structured Query Language is often abbreviated with the letters SQL. Some people pronounce it by spelling out the letters, as in “ESS-CUE-ELL”. Define and Understand the Basics of SQL 19 Others pronounce it as “sequel”. Both pronunciations are fine, and both are used by respected professionals in the industry. Whatever you do, just don’t call it “squeal”. SQL is a language to n Create databases and the objects within them. n Store data in those databases. n Change and analyze that data. n Get that data back out in reports, web pages, or virtually any other use imaginable. Let’s look at a very simple example: consider the ships listed in Figure 1-1. A valid SQL command to create a table in which we could store that information might look like this: CREATE TABLE SHIPS (SHIP_ID SHIP_NAME CAPACITY LENGTH NUMBER, VARCHAR2(20), NUMBER, NUMBER ); I say “might” look like this because there are a number of options that you might include here, including primary or foreign key declarations, data filtering, storage assignment, and other options that go beyond our simple example. We’ll look at many of those options later in the book. But this code definitely works in an Oracle SQL database. Next, here’s a SQL command to add our sample record to this table: INSERT INTO SHIPS (SHIP_ID, SHIP_NAME, CAPACITY, LENGTH) VALUES (1,'Codd Crystal', 2052, 855); Again, this is a valid command, albeit a simplified version. It inserts one record of information about one ship into our new table SHIPS. Finally, let’s create a SQL command to display the contents of our newly populated SQL table: SELECT FROM SHIP_NAME, CAPACITY, LENGTH SHIPS; 20 Chapter 1: Introduction to SQL Figure 1-3 Output of our sample SQL SELECT statement If all has gone correctly, we should get a display that appears something like the display shown in Figure 1-3. (Note: Figure 1-3 shows the output as seen in the Oracle tool known as SQL Developer.) As you can see, our data is stored in the table, and it is still there—SELECT merely displays the data; it doesn’t change the data at all. At its simplest level, this is what SQL is all about—writing statements to create database objects, and then working with those objects to store and retrieve data. There are many SQL commands. Some of the more commonly used SQL commands are shown in Table 1-3. There are more commands than are shown here. For the commands that are shown here, there are many, many clauses, parameters, and other additional features for each one. Later in the book we will look in great detail at each command that is covered by the exam. Table 1-3 SQL Command Description Some of the More Commonly Used SQL Commands SELECT Retrieves data from a table. INSERT Adds new data to a table. UPDATE Modifies existing data in a table. DELETE Removes existing data from a table. CREATE object_type Creates a new database object, such as a table. ALTER object_type Modifies the structure of an object, such as a table. DROP object_type Removes an existing database object, such as a table. Understand the Oracle RDBMS and Oracle SQL 21 Certification Objective 1.04 Understand the Oracle RDBMS and Oracle SQL So where does Oracle enter the picture? Let’s revisit Dr. Codd’s story. After Codd’s paper was published in 1970, it eventually created quite a reaction in the software industry and triggered an effort within IBM to create a commercial database product. But as IBM engineers worked on their RDBMS concept and spoke about their efforts at conferences and throughout the industry, they inadvertently inspired a young entrepreneur named Larry Ellison to create an RDBMS product of his own, one that might complement IBM’s product and, in the end, actually aligned more closely with Codd’s original theories. That competing product is known today as Oracle, and was officially released first, a few weeks before IBM’s product, which today is known as DB2. There are many commercially available RDBMS products on the market. But only one is the dominant and unquestioned leader in the field: Oracle. Oracle Is the Market Leader The Oracle relational database management system (RDBMS) is the preeminent data management platform in use throughout the world today. It is the most reliable, comprehensive, robust, scalable, extensible, secure, and dynamic system for managing any amount of information, in any form, on any platform, for any number of end users, in any implementation of business rules available today. Its dominant market share is clear evidence that the marketplace recognizes the established and growing power and significance of Oracle and shows no sign of reversing this trend. Do we have to elaborate any more on this? Does anyone dare to disagree? I’m very tempted to quote Marvel Comics legend Stan Lee with his signature “’nuff said!” And yet . . . there really is so much more to say here. I think it’s fair to say that a lot of people in the world of technology, finance, and American culture see Microsoft as the number one software maker in the world. Part of the reason is that Bill Gates, the founder of Microsoft, has been the richest man in the world for quite some time now. Not too far behind him, though, is Larry Ellison, the legendary founder of the Oracle Corporation, a company that is often considered the second largest software maker in the world. 22 Chapter 1: Introduction to SQL None of this is probably new to you, but consider this: Microsoft is behind a wide array of products: the operating system, integrated office software suites, a variety of development tools, games for your PC, the Xbox line, even the MSNBC cable news channel and web site, which is their joint venture with NBC. Oracle Corporation, on the other hand, is built on the foundation of their flagship database product and the complement of tools that support it. That’s really about it. In other words, you could argue that Oracle is the world’s number two software company on the strength of what is really just one product, and its associated tools. It’s an amazing testament to the significant position in the world today that’s held by the Oracle RDBMS. Two of the leading competitors to Oracle’s RDBMS are Microsoft SQL Server, and IBM’s DB2. Both are respectable products. But Microsoft’s database only runs on the Microsoft operating systems. It doesn’t run on Linux or Unix or other platforms. DB2, on the other hand, does run on multiple platforms and offers some competition to Oracle, but as evidenced by market share, Oracle is still seen as an overall superior product in terms of interoperability, ease of maintenance, integration with other tools, and more. Since its inception, Oracle Corporation has grown quite dramatically, with no end in sight. Through corporate acquisitions, many of the leading industry commercial application products, such as PeopleSoft, J.D. Edwards, Hyperion, and other products—that started with other companies—are now part of the Oracle family. The annual Oracle Open World conference, once a gathering of a few thousand technical developers, has exploded into a gargantuan event featuring several tens of thousands of attendees from every industry imaginable. But each of these acquisitions, and all of Oracle’s tools, have one feature in common: their dependence on, use of, or relationship to the core product of the company, which to this day is still the Oracle RDBMS. Oracle Corporation used to be fond of reminding Open World attendees that 99 of the top 100 revenuegenerating web sites were all built on the Oracle database: Amazon, eBay, Google, Dell, the list goes on and on—all relying on Oracle databases. (One exception: IBM, whose online order processing system uses DB2.) You may be asking yourself: where is Microsoft Access in relationship to Oracle? The answer is simple: it doesn’t have memory management capabilities comparable to Oracle, and is not capable of “scaling up” well, meaning that you cannot easily add large numbers of end users to a given application on an instance of Microsoft Access. Understand the Oracle RDBMS and Oracle SQL 23 Certification: Oracle SQL Versus ANSI SQL The certification exam will test you for Oracle SQL. Oracle SQL is close to, but not identical to, the standard established for SQL by the American National Standards Institute, also known as ANSI standard SQL. You will not be required to know the differences between them. There’s a lot more I could say here, but it’s not relevant to the exam, so let’s move on. Certification: Oracle SQL Versus Oracle SQL*Plus The certification exam will test you for Oracle SQL, but not for Oracle’s enhancements to SQL known as SQL*Plus. Note, however, that SQL*Plus is a set of commands, and it’s also a software tool with an interface into which you can type SQL and SQL*Plus commands and monitor their execution. You won’t be studying SQL*Plus commands in this book, but we will use the SQL*Plus Command Line Interface from time to time to demonstrate Oracle SQL commands. Oracle’s Tools for Working with SQL Most of Oracle’s various products and tools, such as Oracle Financials, Oracle Project, and others, all use SQL. Many development tools, such as Oracle JDeveloper, provide the ability to enter SQL statements and execute them. Two of the most commonly used tools for this purpose are the SQL*Plus Command Line Interface and SQL Developer. The SQL*Plus Command Line Interface The SQL*Plus command line interface is a simple way to type SQL commands, execute them, and observe the result. It’s a universal system that operates the same way in every operating system. See Figure 1-4 for an example of what the command line interface looks like. The advantage to the command line interface is that it functions identically in Windows, Unix, and Linux operating systems. That’s one of the many advantages that Oracle has always offered—ease of use in any operating system. 24 Chapter 1: Introduction to SQL Figure 1-4 The SQL*Plus command line interface SQL Developer The SQL Developer interface is a GUI-style interactive point-and-click menudriven interface that’s very powerful and gives the developer a quick overview of the entire database. Some commands may be entered by either typing them in or using point-and-click-style interaction with a graphic menu. See Figure 1-5 for an example of what SQL Developer looks like. Figure 1-5 The SQL Developer tool Understand the Oracle RDBMS and Oracle SQL 25 There are other tools that process SQL statements: n Oracle JDeveloper n Oracle Application Express n SQL Workshop n . . . and others For purposes of the certification exam, your choice of interface is irrelevant. SQL statements execute correctly in all Oracle interfaces. The exam will test for your knowledge of the syntax of SQL, not your ability to point and click your way through a GUI. In other words, the fact that you might be able to create a SQL table using a code generator through a point-andclick interface will not help you during the exam. Furthermore, if you are a serious applications architect / programmer, there will eventually come a time—probably frequently—when you need to design and/or program such a feature as part of a larger application, and design and embed SQL code into other programming languages that have no access to the nice GUI tools during application run time. Furthermore, as we’ll see in numerous instances in this book, there are many types of SQL statements in which you can combine features and clauses in such a way that they appear to be correct, execute without error, and produce lots of output—all of which can be totally erroneous. A trained eye glancing at the SQL code will recognize the mistake; an untrained eye will not even realize there is a problem. In other words: there is no substitution for comprehensive knowledge of the syntax of SQL, neither in the world of the serious software developer, nor on the certification exam. Know your syntax. As you study for this exam, type your commands and make sure they are done correctly. Oracle’s Documentation for SQL Oracle Corporation offers a wealth of documentation at its web site, particularly through the Oracle Technology Network, accessible at http://otn.oracle.com. The amount of documentation is almost overwhelming, particularly to a newcomer. 26 Chapter 1: Introduction to SQL But one volume in particular is of interest to us for the purpose of the certification exam, and that volume is the SQL Language Reference Manual. It is a huge book, at close to 1,500 pages long. The size of the PDF version is 22MB. Its syntax charts are complex and go far beyond the needs of the exam. The book contains far more information than what you’ll need to pass, all of which is yet another reason why you’re brilliant to have obtained this book you now have in your hands. I will refer to the SQL Language Reference Manual from time to time, but I will only focus on the parts that are relevant to pass the exam. Other useful references of relevance to this book and the exam include Oracle’s Advanced Application Developer’s Guide, Concepts, Security Guide, Globalization Support, and the Administrator’s Guide. We will refer to the set of manuals for the Oracle database version 11g, Release 1, which is to say version 11.1. The questions for exam 047 have been tested against database versions 10g and 11g. Certification Objective 1.05 Understand the Unique Role of SQL in Modern Software Systems By becoming a certified expert in Oracle SQL, you’re establishing yourself in a very unique position in the world of software systems. Go back and look at the demand for different skills over the past few decades, and you’ll see that the demand for many different computer professionals with other skill sets has spiked and fallen. But SQL has always been in steady demand for as long as it has existed. There’s a reason for that. We’ll consider two in the next sections. SQL Is a 4GL SQL is unusual in the world of computer languages, in that it is arguably the most successful and widely used fourth-generation language, or 4GL. The term “generations” is used in describing computer languages to help to identify where a particular computer language falls on the spectrum of computer languages (see Figure 1-6) between the ones and zeros that a computer speaks versus the plain English or whatever other human language is spoken by the people who use the database. Take a look at Table 1-4. Understand the Unique Role of SQL in Modern Software Systems Figure 1-6 1GL Language spectrum 1010 0111 0110 1010 0011 Table 1-4 Generations of Computer Languages 2GL Assembly language 3GL Java PHP C++ FORTRAN COBOL … etc.… 27 4GL SQL English Generation of Computer Languages Examples Code Sample First Machine code 0011011010 Second Assembly language MV R1 R2 Third FORTRAN, COBOL, C, C++, Java, PHP, Perl, etc. IF TRUE THEN ... END IF; Fourth SQL, assorted artificial intelligence languages SELECT FIRST_NAME FROM EMPLOYEES; A first-generation language (or 1GL) is really just one single language: machine language, which is made up of the ones and zeros that computers use to communicate. All computers speak in some form of machine language, all the time. You can write a program in machine language, and if you’ve been around long enough, perhaps you have. But it’s tedious. Second-generation languages (2GLs) include “assembly language”, which is still very detailed and tedious, albeit an improvement over machine language. For example, when writing assembly code, you don’t just write a command to add two numbers together—instead, you write code that identifies which register in the computer’s central processing unit (CPU) contains the first number, and which register contains the second number, then invoke a command to perform the arithmetic and store the result in a third location. In assembly language, the programmer is obligated to deal with very low levels of detail within the computer’s hardware to perform relatively common coding tasks. Assembly language is a bit easier to code than machine language, but not much—it’s still rather tedious and not much more efficient than machine language. 28 Chapter 1: Introduction to SQL Third-generation languages (3GLs) are a significant improvement over machine or assembly language, in that their language syntax is much easier to understand for most software developers, relatively speaking. 3GLs include common language features such as variables and constants, “IF THEN ELSE” constructs, loops, error handling, and more. Most of the computer languages in common use today are 3GLs—for example, languages such as Java, C++, and PHP are in this category. The programmer still must code according to the syntax rules of the language, and eventually that code is translated to machine code for the computer to actually execute. But the coding process is far more productive. The general idea with each generational step away from machine language is to try to get closer to the point where plain spoken human language will be sufficient to program a computer. Whether that goal will ever be fully realized is a subject for another book, but the point here is that the higher the GL number, the closer the language used by the programmer is to human language, and the further away it is from machine language. So it’s interesting to note that all common software languages in general use today are no higher than the third generation, with one exception: SQL. SQL is unusual in that it is categorized as a fourth generation language, or 4GL. It is the only widely used 4GL in commercial use today. (Other 4GLs include artificial intelligence languages.) As a 4GL, it’s theoretically closer to human language than any 3GL. This is good, in that it is more powerful and enables SQL developers to do more work with fewer commands. But it’s also tricky, in the sense that this increased power makes it possible to make huge mistakes at a larger degree than a typical 3GL might allow. In other words, a 4GL carries with it the inherent obligation that its practitioner be well trained, and thoroughly knowledgeable of its power. SQL: Gateway to the RDBMS for All Other Languages When an application is said to be compatible with a database like Oracle, then you can be assured of one fact: there’s SQL code in that application. The overall application may be written in something else—like Java or C++. But the code that interacts with the Oracle database will be written in SQL. SQL is the only language that can talk directly to a SQL RDBMS, such as Oracle, from within any other software system, such as a front-end application, or a web service, or even another database. (I’m making the distinction of a “SQL RDBMS” because there are some RDBMS products out there that are not SQL compliant. But the vast majority are SQL compliant.) While any software developer today Understand the Unique Role of SQL in Modern Software Systems 29 has a wide variety of tools and languages from which to choose when developing an application, there’s only one choice when it comes to database interaction, and that’s SQL. “But,” you might say, “I have this friend who wrote a database program in Java.” And you probably do. But I guarantee you that embedded somewhere in that application is SQL. “But,” you might say, “I read that Oracle has this other language called PL/SQL for writing applications.” And they do. But part of the PL/SQL language syntax is SQL code. Thus the name—“Procedural Language / SQL”. So no matter what language you choose to create an application, if that application is going to converse with an RDBMS—and most serious commercial and government applications will require some sort of RDBMS—then regardless of the language of your application, you’ll still end up using SQL to interact with the database. For an illustration, see Figure 1-7. So how many applications require the use of a database? One might argue that virtually all do. Given that, here’s a question that won’t be on the test; this is just between us. Here it is: which of the following answers best describes a typical database? A typical database tends to A. Shrink in size B. Stay the same size C. Grow in size What do you think the answer is? I’m not sure there’s any empirical evidence to back me up on this, but I should think common sense would tell us all that databases tend to grow, and often grow dramatically, all the time, ad infinitum. Figure 1-7 Java All 3GLs use SQL to communicate with the RDBMS. SQL C++ Any 3GL PHP RDBMS 30 Chapter 1: Introduction to SQL The result: SQL has never gone “out of style” as many other languages have. Demand for other languages ebbs and wanes, but the demand for skilled SQL professionals has been persistently high ever since the early 1980s. Syntax Isn’t Enough SQL is a deceptively tricky language. It’s not a language where a rookie programmer can “try stuff until it works”. Sure, that rookie might get some output, but is it the output that the query intended? And if it is correct today, will it be correct tomorrow? One reason SQL is so tricky is the dynamic nature of the database. It’s entirely possible to test a completed SQL script against a given database, testing against every single available record in the database at a given moment in time, and for that script to pass successfully—and yet for the script to suddenly stop working correctly some time later, with no apparent warning. The reason has to do with the nature of databases. Databases aren’t static. They change and grow with use over time. It’s not enough to test your SQL scripts against existing data or sample data—you must structure your database and write your SQL code with a confident and thorough understanding of all the possible data combinations that might exist now or in the future. This cannot be accomplished with trial and error. You have to have a comprehensive command of all of SQL’s capabilities, and apply that thorough understanding to whatever business task you are facing. Anything short of that runs the risk of creating an erroneous program at best, and an unmitigated disaster at worst. Several years ago I was brought in to clean up a database that was in use at a particular military installation. The problem: a few months before my arrival, someone very high up in the military had demanded to know how much money was being spent on a particular task. The directive went out to whoever could identify the answer. Three different not-quite-as-high-up people took on the task, and eventually all three sent inquiries to this particular installation to get the answer from the one SQL database that existed on the project. The trouble occurred when each of the three incoming requests ended up on the desks of three different SQL programmers at the installation. Each SQL programmer, unaware of the others, created a SELECT statement that he or she thought would produce the answer. Each SQL programmer created a syntactically correct report, but all were logically incorrect—they each produced a totally different number. One number was three times the amount of another. Not one was correct. When all three numbers arrived at the desk of the requesting authority, it created quite an uproar—this was a Confirm Appropriate Materials for Study 31 rather visible project politically. Needless to say, the project was embarrassed, and eventually I was brought in to help clean up the system and prevent such problems from occurring in the future. But the database system was fine. The problem was a lack of proper understanding on the part of those developers about how the database was structured, and—in this particular case—of how SQL’s aggregate functions worked when joining multiple tables in the context of a GROUP BY clause. So the resulting numbers were all wrong— but hey, the SELECT statement returned an answer, didn’t it? So that means it worked, right? Unfortunately, no. One common theme on The moral to the story: a successful SQL the exam is to present you with a business statement is not one that merely executes case, then a series of SQL statements, without producing an error message. It’s one and then ask you if the SQL statements that executes and produces the intended result, will produce the intended result. In other both now and—equally important, perhaps words, the question will not be about dramatically more important—in the future, as syntax.The assumption will be that the new data is added to the system. code is correct. But does it match the There is no way to confidently produce business case? You’ll need to recognize the such SQL without having a comprehensive complexities of the SQL language in that understanding of SQL, the sort of situation to determine if the code, which comprehensive understanding for which this will be syntactically correct, is logically certification exam tests. Testing your scripts accurate. against sample data won’t do the trick by itself. Databases change over time. New records are added, and existing records might be changed or removed. What works today might not produce the same logical result tomorrow. There is no substitute for you, the SQL professional, developing and maintaining a mastery of SQL. Certification Objective 1.06 Confirm Appropriate Materials for Study This section lists some items you may want to gather as you prepare to study for the exam. If you are a seasoned veteran in the Oracle business, you may not need any of it—this book will suffice. But if you’d like to put forth that extra bit of effort, it 32 Chapter 1: Introduction to SQL might be a good idea to get your software and documentation together as listed in this section. Software Oracle Corporation states that they have validated the 1Z0-047 exam questions against Oracle database versions 10g and 11g. In other words, you can practice with either version; so either way, you’ll be prepared for the exam. (Note: I used version 11g, Release 1, in preparing the SQL statements for this book.) If you don’t have the software you need, you can download it from the official Oracle Corporation web site, at www.oracle.com. If you haven’t joined the Oracle Technology Network, then you should do it right away.There’s no charge for it. Visit http://otn.oracle.com and sign up today. From there, you can download a great deal of Oracle software for evaluation and study, including the database itself. If you install the personal version of Oracle, you’ll probably get SQL*Plus and SQL Developer, either of which you can use for entering and executing SQL statements. You’ll need one or both of those, or if not them, then some sort of tool for entering and executing SQL commands. Chances are you already have something that you’re using anyway, or else you probably wouldn’t be considering certification. Documentation The book you have in your hands is an outstanding reference and is all you need in the way of documentation. This book is the single best guide you could possibly get to prepare you for taking the exam. But if you crave more documentation, you can download additional documentation from Oracle’s OTN website. Remember that the exam has been tested for versions 10g and 11g of the database. I used 11g, Release 1 for this book. There is a set of documentation for each version. Any one version will do—you may as well get the latest version if you choose to download documentation. The SQL Language Reference Manual is Oracle’s “bible” of SQL language syntax. It’s good to have on hand as a matter of practice, and to reference from time to time as we cover features about which you may have additional questions. As a study Confirm Appropriate Materials for Study 33 guide for the exam, however, it’s overkill: the detail goes far, far beyond the exam requirements and would be extremely difficult to use as a primary study reference. Anyone attempting to use that book alone as a guide for the exam will quickly realize it would be extremely difficult and incredibly time consuming. The manual addresses all aspects of language syntax, whereas the exam does not. So the best thing you can do is to use this book to guide you through your exam preparation. From time to time in this book, I’ll make reference to the SQL Language Reference Manual. You won’t need it. But some readers may prefer to download a copy to have on hand for further study and exploration of the SQL language. Like many of Oracle’s certification exams, the 1Z0-047 exam includes many multiple-choice questions that have more than one correct answer. In other words, a single question will require you to “select all of the following answers that are correct”.The result: you must evaluate each individual answer. Once you find a correct answer, you aren’t done— you have to continue checking them all. In other words, on these types of questions you can’t rule out any of the answers based on the process of elimination, since all answers are possible candidates for being correct. One question in this format is really more like several questions rolled into one.The result is a more demanding test that requires you to be more knowledgeable, and requires more of your time to answer. So study well. Review this book thoroughly.This is not a simple exam. But you can do it—equipped with this book, your odds of success increase dramatically. Recently, Oracle began publishing an e-magazine called Oracle Certification E-Magazine, and it’s available at no charge from the Oracle web site. At the time of this writing, you can find it quickly if you take these steps: n Visit www.oracle.com. n Use the upper-right corner pair of “search” boxes. n Enter the keywords ORACLE CERTIFICATION EMAGAZINE. n Choose Education in the pop-up list. n Click the magnifying glass to activate your search. 34 Chapter 1: Introduction to SQL This should list the link to the Oracle Certification Magazine’s summary page of current and past issues. From there, you can survey the latest and greatest information on any and all of Oracle’s certification programs. Certification Summary The relational database management system, or RDBMS, is a structure within which database programmers can build database objects to store data. Furthermore, the RDBMS comes with built-in support for many types of objects and features that are typically needed by the programmer to perform common steps, such as adding, modifying, and removing data from the database. The tool used by database programmers to communicate with the RDBMS and its objects is the Structured Query Language, which is commonly called SQL. SQL commands such as SELECT and CREATE object type are used by SQL programmers to build database objects, store data in them, modify that data, and more. SQL-based RDBMS products dominate the world of database products in use today. Oracle Corporation’s RDBMS has always been, and continues to be, the undisputed industry leader in the field of SQL-based RDBMS products. SQL is the single gateway through which all other languages must go to access any SQL-based RDBMS. Even if an application is written in another computer language, that language will contain embedded SQL statements to interact with any SQL-based RDBMS. Among all computer languages in use today, SQL is the only widely used fourth-generation language, or 4GL. This means it is a powerful language, but it’s also a tricky language to use. You can write commands that are syntactically correct and that execute successfully but are logically incorrect. Furthermore, the database changes over time and SQL code that appears to test correctly now—both syntactically and logically—may fail tomorrow, depending on how the data changes over time. It is imperative that the SQL programmer have a comprehensive command of the SQL language syntax to ensure proper functionality and avoid potential disaster. Two-Minute Drill 3 35 Two-Minute Drill The Exam: An Overview q This chapter provides introductory material that is important to understand in preparing for the exam. q The 1Z0-047 Oracle Database SQL Expert exam, which is the subject of this exam guide, has 19 certification objective categories, of which ten are common to another exam, 1Z0-051 SQL Fundamentals I. While 1Z0-047 tests for all 19 of its categories, the exam tends to emphasize the nine areas that are unique to 1Z0-047 and not addressed on 1Z0-051. q The exam includes 70 questions and allows 120 minutes to complete them. That’s an average of less than two minutes per question. Define and Understand the Basics of the RDBMS q A relational database consists of collections of data known as tables. A table could be a list of ship names and some statistics about each ship. Another table might be a list of employees who work on different ships. The “relational” aspect to a “relational database” has to do with the common information that “relates” two tables together—for example, the list of employees might include an entry for each employee’s ship assignment, which would relate back to the list of ships and each ship’s statistics. q A relational database management system, or RDBMS, is a system in which these relational tables and related objects can be created easily, using common functions to add, change, and remove data and database objects from the RDBMS. Define and Understand the Basics of SQL q The Structured Query Language, or SQL, is the language used by program- mers to interact with an RDBMS. q SQL statements can be used to create, alter, and drop database objects, such as tables. q SQL statements can add, change, and remove data from tables and other database objects. 36 Chapter 1: Introduction to SQL Understand the Oracle RDBMS and Oracle SQL q Oracle Corporation released the first commercial RDBMS product. Today, Oracle is the industry leader in the RDBMS market. q The American National Standards Institute publishes a set of industry- r ecognized standards for SQL. Oracle’s implementation of SQL largely matches the ANSI standard but isn’t 100 percent compliant. Oracle’s competition is not fully compliant either. q Oracle’s SQL*Plus command line interface is a great tool for entering and executing SQL commands from within any operating system platform. q Oracle’s SQL Developer tool is a great GUI for entering and executing SQL commands from within the Windows operating system. q The SQL Language Reference Manual is Oracle’s nearly 1,500-page manual that describes the Oracle implementation of the SQL language. Understand the Unique Role of SQL in Modern Software Systems q SQL is most widely used fourth-generation language (4GL) in commercial use today. q SQL is the only language for interacting with the RDBMS. Any other programming language must use embedded SQL calls to interact with the RDBMS. q The constantly changing nature of databases makes them a tricky place to test software. If a SQL script is written and tested successfully today, it’s entirely possible that it may break down and produce erroneous information later on. The solution is that the script must not only be tested, but must originally be designed and written by a capable SQL developer who understands proper database design and is thoroughly versed in the RDBMS and SQL syntax. q The 1Z0-047 has been validated against Oracle database versions 10g and 11g, so using either to prepare for the exam will be satisfactory. Two-Minute Drill 37 Confirm Appropriate Materials for Study q This book will prepare you to study and successfully take and pass the exam. q Oracle’s SQL Language Reference Manual is overkill as an exam study guide, as it contains far more than you’ll need for the exam. But it’s a good reference companion to this book. q Oracle has recently published an online magazine with the latest news and developments about Oracle’s complete line of certification exams covering all of Oracle’s products. 38 Chapter 1: Introduction to SQL Self Test The following questions will help you measure your understanding of the material presented in this chapter. While this particular material is not specifically addressed in the exam, an understanding of this material is assumed on the part of anyone studying for and taking the certification exam. Furthermore, these questions are written in the style and format of the certification exam, so it can be good practice to help you get going. As is the case with the exam, some of these self test questions may have more than one correct answer, so read carefully. Choose all the correct answers for each question. The Exam: An Overview 1. Which of the following topics are not included in the SQL Fundamentals I exam but are addressed on the SQL Expert exam? (Choose all that apply.) A. CUBE B. Hierarchical retrieval C. FLASHBACK D. External tables 2. If you target the specific passing grade requirement of the exam, you can study more efficiently. A. True B. False Define and Understand the Basics of the RDBMS 3. A database system is “relational” if it does which of the following? (Choose all that apply.) A. Includes “keys” to relate records in one table to records in another table. B. Uses SQL. C. Stores data. D. All databases are “relational”. 4. The most commonly used form of database normalization for transaction-based applications is which of the following? A. 1NF B. 2NF C. 3NF D. None of the above Self Test 39 5. A table consists of (choose the single best answer): A. Names and statements B. Rows and columns C. Relations D. Keywords Define and Understand the Basics of SQL 6. The language used to create objects in an Oracle database is called: A. RDBMS B. SQL C. Oracle D. CREATE 7. Which of the following SQL statements is used to remove a database object, such as a table, from the database? A. REMOVE B. DROP C. KILL D. DELETE Understand the Oracle RDBMS and Oracle SQL 8. Choose all of the following statements that are true: A. There’s only one right way to design any and every database. B. Oracle is the only manufacturer of SQL-compliant databases. C. SQL can be used to add data to a table, but not change it. D. SQL can be used to add data to a table, and also to change that data. 9. Which of the following tools can be used to execute SQL statements against the database? (Choose all that apply.) A. SQL Developer B. The SQL Language Reference Manual C. The SQL*Plus command line interface D. None of the above 40 Chapter 1: Introduction to SQL 10. What can be said of the SQL*Plus command line interface? (Choose all that apply.) A. It is an ANSI-standard tool for executing SQL commands in the database. B. It can be used to format report output in ways that pure SQL cannot do. C. It only runs in Windows. D. It was created by Microsoft to try to steal market share from Oracle Corporation. 11. Which of the following statements are true? (Choose all that apply.) A. Almost all medium- to large-size government agencies, companies, and nonprofits depend on data to stay in business. B. Oracle was the first commercial RDBMS product on the market. C. Oracle is the leading commercial RDBMS on the market today. D. Most revenue-generating web sites depend on the Oracle RDBMS for storing data. Understand the Unique Role of SQL in Modern Software Systems 12. Which of the following statements about SQL are true? (Choose all that apply.) A. A given SQL statement will always produce the same answer, no matter when the statement is executed. B. It is not the only choice for communicating with a SQL RDBMS, but it is the best choice. C. SQL is a fourth-generation language (4GL). D. All commercial implementations of SQL are 100 percent ANSI standard. 13. You can be sure that a SQL SELECT statement is performing as intended if it executes without producing an error message. A. True B. False 14. You can be sure that a SQL SELECT statement is performing as intended if it executes and returns data from the database. A. True B. False 15. You can be sure that a SQL statement is performing as intended if it executes and doesn’t change any data. A. True B. False Self Test 41 Confirm Appropriate Materials for Study 16. The 1Z0-047 exam (which is the subject of this book) has been officially validated by Oracle Corporation against which of the following versions of the Oracle database? (Choose all that apply.) A. Every version B. 9i C. 10g D. 11g 17. The best exam guide you could possibly get for preparing to take and pass the “1Z0-047 SQL Expert” certification exam is which of the following? (Choose all that apply.) A. This book B. The book you are holding right now C. This here book D. Don’t make me tell you again 42 Chapter 1: Introduction to SQL Self Test Answers The Exam: An Overview 1. ˛ A, B, C, and D. See Table 1-1 for a full listing of all the topics included in either or both of the exams. 2. ˛ B is correct. Although, granted, it’s a subjective issue, but Oracle Corporation specifically warns against this. The reason: the published minimum requirement for a passing score can be changed without notice. Define and Understand the Basics of the RDBMS 3. ˛ A and B. SQL can only be used with an RDBMS. And the “keys” in an RDBMS are the feature that makes a relational database “relational”. ˝ C and D are incorrect. It’s not true that all databases are “relational”; some are simple flat file databases, and other forms exist as well. 4. ˛ C. Third normal form is not the only form that’s used, but it’s the most common for transactional applications. ˝ A, B, and D are incorrect. First and second normal forms, while not totally unheard of in professional applications, are generally considered poor design and introduce potential problems in many transaction-based database application scenarios. 5. ˛ B. Tables consist of rows of data stored in columns. Data is added to a table in rows. Note: technically, if the table happens to be empty, one might argue that there’s no data in it. Nevertheless, Oracle documentation often speaks of tables consisting of rows and columns, so we do as well. ˝ A, C, and D are incorrect. Tables have names, it’s true, as do a table’s columns, but “names” do not singularly form a table’s structure. Statements are used to work with tables, not reside in them. Theoretically you could type a statement as text and store it in table, but then the table would see the result as data, and not a statement per se. Tables may optionally relate to other tables, but it’s not required. Keywords represent many features throughout the database and in any programming language; they have no unique relationship to a table’s structure. Define and Understand the Basics of SQL 6. ˛ B. SQL is the only language that interacts with the database. ˝ A, C, and D are incorrect. The RDBMS is not the language, but the type of system in which the language operates. Oracle is the brand name of the particular RDBMS product from Self Test Answers 43 Oracle Corporation. CREATE is one example of a SQL statement, but not a reference to the language itself. 7. ˛ B. The correct SQL statement is DROP, as in DROP TABLE SHIPS. ˝ A, C, and D are incorrect. REMOVE is not a SQL statement. DELETE is used to remove records from an existing table, but it leaves the table’s structure intact, as well as any data not referenced by the DELETE statement. There is no KILL statement in SQL. Understand the Oracle RDBMS and Oracle SQL 8. ˛ D. SQL can be used to create tables, to add data to tables, to modify that data, to remove that data, to remove the table from the database altogether, and more. ˝ A, B, and C are incorrect. There can be many good ways to design a database; there might be many reasons why a database design would change. Oracle is not the only maker of SQL-compliant databases—other vendors include IBM and Microsoft. And SQL can be used to change data. 9. ˛ A and C. The SQL Developer tool is a Windows-based interface, and the SQL*Plus command line interface works in any operating system. ˝ B and D are incorrect. The SQL Language Reference Manual is very helpful, but it is just a book, nothing more. 10. ˛ B. It provides enhancements to ANSI-standard SQL to support features not provided by the ANSI standard. Among those enhancements is formatting for report output. ˝ A, C, and D are incorrect. SQL*Plus is not ANSI standard. It runs in any operating system. And it’s an Oracle product. 11. ˛ A, B, C, and D. These are all correct. Understand the Unique Role of SQL in Modern Software Systems 12. ˛ C. SQL is a 4GL. ˝ A, B, and D are incorrect. SQL statements will not necessarily produce the same answer every time. One reason is that the database is dynamic, and as data is changed in the database, the SQL statement’s results will probably change as well. And SQL is the only choice for communicating with a SQL RDBMS. And it’s not true that commercial SQL implementations are all completely ANSI compliant—many are not, including Oracle. 13. ˛ B. The lack of an error message merely means that the statement’s syntax is correct. But the logic may be incorrect. An error message does not result from inaccurate logic in the statement. 44 Chapter 1: Introduction to SQL 14. ˛ B. The fact that a query returns data does not mean that the query is performing as intended. The data returned may be different from the desired response. 15. ˛ B. Some SQL statements, such as the UPDATE statement, are intended to change data. Confirm Appropriate Materials for Study 16. ˛ C and D. The test has been officially validated against these two versions of the database. ˝ A and B are incorrect. The exam tests for functionality that did not exist in earlier versions of the Oracle database. 17. ˛ A, B, C, and D. Duh. 2 Using DDL Statements to Create and Manage Tables Certification Objectives 2.01 Categorize the Main Database Objects 2.02 Create a Simple Table 2.03 Review the Table Structure 2.04 List the Data Types That Are Available for Columns 2.05 3 Q&A Explain How Constraints Are Created at the Time of Table Creation Two-Minute Drill Self Test 46 Chapter 2: Using DDL Statements to Create and Manage Tables T his chapter begins to examine the building blocks of a SQL database, which are the objects inside the database that programmers create to store the data that populates the database. Certification Objective 2.01 Categorize the Main Database Objects Database objects are the foundation of any database application. Database objects house and support everything any database application needs in order to form a working application. This section takes a high-level look at the database objects that can be created in an Oracle RDBMS, focusing on those objects that are tested on the exam. Here we will separate database objects into categories and discuss the relationship between objects and schemas. The rest of the book will delve into greater detail on each database object that is included in the exam. What Are Database Objects? There are many different types of database objects that can be created in the Oracle RDBMS. The exam looks at eight of those objects in great detail. The Complete List A database consists of one or more database objects. The following list shows objects that a database developer can create in the Oracle 11g RDBMS. Those marked with an asterisk are included on the exam. (Source: SQL Language Reference Manual.) Clusters Constraints* Contexts Database links Database triggers Dimensions Directories External procedure libraries Indexes* Index-organized tables Indextypes Java classes, etc. Materialized view logs Materialized views Mining models Object tables Object types Object views Categorize the Main Database Objects Operators Packages Profiles Restore points Roles* Rollback segments Sequences* 47 Stored functions/procedures Synonyms* Tables* Tablespaces Users* Views* Note that the exam doesn’t test for all of these objects. It ignores objects such as PL/SQL program units, Java program units, and objects that are of more interest to database administrators. We will only concern ourselves in this book with those database objects that are included in the exam. The types of database objects on the exam are listed here, in alphabetical order. Constraints Indexes Roles Sequences Synonyms Tables Users Views A Brief Description Let’s take a brief look at the types of objects that are the subject of the exam. A structure that can store data. All data is structured in columns and rows. Each column’s datatype is explicitly defined. n TABLE An object designed to speed up searches in a table. An INDEX performs much the same way as an index to a book, by copying a relatively small, select amount of information, sorting it for speedy reference, and tying it back to locations in the table for supporting quick lookups of rows in the source table. n INDEX A “filter” through which you can search a table, and interact with a table, but that stores no data itself, and simply serves as a “window” onto one or more tables. VIEW objects can be used to mask portions of the underlying table logic for various reasons—perhaps to simplify business logic, or perhaps to add a layer of security by hiding the real source of information. A VIEW can be used to display certain parts of a table, while hiding other parts of the same table. n VIEW A counter, often used to generate unique numbers as identifiers for new rows as they are added to a table. n SEQUENCE 48 Chapter 2: Using DDL Statements to Create and Manage Tables An alias for another object in the database, often used to specify an alternative name for a table or view. n SYNONYM A small bit of logic defined by you, to instruct a particular table about how it will accept, modify, or reject incoming data. n CONSTRAINT n USERS The “owners” of database objects. n ROLES A set of one or more privileges that can be granted to a user. We’ll review each of these objects in greater detail throughout the book. Next: each database object is considered to either be a “schema object”, or a “non-schema object”. Before we can make sense of that, we must first answer the question: what is a schema? Schemas This section describes schemas—what they are, and how they relate to database objects. What Is a Schema? A schema is a collection of certain database objects, such as tables, indexes, and views, all of which are owned by a user account. You can think of a “schema” as being the same thing as a user account, but there is a slight difference—the user account houses the objects owned by a user, and the schema is that set of objects housed therein. One definition of “schema” that you’ll often find in Oracle’s documentation—and elsewhere—is that a schema is a “logical collection of database objects”. Technically that’s true, but it depends on how logical the user chooses to be when building and placing those objects within his or her user account. Ideally there should be some sense to why all those objects are in there, and ideally a “schema” shouldn’t be just a random collection of objects, but the fact is that there is nothing built into the Oracle or SQL systems that prevents a user from doing just that— randomly collecting objects into a user account, and thus creating a “schema” of random objects. Ideally, though, a user account should be seen and used as a logical collection of database objects, driven by business rules, collected into one organized entity—the schema. A schema has the same name as the user account. Keep in mind, though, that it’s entirely possible to create a schema (i.e., a user account) whose “owner” isn’t a human being at all, but perhaps is an application process, or some other sort of virtual entity—perhaps a particular background process—or whatever makes sense Categorize the Main Database Objects 49 to suit the business rules that are in force. So in other words, one user will often have one user account, and therefore one schema. But the opposite isn’t necessarily true. There can be more user accounts than there are actual users. Now that you understand what a “schema” is, and what a user account is, we can begin to look at different types of database objects, some of which are owned by a user—and are thereby “schema” objects—and some of which are not schema objects but are still database objects nonetheless. Schema and Non-Schema Objects All database objects fall into one of two categories, or “types”. These “types”, as the Oracle documentation calls them, are “schema” and “non-schema”. All database objects are said to be either “schema” database objects or “non-schema” database objects. Table 2-1 shows the list of both “schema” and “non-schema” objects. “Schema” objects are those objects that can be owned by a user account. “Non-schema” objects cannot be owned by a user account. For example, the USER object is a non-schema object. Think about it—how can a user account own itself? It cannot, unless you live in a bizarre time warp or want to fracture your brain. Therefore the USER object, which is a user account, is a “non-schema” object, and is a property of the database as a whole. The same is true for ROLE objects. ROLE objects represent one or more privileges that can be granted to one or more USER objects. Therefore a ROLE inherently exists at a level outside of an individual USER account—and it’s therefore a “non-schema” object. A PUBLIC SYNONYM is a variation on the SYNONYM object that is owned by the special user account PUBLIC, whose owned objects are automatically available to the entire database by definition, as we’ll see later in Chapter 10. All other objects are “schema” objects—TABLE, INDEX, VIEW, and the others listed in Table 2-1. Table 2-1 Schema Objects Non-Schema Objects “Schema” and “Non-Schema” Database Objects Tables Constraints Indexes Views Sequences Private Synonyms Users Roles Public Synonyms 50 Chapter 2: Using DDL Statements to Create and Manage Tables Certification Objective 2.02 Create a Simple Table The exam expects you to be able to recognize the correct code to create a “simple” table. By “simple”, Oracle means that you’ll be required to define the table’s name, column names, datatypes, and any relevant constraints. To create a table, we use the SQL command CREATE TABLE. The word CREATE is a SQL reserved word that can be combined with just about any database object (but not all) to form a SQL command. The syntax for the “CREATE objectType” statement is shown in this code listing: CREATE objectType objectName attributes; where n objectType is an object listed in Table 2-1 (except for CONSTRAINT). n objectName is a name you specify according to the naming rules and guidelines described later in this chapter. n attributes is anywhere from zero to a series of clauses that are unique to each individual objectType, which we’ll review later. One of the most frequent usages of the SQL command CREATE is to create a TABLE. When we create a table, we’ll also create the table’s columns and optionally some associated objects. Let’s look at an example of a very basic CREATE TABLE statement. CREATE TABLE work_schedule (work_schedule_id NUMBER, start_date DATE, end_date DATE); If you were to execute this command in a schema that didn’t already have a table named “work_schedule” (that’s important), then you’d get the result shown in Figure 2-1. Create a Simple Table 51 Figure 2-1 Results of CREATE TABLE work_schedule statement Let’s analyze the syntax of the preceding example of a CREATE TABLE statement: n The reserved word CREATE n The reserved word TABLE n The name of the table, chosen by you, in accordance with the rules of naming objects, which we review next n A pair of parentheses, in which are a series of column declarations, each separated by a comma. Column declarations consist of: n The name of the column, chosen by you, in accordance with the rules of naming objects n The datatype of the column, taken from the list of available datatypes n A comma to separate each column definition from the next n A semicolon to end the statement, as is the case with all SQL statements In order to fully understand the syntax as just described, we need to examine two important issues: the rules of naming database objects and the list of available datatypes. Let’s look at naming rules next; after that we’ll look at datatypes. Naming a Table or Other Object Before we move on with the details of creating a table, let’s take a look at the rules for naming database objects. These rules apply to tables, views, indexes, and all database objects—including a table’s constraints, if any are created. The same naming rules also apply to a table’s columns. All tables have a name. Each table consists of one or more columns, and each column has a name. (For that matter, each database object in the database has its own name—each index, view, constraint, synonym, and object in the database has a name.) 52 Chapter 2: Using DDL Statements to Create and Manage Tables When you use the SQL keyword CREATE to create a database object, you must come up with a name and assign it to the object, and sometimes—as in the case of a table—to individual components within the object, such as the columns of a table. The rules of naming objects are identical for all of these objects and object components. In other words, these rules apply to names for tables, table columns, views—anything you must name in the database. Naming Rules—Basics The rules for naming tables, and any database object, include the following: n The length of the name must be at least one character, and no more than 30 characters. n The first character in a name must be a letter. n After the first letter, names may include letters, numbers, the dollar sign ($), the underscore (_), and the pound sign (#), also known as the hash mark or hash symbol. No other special characters are allowed anywhere in the name. n Names cannot be reserved words that are set aside for use in SQL statements, such as the reserved words SELECT, CREATE, etc. See the following complete list of reserved words from Oracle’s SQL Language Reference Manual. These words are off limits when you create names for your database objects. ACCESS ADD ALL ALTER AND ANY AS ASC AUDIT BETWEEN BY CHAR CHECK CLUSTER COLUMN COMMENT COMPRESS CONNECT CREATE CURRENT DATE DECIMAL DEFAULT DELETE DESC DISTINCT DROP ELSE EXCLUSIVE EXISTS FILE FLOAT FOR FROM GRANT GROUP HAVING IDENTIFIED IMMEDIATE IN INCREMENT INDEX INITIAL INSERT INTEGER INTERSECT INTO IS Create a Simple Table LEVEL LIKE LOCK LONG MAXEXTENTS MINUS MLSLABEL MODE MODIFY NOAUDIT NOCOMPRESS NOT NOWAIT NULL NUMBER OF OFFLINE ON ONLINE OPTION OR ORDER PCTFREE PRIOR PRIVILEGES PUBLIC RAW RENAME RESOURCE REVOKE ROW ROWID ROWNUM ROWS SELECT SESSION SET SHARE SIZE SMALLINT START SUCCESSFUL 53 SYNONYM SYSDATE TABLE THEN TO TRIGGER UID UNION UNIQUE UPDATE USER VALIDATE VALUES VARCHAR VARCHAR2 VIEW WHENEVER WHERE WITH These rules are absolute. If you attempt to create a table or any other database object with a name that violates these rules, the attempt will fail, you’ll receive an error code from the database, and your object will not exist. Case Sensitivity and Double Quotation Marks The basic rule for case sensitivity with regard to naming database objects is that database objects are case insensitive and will be treated as though they are typed in uppercase letters. This is generally true—but there is an exception, and it depends on whether you use double quotation marks when you create an object. Here are the rules: n If a name is not enclosed in double quotation marks when it is created, then it will be treated as uppercase regardless of how it is created or referenced. n If a name is enclosed in double quotation marks, then it is case sensitive and must always be referenced with case sensitivity and with double quotation marks. 54 Chapter 2: Using DDL Statements to Create and Manage Tables For example, consider the following CREATE TABLE statement: CREATE TABLE ports (port_id NUMBER, port_name VARCHAR2(20)); In this example, you see a valid SQL statement to create a table. The table name is “ports”, and in this example, the word “ports” is entered in lowercase letters. The database will automatically convert your lowercase letters into uppercase, and you’ll end up with an object called PORTS The object will be stored inside the database using uppercase letters, something we’ll be able to confirm once we look at the data dictionary in a future chapter. For now, it’s important to note that any future references to this newly created object “ports” in your SQL statements will be acceptable in either upper- or lowercase letters, and the database won’t care how you reference it. For example, both SELECT * FROM ports; and SELECT * FROM PORTS; are valid SELECT statements, and both will work just fine, even though the name is stored internally in the database in uppercase letters. However, the same is not true if you create the object using double quotation marks. Consider this valid CREATE TABLE statement: CREATE TABLE "ports" (port_id NUMBER, port_name VARCHAR2(20)); The use of double quotation marks here will cause the database to store the object name exactly as you present it within the double quotation marks, which, in this example, is using lowercase letters. The result: the database object name “ports” will be stored inside the database in lowercase letters: ports Furthermore, every future reference will require both double quotation marks and a case-sensitive reference to this database object. For example, this will work: SELECT * FROM "ports"; Create a Simple Table 55 But this will not work: SELECT * FROM "PORTS"; This will not work either: SELECT * FROM ports; But wait, there’s more! By using double quotation marks, you can also include special characters that are otherwise not allowed—such as spaces. For example, this will work: CREATE TABLE "Company Employees" (employee_id NUMBER, name VARCHAR2(35)); But remember that to refer to the table later, you’ll still need those double quotation marks, like this: SELECT * FROM "Company Employees"; In other words, by using double quotation marks, you can specify database object names that go beyond the standard naming rules of Oracle objects. But if you do this, you will always need to use double quotation marks in every future reference to that object, and you’ll have to be specific with regard to the case of your object name. On a practical level, you may not ever require this. Generally, most database objects are created without the use of double quotation marks in the name. But it’s important to know the full functionality of this particular feature of the database in case it happens to come up sometime. Just sayin’. Unique Names and Namespaces So what happens if you try to create a database object with a name that matches the name of another database object that’s already in the database? Can you do it? What happens to the existing database object? Will you be able to use the resulting database object? The answer is that it depends on your object’s relationship to that other object that already exists, and also to something called the “namespace”. The namespace is a logical boundary within the database that encompasses a particular set of database objects. There are actually several namespaces at work at any given time, depending on the context in which you are working. Understanding the namespace is necessary in order to understand whether you may or may not specify duplicate names for any particular database object. See Figure 2-2 for a diagram that demonstrates the namespace boundaries. Note 56 Chapter 2: Figure 2-2 Diagram of namespace boundaries Using DDL Statements to Create and Manage Tables namespace Users Roles Public Synonyms namespace namespace Tables Views Sequences Private Synonyms User-Defined Types Tables Views Sequences Private Synonyms User-Defined Types namespace namespace Indexes Indexes namespace namespace Constraints Constraints Schema_1 Schema_2 Database that each square encloses a different namespace. In Figure 2-2, there are several namespaces identified: n USER, ROLE, and PUBLIC SYNONYM objects are in their own collective namespace. n TABLE, VIEW, SEQUENCE, PRIVATE SYNONYM, and user-defined TYPE objects have their own unique namespace within a given schema. n INDEX objects have their own namespace within a given schema. n CONSTRAINT objects have their own namespace within a given schema. (Note: we haven’t mentioned user-defined types. They aren’t on the exam. We include them in this discussion to be complete, but you won’t need to understand them for the exam.) What all of this means is that you must provide unique names for an object within its own namespace. Objects that share a namespace must have unique names within that namespace. Objects in different namespaces are allowed to have identical names. Here are some examples: Create a Simple Table 57 n If you create a table in one schema called WORK_SCHEDULE, then you cannot create another table called WORK_SCHEDULE within that same schema. But you can do it in another schema, provided there isn’t already a WORK_SCHEDULE in that schema. n Let’s say you have a schema called HR. (As in Human Resources.) In the HR schema, you can create a table called, say, PAYROLL. You cannot create a VIEW in that same schema called PAYROLL. But you could create an INDEX called PAYROLL. You could also create a CONSTRAINT called PAYROLL. But you could not create a SEQUENCE called PAYROLL. n In the entire database, each USER object must have a unique name. So must each ROLE object. One thing to note: later we’ll see that you can create a TABLE and give it a primary key CONSTRAINT. If you do this, you’ll have the option of naming that CONSTRAINT. If you do, the system will automatically create an INDEX for the CONSTRAINT, and it will name the INDEX with the same name as the CONSTRAINT. You can override this and assign your own name with the USING INDEX clause of the CREATE TABLE statement, something we’ll see later. When naming objects, choose descriptive names that can be pronounced. Be consistent: if your tables of EMPLOYEES, CUSTOMERS, and VENDORS each include a reference to a person’s name, make those column names all the same—NAME, LAST_NAME and FIRST_NAME, whatever—just be consistent. Consider using a standard prefix for every database object that’s associated with a particular application—for example, for a Human Resources application, prefix each table with “HR_”—but avoid using prefixes that Oracle Corporation uses for its system-defined objects: “SYS_”, “ALL_”, “DBA_”, “GV$”, “NLS_”, “ROLE_”, “USER_”, and “V$”. System-Assigned Names You’ll see a bit later that you may create an object indirectly. This happens, for example, when you create a table, and within the CREATE TABLE statement you optionally define an associated constraint, but without providing a name for the CONSTRAINT. The language syntax of the CREATE TABLE statement allows this to happen, as you’ll soon see, and the result is not only your newly created—and named—table, but also a newly created constraint for that table. Some developers refer to these constraints as “anonymous”, but they aren’t anonymous at all—the 58 Chapter 2: Using DDL Statements to Create and Manage Tables system will automatically generate a name for that constraint, a name that adheres to all the rules that we just reviewed. However, system-defined names probably won’t adhere to the naming guidelines we just reviewed. They’ll adhere to the rules, yes. But they most assuredly will not adhere to the guidelines. Those guidelines are recommendations that Oracle makes to you, the developer. And as you can probably tell if you reflect on it a little, it won’t be possible for the system to automatically generate a name that is, for example, pronounceable and meaningful to your application. Therefore it’s good design to avoid the indirect creation of automatically generated names wherever possible. That’s a roundabout way of saying: be sure to name all of the database objects you create, including CONSTRAINTS, INDEXES, and others. However, in order to make sure you name everything, you’ll need to know when and how all objects are created, directly and indirectly. We’ll review those features throughout the book as we encounter them. The SQL Statement CREATE TABLE The SQL statement CREATE TABLE is a complex statement with many clauses and parameters. The exam only tests for some of its functionality, including how to create columns, specify data types for those columns, and create constraints. Here’s an example of a relatively simple CREATE TABLE statement. CREATE TABLE cruises ( cruise_id NUMBER, cruise_type_id NUMBER, cruise_name VARCHAR2(20), captain_id NUMBER NOT NULL, start_date DATE, end_date DATE, status VARCHAR2(5) DEFAULT 'DOCK', CONSTRAINT cruise_pk PRIMARY KEY (cruise_id) ); In this example, we create a table with seven columns and two constraints. Each of the columns is given a name and a datatype. The datatypes provide some rules and requirements for the data that’s entered into the columns. For example, only numbers can be entered into CRUISE_TYPE_ID. Only date values can be entered into START_DATE. Note that the STATUS column has a default value of ‘DOCK’. If a row is added that does not include a value for STATUS, then the value will be automatically assigned as ‘DOCK’. At the end of the CREATE TABLE statement is an additional line that creates a CONSTRAINT. This particular CONSTRAINT defines the CRUISE_ID column Review the Table Structure 59 as a primary key, which means that any row added to the CRUISES table must include a value for CRUISE_ID, and that value must be unique—it cannot duplicate any preexisting value for CRUISE_ID that any other row already present in the table may already have. There’s also a NOT NULL constraint that’s applied to the CAPTAIN_ID column. That CONSTRAINT isn’t explicitly named, but it’s a CONSTRAINT nonetheless, and it will be assigned a system-generated name. In the remainder of this chapter, we’ll look at how you can review the structure of a table. We’ll look at the different datatypes you can use to create columns in a table. We’ll conclude the chapter by looking at constraints and how they can be created at the time you create a table. Certification Objective 2.03 Review the Table Structure Once you have created a table successfully in the database, you can review the table’s structure with the DESCRIBE statement. The DESCRIBE statement, often abbreviated as DESC, isn’t a SQL statement; it’s a SQL*Plus statement that is unique to Oracle. (Some other product vendors have since implemented DESC in their own unique SQL products.) Even though it isn’t SQL, it’s important to understand, since DESC is useful for quickly reviewing a table’s structure. Let’s take a look at an example. Consider the CREATE TABLE CRUISES statement that we saw earlier, namely: CREATE TABLE cruises ( cruise_id cruise_type_id cruise_name captain_id start_date end_date status CONSTRAINT cruise_pk NUMBER, NUMBER, VARCHAR2(20), NUMBER NOT NULL, DATE, DATE, VARCHAR2(5) DEFAULT 'DOCK', PRIMARY KEY (cruise_id) ); Assuming this SQL statement were executed in the database successfully, resulting in the table CRUISES being stored in the database, then you could issue the following SQL*Plus command: DESC cruises 60 Chapter 2: Using DDL Statements to Create and Manage Tables Figure 2-3 Result of the command “DESC cruises” The result is displayed in Figure 2-3. Notice the output list shows a three-column display: n The first column in the output listing is titled “Name” and shows the table’s column names that you specified with the CREATE TABLE statement. n The second column in the output listing is titled “Null?” It shows if there is a NOT NULL constraint applied to that particular column in the table—in other words, will any row that’s added to the database be allowed to omit this particular value, or not? n The third column in the output listing is titled “Type” and shows the datatype for the particular table’s column in question. For example, the DESC CRUISES output shows us that the CRUISES table has a column titled CAPTAIN_ID, its datatype is NUMBER, and it has a NOT NULL CONSTRAINT applied to it. Certification Objective 2.04 List the Data Types That Are Available for Columns The following section lists and explains data types provided by Oracle that can be assigned to columns in a table. We’ll look at examples in later chapters—for now we’re interested only in listing and describing them. Datatypes are assigned to different types of objects in the SQL database and throughout the Oracle system. In a table, each column must be assigned a datatype. A column’s datatype defines what sort of information is—and is not—accepted as input List the Data Types That Are Available for Columns 61 into the column. It determines how the values in the column can be used, how they will behave when compared to other values or evaluated in Oracle’s own expressions, and how they are sorted. documentation refers to datatypes as Most datatypes fall under one of the general both “datatypes” and “data types”.These categories of numeric, character, or date. There’s two expressions are the same thing. more to it than this, but most datatypes fall into one of these three general categories. In addition to these three is a category referred to as “Large Database Objects”, or LOB datatypes. LOBs can include character data but cannot be included in a primary key, DISTINCT, GROUP BY, ORDER BY, or joins. Character Character datatypes are also known as text or string datatypes, and they include the following: The name “char” is short for “character”. This is a fixed-length alphanumeric value. Any alphanumeric character is accepted as input. The n indicates how long the value will be. The CHAR(n) datatype pads any remaining unused space with blanks to ensure that the length of your value will always equal the value of n. For example, if you declare a column with datatype of CHAR(5), then a value of, for example, ‘A’ will be stored—and retrieved—as ‘A ’, where A is followed by four blank spaces. Any attempt to enter a value that is longer than n will result in an error, and the value will not be accepted. The inclusion of n is optional; if it’s omitted in the declaration, a value of 1 is assumed. The maximum allowed value for n is 2000. n CHAR(n) The name “varchar” is sort of an abbreviation for “variable character”. This is a variable-length alphanumeric value. The n indicates the maximum allowable length of the value stored within, but contrary to CHAR, the VARCHAR2 format will not pad its values with blanks. Its length varies according to the data it contains—hence the name “varchar”. Also different from the CHAR datatype is the fact that VARCHAR2 requires n to be specified. The minimum value of n is 1; the maximum allowable length of VARCHAR2 is 4000. (Note: The issue of a maximum value in VARCHAR2 is actually a bit more complex than this— the maximum is technically 4,000 bytes and not really 4,000 characters, and by default most Oracle database implementations are configured so n VARCHAR2(n) 62 Chapter 2: Using DDL Statements to Create and Manage Tables that one character equals one byte. But it’s possible to override this, which would theoretically change the maximum number you can use for n in a VARCHAR2 declaration. For our purposes here it doesn’t really matter—it hasn’t been an issue on the exam.) Numeric Numeric datatypes include the following: Accepts numeric data, including zero, negative, and positive numbers, where n specifies the “precision”, which is the maximum number of significant digits (on either side of the decimal point), and m is the “scale”, meaning the total number of digits to the right of the decimal point. Both n and m are optional; n defaults to the maximum value, m defaults to zero. The value for n can range from 1 to 38; the value for m can range from –84 to 127. Note that these are not the largest values you can have, but rather the largest (and smallest) specifications for values you can have—Oracle’s SQL Language Reference Manual carefully states that the values accepted for a NUMBER datatype range from 1.0 × 10–130 up to “but not including” 1.0 × 10126. If a value entered into a NUMBER column has a precision greater than the specified value, an error message will result and the value will be rejected. On the other hand, if a value is entered that exceeds the declared scale, the entered value will be rounded off (.5 is rounded up) and accepted. Also, a negative value for m identifies how many significant digits to the left of the decimal point will be rounded off. See Table 2-2 for an example of how all of this works. It’s considered good practice to specify the precision and scale as a part of the overall data integrity check, to place some boundaries around the limits of what the business logic of the intent of the column will accept. n NUMBER(n,m) Table 2-2 Datatype Value Entered Value Stored As Examples of NUMBER Precision and Scale NUMBER 4.56 4.56 NUMBER(2) 4.56 5 NUMBER(5,2) 4.56 4.56 NUMBER(5,2) 4.5678 4.57 List the Data Types That Are Available for Columns 63 Table 2-2 Datatype Value Entered Value Stored As Examples of NUMBER Precision and Scale (Continued) NUMBER(3,2) 10.56 Nothing is stored. Instead, displays error code ORA-01438: “value larger than specified precision allowed for this column”. The reason: the value has a precision of 4 (1,0,5,6—four digits), but NUMBER here is declared with a precision of 3. NUMBER(5,-2) 1056.34 1100 Date Date datatypes are sometimes referred to in Oracle’s documentation as “datetimes”. Each date datatype consists of “fields”, and each field is a component of a date or time, such as hours, or minutes, the month value, etc. See Table 2-3 for a list of the fields that are used in various combinations to form date datatypes. The datatypes that support date and time information include the following: Accepts date and time information. The fields stored include year, month, date, hour, minute, and second. Date values may be stored as literals, or using conversion functions which you’ll see later in Chapter 6. Date literals are enclosed in single quotation marks and may be specified in a number of ways. The default Oracle date format for a given calendar day is defined by the parameter NLS_DATE_FORMAT. The value for NLS_ DATE_FORMAT for your database implementation can be displayed using the SQL*Plus command SHOW PARAMETER NLS_DATE_FORMAT. (Note that the parameter NLS_TERRITORY can also change the setting for NLS_DATE_FORMAT—its value can be displayed with the SQL*Plus command SHOW PARAMETER NLS_TERRITORY.) The NLS_DATE_ FORMAT parameter can be changed with ALTER SESSION or ALTER SYSTEM, which are SQL statements that are not included on the exam. By default, installations in the U.S. and UK use the NLS_DATE_FORMAT of ‘DD-MON-RR’, where DD is the two-digit day, MON is the three-letter abbreviation for the month, and RR is the two-digit year, where values of RR ranging from 00 to 49 are assumed to be in the 21st century (2000 to 2049), while RR values ranging from 50 to 99 are assumed to be in the 20th century (1950 through 1999). For example, ‘10-NOV-10’ is the first n DATE 64 Chapter 2: Using DDL Statements to Create and Manage Tables of November, 2010. (Note: The same date in ANSI format is ‘2010-1101’. ANSI format is ‘YYYY-MM-DD’, where YYYY is the four-digit year, MM is the two-digit month, and DD is the two-digit day.) We will have much more to say about dates, formats, and conversions when we discuss functions, in Chapter 6. An extension of DATE that adds fractional second precision. TIMESTAMP stores year, month, day, hours, minutes, and seconds, and fractional seconds. The value for n specifies the precision for fractional seconds. The range for n is 1–9. If n is omitted, it defaults to a value of 6. n TIMESTAMP(n) A variation of TIMESTAMP that adds either a time zone region name, or an offset for time zone. TIMESTAMP WITH TIME ZONE is used in tracking date information across different time zones and geographical areas. The range for n is 1–9. If n is omitted, it defaults to a value of 6. n TIMESTAMP(n) WITH TIME ZONE A variation of TIMESTAMP. The TIMESTAMP WITH LOCAL TIME ZONE differs from TIMESTAMP WITH TIME ZONE in that the time zone offset is not stored with the column’s value, and the value retrieved is sent in the user’s local session time zone. The offset is calculated automatically. If n is omitted, it defaults to a value of 6. n TIMESTAMP(n) WITH LOCAL TIME ZONE Stores a span of time defined in only year and month values, where n is the number of digits used to define the YEAR value. The range of acceptable values for n is 0–9; the default for n is 2. This datatype is useful for storing the difference between two date values. n INTERVAL YEAR(n) TO MONTH Stores a span of time defined in days, hours, minutes, and seconds, where n1 is the precision for days, and n2 is the precision for seconds. The range of values for n1 is 0–9, and the default is 2. The value for n1 specifies how many digits are accepted in declaring the size of a number for DAY to be specified. The value for n2 is the fractional seconds precision for SECOND; acceptable values range from 0 to 9, and the default is 6. Useful for storing the difference between two date values. n INTERVAL DAY(n1) TO SECOND(n2) List the Data Types That Are Available for Columns Table 2-3 Datetime Fields 65 Datetime Field Range of Valid Values YEAR –4712 to 9999 (excluding the year 0) MONTH 01 to 12 DAY 01 to 31 (Limited as appropriate for months in which there are fewer than 31 days, according to the values in MONTH and YEAR.) HOUR 00 to 23 MINUTE 00 to 59 SECOND 00 to 59.9(n), where 9(n) is the precision of time in fractional seconds. That portion—9(n)—does not apply to DATE. TIMEZONE_HOUR –12 to 14. Designed to accommodate changes to daylight saving time. Does not apply to DATE or TIMESTAMP. TIMEZONE_MINUTE 00 to 59. Does not apply to DATE or TIMESTAMP. TIMEZONE_REGION The list of possible values here is contained in the TZNAME column of the data dictionary view V$TIMEZONE_NAMES. Examples: ‘America/Chicago’, ‘Australia/Queensland’. Does not apply to DATE or TIMESTAMP. TIMEZONE_ABBR The list of possible values here is contained in the TZABBREV column of the data dictionary view V$TIMEZONE_NAMES. Examples: ‘CWT’, ‘LMT’. Does not apply to DATE or TIMESTAMP. Heads up: the datatypes that handle time zone differences are very important to the exam—they are specifically referenced in one of the certification objectives. We’ll look at functions in Chapter 6 that deal with these datatypes. Large Objects (LOBs) Large object datatypes, also known as LOBs, include the following: The name “BLOB” is an abbreviation for Binary Large OBject. BLOB accepts large binary objects, such as image or video files. Declaration is made without precision or scale. The maximum size is calculated by way of a formula that includes several items, including a starting size of 4GB, something called n BLOB 66 Chapter 2: Using DDL Statements to Create and Manage Tables the CHUNK parameter, and the setting for the database block size, which is a setting that affects all storage in the database. None of this is an issue on the exam. The exam will instead focus on how to use LOB datatypes in SQL language syntax. LOBs can generally be used like other datatypes. Tables may have multiple columns with LOB datatypes. However, LOBs cannot be primary keys, nor used with DISTINCT, GROUP BY, ORDER BY, or joins. The name “CLOB” is an abbreviation for Character Large OBject. CLOB accepts large text data elements. Declaration is made without precision or scale. Maximum size is calculated in the same manner that it is for the BLOB datatype. n CLOB Accepts CLOB data in Unicode. Maximum size is calculated in the same manner that it is for the BLOB datatype. Regarding Unicode—it is a character set that serves as an alternative to ASCII and represents a more universal standard that supports all major languages more easily than the other implementations in use today. Oracle and most other major vendors have adopted Unicode into their products, and common web technologies already support it. Given the increasing role of globalization and multilanguage support, any legacy application deployed without Unicode may inevitably require a conversion effort down the road. Oracle Corporation is officially recommending the use of Unicode as the database national character set for all new system development. n NCLOB Here’s an example of a table that includes a column of the CLOB datatype: CREATE TABLE CRUISE_NOTES (CRUISE_NOTES_ID NUMBER, CRUISE_NOTES CLOB); The preceding example creates a table with two columns, the second of which is a CLOB. That column can receive extremely large text data as input. Oracle Corporation discourages the use of the old LONG datatype and encourages you to convert them to LOB datatypes, which have fewer restrictions. For example, you can add more than one LOB column to a table, you can select them, you can insert into tables with LOB columns, and delete rows with LOB values. However, you cannot use LOBs in GROUP BY or ORDER BY. All of the datatypes you’ve seen so far are built in by Oracle and included with SQL. All of these datatypes are known as “built-in” datatypes. However, it’s possible for users to create their own unique “user-defined” datatypes. Userdefined datatypes are created using the SQL statement CREATE TYPE.They are used in PL/SQL code and are not a subject of the exam. Explain How Constraints Are Created at the Time of Table Creation 67 Certification Objective 2.05 Explain How Constraints Are Created at the Time of Table Creation You can create a CONSTRAINT to support other objects, specifically TABLE objects. As such, there isn’t a CREATE CONSTRAINT statement per se. Instead, you create a CONSTRAINT as part of another statement, such as CREATE TABLE or ALTER TABLE. Here’s an example of a CREATE TABLE statement that includes the necessary syntax to create a CONSTRAINT: CREATE TABLE positions ( position_id NUMBER , position VARCHAR2(20) , exempt CHAR(1) , CONSTRAINT positions_pk PRIMARY KEY (position_id) ); In the preceding example, we create a TABLE called POSITIONS, which consists of three columns, POSITION_ID, POSITION, and EXEMPT. After the EXEMPT column is defined, this particular example shows an additional line of code to create a CONSTRAINT. That’s not the only way to create a constraint, but it’s how this example chooses to do it. Also in this example, we are choosing to name the CONSTRAINT, something that we don’t necessarily have to do. The CONSTRAINT is named POSITIONS_PK. We’re specifying that this CONSTRAINT is of type PRIMARY KEY, and we’re applying the CONSTRAINT to the column in this table that’s called POSITION_ID, which we defined first. Let’s look at some specifics next. Creating CONSTRAINTS in the CREATE TABLE Statement There are two ways in which a CONSTRAINT can be created at the time of TABLE creation: “in line” and “out of line”. CREATE TABLE: “In Line” Constraints Here is an example of how to create a PRIMARY KEY constraint “in line”: CREATE TABLE PORTS (PORT_ID NUMBER PRIMARY KEY, PORT_NAME VARCHAR2(20)); 68 Chapter 2: Using DDL Statements to Create and Manage Tables In this example, we create an anonymous PRIMARY KEY constraint on the column PORT_ID. We can optionally give that constraint a name by preceding the reserved words PRIMARY KEY with the reserved word CONSTRAINT, followed by a name we make up according to the rules of naming database objects, like this: CREATE TABLE PORTS (PORT_ID NUMBER CONSTRAINT PORT_ID_PK PRIMARY KEY, PORT_NAME VARCHAR2(20)); These two approaches are referred to as “in line” constraints, since in both examples the declaration of the constraint is included with the column definition. Here’s another “in line” example. This example creates a table with a NOT NULL constraint: CREATE TABLE VENDORS (VENDOR_ID NUMBER, VENDOR_NAME VARCHAR2(20), STATUS NUMBER(1) NOT NULL, CATEGORY VARCHAR2(5)); The result of this constraint is to ensure that a value for STATUS must be included with each row entered into VENDORS. The value might be zero or any other single digit, but it must be provided—it cannot be left out. It cannot be unknown to the database—in other words, it cannot be NULL. Here is the same table with a name assigned to the constraint: CREATE TABLE VENDORS (VENDOR_ID NUMBER, VENDOR_NAME VARCHAR2(20), STATUS NUMBER(1) CONSTRAINT STATUS_NN NOT NULL, CATEGORY VARCHAR2(5)); You may combine multiple constraint declarations in a single CREATE TABLE statement, like this: CREATE TABLE VENDORS (VENDOR_ID NUMBER PRIMARY KEY, VENDOR_NAME VARCHAR2(20), STATUS NUMBER(1) CONSTRAINT STATUS_NN NOT NULL, CATEGORY VARCHAR2(5)); Note that if you do not provide a name for a constraint, the system will automatically assign one, and it will be something like this: SYS_C009981 Explain How Constraints Are Created at the Time of Table Creation 69 You’ll see how you’ll be able to identify the system-assigned name when you look at the data dictionary, in Chapter 14. CREATE TABLE: “Out of Line” Constraints In addition to “in line” constraints, you may optionally define a constraint within a CREATE TABLE statement after the columns have been created. Here’s an example of a PRIMARY KEY defined with the “out of line” syntax: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), PRIMARY KEY (PORT_ID) ); After the final column is defined for the table, there is a comma, followed by the reserved words PRIMARY KEY. Notice that the “out of line” syntax requires that you indicate which column (or columns) are affected by the constraint. Since we’re not “in line” with the column, the statement cannot know which column you’re intending to constrain, unless you specifically indicate it within the clause. Here’s an “out of line” example that names the constraint: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), CONSTRAINT PORT_ID_PK PRIMARY KEY (PORT_ID) ); This example gives the constraint a name that we’ve chosen. As is the case with “in line” constraints, any “out of line” constraints that you do not provide with a name will be named automatically by the system. Additional Ways to Create Constraints: ALTER TABLE The CREATE TABLE statement isn’t the only way to create a constraint. Constraints may also be created using the ALTER TABLE statement. For example, we can first create the PORTS table like this: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20)); Afterward, we can ALTER the table to add a constraint by modifying the definition for a column: ALTER TABLE PORTS MODIFY PORT_ID PRIMARY KEY; 70 Chapter 2: Using DDL Statements to Create and Manage Tables In the preceding code, we’re modifying the declaration of the column itself by adding the primary key and letting the system assign a name. That syntax is the ALTER equivalent to this: CREATE TABLE PORTS (PORT_ID NUMBER PRIMARY KEY, PORT_NAME VARCHAR2(20)); In addition, we can use ALTER to do the same with a constraint name we assign, like this: ALTER TABLE PORTS MODIFY PORT_ID CONSTRAINT PORT_ID_PK PRIMARY KEY; Those are the “in line” equivalents of ALTER TABLE. Here are the “out of line” equivalents. First, depending on a system-defined name: ALTER TABLE PORTS ADD PRIMARY KEY (PORT_ID); Alternatively, we can name the constraint ourselves: ALTER TABLE PORTS ADD CONSTRAINT PORT_ID_PK PRIMARY KEY (PORT_ID); We’ll explore the methods for using ALTER TABLE to create constraints in more detail in Chapter 11. Warning: NOT NULL Is Different We’re about to look at the five different types of constraints, but before we do, a word of warning about the syntax variations for one particular constraint: the NOT NULL constraint is a bit different when it comes to syntax. The NOT NULL constraint cannot be created “out of line”. In other words, this is invalid: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), NOT NULL (PORT_ID) ); This is also invalid: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), CONSTRAINT PORT_ID_NN NOT NULL (PORT_ID) ); Explain How Constraints Are Created at the Time of Table Creation 71 Either of those will produce error messages if you try to execute either one. No table or constraint will be created. And yet, the same syntax is perfectly fine for other types of constraints. For example, here’s the UNIQUE constraint: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), CONSTRAINT PORT_ID_UN UNIQUE (PORT_ID) ); And of course, this is fine, too—this is the PRIMARY KEY constraint: CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), CONSTRAINT PORT_ID_PK PRIMARY KEY (PORT_ID) ); So NOT NULL cannot be declared with the “out of line” format. The others can. But wait, there’s more about NOT NULL. This won’t work either: ALTER TABLE PORTS ADD NOT NULL (PORT_NAME); And this won’t either: ALTER TABLE PORTS ADD CONSTRAINT PORT_NAME_NN NOT NULL (PORT_NAME); Those won’t work because they are the ALTER TABLE equivalents for “out of line” declarations. But the ALTER TABLE “in line” equivalents are fine: ALTER TABLE PORTS MODIFY PORT_NAME NOT NULL; And this is also fine: ALTER TABLE PORTS MODIFY PORT_NAME CONSTRAINT PORT_NAME_NN NOT NULL; So beware. NOT NULL is a bit unusual. It’s a valid constraint and can be created using the other forms of syntax, but not with the “out of line” format. The list of certification objectives specifically states in one objective that you will be tested on the topic of creating constraints at the time of table creation, and in a separate certification objective that you will also be tested on how to add constraints to tables after they have already been created. 72 Chapter 2: Using DDL Statements to Create and Manage Tables The Types of CONSTRAINTS There are several types of constraints that can be applied to a table. They are: PRIMARY KEY, FOREIGN KEY, NOT NULL, CHECK, and UNIQUE. (Note: the REF type is not included on the exam.) Let’s explore each of these in detail. NOT NULL The NOT NULL constraint is very simple—when applied to a column, it ensures that for any row that is added to the TABLE, the column on which the NOT NULL constraint is applied shall always be provided with a value. Meanwhile, the column’s datatype ensures that the data entered into the column is consistent with the datatype’s rules. To fully appreciate this constraint, it helps to understand what the concept of NULL is. So let’s take a look. The Concept of NULL The reserved word NULL is, in this author’s ever-sohumble opinion, one of the most misunderstood aspects of the SQL database. The definition of NULL is the “absence of information”. Sometimes it’s mischaracterized as “zero” or “blank”, but that is incorrect—a “zero”, after all, is a known quantity. So is a blank. But NULL is “unknown”. It’s the way the database acknowledges that it, the database, is merely an imperfect repository of information about some real-life business situation or some other application out there in the world, and the database is ultimately dependent on the data it’s been given to mirror that enterprise situation. But ultimately, it’s the enterprise—not the database—that is the final authority. So it’s entirely possible—and quite likely—that some information hasn’t been provided to the database. NULL is a placeholder for where that information goes— where the database has not been given clear instruction about whether a value exists or not, and if it does exist—what value it might be. For example, consider a table containing the names of customers: CREATE TABLE CUSTOMERS ( FIRST_NAME VARCHAR2(20), MIDDLE_NAME VARCHAR2(20), LAST_NAME VARCHAR2(30)); Let’s add a row to this table: INSERT INTO CUSTOMERS (FIRST_NAME, LAST_NAME) VALUES ('Angelina', 'Ellison'); Notice that no value is provided here for MIDDLE_NAME. When this happens, then in the absence of other information, the database stores a NULL in its place. Explain How Constraints Are Created at the Time of Table Creation 73 Does this mean that somewhere out there in the world is a real-life person named “Angelina Ellison” who has no middle name? Well . . . maybe she does, and maybe she doesn’t. The point is that the database doesn’t know if she has a middle name or not—the value is unknown to the database. This becomes very important when it comes to such situations as mathematical expressions. Consider the following expression: CRUISE_PRICE * DISCOUNT Let’s say that the value for CRUISE_PRICE is 300, and the value for DISCOUNT is NULL in the database—in other words, maybe there’s a discount value out there somewhere, and maybe there isn’t. But the database doesn’t know either way—it’s unknown to the database. The value is NULL. If that’s the case, then what is the answer to the equation given in this expression? The answer for the equation of 300 times NULL is . . . what? Give up? The answer is NULL. The reason is simple: “300” multiplied by “I don’t know” results in . . . “I don’t know”. In other words—perhaps the equation really does have an answer, but if we don’t know what the DISCOUNT value is, then we don’t have enough information to calculate the answer of the expression. Therefore the answer is unknown—i.e., NULL. We’ll address NULL some more in the section on functions. For now, all that we’re concerned with is the NOT NULL constraint. When the NOT NULL constraint is applied to a column, you’re requiring that any rows added to the table include a value for that column. Let’s go back to our earlier example. If we had applied a NOT NULL constraint to the MIDDLE_NAME column of the CUSTOMERS table, then we never would have had a row like “Angelina Ellison” with no middle name. The NOT NULL constraint, if applied to the MIDDLE_NAME column, would have required a middle name value for any row being added to the table. By default, all columns allow NULL values when first created. You must apply a NOT NULL constraint—or an equivalent—to a column to require data for that column. When we say “or an equivalent”, we mean that there are alternative ways to require data in a column—one way is the PRIMARY KEY constraint, which is a NOT NULL rule combined with the UNIQUE constraint, which we’ll see next. If you apply a PRIMARY KEY constraint on a column, you do not need to also apply a NOT NULL constraint. But if there is no PRIMARY KEY constraint for a given column, the NOT NULL constraint will ensure that any rows added to the table will include a value for that particular column. 74 Chapter 2: Using DDL Statements to Create and Manage Tables UNIQUE The UNIQUE constraint, when applied to a column, ensures that any data added to the column in the future will be unique when compared to data already existing in the column. No other row will possess the same value for that particular column. A few notes about UNIQUE: n UNIQUE can be applied to one column or multiple columns. n UNIQUE, by itself, allows NULL values to be added to the column. It only restricts data that’s provided for the column to being one-of-a-kind for the column. Note that the PRIMARY KEY constraint represents the combination of NOT NULL and UNIQUE. Use the PRIMARY KEY constraint instead of the NOT NULL and UNIQUE constraints if your intent is to create a single unique identifier for each row in the table. Composite UNIQUE Constraint You may create a UNIQUE constraint that applies to multiple columns simultaneously. This has the effect of requiring the combination of columns to be unique. In other words, each individual column may repeat data, but collectively the combination of data in all of the columns for any given row will have to be unique. PRIMARY KEY The PRIMARY KEY defines one or more columns in a table that will form the unique identifier for each row of data that is added to the table. The PRIMARY KEY constraint is a combination of the NOT NULL and UNIQUE constraints. A table may have only one PRIMARY KEY constraint. A single-column PRIMARY KEY is the most common form, and it ensures that for all rows of data added to the table in the future, the column upon which the PRIMARY KEY constraint has been applied will always contain a value, and that value will always be unique when compared to existing values that are already in the table for that particular column. Here is an example of a CREATE TABLE statement that creates a PRIMARY KEY constraint: CREATE TABLE employees ( employee_id NUMBER , ship_id NUMBER Explain How Constraints Are Created at the Time of Table Creation , , , , 75 first_name VARCHAR2(20) last_name VARCHAR2(30) position_id NUMBER CONSTRAINT employees_pk PRIMARY KEY (employee_id)); In the preceding example, we create a PRIMARY KEY constraint on the EMPLOYEE_ID column. In this example, we’ve given the constraint a name of EMPLOYEES_PK. (The PK suffix is not required, just one of many good design approaches that clarifies to anyone who might review a long list of database constraints later on that this particular constraint is a primary key.) Now that we’ve created this table with the PRIMARY KEY constraint, any row that’s added to the EMPLOYEES table in the future will require a unique value for each row added. Composite Primary Keys A multicolumn PRIMARY KEY is based on two or more columns that collectively serve the same purpose as a single-column PRIMARY KEY. In other words, the combination of column values will collectively have to be unique, and all columns—individually and collectively—will have to contain values. See Figure 2-4 for some sample data. Notice the three columns CATEGORY, YEAR, and TICKET. Individually each shows data that repeats throughout the data listing. But together each row of combined columns represents unique data. A UNIQUE constraint could be applied to this sort of data in a table. Here’s an example of a CREATE TABLE statement that would create a composite PRIMARY KEY constraint to support Figure 2-4. CREATE TABLE HelpDesk ( HD_Category NUMBER, HD_Year NUMBER, HD_Ticket_No NUMBER, HD_Title VARCHAR2(30), CONSTRAINT HelpDesk_PK PRIMARY KEY (HD_Category, HD_Year, HD_Ticket_No)); The preceding code has the effect of creating NOT NULL and UNIQUE constraints across all three columns. For each row entered in the table “HelpDesk”, a value will be required in each of the three columns HD_Category, HD_Year, and HD_Ticket_No, and the combination of those three values will need to be unique for every row. As you saw in the earlier sample data, it’s possible to repeat values in the individual columns, but the combination must always be unique in each row. 76 Chapter 2: Figure 2-4 Sample data from HELP_DESK table Using DDL S tatements to Create and Manage Tables Category Year Ticket Title Order 2009 000001 Inkjet cartridges Order 2009 000002 Printer paper Bug Rpt 2009 000001 Screen fails for PDF Order 2009 000003 Hard drive - external for conference Bug Rpt 2009 000002 FOREIGN KEY A FOREIGN KEY constraint applies to one or more columns in a particular table, and works in conjunction with a second table’s PRIMARY KEY constraint. A FOREIGN KEY is the feature that helps ensure that two tables can “relate” to each other, and in many ways really represents the “heart and soul”, so to speak, of what a relational database is all about. The FOREIGN KEY constraint does the following: n It identifies one or more columns in the current table. n For each of those columns, it also identifies one or more corresponding columns in a second table. n It ensures that the other table already has a PRIMARY KEY (or unique) constraint on the corresponding columns in that second table. n It then ensures that any future values added to the FOREIGN KEY– constrained columns of the current table are already stored in the corresponding columns of the second table. In other words, a FOREIGN KEY constraint, along with the PRIMARY KEY constraint on the second referenced table, enforces “referential integrity” between the two tables. This means that the constraints work to ensure that any future data that is added to one or both of the tables continues to support the ability to relate data from one table to another. Note: the referenced table is not actually required to have a PRIMARY KEY constraint on the referenced columns, but only a UNIQUE constraint on the referenced columns. But you’ll recall that a PRIMARY KEY constraint is a Explain How Constraints Are Created at the Time of Table Creation 77 combination of the UNIQUE and NOT NULL constraints, so the PRIMARY KEY satisfies the requirement for a UNIQUE constraint. Let’s look at a sample scenario. First, a listing of data in the PORTS table: PORT_ID ------1 2 3 4 5 PORT_NAME --------Baltimore Charleston Tampa Miami Galveston COUNTRY ------USA USA USA USA USA CAPACITY -------2 2 8 6 4 Next, a listing of information in the SHIPS table: SHIP_ID ------1 2 3 4 SHIP_NAME ---------Codd Crystal Codd Elegance Codd Champion Codd Victorious HOME_PORT_ID -----------1 3 4 4 As you might have already surmised, the value for each ship’s HOME_PORT_ID should correspond to a PORT_ID value in the PORTS table. In order to ensure that the two tables only accept incoming rows of data that support this business rule that requires all HOME_PORT_ID values to be valid PORT_ID values, we can create a PRIMARY KEY constraint on the PORTS table (or a UNIQUE constraint), and then a FOREIGN KEY constraint on the SHIPS table that correlates back to the PRIMARY KEY constraint on the PORTS table. First, the PORTS table: 01 02 03 04 05 06 CREATE TABLE PORTS (PORT_ID NUMBER, PORT_NAME VARCHAR2(20), COUNTRY VARCHAR2(40), CAPACITY NUMBER, CONSTRAINT PORT_PK PRIMARY KEY (PORT_ID)); Next, the SHIPS table: 07 08 09 10 11 12 CREATE TABLE SHIPS (SHIP_ID NUMBER, SHIP_NAME VARCHAR2(20), HOME_PORT_ID NUMBER, CONSTRAINT SHIPS_PORTS_FK FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID)); 78 Chapter 2: Using DDL Statements to Create and Manage Tables Note that the foreign key constraint clause in the CREATE TABLE SHIPS statement starts on line 11 and continues through line 12. It references the PORTS table and the PORTS table’s PORT_ID column, which already has a PRIMARY KEY constraint applied to it. If it did not already have either a PRIMARY KEY constraint or a UNIQUE constraint on it, then the CREATE TABLE SHIPS statement would result in an error and let you know that the PORTS table already must exist and must have a PRIMARY KEY or UNIQUE constraint on the PORT_ ID column. The FOREIGN KEY on SHIPS makes sure that any row added to the SHIPS table will only accept values for HOME_PORT_ID if that value already exists in the PORTS table. Note that the HOME_PORT_ID value is not required—if your goal is to ensure that the HOME_PORT_ID value is always provided, you’ll have to also add a NOT NULL constraint on HOME_PORT_ID as well as FOREIGN KEY. This is one way to do that: 07 08 09 10 11 12 CREATE TABLE SHIPS (SHIP_ID NUMBER, SHIP_NAME VARCHAR2(20), HOME_PORT_ID NUMBER NOT NULL, CONSTRAINT SHIPS_PORTS_FK FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID)); In the preceding example, we create two separate constraints. Of those two constraints, one of them is on lines 11 through 12, and exists to make the HOME_ PORT_ID column a foreign key, and another constraint—at the end of line 10—to ensure that there is always a value entered for HOME_PORT_ID. In my professional experience, I find it much easier to create foreign keys with ALTER TABLE statements instead of with CREATE TABLE statements. One reason is that the resulting code is more modular. Note that you cannot create a foreign key constraint that refers to a table that doesn’t exist. If your goal is to build a script for creating (and if necessary, re-creating) your entire database, then trying to create all of your foreign key constraints within your CREATE TABLE statements so that they occur after the creation of their respective primary key tables—all of that can suddenly turn into quite a puzzle of trying to ensure your CREATE TABLE statements all run in the correct order so that your referred tables already exist before you create foreign key constraints against them. Not only is such an effort difficult, it may prove to be impossible in a data model where the relationships run in both directions. All of this is an unnecessary effort when you can easily build all of your foreign keys within a series of ALTER TABLE Explain How Constraints Are Created at the Time of Table Creation 79 statements, and place them all after your CREATE TABLE statements as a whole. The complexity is completely eliminated with that approach. Other complications you might avoid include the fact that you cannot create a foreign key within a CREATE TABLE statement that uses the “as query” approach—that approach creates the table and populates it with data using a subquery’s SELECT statement all at once, which we’ll examine in Chapter 15. In that sort of situation, the clause to create a foreign key constraint isn’t allowed. Given such restrictions, I find no benefit to struggling to build a foreign key from within the CREATE TABLE statement, and would just as soon use an ALTER TABLE statement where these restrictions don’t exist. But . . . that’s just me. CHECK A CHECK constraint attaches an expression to a constraint. In other words, it applies a small bit of code to define a particular business rule on incoming rows of data. A CHECK constraint may, for example, restrict incoming data so that all incoming values are required to be greater than some minimum value, or fall within a set of predetermined options. A CHECK constraint can ensure that a twocharacter column only accepts valid abbreviations for American states, for example, or that the date entered in one column is always greater than the date entered in another column. Here’s an example of a CHECK constraint that only allows rows in the VENDORS table with a STATUS value of either 4 or 5. CREATE TABLE VENDORS (VENDOR_ID NUMBER, VENDOR_NAME VARCHAR2(20), STATUS NUMBER(1) CHECK (STATUS IN (4,5)), CATEGORY VARCHAR2(5)); While rows may be added to VENDORS with no STATUS value, they can only be given a STATUS value if it is either 4 or 5. Any valid SQL expression may be used in a CHECK constraint. Multiple Constraints A table may be declared with multiple constraints. Here’s an example: CREATE TABLE VENDORS (VENDOR_ID NUMBER CONSTRAINT VENDOR_ID_PK PRIMARY KEY, VENDOR_NAME VARCHAR2(20) NOT NULL, 80 Chapter 2: Using DDL Statements to Create and Manage Tables STATUS CATEGORY CONSTRAINT CONSTRAINT NUMBER(1) CONSTRAINT STATUS_NN NOT NULL, VARCHAR2(20), STATUS_CK CHECK (STATUS IN (4, 5)), CATEGORY_CK CHECK (CATEGORY IN ('Active','Suspended','Inactive'))); In the preceding example, we have a single CREATE TABLE statement that creates a table along with five constraints: n A user-named PRIMARY KEY on VENDOR_ID n A system-named NOT NULL constraint on VENDOR_NAME n A user-named NOT NULL constraint on STATUS n Two CHECK constraints: one on STATUS and another on CATEGORY Any single table may have only one PRIMARY KEY constraint. It can have any other combination of any other constraints. Datatype Restrictions There are some restrictions on some constraints. See Table 2-3 for a summary of datatype restrictions on constraints. These restrictions mean that the datatypes identified cannot and will not receive a constraint applied against them if they are of the types indicated in the table with a “NO” in the appropriate field. For example, the PRIMARY KEY constraint cannot include any columns with a datatype of BLOB, CLOB, or TIMESTAMP WITH TIME ZONE. (Note, however, that constraints may be applied to columns that have the datatype of TIMESTAMP WITH LOCAL TIME ZONE.) Table 2-3 Datatypes and Constraint Restrictions. NO = Not Allowed Datatype NOT NULL UNIQUE PRIMARY KEY FOREIGN KEY CHECK TIMESTAMP WITH TIME ZONE — NO NO NO — BLOB — NO NO NO — CLOB — NO NO NO — Certification Summary 81 Certification Summary The main database objects that are subjects of the exam include tables, views, sequences, synonyms, indexes, users, and roles. Constraints, which are not objects, are created to support tables. A table stores data. A constraint is a rule on a table that controls what sort of data can be stored in the table. A view is something that looks and acts like a table but serves as a filter onto one or more tables. A sequence is a counter, and it’s often used to generate unique numbers for storing identifiers with new rows that are added to a table. A synonym is an alias for another object. An index is an object that provides lookup support to a table, in order to speed up queries on the table. A user is an object that defines a user account. A role represents a set of one or more privileges that are granted to a user in order for that user to have access rights to other objects. All database objects are either “schema” or “non-schema” objects. Schema objects are owned by a user and exist within a user account. Non-schema objects exist to support the database at large. Of the main database objects we are looking at for the exam, the schema objects are table, view, sequence, private synonym, index. The non-schema objects are user, role, and public synonym. We use the CREATE TABLE statement to create a table, name the table, name the columns, assign datatypes to the columns, and optionally create various constraints to the table as well. Objects that exist in the same namespace must have unique names. Objects that exist in different namespaces may have duplicate names. Indexes have their own namespace within a schema; so do constraints. Beyond that, a schema has one namespace for the collective set of tables, views, sequences, and private synonyms. Outside of the schema, user and role objects, along with public synonyms, share one namespace for the entire database. Columns must be assigned a datatype when they are created. Datatypes include character, numeric, and date datatypes. Character datatypes include CHAR and VARCHAR2; numeric datatypes include NUMBER and FLOAT; date datatypes include DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE, INTERVAL YEAR TO MONTH, and INTERVAL DAY TO SECOND. There are also LOB, or Large OBject, datatypes, such as BLOB, CLOB, and NCLOB. Constraints can be created within the CREATE TABLE statement or afterward, in the ALTER TABLE statement. They can be created “in line”, meaning as part of a column’s definition, or “out of line”, meaning afterward as a separate line item within the CREATE TABLE or ALTER TABLE statement. An exception is NOT NULL, which cannot be created “out of line”. The five types of constraints are NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, and CHECK. 82 Chapter 2: 3 Using DDL Statements to Create and Manage Tables Two-Minute Drill Categorize the Main Database Objects q Tables store data. q Constraints are rules on tables. q Views serve as a sort of “window” onto tables. q Indexes provide lookup support to speed queries on a table, like an index to a book. q Sequences are simple counter objects. q Synonyms are alternative names for existing objects. q Users are objects that own other objects. q Roles are sets of rights, or privileges, that can be granted to a user to give that user access to other objects. q Objects are either “schema” or “non-schema” objects. q Tables, views, indexes, sequences, and private synonyms are “schema” objects. q Users and roles, along with public synonyms, are “non-schema” objects. Create a Simple Table q The CREATE TABLE statement is used to create a table. q You assign a name to a table by using the rules of naming database objects. q You also assign names to the table’s columns using the same rules. q All tables have at least one column. Review the Table Structure q The DESC command can be used to display a table’s structure. q The structure includes the table name, table columns, datatypes, and optional constraints. List the Data Types That Are Available for Columns q Each column must be assigned a datatype. q Datatypes include numeric, character, and date types, such as VARCHAR2, NUMBER, and DATE. q Datatypes also include large object types, including BLOB. Two-Minute Drill 83 Explain How Constraints Are Created at the Time of Table Creation q The types of constraints are NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, and CHECK. q A column with a NOT NULL constraint must be assigned a value for each row that is added to the table. q A UNIQUE constraint requires that if data is added to a column for a given row, that data must be unique for any existing value already in the column. q A PRIMARY KEY constraint is the combination of NOT NULL and UNIQUE. q A PRIMARY KEY may be assigned to one or more columns. q A PRIMARY KEY assigned to multiple columns is called a composite key. q A single table may only have one PRIMARY KEY. q A FOREIGN KEY correlates one or more columns in one table with a set of similar columns in a second table. q A FOREIGN KEY requires that the second table already have a PRIMARY KEY assigned to the correlated columns before the FOREIGN KEY can be created. q Once created, the FOREIGN KEY ensures that any values added to the table will match existing values in the PRIMARY KEY columns of the second table. q Constraints can be created with the CREATE TABLE statement or within the ALTER TABLE statement. q Constraints can be defined as part of the column definitions—“in line”—or after—“out of line”. 84 Chapter 2: Using DDL Statements to Create and Manage Tables Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Categorize the Main Database Objects 1. A table is which of the following? (Choose all that apply.) A. A schema object B. A non-schema object C. A role D. All of the above 2. Which of the following are schema objects? (Choose all that apply.) A. SEQUENCE B. PASSWORD C. INDEX D. ROLE 3. A CONSTRAINT is assigned to which of the following? (Choose all that apply.) A. TABLE B. SYNONYM C. SEQUENCE D. INDEX Create a Simple Table 4. Which of the following are valid CREATE TABLE statements? (Choose three.) A. CREATE TABLE $ORDERS (ID NUMBER, NAME VARCHAR2(30)); B. CREATE TABLE CUSTOMER_HISTORY (ID NUMBER, NAME VARCHAR2(30)); C. CREATE TABLE “Boat Inventory” (ID NUMBER, NAME VARCHAR2(30)); Self Test 85 D. CREATE TABLE workSchedule (ID NUMBER, NAME VARCHAR2(30)); 5. Which of the following may follow the reserved word CREATE to form a complete SQL statement? (Choose three.) A. TABLE B. VIEW C. CONSTRAINT D. SEQUENCE 6. You are logged in to user FINANCE. It is currently the only schema in the entire database. The following exist in the database: – A VIEW named VENDORS – A CONSTRAINT named VENDORS – An INDEX named CUSTOMER#ADDRESS You attempt to execute the following SQL statement: CREATE TABLE CUSTOMER#ADDRESS (ID NUMBER, NAME VARCHAR2(30)); Which one of the following is true? A. The question is flawed because you cannot have an INDEX named CUSTOMER#ADDRESS. B. The question is flawed because you cannot have a VIEW and a CONSTRAINT with identical names in the same schema. C. The SQL statement will fail to execute and result in an error message because you cannot create a TABLE name with the “#” character. D. The SQL statement will fail to execute and result in an error message because you cannot create a TABLE that has the same name as an INDEX in the same schema. E. The SQL statement will execute and the TABLE will be created. 7. You have a single database, with only one schema. The following four objects exist in the database: – A TABLE named PRODUCT_CATALOG – A TABLE named ADS – A USER named PRODUCT_CATALOG – A VIEW named CONFERENCE_SCHEDULE 86 Chapter 2: Using DDL Statements to Create and Manage Tables How many of the four objects are owned by the schema? A. 0 B. 2 C. 3 D. 4 8. ROLES: A. Are schema objects, but only when created from within a user account. B. Are in the same namespace as CONSTRAINTS. C. Are in the same namespace as TABLES. D. Are in the same namespace as USERS. Review the Table Structure 9. The DESCRIBE, or DESC, command, can be used to do which of the following? A. Show a table’s columns and the datatypes of those columns. B. Show a brief paragraph describing what the table does. C. Show a table’s name and who created it. D. Show the data that is contained within a table. List the Data Types That Are Available for Columns 10. You attempt to execute the following SQL statement: CREATE TABLE (VENDOR_ID VENDOR_NAME CATEGORY VENDORS NUMBER, VARCHAR2, CHAR); Which one of the following is true? A. The execution fails because there is no precision indicated for NUMBER. B. The execution fails because there is no precision indicated for VARCHAR2. C. The execution fails because there is no precision indicated for CHAR. D. The execution succeeds and the table is created. 11. The following SQL statements create a table with a column named A, and then add a row to that table. CREATE TABLE NUMBER_TEST (A NUMBER(5,3)); INSERT INTO NUMBER_TEST (A) VALUES (3.1415); SELECT A FROM NUMBER_TEST; Self Test 87 What is the displayed output of the SELECT statement? A. 3.1415 B. 3.142 C. 3.141 D. None of the above Explain How Constraints Are Created at the Time of Table Creation 12. Which of the following SQL statements creates a table that will reject attempts to INSERT a row with NULL values entered into the POSITION_ID column? A. CREATE TABLE POSITIONS (POSITION_ID NUMBER(3), CONSTRAINT POSITION_CON UNIQUE (POSITION_ID)); B. CREATE TABLE POSITIONS (POSITION_ID NUMBER(3), CONSTRAINT POSITION_CON PRIMARY KEY (POSITION_ID)); C. CREATE TABLE POSITIONS (POSITION_ID NUMBER(3), CONSTRAINT POSITION_CON REQUIRED (POSITION_ID)); D. None of the above 13. Review the following SQL statement. CREATE TABLE shipping_Order ( order_ID NUMBER, order_Year CHAR(2), customer_ID NUMBER, CONSTRAINT shipping_Order PRIMARY KEY (order_ID, order_Year)); Assume there is no table already called SHIPPING_ORDER in the database. What will be the result of an attempt to execute the preceding SQL statement? A. The statement will fail because the datatype for ORDER_YEAR is a CHAR, and CHAR datatypes aren’t allowed in a PRIMARY KEY constraint. B. The statement will fail because there is no precision for the ORDER_ID column’s datatype. C. The table will be created, but the primary key constraint will not be created because the name does not include the “_PK” suffix. D. The statement will succeed: the table will be created and the primary key will also be created. 88 Chapter 2: Using DDL Statements to Create and Manage Tables 14. Review the following SQL statement. CREATE TABLE personnel ( personnel_ID NUMBER(6), division_ID NUMBER(6), CONSTRAINT personnel_ID_PK PRIMARY KEY (personnel_ID), CONSTRAINT division_ID_PK PRIMARY KEY (division_ID)); Assume there is no table already called PERSONNEL in the database. What will be the result of an attempt to execute the preceding SQL statement? A. The statement will fail because you cannot create two primary key constraints on the table. B. The statement will successfully create the table and the first primary key, but not the second. C. The statement will successfully create a single table and one composite primary key consisting of two columns. D. The statement will successfully create the table and two primary keys. Self Test Answers 89 Self Test Answers Categorize the Main Database Objects 1. ˛ A. All database objects are either schema or non-schema objects, and a table falls under the category of schema objects. ˝ B, C, and D are incorrect. A table, which is a schema object, is not a non-schema object. A role is another form of a database object. 2. ˛ A and C. A sequence and an index are both schema objects, and are owned by a schema. ˝ B and D are incorrect. A password is not a database object. A role consists of one or more privileges that are assigned to a user object, and both the user and role objects are non-schema objects. 3. ˛ A. A CONSTRAINT is a rule that restricts what sort of data can be added to a table. ˝ B, C, and D are incorrect. You cannot attach a constraint to a synonym, sequence, or index object. Create a Simple Table 4. ˛ B, C, and D. Underscores are acceptable characters in any database table name, provided the first character is not an underscore. Quotation marks, when used, enable any character to be used throughout the name, including spaces, although all future references to the name will be case sensitive and require quotation marks. Finally, mixed case can be used to create a table name, although when created, the table name will be stored and treated as uppercase. All future references to the name may continue to be in any case—SQL will perform the necessary case conversion so that the table name, on a practical level, is treated as though it is case insensitive, even though it is stored internally in uppercase. ˝ A is incorrect. The first character in any database object name must be a letter; it cannot be a number or special character—unless the name is enclosed in double quotation marks, which this was not. 5. ˛ A, B, and D. The database objects TABLE, VIEW, and SEQUENCE can each be created directly with a CREATE reserved word to form a complete SQL statement. ˝ C is incorrect. A CONSTRAINT is not created directly with a CREATE CONSTRAINT statement, but instead is created indirectly as a clause within the CREATE TABLE and ALTER TABLE statements. 90 Chapter 2: Using DDL Statements to Create and Manage Tables 6. ˛ E. The table name may include the “#” character, as long as it isn’t the first character in the table name. An INDEX in the same schema is allowed to have the same name since the INDEX is inside its own namespace within the schema, separate from the namespace in which the TABLE will be created. ˝ A, B, C, and D are incorrect. The question is not flawed—the hash mark (#) is an acceptable character in an object name anywhere from the second character position through to the final character. You are allowed to have a VIEW and a CONSTRAINT with the same names within a single schema, since CONSTRAINTS are contained within their own unique namespace in each schema. 7. ˛ C. TABLE and VIEW objects are schema objects, and since we only have one schema in the database, then both have to be owned by the only schema in the database. But the USER object is a non-schema object—in fact, it’s the definition of the schema itself. It does not own itself, and it exists at the database level. ˝ A, B, and D are incorrect. 8. ˛ D. Both ROLES and USERS exist at the database level and share the same namespace. ˝ A, B, and C are incorrect. It doesn’t matter that a ROLE is created from within a schema’s user account, it’s still a non-schema object and exists in the same namespace. CONSTRAINTS and TABLES both have their namespaces within a schema. Review the Table Structure 9. ˛ A. DESC, or DESCRIBE, presents a display showing a table’s columns, and the datatypes of those columns. ˝ B, C, and D are incorrect. The DESC command doesn’t show data, the creator, or a text description of the table. All of that information is available through other means, but not the DESC command. List the Data Types That Are Available for Columns 10. ˛ B. The VARCHAR2 datatype requires precision, for example: VARCHAR2(30). ˝ A, C, and D are incorrect. NUMBER and CHAR can be declared without precision. But VARCHAR2 cannot and the statement will fail. 11. ˛ B. The NUMBER datatype has a precision of 5 and a scale of 3. The scale indicates that three digits—but no more than three digits—to the right of the decimal point are allowed. The number is rounded off, and 5 is always rounded up. ˝ A, C, and D are incorrect. Self Test Answers 91 Explain How Constraints Are Created at the Time of Table Creation 12. ˛ B. The primary key constraint performs two main jobs, one of which is to ensure that the column upon which it is applied is never allowed to be NULL. The other job is to ensure that any value added to that column is UNIQUE. ˝ A, C, and D are incorrect. The UNIQUE constraint allows for NULL values. There is no such thing as a REQUIRED constraint. There is a NOT NULL constraint that essentially does what a REQUIRED constraint might do, if one existed. 13. ˛ D. The syntax of the statement is fine. Both the table and the primary key constraint will be successfully created. ˝ A, B, and C are incorrect. It is perfectly acceptable to create a primary key in any form— single-column or composite—with the CHAR datatype. NUMBER is also fine with or without precision and/or scale. The “_PK” suffix is not required. 14. ˛ A. A statement is attempting to create two different primary key constraints, but a table may only have one primary key and no more. ˝ B, C, and D are incorrect. The syntax is not attempting a composite primary key, but rather two separate primary key constraints, and that is not allowed on any table. The entire statement will fail to execute. This page intentionally left blank 3 Manipulating Data Certification Objectives 3.01 Describe Each Data Manipulation Language (DML) Statement 3.04 Delete Rows from a Table 3.02 Insert Rows into a Table 3.05 Control Transactions 3 3.03 Update Rows in a Table Q&A Two-Minute Drill Self Test 94 Chapter 3: Manipulating Data T his chapter begins to look at that part of SQL known as Data Manipulation Language, or DML. We’ll get some perspective by looking at DML and where it fits into the larger context of SQL as a whole. Then we’ll review DML statements and look at some specific examples and usages of DML statements, and review some supplemental statements that are used to control transactions involving DML. Certification Objective 3.01 Describe Each Data Manipulation Language (DML) Statement In the last chapter, we looked at some DDL statements. Before we look at DML statements in detail, let’s put both DDL and DML in context with the rest of the set of the types of SQL statements. Then we’ll introduce the DML statements of interest to the exam. SQL Statement Overview All SQL statements are categorized into one of six different types of statements. The two largest and most significant “types” are Data Definition Language (DDL) and Data Manipulation Language (DML). The six types of SQL statements in Oracle SQL are shown in Table 3-1. As you can see in the table, many SQL statements are ignored by the exam. Naturally we will only concern ourselves with the exam, so in this book we’ll only look at three types of SQL statements: DDL, DML, and TCL. Describe Each Data Manipulation Language (DML) Statement Table 3-1 # Abbrev. 95 Six Types of SQL Statements in Oracle SQL Type of SQL Statement SQL Statements and Reserved Words Covered by the Exam Ignored by the Exam 1 DDL Data Definition Language CREATE ALTER (1) DROP RENAME TRUNCATE GRANT REVOKE FLASHBACK PURGE COMMENT ANALYZE AUDIT ASSOCIATE STATISTICS DISASSOCIATE NOAUDIT 2 DML Data Manipulation Language SELECT INSERT UPDATE DELETE MERGE CALL LOCK TABLE EXPLAIN PLAN 3 TCL Transaction Control Language COMMIT ROLLBACK SAVEPOINT SET TRANSACTION SET CONSTRAINT 4 Session Control Statements ALTER SESSION SET ROLE 5 System Control Statements ALTER SYSTEM 6 Embedded SQL Statements Any DML, DDL, or TCL that is integrated into a 3GL. (1) Except ALTER SYSTEM and ALTER SESSION, which are categorized under “System Control Statements” and “Session Control Statements”, respectively. Data Definition Language (DDL) DDL refers to those SQL statements that are used to build database objects. Specifically, DDL statements are used to n Create, alter, and drop tables and other database objects. n Add comments on a particular object to be stored in the database and associated with that object. 96 Chapter 3: Manipulating Data n Issue privileges to users to perform various tasks in the database. n Initiate performance analysis on objects using built-in tools. The following section briefly describes DDL statements that are tested by the exam. Used to create tables, views, indexes, synonyms, and other objects in the database. n CREATE Used to modify the structure, name, or some other attribute of an already existing object in the database. (Two exceptions are the uses of ALTER with the reserved words SESSION and SYSTEM. ALTER SESSION and ALTER SYSTEM are not technically considered DDL statements but fall under a different category. Neither is included on this exam.) n ALTER Used to remove a database object from the database that has already been created with the CREATE statement. n DROP Changes the name of an existing database object. n RENAME Removes all of the rows—i.e., data—from an existing table in the database. This is a special-purpose way to remove rows that serves as an alternative to the more commonly used DELETE statement. n TRUNCATE Provides “privileges”, or rights, to users to perform various tasks in the database. n GRANT n REVOKE Removes privileges that have been issued with the GRANT statement. n FLASHBACK n PURGE Restores an earlier version of a table or database. Removes database objects from the recycle bin. Adds comments to the data dictionary for database objects you have created. n COMMENT Each DDL statement is rich with options and clauses. We’ve already looked at CREATE TABLE; we’ll review others as we progress through the book. Data Manipulation Language (DML) DML refers to those statements in SQL that are used to work with data in the objects. DML statements are used to add, modify, and delete data in a database object, such as a table. Describe Each Data Manipulation Language (DML) Statement 97 The following section briefly describes each DML statement that is tested by the exam. n SELECT Displays data contained within a database table or view. n INSERT Adds data to a database table. n UPDATE n DELETE Modifies existing data in a table. Removes existing data from a table. Performs a combination of INSERT, UPDATE, and/or DELETE statements in one single statement. (MERGE is discussed in Chapter 15.) n MERGE The SELECT statement is rather involved and will get several chapters’ worth of review. The other DML statements are reviewed in this chapter and in various sections that follow. Transaction Control Language (TCL) No discussion of DDL and DML would be complete without a word about Transaction Control Language, or TCL. TCL statements can be used to save or cancel changes made to a database with DML within a given session. There are three TCL statements: n COMMIT Saves data to the database. n ROLLBACK Restores the database to an earlier state. Marks a point in a session to which future ROLLBACKS may optionally be issued. n SAVEPOINT These have been brief summaries; each statement will be thoroughly reviewed in greater detail as we progress through the book. Certain SQL keywords, such as CREATE, are not really a “command” or “statement” by themselves but become a command when combined with other reserved words, as in CREATE TABLE or CREATE SEQUENCE, which are commands or statements. In practice, CREATE may be called a “statement” or “command” by professionals in the field, and even by Oracle Corporation in various forms of documentation. But technically there is a difference. However, this isn’t an issue on the exam. Similarly, the terms “command” and “statement” tend to be used interchangeably by Oracle’s documentation. If you were to do some searches in the SQL Language Reference Manual, you’ll find plenty of examples of SQL statements being referred to as commands. Either is fine. And none of these issues are of concern on the exam. 98 Chapter 3: Manipulating Data DML Statement Descriptions DML statements are those statements that work with existing database objects to manipulate data. The DML statements that are of primary importance to the exam are as follows: n INSERT n UPDATE Add one or more rows of values to a table. Modify data within one or more existing rows of data in a table. n DELETE Remove one or more rows of data from a table. n SELECT Display one or more rows of data from a table. n MERGE A combination of INSERT, UPDATE, and/or DELETE. In addition to these DML statements, there are three additional SQL statements that are important for working with DML. These statements are not part of DML but instead are categorized as TCL. These statements are specifically identified by Oracle within the certification objectives for DML, so we’ll discuss them in this chapter. These are the statements we need to study: Save a set of DML modifications performed in the current database session. n COMMIT Undo a set of DML modifications performed during the current database session. n ROLLBACK Mark a position within a series of SQL statements in order to reserve the right to perform a selective ROLLBACK of segments of statements later, rather than performing an all-or-nothing ROLLBACK. n SAVEPOINT Certification Objective 3.02 Insert Rows into a Table The SQL statement to add rows to a table is the INSERT statement. The INSERT statement is often used to add one row at a time, but it may also be used to add Insert Rows into a Table 99 multiple rows at once by drawing them from elsewhere in the database and adding them to the target table with a single INSERT statement. INSERT may use expressions within its syntax. INSERT is used to add rows into a TABLE object. It can also be used to add rows to certain VIEW objects, but as we’ll see, a VIEW is simply a filter onto one or more tables, so ultimately—INSERT is still adding rows to TABLE objects. Default Column List Let’s look at an example of an INSERT statement. We’re going to add a row to the CRUISES table. First, let’s describe the CRUISES table so that we can see the columns—we’ll need to know the names and datatypes of those columns so we can build our INSERT statement (see Figure 3-1). Here’s an example of an INSERT statement you could use on this table (line numbers added): 01 02 03 04 05 06 07 08 Figure 3-1 The CRUISES table INSERT INTO CRUISES (CRUISE_ID, CRUISE_TYPE_ID, CRUISE_NAME, CAPTAIN_ID, START_DATE, END_DATE, STATUS) VALUES (1, 1, 'Day At Sea', 101, '02-JAN-10', '09-JAN-10', 'Sched'); 100 Chapter 3: Manipulating Data As with all SQL statements, the INSERT statement can be on a single line, or it can span multiple lines. The choice doesn’t matter as far as the syntax is concerned. We separated the components of the preceding statement in order to discuss it more easily here. Let’s analyze the syntax for this example of INSERT: The reserved words INSERT and INTO, followed by the name of the target table. n Line 1 Within a set of parentheses, a list of the table’s columns in no particular order. The order doesn’t need to match the order of columns in the table’s structure as shown with the DESC command, nor does it need to include all of the table’s columns, as long as we provide for all of the “required” columns, i.e., those with a NOT NULL constraint or something comparable (like the PRIMARY KEY constraint). n Lines 2–4 n Line 5 The reserved word VALUES. Within a set of parentheses, a series of expressions, in a very specific order—that is, in the same order as the columns are listed in lines 2–4, for this is how the data will be inserted—the first value in this list will be placed in the first column identified on line 2, and the second value identified in line 6 will be inserted into the second column identified in line 2, etc. n Lines 6–8 When the INSERT statement is submitted for execution, the following steps will be performed before the statement returns any results: n The existence and validity of the table in line 1 will be confirmed. n The existence and validity of the columns in lines 2–4 will be confirmed. n The expressions in lines 6–8 will be evaluated. n The datatypes of the expressions in lines 6–8 will be compared against the datatypes of the associated columns and evaluated for compatibility. n The values of the expressions in lines 6–8 will be applied to any constraints that might exist in the table. If all requirements for data entry to the target table are satisfied, and the INSERT statement is determined to be valid, then the statement will execute, and the row will be inserted into the table. In this example, the columns in our INSERT statement (lines 2–4) just happen to line up exactly with the sequence of the columns in the table’s structure. In that Insert Rows into a Table 101 sort of situation, the column list at the beginning of the INSERT statement is not required. In other words, we could have omitted lines 2–4 in that example. Let’s do that—here is a valid alternative to the INSERT statement we just reviewed: 01 02 03 04 05 INSERT INTO CRUISES VALUES (1, 1, 'Day At Sea', 101, '02-JAN-10', '09-JAN-10', 'Sched'); This example will produce the same result, because the expressions in line 3 through line 5 just happen to coincide in number (there are seven) and datatype with the columns in the CRUISES table structure, in order, as we saw in Figure 3-1. If that structure changes, the statement above may fail. For example, if a new column is added to CRUISES, the above example will fail, whereas the prior INSERT example—which names the columns—will probably continue functioning correctly. As before, all datatypes and constraints must be honored with the INSERT. If you’re following along at home with your own database, note that if you’ve already entered the earlier version of this particular INSERT statement, this variation will not work because the value for CRUISE_ID is repeated here; since CRUISE_ID is declared as a PRIMARY KEY in the CRUISES table, the duplicate value of “1” will not be accepted in this second INSERT statement, since a “1” already exists from the earlier INSERT. But that aside—the syntax of this INSERT statement is just as valid as the first example we looked at. So now you’re asking yourself—which is better? Identifying the column list by name, or depending on the default approach? The answer is: it depends on the situation. Generally speaking, in my experience, I tend to prefer the method by which I name each column specifically, and not depend on the default. There are several advantages to this approach. One: the table structure might change over time—for example, if the table is dropped and recreated in some sort of future upgrade or maintenance effort, the columns could end up in a different sequence. That could trigger a syntax error with the default INSERT, or it could result in something worse—no syntax error, but a column mismatch where the datatypes happen to line up and the INSERT statement works—technically—but isn’t putting the data in the columns you originally intended. For example, consider the SQL statements shown in Figure 3-2. Here we see a table called TEST_SCORES and an INSERT statement for it. Note that the INSERT uses the default column list. Nothing wrong with that—technically. But now look at Figure 3-3. Notice that the TEST_SCORES columns are in a different order. Yet the same INSERT statement—with the syntax that does not list columns 102 Chapter 3: Manipulating Data by name—successfully executes. Why? Because SQL sees only the datatypes of the list of values in the INSERT statement. In this case, both values being inserted are numeric literals, and numeric literals are acceptable in either column. So what is the intent here? Is 100 the value for the TEST_SCORE_ID and 85 is the value for the SCORE? Or is it the other way around? The point is that you cannot tell in this particular variation of INSERT statement syntax. By always enumerating the list of columns, you can avoid any confusion. However, there’s one issue to keep in mind: if, in the future, the table into which you are inserting values might be modified in such a way that new columns are added to it, then you’ll need to remember to revisit INSERT statements like this and edit them if necessary. If you’ve enumerated a column list, and the table is later altered with the addition of new columns, your old INSERT statement will continue to function normally; it just won’t provide data for the new columns—assuming, of course, that no constraints have been applied to the new columns that would require data. But in all the professional situations I’ve encountered, these types of issues are less problematic and easier to maintain than the problem of datatype matches that support illogical data entry. The moral of this story: always identify your column names in an INSERT statement. Figure 3-2 The TEST_ SCORES table Figure 3-3 The TEST_ SCORES table with a different structure Insert Rows into a Table 103 Enumerated Column List The INSERT syntax we just reviewed assigns values to each column in the table. It accomplishes that feat by first listing, by name, each column in the table, in the same order in which the columns appear in the table’s structure. But you are not required to list the columns in order. For example: 01 02 03 04 05 06 INSERT INTO CRUISES (CRUISE_ID, CRUISE_NAME, STATUS, CAPTAIN_ID, START_DATE, END_DATE) VALUES (2, 'Bermuda and Back', 'Done', 101, '07-APR-08', '14-APR-08'); This is also a valid INSERT statement. Notice how in lines 2–3 we list the columns in a different order from the table structure. This is fine, so long as the list of expressions to be inserted (lines 5 and 6) are in the order as the column list (lines 2 and 3). And they are: CRUISE_ID CRUISE_NAME STATUS CAPTAIN_ID START_DATE END_DATE = = = = = = 2 'Bermuda and Back' 'Done' 101 '07-APR-08' '14-APR-08' Another change with this INSERT is that we do not include every column in the table. We ignore the column CRUISE_TYPE_ID. That’s also fine, provided that all required columns are included, and in this particular table, we have two columns that are NOT NULL, and both are included in this INSERT statement. Datatype Conversion When the INSERT statement is evaluated for syntactical correctness, the datatypes of the values listed in lines 6–7 will be compared to the datatypes of the columns identified in lines 2–3. The datatypes must be compatible. But the operative word here is “compatible”, not identical. For example, this would actually work: 01 02 INSERT INTO CRUISES VALUES (2, '101'); (CRUISE_ID, CAPTAIN_ID) Notice that the 101 value in line 2 is in quotation marks, identifying that value as a string literal. Normally that is used for text, and in this case the text is being assigned to the column CAPTAIN_ID, which only accepts numeric data. But no 104 Chapter 3: Manipulating Data error message occurs, and this INSERT will execute. The reason: Oracle SQL is smart enough to figure out that the text contained within the literal value is all numeric data anyway, and will process the INSERT statement correctly. Naturally you don’t want to depend on this in serious software application design when you don’t have to, but it’s an important feature to be aware of. This feature is known in Oracle documentation as “implicit datatype conversion”. Oracle Corporation formally advises that software developers avoid depending on implicit datatype conversion in serious application development, relying instead on explicit datatype conversion, which we’ll look at when we review SQL conversion functions such as TO_CHAR, TO_NUMBER, and TO_DATE. The rule of thumb is that wherever it makes sense, Oracle SQL will perform an implicit datatype conversion if at all possible. Naturally it cannot convert something like ‘Montana’ to a DATE datatype. But if you try to enter a numeric value such as 2011 into a datatype such as VARCHAR2, an implicit datatype conversion will convert the value of 2011 to ‘2011’ and the statement will succeed. INSERT and Constraints If we happen to include data that violates a constraint, then we might get a run-time error. This is important: violation of a constraint is not a syntax error, but a runtime error. For example, let’s say we’ve created a table with the following CREATE TABLE statement: CREATE TABLE CRUISES (CRUISE_ID NUMBER, CRUISE_NAME VARCHAR2(30), START_DATE DATE, END_DATE DATE, CONSTRAINT CRUISE_ID_PK PRIMARY KEY (CRUISE_ID), CONSTRAINT CRUISE_NAME_CK CHECK (CRUISE_NAME IN ('Hawaii','Bahamas','Bermuda', 'Mexico','Day at Sea') ) ); This table includes a CHECK constraint that will limit any values for the CRUISE_NAME to one of the listed strings: ‘Hawaii’, ‘Bahamas’, ‘Bermuda’, ‘Mexico’, or ‘Day at Sea’. Anything else will be rejected. Next, let’s peek ahead a little bit and create a SEQUENCE object, like this: CREATE SEQUENCE SEQ_CRUISE_ID; Insert Rows into a Table 105 This CREATE SEQUENCE statement creates an object that will dispense individual values, and we’ll use it to generate primary key values for our INSERT statements. Next, let’s use that SEQUENCE object and issue the following INSERT statement (line numbers added): 01 02 03 04 INSERT INTO CRUISES (CRUISE_ID, CRUISE_NAME) VALUES (SEQ_CRUISE_ID.NEXTVAL, 'Hawaii'); This INSERT statement adds a single row to the CRUISES table. The new row consists of two values. In line 4, the first value calls on the newly created SEQUENCE object and asks for the next available value from the sequence, indicated with the reserved word NEXTVAL. Given that our sequence is brand new, and it was created with all the default settings and has never been used before, then the next available value will be 1. The second value we’re inserting here is the literal string ‘Hawaii’, which is syntactically correct, and it also satisfies the constraint object attached to the CRUISE_NAME column in the CREATE TABLE statement. However, had we violated the constraint, the INSERT could be syntactically correct but logically incorrect. For example, consider this variation on the same INSERT statement: 01 02 03 04 INSERT INTO CRUISES (CRUISE_ID, CRUISE_NAME) VALUES (SEQ_CRUISE_ID.NEXTVAL, 'Hawaii and Back'); In this example, the string ‘Hawaii and Back’ violates the CHECK constraint we created for the CRUISES table. Therefore, even though this version of the INSERT statement is syntactically correct, it will fail on execution and the CHECK constraint will reject the attempt to enter this row. See Figure 3-4 for a sample of the execution error resulting from this INSERT statement—and while we’re at it, let’s show this from the SQL Developer tool instead of the SQL*Plus tool that we’ve been using up to now. Note the “ORA-02290” run-time error message. The CHECK constraint is identified, and we see in this display that we’re logged in to the “EFCODD_TEST” user account. We’re far from done with INSERT, and we will address more advanced concepts of INSERT in later chapters, when we look at subqueries (Chapter 9) and large data sets (Chapter 15). But first, let’s look at the rest of the major DML statements. 106 Chapter 3: Manipulating Data Figure 3-4 Execution error for the INSERT statement Certification Objective 3.03 Update Rows in a Table The UPDATE statement is a DML statement that is used to modify existing data in the database. It operates on one table at a time. It is used to modify one or more columns of data and can be used to change all the rows in a table, or it can be used to change data in only selected rows. As with INSERT, the UPDATE statement can also work with VIEW objects, and as with INSERT, we’ll see later that VIEW objects simply represent one or more TABLE objects, so that any UPDATE that operates on a VIEW is ultimately changing data in TABLE objects. Let’s look at an example of UPDATE. 01 02 03 04 UPDATE CRUISES SET CRUISE_NAME = 'Bahamas', START_DATE = '01-DEC-11' WHERE CRUISE_ID = 1; This UPDATE will look for any and all existing rows in the CRUISES table where the value for CRUISE_ID equals 1. For all of those rows, it will change the value for CRUISE_NAME to ‘Bahamas’, and change the value for START_DATE to ‘01-DEC-11’. When we say that it will “change” those values, this example of UPDATE doesn’t care if the column in question is already populated with data, or if the existing value Update Rows in a Table 107 is NULL. Either way, UPDATE will overwrite whatever else may or may not already be there, and place the new value in the column. Also—this particular example is changing all the rows where the CRUISE_ID value is 1, but remember—we specifically created the CRUISES table so that its CRUISE_ID column has a PRIMARY KEY constraint applied to it. In other words—in this example there will only be one row with a CRUISE_ID of 1. But there’s nothing inherent in the UPDATE statement itself that makes this restriction; that is solely the result of the constraint. In other words, if all you saw was this UPDATE statement, you would have to say that “all” rows with a value of 1 in the CRUISE_ID column will be updated. This is a major reason why we create PRIMARY KEY constraints—to help UPDATE statements like this identify a single row within a table. Let’s look a little more closely at the syntax of this UPDATE statement. n Line 1 The reserved word UPDATE, followed by the name of the target table One occurrence of the reserved word SET, followed by a series of one or more expressions consisting of four elements: n Lines 2–3 n A column name n The assignment operator “=” n An expression resulting in a value appropriate for the column’s datatype n Either a comma, if additional expressions are to follow—or nothing, if the list of expressions is completed An optional WHERE clause, defining a condition to identify rows in the table n Line 4 Now that we’ve reviewed our sample UPDATE in detail, let’s observe a few important issues about the UPDATE statement in general: n The series of columns enumerated in the SET clause does not need to refer to the table’s columns in any particular order. n The SET clause does not need to reference all required columns—i.e., NOT NULL columns. Remember—UPDATE is not adding a row, but modifying existing data. The row is already in the table, so presumably the data within the row already honors all required constraints. n Any column names that are not included in the UPDATE statement’s SET clause will not be changed. 108 Chapter 3: Manipulating Data n Any attempt by UPDATE to change data so that the result would be to cause the row to violate a constraint—will be rejected at execution. n The WHERE clause is not required. If it is omitted, the UPDATE will process each row in the table. Expressions The UPDATE statement can use expressions to assign values to any given column. Expressions may include literal values, valid column references, mathematical expressions, and SQL functions. Expressions are an involved topic and will be discussed in Chapter 4 when we look at the SELECT statement. For now, let’s look at an example to get an idea of what can be done. Here’s an UPDATE statement that uses expressions in the SET clause: UPDATE COMPENSATION SET SALARY = SALARY * 1.03, LAST_CHANGED_DATE = SYSDATE WHERE EMPLOYEE_NUMBER = 83; The preceding statement is an UPDATE statement intended to change data in a table called COMPENSATION. The UPDATE statement will change data in any and all rows with a value of 83 in the EMPLOYEE_NUMBER column. There are two columns whose values are changed: n The SALARY column is changed to equal itself times 1.03. This has the effect of increasing its own value by 3 percent. n The LAST_CHANGED_DATE column is set to the value of SYSDATE. SYSDATE is a built-in SQL function that contains the current date and time according to the operating system wherever the database is installed. We’ll discuss expressions in full in Chapter 4. The point of this example is to demonstrate how expressions may be used within an UPDATE statement. Constraints If the UPDATE statement violates any constraint on a table, the entire UPDATE statement will be rejected, and none of the modifications will be accepted for any of the rows. In other words, if the UPDATE statement attempts to change any data in any column of any row in a table, and any one change results in any one constraint violation, then the entire UPDATE statement is rejected. Update Rows in a Table 109 For example, review these SQL statements: CREATE TABLE PROJECTS ( PROJECT_ID NUMBER PRIMARY KEY , PROJECT_NAME VARCHAR2(40) , COST NUMBER , CONSTRAINT CK_COST CHECK (COST < 1000000)); INSERT INTO PROJECTS (PROJECT_ID, PROJECT_NAME, COST) VALUES (1,'Hull Cleaning', 340000); INSERT INTO PROJECTS (PROJECT_ID, PROJECT_NAME, COST) VALUES (2,'Deck Resurfacing', 964000); INSERT INTO PROJECTS (PROJECT_ID, PROJECT_NAME, COST) VALUES (3,'Lifeboat Inspection', 12000); In this code, we create a table PROJECTS that includes a couple of constraints; one in particular is the CHECK constraint that limits any value in the COST column to numbers that are less than a million. Now see Figure 3-5. Notice how we issue an UPDATE statement in which we increase the cost of each project by 20 percent. This will cause the row identified by PROJECT_ID 2 to bump up over our limitation on the COST column. The result: the entire UPDATE statement is rejected. However, see Figure 3-6: here we execute a slight variation of that UPDATE statement where we avoid the problem row, and the UPDATE statement executes. Figure 3-5 UPDATE statement: one constraint violation rejects the entire statement. 110 Chapter 3: Manipulating Data Figure 3-6 UPDATE statement: no constraints violated Don’t get the UPDATE statement’s SET clause mixed up with the “set” operators of UNION, INTERSECT, and MINUS.Those are two completely separate issues and both are addressed on the exam. You’ll study the “set” operators in Chapter 12. The WHERE Clause The UPDATE statement’s WHERE clause is arguably its most powerful and important feature. WHERE determines which of the existing rows in the table will be modified by the SET clause. The WHERE clause is not unique to the UPDATE statement; it’s also used for similar purposes with DELETE and SELECT. We’ll review WHERE in more detail in the chapter on the SELECT statement. A word about terminology: UPDATE can only be used to modify existing rows in a table. On a practical level, end users may speak in terms of “adding” data to a table when all they really mean is that they wish to set a value to a column within an existing row. In other words, when you are speaking with non-technical users and the subject of “adding” data to a table is discussed, be aware that this doesn’t necessarily mean you’ll be using the INSERT statement—an UPDATE may actually be in order. Similarly, you can use UPDATE to “remove” values from the table by setting a given row’s column to NULL. But you aren’t necessarily removing a row in that situation—just modifying the contents of it.To remove a row, you need the DELETE statement. Delete Rows from a Table 111 Certification Objective 3.04 Delete Rows from a Table The DELETE statement is used to remove rows from tables in the database. Rows are identified by the WHERE clause of DELETE. If WHERE is omitted, DELETE removes all the rows from the table. When DELETE identifies a row with the WHERE clause, it removes the entire row from the table, not just an individual data element from within a row. If your goal is to remove a single value from within an existing row, while retaining the row in the table, then you don’t use DELETE—you use UPDATE to identify the row and set the desired value to NULL. The DELETE clause is very simple. Here’s an example: 01 02 DELETE FROM PROJECT_LISTING WHERE CONSTRUCTION_ID = 12; This sample deletes any and all rows in the PROJECT_LISTING table where a column called CONSTRUCTION_ID contains a value of 12. All rows that contain a 12 in the CONSTRUCTION_ID column will be deleted from the table. Let’s look at this sample statement: The required reserved word DELETE, followed by the optional reserved word FROM, followed by the required name of the target table n Line 1 n Line 2 An optional WHERE clause As we just said, the reserved word FROM is optional. In other words, this variation of the preceding DELETE statement is also valid: 01 02 DELETE PROJECT_LISTING WHERE CONSTRUCTION_ID = 12; This DELETE statement performs the same function without the reserved word FROM. The WHERE clause for DELETE performs the same function as the WHERE clause in the UPDATE statement and in the SELECT statement. It is very powerful, and there’s a lot to it. We’ll look at it in more detail when we discuss SELECT and throughout other chapters in the book. 112 Chapter 3: Manipulating Data One thing to note, however—if you omit the WHERE clause, you’ll delete every row in the table. Certification Objective 3.05 Control Transactions So far in this chapter, we’ve looked at the SQL statements INSERT, UPDATE, and DELETE. Those three statements, along with SELECT, form a set of SQL statements known as Data Manipulation Language, or DML. There are other types of SQL statement, but one type in particular is of special importance to DML. As mentioned earlier in the chapter, that type is known as Transaction Control Language, or TCL. These statements are important to any SQL session in which you use DML statements, as TCL statements provide the functionality to save or undo the changes made with DML statements. There are three TCL statements we’ll look at in this section: COMMIT, ROLLBACK, and SAVEPOINT. Saves changes to the database since the session began, or since the most recent commit event in the session, whichever is more recent. n COMMIT Undoes changes to the database back to the last “commit” point in the session. n ROLLBACK Provides an optional “commit” marker in a session, in order to empower future “commit” or “rollback” actions by providing one or more optional points at which you may—or may not—undo changes. n SAVEPOINT Let’s look at each statement in more detail. COMMIT One reason that women love men who are Oracle professionals: we’re not afraid to “commit”. The SQL statement COMMIT is used to save changes made to any tables that have been modified by the DML statements INSERT, UPDATE, and DELETE. In other words, COMMIT makes changes to the database permanent, and once committed, those changes can no longer be undone with a ROLLBACK Control Transactions 113 statement. That isn’t to say that the data cannot be changed back with additional DML statements; of course it can. But before a COMMIT is executed, changes to the database can be undone with a ROLLBACK statement. After the COMMIT, however, that option no longer exists. A series of SQL statements is considered a “transaction” by SQL and is treated as one unit. The changes you make within a transaction are not made permanent until they are committed. A commit event completes a transaction. There are two kinds of commit events: n An explicit commit, which occurs when the COMMIT statement is executed n An implicit commit, which occurs automatically when certain database events occur Until a commit event of either type occurs, no changes that may have been performed to tables in the database are made permanent, and all changes have the potential for being undone. Explicit commits occur when the COMMIT statement is executed. Implicit commits occur without the COMMIT statement but instead occur when certain types of database events occur. Let’s discuss both situations. Explicit Commit An explicit commit occurs whenever the COMMIT statement is executed. The syntax of COMMIT is simple: COMMIT; The COMMIT statement has a few parameters that are not required for the exam. One worth noting, however, is the optional keyword WORK, as in COMMIT WORK; The WORK keyword is included for compliance with ANSI standard SQL, but it is not required in Oracle SQL. To understand how COMMIT works, consider the following series of SQL statements: 01 02 03 04 05 INSERT INTO POSITIONS (POSITION_ID, POSITION_NAME) VALUES (100, 'Manager'); SELECT POSITION_ID, POSITION_NAME FROM POSITIONS; COMMIT; 114 Chapter 3: Manipulating Data In this series of statements, the change to the table made by the INSERT statement is made permanent by the COMMIT statement. Without it, the INSERT changes could be undone with a ROLLBACK statement. Implicit Commit An implicit commit occurs when certain events take place in the database. Those events include n Immediately before and immediately after an attempt to execute any DDL statement, such as CREATE, ALTER, DROP, GRANT, or REVOKE. Note: even if the DDL statement fails with an execution error (as opposed to a syntax error), the “before” implicit commit is executed and takes effect. n A normal exit from most of Oracle’s utilities and tools, such as SQL*Plus or SQL Developer. (One exception: Oracle’s precompilers, which do not perform an implicit commit upon exit but instead perform a rollback.) When these events take place, an implicit commit is automatically executed— meaning that all uncommitted changes become permanent in the same way as they would if you had executed the COMMIT statement. Here’s an example: UPDATE SHIPS SET HOME_PORT_ID = 12 WHERE SHIP_ID = 31; ALTER TABLE PORTS ADD AUTHORITY_NOTE VARCHAR2(75); In this example, the change performed with the UPDATE statement has become permanent. Why? Because ALTER TABLE is a DDL statement and carries with it an implicit commit. As far as the SHIPS table is concerned, this would have an equivalent impact: UPDATE SHIPS SET HOME_PORT_ID = 12 WHERE SHIP_ID = 31; COMMIT; In both examples, the UPDATE statement is committed. The first example results in an implicit commit. The second example—above—results in an explicit commit. From the perspective of the SHIPS table, the ultimate effect is the same— an ALTER TABLE command or a COMMIT command both have the end result of issuing a commit event on the changes involved with the UPDATE statement, and with any previous statements that may have not yet been committed. Control Transactions 115 COMMIT and Other Users The COMMIT statement is very important when multiple users are logged in simultaneously. In a typical scenario, a set of database tables will exist and be “owned” by a given user for the benefit of other users throughout the database. Those other users, as we’ll see later, must be granted “privileges” to get access to those tables. Those privileges can range from reading, modifying, and deleting data, but for the purpose of our discussion here, we want to look at how COMMIT changes the appearance of the data. Let’s say that one user account owns a schema that includes several tables, and that all users have been granted privileges to see (SELECT) data from these tables, and that only the owning user account retains the privilege of modifying any data in those tables. If that owning user then proceeds to perform a series of DML statements, those changes will be entirely visible to that owning user, but not to any of the other users with read privileges on the tables—until a commit event occurs. Unless the data is committed, the other users will not see the changes. The owning user may perform a large series of INSERT, UPDATE, and DELETE statements, and even print reports and snapshot screen displays showing the results of the modifications, performing SELECT statements to do it—but unless and until a commit event occurs, nobody else in the database, regardless of whatever privileges they may have, will be capable of seeing the changed data. Only after some sort of commit event occurs—either explicit or implicit—do the changes become “permanent”, as Oracle likes to say, and therefore visible to the full user population. Now, let’s look at a variation of this scenario. Look at Figure 3-7. In this scenario, USER_1 owns a table SHIPS, and has granted UPDATE privileges to USER_2. This means that USER_2, who does not own the SHIPS table, has the right to issue UPDATE statements and change that data. So USER_2 issues an UPDATE statement on SHIPS—but does not commit the changes. The result: If USER_3 has SELECT privileges and tries to query the SHIPS table owned by USER_1, the changes made by USER_2 are not visible to anyone other than USER_2. USER_3, for example, cannot see the changed data. In this example, the value for CAPTAIN_ID is 0, and USER_2 issues a change to that value and updates it to 7. But USER_3 does not yet see the change, since it hasn’t been committed to the database. For that matter, nobody sees the change—other than USER_2. Not even the table owner, USER_1, will see USER_2’s change until USER_2 causes a commit event to occur. 116 Chapter 3: Manipulating Data Figure 3-7 USER_2 USER_1 Uncommitted change Table SHIPS UPDATE privilege UPDATE SHIPS SET CAPTAIN_ID = 7 WHERE SHIP_ID = 1; USER_3 SELECT privilege SELECT CAPTAIN_ID FROM SHIPS WHERE SHIP_ID = 1; CAPTAIN_ID ---------0 Database Next, look at Figure 3-8. Here, USER_2 has issued a COMMIT statement to create an explicit commit event. The result: when USER_3 queries the SHIPS table, the change issued by USER_2 is visible. In this way, changes made prior to any commit event are in a sort of staging area, where the user can work in what is almost a “draft” mode. However, any commit event—explicit or implicit—will make changes permanent and expose the new data to the user population at large. ROLLBACK The ROLLBACK statement is somewhat equivalent to the “undo” function common to many software applications. ROLLBACK undoes any changes to the database that have been performed within a given session by the user who issues the ROLLBACK. It does not remove any changes that have already been committed. Control Transactions Figure 3-8 USER_1 Committed change Table SHIPS 117 USER_2 UPDATE privilege UPDATE SHIPS SET CAPTAIN_ID = 7 WHERE SHIP_ID = 1; COMMIT; USER_3 SELECT privilege SELECT CAPTAIN_ID FROM SHIPS WHERE SHIP_ID = 1; CAPTAIN_ID ---------7 Database Also, if other users have committed any changes during their own respective sessions, those changes are unaffected—the only changes that are rolled back are those changes issued by the user performing the rollback. Here’s an example: COMMIT; INSERT INTO PORTS (PORT_ID, PORT_NAME) VALUES (701, 'Chicago'); DELETE FROM SHIPS; ROLLBACK; In this example, one INSERT statement and one DELETE statement are issued. The results: we add one row to the PORTS table and delete all of the rows in the SHIPS table. But then we issue a ROLLBACK statement, and both changes are eliminated. It is as if those two DML statements never happened. The PORTS and SHIPS tables are both restored to their original condition at the time of the last COMMIT event. 118 Chapter 3: Manipulating Data Furthermore, since none of the DML statements were ever committed, no users saw the changes—other than, of course, the one who issued the statements. One aspect that’s interesting about this series of statements is that the changes performed by uncommitted DML statements are visible to the issuing user until they are rolled back. For example, see Figure 3-9. The figure shows the following series of steps: n An explicit COMMIT statement n A SELECT to demonstrate the data within the SHIPS table n An UPDATE to change data in the SHIPS table n The same SELECT statement to demonstrate the changed data n A ROLLBACK to remove the effects of the UPDATE statement n The same SELECT statement yet again, showing that the SHIPS table’s condition has been restored At no time during this process did any other user see the effects of the UPDATE statement. The changes were visible only to the user issuing the statements. Figure 3-9 Sample session with ROLLBACK Control Transactions 119 An implicit rollback occurs when a program abnormally terminates. In other words, uncommitted changes at the time of an abnormal termination of, for example, SQL*Plus or SQL Developer will not be committed to the database. SAVEPOINT The SAVEPOINT statement is part of TCL that supports the ROLLBACK and COMMIT statements. The SAVEPOINT statement establishes demarcation points within a transaction in order to empower any following COMMIT and/ or ROLLBACK statements to subdivide the points at which data can be saved or undone. In other words, without SAVEPOINT, the COMMIT and ROLLBACK statements can only operate on a sort of all-or-nothing basis. Once a series of statements have been executed, the entire series can either be saved or undone in one large group. But if periodic SAVEPOINTs have been issued along the way, then the following COMMIT or ROLLBACK can be designed to save or restore data to those points in time marked by one or more SAVEPOINT statements, thus providing a finer level of detail at which the transaction can be controlled. Here is an example of SAVEPOINT: 01 02 03 04 05 06 COMMIT; UPDATE SHIPS SET HOME_PORT_ID = 21 WHERE SHIP_ID = 12; SAVEPOINT SP_1; UPDATE SHIPS SET HOME_PORT_ID = 22 WHERE SHIP_ID = 12; ROLLBACK WORK TO SP_1; COMMIT; In this example, we start with an explicit COMMIT on line 1 and then issue an UPDATE statement. Then on line 3, we issue a SAVEPOINT statement and name it “SP_1”. That’s followed by a second UPDATE statement. Given that we elected to issue the SAVEPOINT, we have an option on line 5 that we haven’t seen yet, and that is to “undo” the previous UPDATE statement, but only that second UPDATE, not the first, and we accomplish this by rolling back to the SAVEPOINT. Then we COMMIT our changes. End result: the value in the SHIP_ID 12 row for HOME_PORT_ID is 21. Here’s another example; see if you can determine what the resulting value for HOME_PORT_ID will be here: 01 02 03 COMMIT; UPDATE SHIPS SET HOME_PORT_ID = 21 WHERE SHIP_ID = 12; SAVEPOINT MARK_01; 120 Chapter 3: Manipulating Data 04 05 06 07 08 UPDATE SHIPS SET HOME_PORT_ID = 22 WHERE SHIP_ID = 12; SAVEPOINT MARK_02; UPDATE SHIPS SET HOME_PORT_ID = 23 WHERE SHIP_ID = 12; ROLLBACK TO MARK_02; COMMIT; In this series of SQL statements, what is the resulting value of the SHIPS table’s HOME_PORT_ID column where the SHIP_ID is equal to 12? The answer: 22. That is the value that is permanently saved to the database after the final COMMIT statement is executed. In this example, we created two SAVEPOINTs—one we chose to name “MARK_01”, and another we chose to name “MARK_02”. We could have chosen any name for these savepoints that we wanted, according to the rules of naming database objects. By naming them, we reserve the right to selectively roll back to one or the other named SAVEPOINT. In this case, we chose to issue a ROLLBACK to the SAVEPOINT named “MARK_02”. This statement effectively restores the condition of the entire database to the point where the SAVEPOINT was executed, which, in this example, is prior to the UPDATE statement on line 6. In other words, it’s as if the line 6 UPDATE statement had never been executed. The rules for using SAVEPOINT include the following: n All SAVEPOINT statements must include a name. Behind the scenes, the SAVEPOINT name you create is associated with a “system change number”, or SCN. This is what the SAVEPOINT is marking (you’ll read more about SCN in Chapter 11); n You should not duplicate SAVEPOINT names within a single transaction— and remember that a transaction is a series of one or more SQL statements that ends with a commit event. If you duplicate a name, know that you will not receive a syntax or execution error. Instead, the new SAVEPOINT will simply override the earlier SAVEPOINT, effectively erasing it. n Once a commit event occurs—either an explicit or implicit commit event— all existing savepoints are erased from memory. Any references to them by future TCL statements will produce an error code. Regarding that last point, here’s an example of what we’re talking about: 01 02 03 04 05 COMMIT; UPDATE SHIPS SET HOME_PORT_ID = 21 WHERE SHIP_ID = 12; SAVEPOINT MARK_01; COMMIT; ROLLBACK TO MARK_01; Control Transactions 121 In the preceding example, the ROLLBACK statement on line 5 is wrong for two reasons. One, it’s logically irrelevant since there is nothing to roll back—the COMMIT on line 4 permanently saved everything, and no additional SQL statements have been executed by the time the ROLLBACK is executed on line 5. But in addition, the ROLLBACK makes a reference to a SAVEPOINT that does not exist, so it will produce an error. Without the named savepoint reference, the ROLLBACK would execute just fine and simply have no impact on the database. But with the reference to a named SAVEPOINT that no longer exists by the time the ROLLBACK is executed, the result of line 5 is an error code. SAVEPOINT is particularly useful when managing a large series of transactions in which incremental validation must be required, wherein each individual validation requires a complex series of DML statements that might fail but can be programmatically corrected and validated before moving on to the next increment. A great example of this occurs in the financial world. When reconciling a set of financial books for a given organization, you might find it necessary to validate an account within a larger chart of accounts. During each individual account validation process, there may be a need to roll back some statements before making some changes and attempting validation again. Then, once a given account is validated, you might want to declare that account “temporarily authorized” and then move on to attempt to validate the next account. Furthermore, you may wish to defer a complete COMMIT until all accounts have been validated, and yet not necessarily have to undo everything when a particular account fails, and simply redo that one account before moving on. SAVEPOINT is perfect for this—as each individual account is validated, a SAVEPOINT can be established, so that subsequent account validation attempts that might fail can trigger a ROLLBACK without undoing the earlier accounts that were already successfully validated. Then, when all accounts are validated—and not before—a single COMMIT can declare the full set of validated rows to the database with a permanent save. ROLLBACK Revisited Now that we’ve seen SAVEPOINT, let’s take another look at the syntax for ROLLBACK and see how it can be used to roll back to a particular named SAVEPOINT. So far, we’ve seen this form of the ROLLBACK statement: ROLLBACK; If the single word ROLLBACK is executed by itself, it will ignore any SAVEPOINT statements that may have been executed since the most recent commit event, and undo any changes made by the user since the time of the last commit event. 122 Chapter 3: Manipulating Data However, if ROLLBACK is intended to undo any changes since a named SCN was established by SAVEPOINT, then it can name the SCN specifically. For example, if a SAVEPOINT statement established a demarcation with an SCN named “scn_01”, like this: SAVEPOINT scn_01; . . . then a subsequent ROLLBACK can selectively undo changes to this point like this: ROLLBACK WORK TO scn_01; Let’s look at the components of this form of the ROLLBACK statement: n First, the reserved word ROLLBACK n The optional reserved word WORK n The required reserved word TO n The name of an SCN as named by a SAVEPOINT statement that was executed after the most recent commit event Note that the WORK reserved word is optional. WORK is part of the ANSI standard but is not required in the Oracle implementation. If a ROLLBACK statement is executed that names a non-existent SAVEPOINT, SQL will display an error code warning that the rollback was attempting to roll back to a save point that was never established. The ROLLBACK will fail, and nothing will change regarding the state of the database. At that point, any outstanding changes will remain in an uncommitted state and could still be committed or rolled back. Certification Summary There are six types of SQL statements: DDL, DML, TCL, and three others. The exam concerns itself with the first three. DDL, or Data Definition Language, consists of those statements that are used to build objects in the database, change the structure of those objects, or remove those objects from the database. DDL also includes statements to issue or retract privileges for other users to work with database objects. DDL statements include those that start with the reserved words CREATE, ALTER, DROP, GRANT, and REVOKE. We say “start with” because of situations like CREATE, which by itself is only a “reserved word”, but when combined with Control Transactions 123 various database object names can become a statement. (A statement is also known as a command.) Examples include CREATE TABLE, CREATE INDEX, and others. DML is Data Manipulation Language. DML consists of those SQL statements that are used to work with data that is contained within database objects, such as tables. DML statements include INSERT, UPDATE, DELETE, and SELECT. The INSERT statement adds rows of data to a table. In its simplest form, it adds one row at a time. Its syntax starts with the reserved words INSERT INTO and the name of a single database table, followed by an optional column list, followed by the reserved word VALUES, followed by a list of values to be inserted into the table, enclosed in parentheses. The list of values is presented in the same sequential order as the column list, meaning that for the row that the INSERT statement is adding to the table, the first value in the list will be added to the first column in the column list, then the second value will be added to the second column, and so on. The datatypes of the values should be appropriate for the datatypes of the columns to which the values are being inserted. Any constraints that are not honored will cause the INSERT statement to be rejected at execution time. For example, if a column has a NOT NULL constraint, then the INSERT statement needs to provide a valid value for that particular column or else the entire effort to insert the entire row will fail. If the INSERT statement omits the column list, then the value list is assumed to be in the order of the columns according to the target table’s structure, and each column is assumed to be accounted for in the values list. The UPDATE statement is used to modify rows of data in the table. It includes the optional WHERE clause, which is used to identify which rows the UPDATE is intended to modify. If the WHERE clause is omitted, then the UPDATE statement will attempt to modify all rows in the target table. The UPDATE statement uses the reserved word SET, followed by pairs of column names and values. Each value can be substituted with an expression. Expressions may include literal values, any available table column, mathematical equations, and SQL functions (which we’ll review in Chapter 6, among others). The DELETE statement removes rows from a table. The optional WHERE clause can be used to identify which rows are to be deleted. However, if the WHERE clause is omitted, then every row in the table shall be deleted. TCL, which is separate from DML, is used extensively within DML transactions in order to control whether data will be committed to the database—i.e., made “permanent” as Oracle documentation (and others) like to say. The TCL commands include COMMIT, ROLLBACK, and SAVEPOINT. COMMIT makes permanent any outstanding changes to the table since the last commit event. Commits can occur explicitly or implicitly. Explicit commits 124 Chapter 3: Manipulating Data occur with the simple SQL statement of COMMIT. Implicit commits occur when other events take place in the database, such as any DDL statement. A GRANT, for example, will automatically commit all changes to the database since the last COMMIT. ROLLBACK can be used to “undo” a series of statements. ROLLBACK used by itself undoes any changes made by the user to the database since the most recent commit event, implicit or explicit, took place. But if a SAVEPOINT has been issued, then the ROLLBACK may optionally roll back to the SAVEPOINT. SAVEPOINT names a “system change number”, or SCN, and empowers future executions of the ROLLBACK statement to go back to earlier versions of the database incrementally. Two-Minute Drill 3 125 Two-Minute Drill Describe Each Data Manipulation Language (DML) Statement q There are six types of SQL statements; three types are subjects on the exam. q Data Definition Language is DDL. q Data Manipulation Language is DML. q Transaction Control Language is TCL. q There are five DML statements of primary importance to the exam: INSERT, UPDATE, DELETE, SELECT, and MERGE. q INSERT adds rows to a table. q UPDATE modifies existing rows in a table. q DELETE removes existing rows from a table. q SELECT displays data from tables. q MERGE is discussed further in Chapter 15. Insert Rows into a Table q The INSERT statement adds one or more rows to a table. q The INSERT syntax we reviewed in this chapter consists of the reserved words INSERT INTO, the name of the table, the optional column list, the reserved word VALUES, and the list of values to be entered. q If the INSERT statement is written so that the list of columns in the table is omitted, then the list of values must include one value for each column in the table, and the order of the columns in the table’s structure will be how the list of values is expected to be sequenced within the INSERT statement. q The list of values in the INSERT statement may include expressions. q If any values violate any constraints applied to the target table, then an execution error will result—for example, all NOT NULL columns must be provided with some sort of value appropriate to the datatype of the column within the INSERT statement’s list of values. 126 Chapter 3: Manipulating Data Update Rows in a Table q The UPDATE statement modifies existing data in one or more rows within a database table. q The UPDATE statement syntax starts with the reserved word UPDATE and the name of the target table, the reserved word SET, and then a series of assignment expressions in which the left side element is a table column, then the assignment operator (an equal sign), and then an expression that evaluates to a datatype appropriate for the target table’s column identified on the left side of the equal sign, and finally an optional WHERE clause. q If additional assignment expressions are required, each additional assignment expression is preceded by a comma. q If the WHERE clause is omitted, then all the rows in the table are changed according to the series of SET values listed in the UPDATE statement. Delete Rows from a Table q The DELETE statement is used to remove rows of data from a table. q The syntax starts with the reserved words DELETE and the optional FROM, then the name of the target table, then an optional WHERE clause. q If the WHERE clause is omitted, all of the rows in the table are deleted. Control Transactions q TCL statements include COMMIT, ROLLBACK, and SAVEPOINT. q There are two types of commit events: explicit commit and implicit commit. q An explicit commit occurs with the COMMIT statement. q An implicit commit occurs immediately before and after certain events that take place in the database, such as the execution of any valid DDL statement, such as CREATE, ALTER, DROP, GRANT, and REVOKE. Each is preceded and followed by an implicit commit. q If a DDL statement fails during execution, the implicit commit that preceded it still is in effect, ensuring that the commit at least occurred, whether the DDL statement was successful or not. The same is not true for syntax errors. q The ROLLBACK statement is used to undo changes to the database. Two-Minute Drill 127 q The SAVEPOINT statement can be used to name a point within a series of SQL statements to which you may optionally roll back changes after additional DML statements are executed. q Once a COMMIT is issued, all existing SAVEPOINTs are erased. q Any ROLLBACK that names non-existing SAVEPOINTs will not execute. q If ROLLBACK is issued without naming a SAVEPOINT, changes made by the user during the current session are rolled back to the most recent commit event. 128 Chapter 3: Manipulating Data Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose the best single answer for each question unless otherwise specified. Describe Each Data Manipulation Language (DML) Statement 1. Which of the following statements are considered DML? (Choose two.) A. SELECT B. GRANT C. INSERT D. DROP 2. An INSERT statement can be used to: A. Create tables in which to place data. B. Create rows of data in a table. C. Add values to an existing row of data in a table. D. None of the above. 3. By issuing a ROLLBACK statement, a user can choose to undo DML changes he or she has performed on the database during the current session since either (a) the most recent commit event, or (b) any one of a number of demarcation points that may have been established within the session—whichever is more recent. If any such demarcation points exist, they would have been created with the SQL statement whose first keyword is: A. MARK B. SAVEPOINT C. UNDO D. Any DDL statement can do this Insert Rows into a Table 4. Review the following statement. CREATE TABLE STUDENT_LIST (STUDENT_ID NUMBER, NAME VARCHAR2(30), PHONE VARCHAR2(30)); INSERT INTO STUDENT_LIST VALUES (1, 'Joe Wookie', 5551212); The table will create successfully. What will result from the INSERT statement? Self Test 129 A. The INSERT will fail because there is no list of columns after STUDENT_LIST. B. The INSERT will fail because the literal value for PHONE is numeric and PHONE is a character datatype. C. The INSERT will execute—the table will contain one row of data. D. None of the above. 5. Consider the following set of SQL statements: CREATE TABLE INSTRUCTORS (INSTRUCTOR_ID NUMBER, NAME VARCHAR2(20), CONSTRAINT ID_PK PRIMARY KEY (INSTRUCTOR_ID), CONSTRAINT NAME_UN UNIQUE (NAME)); INSERT INTO INSTRUCTORS (INSTRUCTOR_ID, NAME) VALUES (1, 'Howard Jackson'); INSERT INTO INSTRUCTORS (INSTRUCTOR_ID, NAME) VALUES (2, 'Trish Mars'); The table will create successfully. What will be the result of the two INSERT statements? A. Neither will execute. B. The first will execute, but the second will fail. C. The first will fail, but the second will execute. D. Both will execute successfully. 6. Consider the following set of SQL statements: CREATE TABLE MAILING_LIST (FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(30)); INSERT INTO MAILING_LIST VALUES ('Smith', 'Mary'); What will be the result of the INSERT statement? A. It will fail because there is no column list in the INSERT statement. B. It will fail because there is no PRIMARY KEY in the table. C. It will execute and create a new row in the table. D. It will fail because the last name and first name values are reversed. Update Rows in a Table 7. Which of the following reserved words is not required in order to form a syntactically correct UPDATE statement? A. UPDATE B. SET C. WHERE D. None of the above 130 Chapter 3: Manipulating Data 8. Which of the following is true about the UPDATE statement? (Choose all that apply.) A. It can be used to add rows to a table by setting values to all of the columns. B. It can be used to remove a row from a table by setting all of the row’s columns to a value of NULL. C. For existing rows in a table, UPDATE can add values to any column with a NULL value. D. For existing rows in a table, UPDATE can remove values from any column by changing its value to NULL. 9. Review the following SQL statements: CREATE TABLE INSTRUCTORS (INSTRUCTOR_ID NUMBER, EXEMPT VARCHAR2(5), VACATION NUMBER, PAY_RATE NUMBER); INSERT INTO INSTRUCTORS VALUES (1, 'YES', NULL, 25); INSERT INTO INSTRUCTORS VALUES (2, NULL, NULL, NULL); UPDATE INSTRUCTORS SET EXEMPT = 'YES', SET VACATION = 15 WHERE PAY_RATE < 50; What can be said of the statements listed here? A. One row will be updated. B. Two rows will be updated. C. At least one of the statements will not execute. D. None of the above. 10. Review the following SQL statements: CREATE TABLE BOUNCERS (NIGHTCLUB_CODE NUMBER, STRENGTH_INDEX NUMBER); INSERT INTO BOUNCERS VALUES (1, NULL); UPDATE BOUNCERS SET STRENGTH_INDEX = 10; What is the end result of the SQL statements listed here? A. The BOUNCERS table will contain one row. B. The BOUNCERS table will contain two rows. C. The UPDATE will fail because there is no WHERE clause. D. None of the above. Self Test 131 Delete Rows from a Table 11. Which of the following reserved words is required in a complete DELETE statement? (Choose all that apply.) A. FROM B. WHERE C. DELETE D. None of the above 12. Consider the following data in a table called PARTS: PNO --1 2 3 PART_TITLE ---------------PROCESSOR V1.0 ENCASEMENT X770 BOARD CPU XER A7 STATUS ------VALID PENDING PENDING Which of the following SQL statements will remove the word “VALID” from row 1, resulting in one row with a status of NULL and two rows with a status of ‘PENDING’? A. DELETE FROM PARTS WHERE STATUS = ‘VALID’; B. DELETE PARTS WHERE PNO = 1; C. DELETE FROM PARTS SET STATUS = NULL WHERE PNO = 1; D. None of the above 13. Review the following SQL statements: CREATE TABLE AB_INVOICES (INVOICE_ID NUMBER, VENDOR_ID NUMBER); ALTER TABLE AB_INVOICES ADD PRIMARY KEY (INVOICE_ID); INSERT INTO AB_INVOICES VALUES (1,1); DELETE AB_INVOICES WHERE INVOICE_ID = 2; Which of the following best describes the results of attempting to execute the DELETE statement? A. The DELETE statement will fail because it is missing a column list between the word DELETE and the name of the table AB_INVOICES. B. The DELETE statement will execute, but no rows in the table will be removed. C. The DELETE statement will produce a syntax error because it is referencing a row that does not exist in the database. D. None of the above. 132 Chapter 3: Manipulating Data Control Transactions 14. Review the following SQL statements: 01 02 03 04 05 06 SELECT PRODUCT_ID FROM PRODUCTS; DROP TABLE SHIP_STAFF; INSERT INTO ENGINEERING (PROJECT_ID, MGR) VALUES (27,21); COMMIT; INSERT INTO ENGINEERING (PROJECT_ID, MGR) VALUES (400,17); ROLLBACK; In this series of SQL statements, which line represents the first commit event? A. Line 1 B. Line 2 C. Line 4 D. Line 6 15. Review the SQL statements that follow, and assume that there is no table called ADDRESSES already present in the database: CREATE TABLE ADDRESSES (ID NUMBER, ZONE NUMBER, ZIP_CODE VARCHAR2(5)); INSERT INTO ADDRESSES (ID, ZONE, ZIP_CODE) VALUES (1, 1, '94065'); SAVEPOINT ZONE_CHANGE_01; UPDATE ADDRESSES SET ZONE = 2 WHERE ZIP_CODE = 94065; ROLLBACK; What will be the result of the execution of the SQL statements shown here? A. The ADDRESSES table will have one row with a value of 1 for ZONE. B. The ADDRESSES table will have one row with a value of 2 for ZONE. C. The ADDRESSES table will have no rows. D. None of the above. Self Test Answers 133 Self Test Answers Describe Each Data Manipulation Language (DML) Statement 1. ˛ A and C. The DML statements listed are SELECT and INSERT. ˝ B and D are incorrect. GRANT is DDL. So is DROP. 2. ˛ B. It appears a bit tricky to say that the INSERT statement “creates” something, since we’ve primarily spoken of DDL statements as creating objects, and SQL has already reserved the word CREATE for the statement that creates database objects. But it’s important to recognize the purpose of each statement, and with regard to the INSERT, what’s important is that you’re adding rows of data to a table that weren’t there before. ˝ A, C, and D are incorrect. INSERT creates rows of data that are stored within a table, but it doesn’t create the table itself. INSERT may be used to selectively put data in certain columns of a table, but even then, it’s creating an entirely new row for the table when it does this, and is incapable of adding data to an existing row—that’s the purpose of the UPDATE statement. 3. ˛ B. The SAVEPOINT statement will establish a demarcation within a series of transactions so that a subsequent ROLLBACK statement can undo any changes made by the user during the session back to the point of the SAVEPOINT, or to the most recent commit event, whichever is more recent. ˝ A, C, and D are incorrect. MARK is not a valid SQL statement; neither is UNDO. Any DDL statement will trigger an implicit commit event, but they have no particular and unique correlation to the SAVEPOINT statement and functionality. Insert Rows into a Table 4. ˛ C. The statements are syntactically and logically correct. The INSERT statement omits the column list, requiring the list of values to be provided in the same sequence in which the columns appear in the table’s structure, as indicated in the CREATE TABLE statement. ˝ A, B, and D are incorrect. The PHONE value is fine; character data accepts both numeric and text data. In fact, values like phone numbers and ZIP codes are best treated as character data; otherwise, leading zeros will be truncated, and in the case of a ZIP code, that can be a disaster for a lot of addresses in the Northeastern United States. 5. ˛ D. The syntax is fine, and both INSERT statements will execute. ˝ A, B, and C are incorrect. 134 Chapter 3: Manipulating Data 6. ˛ C. It will create a new row in the table. The fact that the column values are probably reversed may represent a logical error now and create problems down the road, but there’s nothing about the statement that will prevent it from executing successfully. ˝ A, B, and D are incorrect. The lack of a column list in the INSERT merely requires there to be a list of values that match the number and datatypes of the columns in the table’s structure, and this INSERT statement’s list of values satisfies that requirement, albeit in an apparently illogical way, but nevertheless, the requirements for SQL are met. The lack of a PRIMARY KEY on the table probably represents poor design but is not a problem with regard to the successful execution of the SQL statements here. Update Rows in a Table 7. ˛ C. An UPDATE statement does not have to have a WHERE clause. If a WHERE clause is omitted, then every row in the target table is subject to be changed by the UPDATE statement, depending on whether or not any constraints exist on the table and whether they permit or reject the data changes the UPDATE statement is attempting to make. ˝ A, B, and D are incorrect. The reserved word UPDATE is required for a valid UPDATE statement. The same is true for the reserved word SET. 8. ˛ C and D. Adding a value to a column in an existing row is the purpose of the UPDATE statement. Setting a value to NULL is as acceptable as setting a value to some other specific value. ˝ A and B are incorrect. INSERT adds new rows to a table, and DELETE removes them. UPDATE doesn’t remove rows from a table. The UPDATE statement can only modify existing rows. If you choose to SET each column’s value to NULL—assuming the constraints will allow you to do that—then you’ll still have a row in the table; it will simply consist of NULL values. But you’ll still have a row. And you cannot create a new row by using SET to set values to each column; all you can do is modify existing rows. 9. ˛ C. The UPDATE statement contains an extra occurrence of the reserved word SET. Only the first “SET” belongs; the second should be removed. ˝ A, B, and D are incorrect. 10. ˛ A. The INSERT statement enters a single row, and the UPDATE statement modifies that single row, leaving one modified row in the table. ˝ B, C, and D are incorrect. There is only one row in the table—the UPDATE does not add a new row but rather changes the existing row. UPDATE does not require a WHERE clause; without it, the UPDATE statement applies its changes to all the rows in the table, and this table contains one row. Self Test Answers 135 Delete Rows from a Table 11. ˛ C. The only required reserved word is DELETE. ˝ A, B, and D are incorrect. FROM is optional. WHERE is also optional. 12. ˛ D is correct. DELETE removes entire rows from the database. To remove a single value from a single column requires use of the UPDATE statement. ˝ A, B, and C are incorrect. A and B are valid DELETE statements, either of which will remove the first row from the table, instead of just removing the value for the “status” column. C is an invalid statement that will trigger a syntax error—the SET reserved word has no place in the DELETE statement. 13. ˛ B. The syntax is fine, and the statement will execute as intended, which is to remove any rows from the table with an INVOICE_ID value of 2. It just so happens that there aren’t any rows that match the stated criteria at the time the DELETE statement is issued—and there’s nothing illogical about that. ˝ A, C, and D are incorrect. There is no column list in a DELETE statement before the table name. And the fact that the WHERE clause does not identify any relevant rows is not a syntax problem, nor is it a compilation problem—the statement will simply not delete any rows. Control Transactions 14. ˛ B. Line 2 is a DROP statement, which falls under the type of SQL statements known as Data Definition Language, or DDL. All DDL statements cause an implicit commit to occur. ˝ A, C, and D are incorrect. The SELECT statement has no impact on a commit event at all. Line 4 is an explicit COMMIT, and were it not for line 2, this would be the first commit event in this set of statements. Line 6 undoes the effects of line 5 and undoes the user’s changes to the database since the previous commit event, which at this stage is represented by the line 4 commit. 15. ˛ C. The ROLLBACK statement does not reference the SAVEPOINT name, so instead it rolls all the way back to the last COMMIT event, which in this case is the implicit commit that occurred with the CREATE TABLE statement. ˝ A, B, and D are incorrect. This page intentionally left blank 4 Retrieving Data Using the SQL SELECT Statement Certification Objectives 4.01 Execute a Basic SELECT Statement 4.03 4.02 List the Capabilities of SQL SELECT Statements 3 Describe How Schema Objects Work Two-Minute Drill Q&A Self Test 138 Chapter 4: Retrieving Data Using the SQL S ELECT Statement T his chapter introduces the basic syntax of the most commonly used SQL statement, which is the SELECT statement. The SQL SELECT statement retrieves data from the database. The SELECT statement does not change the data that’s stored in the database, but it does have the ability to transform that data as it is pulled out of the database and displayed, and therein lies its power and usefulness. SELECT has the ability to show raw information, but also to edit information before it’s displayed. It can perform mathematical analysis on numeric data, and perform string manipulation on text data; it can format raw numbers for financial reports, abbreviate lengthy data, or spell out abbreviations. It can sort rows of data according to date, time, text, and numeric values. It can aggregate multiple rows of information in various ways, showing summary data at various levels, or creating organizational hierarchies. It can join related information from multiple sources and present its findings in a single consolidated form at various levels of detail or aggregation. In other words, the functionality involved in the SELECT statement is the ultimate reason why most databases exist: to analyze, transform, and present data in virtually any format necessary. It is surprisingly easy and quick to use, yet deceptively tricky in its full implementation in the context of a comprehensive mission-critical application. I’m tempted here to quote the pop singer Billy Joel and say that the SELECT statement is “frequently kind and it’s suddenly cruel”. But I won’t do that. Because in the hands of an Oracle Database SQL Expert, the SELECT statement is a tame and powerful tool that is flexible and infinitely productive. Certification Objective 4.01 Execute a Basic SELECT Statement In this section you’ll get a high-level look at the SELECT statement and go through the complete process of creating and executing a simple SELECT statement. We’ll discuss some basic rules for forming SELECT statements, including the minimum requirements for formulating a complete executable statement. Then you’ll execute a SELECT statement and look at its output. This section introduces some key concepts that you’ll need for the exam, but it’s hardly the last word on SELECT that you’ll need on the job—nor on the exam. Execute a Basic SELECT Statement 139 We’ll explore SELECT in greater detail throughout many other sections of this guide. This chapter will get us started. The SELECT Statement—An Example Let’s take a look at an example of a simple SELECT statement. First, see Figure 4-1 for a sample database table listing of data we’ll use for our SELECT statement. In this figure, our table has three columns and four rows. Let’s create a SELECT statement to retrieve this data: 01 02 03 SELECT SHIP_ID, SHIP_NAME, CAPACITY FROM SHIPS ORDER BY SHIP_NAME; If you were to type this SELECT statement into the SQL*Plus interface and execute it, the results might look like Figure 4-2. Figure 4-1 Data in the SHIPS table Figure 4-2 Output of SELECT statement SHIP_ID SHIP_NAME CAPACITY 1 Codd Crystal 2052 2 Codd Elegance 2974 3 Codd Champion 2974 4 Codd Victorious 2974 140 Chapter 4: Retrieving Data Using the SQL S ELECT Statement This example demonstrates three clauses in a SELECT statement: The expression list, also known as the select list, is a list of one or more expressions. Often the list is merely column names, but it could include expressions consisting of a combination of column names, arithmetic operators, literal values, and SQL functions, as you’ll see later. If column names are referenced, they must match the names of existing columns in the table’s structure. The select list identifies the data you wish to retrieve. When the results of your statement are displayed, each expression’s values are listed in an output column (not to be confused with a database column) in your results. Each expression forms an output column from left to right, horizontally, in the same sequence as you list them in your expression list. In our example, the expression list consists of three columns: SHIP_ID, SHIP_NAME, and CAPACITY; the output will list the SHIP_ID values first, then the SHIP_NAME values to the right of SHIP_ID, and finally the values for CATEGORY. n On line 1, the expression list This consists of the keyword FROM followed by the name of one or more tables. n The FROM clause This consists of the keywords ORDER BY, followed by an expression that identifies to the database how you wish the rows to be sorted. n The ORDER BY clause Note that there is no WHERE clause in this SELECT statement example. This means that the results of this particular example will show all of the rows in the table. In order to restrict the output to a certain number of rows, a WHERE clause should be added to define exactly which rows are desired—something you’ll look at in detail in the next chapter. There is more functionality to the SELECT statement than what we’re mentioning here. We will review additional features later that may be included in the exam. SELECT: Minimum Requirements In order to create a valid SELECT statement that will parse correctly, the following elements are required: n The SELECT keyword, followed by at least one valid expression in the expression list n The FROM keyword, followed by at least one valid name of a database table List the Capabilities of SQL SELECT Statements 141 That is all that is required. Here is an example: SELECT 1 FROM SHIPS; In this example, we’re selecting the literal value of 1 from the table named SHIPS. Obviously we don’t need to call on the SHIPS table to understand what the literal value of 1 is—it’s just a number 1; there’s no trick to it. But the point is that any valid expression can be selected from any valid table, and as long as the SHIPS table is valid, then the preceding SELECT statement is a syntactically correct, if perhaps somewhat useless, SQL statement. Of course, we can also reference a column name in the table specified in the FROM clause. For example, as long as the SHIPS table has a column called SHIP_NAME, then this is also a valid SELECT statement: SELECT SHIP_NAME FROM SHIPS; Any column that may be referenced in the SELECT statement must exist in the table identified in the FROM clause. Anything less than one item in the SELECT statement’s expression list, and one item in the FROM clause, and there is not sufficient information to build a SELECT statement. SQL statements may be displayed on one line or multiple lines. Any number of line breaks may occur anywhere within a SQL statement, provided that any given line break does not interrupt keywords, literal values, expressions, etc. The semicolon indicates the termination of the SQL statement. In the following sections, we’ll expand on our knowledge of the SELECT statement. Certification Objective 4.02 List the Capabilities of SQL SELECT Statements You’ve seen some examples of how the SELECT statement works, and discussed the minimum requirement for a syntactically complete SELECT. Now let’s expand our knowledge a bit and look at other clauses that are used in a SELECT, and discuss its capabilities. 142 Chapter 4: Retrieving Data Using the SQL S ELECT Statement The SELECT Statement—An Overview The SELECT statement is used to retrieve data from one or more tables in the database. It can specifically display a subset of the available data by identifying certain columns and rows, by analyzing data contained within those columns and rows, and/or by performing real-time mathematical calculations or text searches, date or time checking. It can sort the results, format the individual values that are displayed, and more. Let’s look at the individual components that form a SELECT statement. We’ll start with the first part, known as the expression list, and sometimes called the select list. Selecting Columns From Tables The first part of a SELECT statement is the select list, or expression list, which generally includes column references. Expressions are listed in the order in which you wish for them to be displayed as output. Each expression is separated from the next by a comma. The last expression is not followed by a comma. As you might recall from Chapter 1, a table consists of columns and rows. Figure 1-1 showed us a very simple table structure, in which you saw a table called SHIPS, containing two columns—one called SHIP_ID and another called SHIP_ NAME. The SHIPS table displayed four rows of data. Here is an example of a SELECT statement we could create for that SHIPS table in Chapter 1, Figure 1-1. SELECT SHIP_ID, SHIP_NAME FROM SHIPS; The columns SHIP_ID and SHIP_NAME are indicated in the column list of this SELECT statement. The results of this SELECT statement are shown in Figure 4-3. Notice that the output displays the columns in the same sequence in which they are specified in the SELECT statement. The SELECT statement may identify the Figure 4-3 Sample output of a SELECT statement List the Capabilities of SQL SELECT Statements 143 Figure 4-4 Sample output of the same SELECT statement with the column list reordered columns in any order, regardless of the order in which the columns appear in the table’s structure. For example: SELECT SHIP_NAME, SHIP_ID FROM SHIPS; The results of this statement are shown in Figure 4-4. The select list may include any columns, in any order, and can repeat them as often as is desired. Pseudocolumns Pseudocolumns are values that are defined automatically by the Oracle system for every table. Pseudocolumns will not appear in the results of the DESCRIBE statement, and they are not actually stored with the table. But you can SELECT from them as though they were a typical column in the table. Pseudocolumns generally return a different value for each row in the table. There are many pseudocolumns that can be available within Oracle SQL in different situations, depending on what is transpiring at the time. For example, some are useful only within hierarchical queries, which you’ll study in Chapter 16. Two pseudocolumns that are more common and can be useful include the following: This is the system-assigned number for a row. If you’re looking for some way to number each row of output from a SELECT statement, ROWNUM might do the trick, but beware: ROWNUM is assigned before the ORDER BY clause is processed, not after. See Figure 4-5. n ROWNUM This is the system-assigned physical address for a given row. This can change from time to time by the database—for example, if you export a table and then import it, the newly imported version will almost certainly have different ROWID values. n ROWID We’ll look at other pseudocolumns later as they become relevant. 144 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Figure 4-5 ROWNUM— without ORDER BY, and with ORDER BY ROWID can be useful for data in tables where a problem might exist. I once was brought in to clean up a database that was in a bit of difficulty. One issue was that of inappropriate duplicate rows in a critical table. I could have used a graphical user interface (GUI) of some sort to selectively delete rows—if one were available, but it wasn’t. I was logged in across a command-line interface, and I was able to make use of the DELETE statement by first identifying the duplicate rows and then carefully using the ROWID values of the duplicates I needed to remove. DISTINCT or UNIQUE The reserved word DISTINCT can be used with SELECT to identify a unique set of values from a table. UNIQUE performs the same task. For example, consider the following list of values: EMPLOYEE_ID -----------1 2 3 4 5 FIRST_NAME ---------Howard Joe Mike Alice Al MIDDLE_INITIAL -------------A. R. L. W. S. LAST_NAME --------Hoddlestein Smith West Lindon Smith List the Capabilities of SQL SELECT Statements 6 7 Trish Joe T. M. 145 West Smith If these rows existed in a table called, say, EMPLOYEES, then we might run the following SELECT statement: SELECT DISTINCT LAST_NAME FROM EMPLOYEES; Such a query would produce output like Figure 4-6. DISTINCT analyzes each row returned by the query and returns one unique line of output for each duplicate set of expressions that might be found. DISTINCT operates on the entire set of expressions in the select list. For example, this query looks for distinct combinations of two columns: SELECT DISTINCT LAST_NAME, FIRST_NAME FROM EMPLOYEES; This query asks for all distinct combinations of values in LAST_NAME and FIRST_NAME. Given our earlier source data, this query would produce the complete list of names with one exception: there would only be one line with the name “Smith” and “Joe”. In other words, DISTINCT takes into consideration all of the column values in the expression list and looks at whether each row is unique or not based on the combination of expressions identified in the SELECT statement’s expression list. The reserved word UNIQUE performs the same task as DISTINCT. Both DISTINCT and UNIQUE are considered a “clause” of the SELECT statement. Figure 4-6 Output of SELECT DISTINCT query 146 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Asterisk:The All-Column Wildcard The use of a single asterisk in the SELECT list is the equivalent of asking for all the columns in the table, in the order they are defined in the table’s structure. For example, consider a table called PORTS with four columns of PORT_ID, PORT_NAME, COUNTRY, and CAPACITY. Given that, the following SELECT statement asks for all of these columns: SELECT * FROM PORTS; This statement is a valid SELECT statement that is the equivalent of the following: SELECT PORT_ID, PORT_NAME, COUNTRY, CAPACITY FROM PORTS; The output of either query is identical. The asterisk, when used in the column list, tells the database that you simply want to show data from all the columns, whatever they are. If new columns are added to the table in the future, this “asterisk” query will automatically pick up those new columns in its output, whereas the second example just shown would need to be edited to incorporate the newly added column names. Expressions In addition to columns in tables, you may also incorporate expressions into a SELECT statement’s select list. Expressions are one way you can “transform” data, as is often said about SELECT statements. Don’t be misled by that term of “data transformation”—when you “transform” data using an expression in the select list of a SELECT statement, you’re not changing anything in the database, you’re simply processing the data after it’s retrieved by the SELECT statement, and before it’s presented as the final output of your SELECT statement. Expressions consist of literal values, arithmetic and other operators, and as you’ll see later, SQL functions. Literals See Table 4-1 for a description of some of the literal values you may use in an expression. List the Capabilities of SQL SELECT Statements Table 4-1 Examples of Literal Values That Can Be Used in an Expression 147 Datatype Description Examples Number Any numeral, including decimal points 1 49.12 Character or String A set of one or more characters enclosed in single quotation marks (not double quotes) ‘Hayden, Doug’ ‘Acme Internet, Inc.’ To include single quotes as part of the string, use two single quotes in succession. For example: ‘Isn’’t it nice outside?’ Date A date that is provided in the format Oracle uses for formatting dates ‘10-MAY-09’ Interval A period of time, either YEAR TO MONTHS or DAY TO SECONDS. Also valid, when used by themselves, are YEAR, MONTH, DAY, MINUTE, and SECOND. ‘INTERVAL ‘24-3’ YEAR(2) TO MONTH’ is 24 years and three months, where (2) is the precision for the YEAR component of the value. ‘INTERVAL ‘24’ MONTH is 24 months, or, in other words, two years. The folowing example of a SELECT statement combines column names and expressions: SELECT FROM WHERE ORDER BY EMPLOYEE_ID, SALARY, SALARY*1.05 PAY_HISTORY END_DATE IS NULL EMPLOYEE_ID; For each row in the PAY_HISTORY table, this query will produce the EMPLOYEE_ID, SALARY, and a value that represents the SALARY with a 5 percent increase. The first two items in the select list are column names. The third is an arithmetic expression that takes data from the database and performs a multiplication operation on that value for each row in the database. An example of what this output might look like is shown in Figure 4-7. 148 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Figure 4-7 Output of PAY_HISTORY query Expressions can be used in: • A SELECT statement’s column list, and its WHERE, HAVING, and ORDER BY clauses; • Hierarchical queries with the CONNECT BY, START WITH, and ORDER BY clauses; • An INSERT statement’s VALUES clause; • An UPDATE statement’s SET clause and WHERE clause; • A DELETE statement’s WHERE clause. There isn’t a specific certification objective about simple expressions. However, expressions are such a common part of the daily life of any SQL developer that you should know them well, be comfortable where they can be used, and not be caught off guard when they appear in the context of a complex exam question that might be focusing on a different topic area. Expressions do appear on the exam, sometimes within a series of SQL statements, along with many other common features of SQL. List the Capabilities of SQL SELECT Statements 149 Operators and Operator Precedence Operators are important in expressions. The arithmetic operators you can use in an expression are shown in Table 4-2. These operators may appear in an expression in any order and frequency. For example: SELECT SALARY * (BASE_PAY * (1.03 * YEARS_OF_SERVICE)) / 12 FROM EMP_COMPENSATION; This example uses a combination of multiplication, division, and parentheses to build a complex expression. The use of parentheses brings up the important topic of operator precedence. If you’re familiar with the basic rules of mathematics, you’ll already know the rules of arithmetic operator precedence. SQL adopts the same rules, and they are shown in Table 4-2. What these rules indicate is the order in which operations are performed within a larger expression that contains multiple operations. Multiplication and division are performed before addition or subtraction, regardless of the sequence in which they are used. For example, consider this arithmetic expression: 10 + 15 * 3 You might assume that this expression is “10 plus 15”, the results of which are multiplied by 3. If so, you would conclude that the result of this equation is 75. But Oracle will calculate the answer of this expression to be 55. That’s because the multiplication is calculated first, like this: 15 * 3 = 45 This result is placed into the addition operation, which is performed next: 10 + 45 = 55 Table 4-2 Name Operator Precedence Arithmetic Operators in Order of Precedence Parentheses () 1 Multiplication, Division *, / 2 Addition, Subtraction +, - 3 150 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Now—if we really wanted our original equation to calculate a value of 75 instead of 55, there’s a way to make it happen. That method is the placement of parentheses to override any other rules of operator precedence. Any operation enclosed in parentheses will be performed first, before all other operations. Here’s a version of the same expression that uses parentheses to ensure the calculation is performed in sequential order: (10 + 15) * 3 The result of this arithmetic expression, as calculated by Oracle, is 75. The reason is the rules of operator precedence. Parentheses may be nested as many times as is necessary. The deeper the nesting, the higher up in the order of precedence. For example: ( 11 - 4 + ((2+3) * .7) / 4) The expression “2+3” will be evaluated first, since it is within the greatest number of parentheses. And incidentally, the answer is 7.875. Functions No discussion of expressions would be complete without at least mentioning SQL functions. A function is represented by a descriptive name or abbreviation, such as ADD_MONTHS or SUBSTR. Functions generally: n Receive one or more bits of incoming data, known as “parameters”. n Perform some task on the data—perhaps to add the parameter values together. n Produce a single answer representing the results of the function’s task. If you’re wondering why I say that functions “generally” do these things, it’s because it’s technically possible for a function to omit some of these steps. For example, it’s theoretically possible in PL/SQL to create a user-defined function that doesn’t take any parameters at all and yet produces some form of output. That being said—most functions do all three of the steps listed here. Parameters may include literal values or table column names. Here’s an example of a SELECT statement that uses a function called UPPER. The UPPER function takes a single character string, changes that string to uppercase characters, and returns the uppercase version of the string. SELECT PORT_NAME, UPPER(PORT_NAME) FROM PORTS; List the Capabilities of SQL SELECT Statements 151 Figure 4-8 Results of a SELECT statement using the UPPER function The output is shown in Figure 4-8. As you can see from the listing, the UPPER function changed the data to uppercase. It’s also worth pointing out that in this example, we referenced the same table column twice in a select list. That’s perfectly acceptable and potentially useful as it is in this example. Columns may be referenced in a SELECT statement column list as often as you wish in any sequence. Additional SELECT Statement Clauses In addition to the select list and the FROM clause, there are several additional clauses that can be used in a SELECT statement. Several are briefly described in Table 4-3. Table 4-3 Additional Clauses Brief Description Additional SELECT Statement Clauses WHERE condition Restricts the rows that are returned according to the criteria described in condition. hierarchical_query_clause Structures the output in a hierarchical order, as you might find in a company organization chart. ORDER BY order_by_clause Sorts the rows. GROUP BY group_by_clause Collects rows in groups in order to identify values that are common to the groups, such as aggregate data. HAVING condition Essentially performs a type of “WHERE” operation for the groups defined in the GROUP BY clause. 152 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Each of these clauses is rich in functionality. For example, one feature that’s highlighted on the exam is a feature known as the subquery, in which a SELECT statement includes an embedded SELECT statement within it. The subquery is often embedded within the WHERE clause, but may be used elsewhere. Each of these additional clauses will be explored in detail as we continue. The Capabilities of SELECT At the highest level, the SELECT statement can be characterized as having three fundamental capabilities: Projection, Selection, and Joining. These are the three fundamental concepts that drive a relational database. Let’s explore each in a little more detail. To explore these concepts, you’ll work with two tables as shown in Figure 4-9. Projection Projection refers to the ability of a SELECT statement to choose a subset of the columns in a given table. For example, see Figure 4-10. The SELECT statement is choosing a subset of the columns from the PORTS table that you saw in Figure 4-9. A query that displays a table’s data by choosing a subset of a given table’s columns is exhibiting the concept of projection. Selection Selection is the ability of a SELECT statement to choose a subset of the rows in a given table. This concept is accomplished by use of the WHERE clause of the SELECT statement. See Figure 4-11 for an example. Figure 4-9 The PORTS and SHIPS tables List the Capabilities of SQL SELECT Statements 153 Figure 4-10 Projection: a SELECT statement that chooses a subset of columns Figure 4-11 Selection: a SELECT statement that chooses a subset of rows A query that displays a table’s data by choosing table rows selectively is exhibiting the concept of selection. In this example, the WHERE clause is limiting our output display to those rows that have a CAPACITY value that’s less than or equal to 4. You’ll study the WHERE clause in more detail in the next chapter. Joining Joining is the reason there’s an “R” in RDBMS. Joining is how we “relate” data from one part of the database to another. When we “join” two or more tables, we are specifying to the database that there is common information shared by both tables and we want to link data from those tables together according to the common data the tables share. 154 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Figure 4-12 Joining: a SELECT statement that relates data from two tables into one output listing A typical database application will consist of many tables that can be joined in a variety of ways. For every additional table you add to a database, you can potentially add a great many additional join possibilities, depending on the structures involved. An example of a SELECT statement that joins data is displayed in Figure 4-12. The SELECT in the figure joins the two tables SHIPS and PORTS. The join is accomplished in lines 2 and 3 of the figure, where we see a FROM clause that identifies both tables and then identifies their common link: the PORT_ID column in the PORTS table and the HOME_PORT_ID column in the SHIPS table. This SELECT statement is instructing SQL to find rows in both tables that have a common value in those columns; where rows are found that match, SQL will treat the combination as though they are one row. We’ll discuss the mechanics of this later in Chapter 8, but for now, the point is this: any query that displays data from two or more tables by identifying common data in the tables is exhibiting the concept of joining. Certification Objective 4.03 Describe How Schema Objects Work As you’ve seen, there are several objects in the database. Many are “schema” objects, meaning they are “owned” by a user and exist in a collection within a user account. The schema objects you’ve looked at include tables, views, indexes, sequences, and synonyms. You’ve seen how to name them, and how namespaces work. You’ve also seen a little about privileges, and the fact that a single user can “own” database tables and then grant privileges to other users for performing SELECT, INSERT, UPDATE, and/or DELETE operations on that information. Describe How Schema Objects Work 155 In this section, we’ll look at some of the functionality of database objects and how they work with each other. Tables All the data in a database is stored in tables. When you create a new table, the information about that table, such as its name and columns and the datatypes of those columns, is all stored in a set of system-defined tables that are collectively known as the “data dictionary”, and which are managed automatically by the Oracle system. (We examine the data dictionary in Chapter 14.) So even data about your data—i.e., “metadata”—is stored in tables. A table’s columns are generally stored in the order in which they are created, but this isn’t necessarily true at all times. Also, if you ALTER a table and add a column to its structure, that column will become the last column in the table’s structure. Constraints A constraint is a rule on a table that puts rules and restrictions on the sort of data that is added to a table. Note that it is not a database object, but it is listed in the data dictionary, and can be named with the same naming rules of an object. You’ve already looked at the different types of constraints: NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, and CHECK. If a SQL statement attempts to add, modify, or delete a row to/from a table, and in so doing violates a constraint, the entire SQL statement will fail with an execution error. Views A view acts like a table. It has a name. You can DESCRIBE the view in the same way you would DESCRIBE a table. You can run a SELECT statement on a view just as you would SELECT from a table. Depending on the kind of view you are working with, you might even be able to execute INSERT, UPDATE, and/or DELETE statements on a view. But a view is not a table, and it stores no data. A view is nothing more than a SELECT statement that is saved in the database with a name assigned to it. The column structure that the view takes on is formed by the SELECT statement’s select list. The datatypes for those columns are picked up automatically from the underlying table, or the expressions used in the SELECT statement used to create the view. 156 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Indexes An index performs the same job that a typical index in a book performs. For example, Oracle Corporation’s SQL Language Reference Manual for Oracle 11g’s 11.1 release is over 1,400 pages long. So what if you were looking for information on the DISTINCT clause of the SELECT statement? You have a few ways to find such information in the book. One way is to sit down and start reading the book at the first page, and keep reading until you find the data you’re looking for. A much more efficient way is to flip to the back of the book and find the index, which contains a summary of important topics in alphabetical order. Within a few seconds you can look up the word DISTINCT and note the page number on which it’s mentioned (Chapter 19, page 13, in case you were wondering), and flip straight to it. That’s a much better approach. The SQL INDEX object performs in much the same way. When you create an INDEX object, you are identifying one or more columns in a table that you believe will be frequently used to look up data. Then you create the index based on that column—or set of columns—and Oracle literally builds a separate object that takes a unique list of all the data currently in that column, sorts it appropriately according to datatype, and then stores internal addressing information that ties the index back to the source table and the rows contained within. The result: any future queries on the table that happen to reference any indexed data will cause the following to occur automatically: n Perform an analysis to determine if the query will benefit by using the index. n If yes, then redirect the focus temporarily to the index, search the index for any of the desired data identified by the query, and obtain direct locations of the appropriate rows. The difference in performance is potentially significant. The more data that is stored in a table, the more beneficial an index may be. Sequences A sequence is a counter, meaning that it issues numbers in a particular series, always keeping track of whatever the next number should be. If you ever watched the classic television sitcom Seinfeld, you might recall the episode where Jerry and Elaine go to a bakery to pick up a chocolate bobka, but don’t know to take a number from the dispenser when they first arrive, and lose their place in line as the bakery gets Certification Summary 157 crowded. That dispenser—which issues paper tickets identifying the holder as being, say, “number 42” in line—serves the same purpose of a SEQUENCE object in the database. The primary purpose of a SEQUENCE is to support the process of adding rows to a particular table and providing the next appropriate value for a PRIMARY KEY for the table. That’s it. There’s nothing inherent in a SEQUENCE object that ties it to a particular table. There’s nothing automatic in the SEQUENCE object that necessarily supports a particular table. It’s up to the software developer to know how to use the SEQUENCE object correctly, as you’ve briefly seen already and will explore in detail later when we address the syntax of a SEQUENCE. Synonyms A synonym is an object that associates an alias with an existing object. If, for example, you already have a table called EMPLOYEE_COMPENSATION_PLANS, you might want to create a SYNONYM for it such as ECP, or something briefer. There are actually two different SYNONYM objects. There is, simply, the SYNONYM, which is often called a “private synonym”, and then there is the PUBLIC SYNONYM. A private SYNONYM is owned by a user account and can be helpful for a variety of reasons. A PUBLIC SYNONYM is owned by the system-provided user PUBLIC and when created becomes automatically available to all users in the database. We’ll discuss the SYNONYM and PUBLIC SYNONYM objects in much greater detail in Chapter 10. Certification Summary The SELECT statement is the most commonly used and most fundamental statement used in SQL. At a minimum, a SELECT statement must include the select list, also known as the expression list, and a FROM clause. The select list can include the names of columns in a table, or expressions. The FROM clause must name a valid table (or view), and any column names referenced in the expression list must be in tables that are identified in the FROM clause. A shorthand way of referencing all columns at once is the asterisk, as in SELECT * FROM PORTS, which is another way of asking for every column name that happens to be in the PORTS table at the time the SELECT statement executes. You can also use the 158 Chapter 4: Retrieving Data Using the SQL S ELECT Statement DISTINCT function to display unique occurrences of data sets from a query. You can substitute DISTINCT with UNIQUE for the same result. Pseudocolumns are defined automatically by the system and are not stored with a table but can be included in the select list of a SELECT statement as though they were columns in a table. Examples include ROWNUM and ROWID. Expressions may appear in many locations in various SQL statement clauses. Regardless of where an expression may appear, it may include literal values, operators, or SQL functions, as well as column names that are incorporated into the expression. The rules of operator precedence determine the sequence in which operators within an expression are processed. There are many other clauses in the SELECT statement, including WHERE, GROUP BY, HAVING, ORDER BY, and others. There are three fundamental concepts represented in the SELECT statement: the concepts of projection, selection, and joining. Projection is the ability to retrieve a subset of columns in a table. Selection is the concept of retrieving a subset of rows from a table. Joining refers to the ability to retrieve data from multiple tables and correlate each table’s data elements to the other by common identifying information. Tables store all the data in a database. Views are named SELECT statements. Indexes act just like an index in a book, by providing a separately stored sorted summary of the column data that is being indexed, along with addressing information that points back to the source table. Sequences provide a mechanism to count off primary key values. Synonyms are aliases for other database objects. A private synonym is owned by a user account. A public synonym is owned by the system user PUBLIC. Synonyms can be used to mask more complex object names and simplify table references. Two-Minute Drill 3 159 Two-Minute Drill Execute a Basic SELECT Statement q A SELECT statement must include a select list and a FROM clause. q Any columns identified in the select list must be in a table that is identified in the FROM clause. List the Capabilities of SQL SELECT Statements q Pseudocolumns are defined by the system and are not stored with a table. q Pseudocolumns may be included in the select list of a SELECT statement. q DISTINCT, or UNIQUE, can be used in a SELECT statement to list unique data sets. q The asterisk is a shorthand way of referring to all of a table’s columns. q Expressions can transform data after it is retrieved from the database and before the data is produced as the SELECT statement’s output. q Expressions may include arithmetic operators, SQL functions, and literal values. q Literal values include numbers, characters, dates, and intervals. q Arithmetic operators obey the rules of operator precedence. q Multiplication and division operators are evaluated before addition and subtraction, regardless of the order in which they appear in an expression. q Parentheses have the highest authority in the order of operator precedence, which means that you can place parentheses to override any behavior in the rest of the operations. q Functions can be used in expressions along with all of the other elements of expressions. q The WHERE clause identifies conditions that individual rows must meet in order to be displayed—in other words, it can be used to “restrict” rows from being displayed. q The ORDER BY clause sorts the data set output of a SELECT statement. q The GROUP BY clause aggregates sets of records within a SELECT statement. 160 Chapter 4: Retrieving Data Using the SQL S ELECT Statement q The HAVING clause can be used with GROUP BY to restrict sets of rows in the same fashion that ORDER BY can be used to restrict individual records. q When a SELECT statement chooses fewer than all of the available columns in a table, it is exhibiting the concept of projection. q Projection is accomplished through the select list, also called the expression list, of the SELECT statement. q When a SELECT statement chooses fewer than all of the available rows in a table, it is exhibiting the concept of selection. q Selection is accomplished with the WHERE clause of the SELECT statement. q When a SELECT statement chooses a combination of rows from more than one table by identifying common data that uniquely identifies rows, it is exhibiting the concept of joining. q Joining can be accomplished in the SELECT statement with the WHERE clause or JOIN clause. Describe How Schema Objects Work q Tables store all the data in a database. q Views are named SELECT statements. q You can SELECT from a view. q You may be able to INSERT, UPDATE, and DELETE from a view, depending on the view’s structure. q An index speeds queries on a table by creating a presorted lookup list for the table’s indexed columns, along with an address pointer back to the indexed table. q Sequences keep track of number counters to make the job of adding primary keys and other unique values easier. q Synonyms are alias references to existing database objects, and can be either private or public. Self Test 161 Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Execute a Basic SELECT Statement 1. Consider the following table structure: DESC ENGINES Name Null? Type ------------ ----- ---------ENGINE_ID NUMBER ENGINE_NAME VARCHAR2(30) DISPLACEMENT NUMBER Now consider the following SELECT statement: SELECT ENGINE_NAME FROM ENGINES; What will be the result of executing the SELECT statement? A. It will display data from no more than one row of the ENGINES table. B. It will display data from all of the rows in the ENGINES table, however many there may be. C. It will fail with a syntax error because it doesn’t include the ENGINE_ID column. D. It will display only the rows in the ENGINES table that contain values for the ENGINE_ NAME column. 2. Review the following SELECT statement (Note: line numbers have been added for readability and reference purposes): 01 02 03 SELECT 1 , UPDATE, FROM EMPLOYEE_REVIEW; Which of the following is incorrect about the SQL statement? (Choose two answers.) A. There is a number included as the first item in the expression list. B. The reserved word UPDATE is included as part of the select list. C. There is a comma at the end of the select list. D. The comma at the beginning of line 2 should be at the end of line 1. 162 Chapter 4: Retrieving Data Using the SQL S ELECT Statement 3. Which of the following is not required to form a syntactically correct SELECT statement? A. SELECT B. A valid name of a column C. FROM D. A valid name of a table or view 4. Which of the following statements can be said of the SELECT statement’s WHERE clause? (Choose two.) A. It specifies which columns are to be returned from the table. B. It specifies which rows are to be returned from the table. C. It is optional. D. It does the same thing as ORDER BY. List the Capabilities of SQL SELECT Statements 5. You are tasked with creating a SELECT statement to retrieve data from a database table named PORTS. The PORTS table has two columns: PORT_ID and PORT_NAME. Which of the following is a valid SELECT statement? (Choose all that apply.) A. SELECT * FROM PORTS; B. SELECT PORT_NAME, PORT_ID FROM PORTS; C. SELECT PORT_ID, PORT_NAME FROM PORTS; D. SELECT ALL THE COLUMNS FROM PORTS; 6. Review the exhibit that follows: DESC SHIPS Name Null? Type ------------ ----- ---------SHIP_ID NUMBER SHIP_NAME VARCHAR2(30) Which of the following SELECT statements will produce a syntax error? (Choose two.) A. SELECT FROM SHIPS; B. SELECT 1*2, (4+5), SHIP_NAME FROM SHIPS; C. SELECT SHIP_ID, SHIP_ID, SHIP_ID FROM SHIPS; D. SELECT (SHIP_ID, SHIP_NAME) FROM SHIPS; Self Test 163 7. Consider the following list of rows from a table called CUSTOMERS: CUSTOMER_ID ----------1 2 3 4 5 FIRST_NAME ---------Bianca Hung Bianca Maya Bianca MIDDLE -----M. A. M. R. T. LAST_NAME -----------Canales Nguyen Jackson Canales Canales ZIP_CODE -------93053 92305 03233 10302 90203 Now consider the following SQL statement: SELECT DISTINCT LAST_NAME, FIRST_NAME FROM CUSTOMERS; What will be the result of the SELECT statement? A. It will execute and display 3 rows of data. B. It will execute and display 4 rows of data. C. It will execute and display 5 rows of data. D. It will fail with a syntax error because you cannot use DISTINCT with more than one column in the SELECT statement. 8. Review the SQL statement that follows: SELECT ROWNUM, * FROM PORTS ORDER BY PORT_NAME; What will be the result of an attempt to execute this statement? A. It will display each row of the PORTS table, with the first column showing a systemassigned row number in numerical order, starting with 1 and continuing until the last row. B. It will display each row of the PORTS table, with the first column showing a systemassigned row number in random order, because ORDER BY is processed after the ROWNUM is assigned. C. It will fail with a syntax error because you cannot use ROWNUM and the asterisk together in a single column list. D. None of the above. 9. Review the following data listing for a table called ONLINE_ORDERS: UNIT_PRICE ---------3.00 SHIPPING -------4.00 TAX_MULTIPLIER -------------1.10 164 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Now consider the following SQL statement: SELECT UNIT_PRICE + SHIPPING * TAX_MULTIPLIER FROM ONLINE_ORDERS; What will be the result of this SELECT statement? A. 12.12 B. 7.70 C. 7.40 D. .70 10. Parentheses can be used in an equation to do which of the following? A. Avoid the need for using database column names in a select list. B. Matrix efficient technologies. C. Enclose reserved words. D. Override the rules of operator precedence. 11. A SELECT that draws data from two or more tables by relating common information between them is said to be doing which of the following? A. Projecting B. Joining C. Provisioning D. Linking Describe How Schema Objects Work 12. The database object that stores lookup information to speed up querying in tables is: A. ROWID B. INDEX C. VIEW D. LOOKUP 13. To create another name for an object, and make that name available to the entire database, you would create which of the following? (Choose the best answer.) A. PUBLIC TABLE B. SYNONYM C. ALIAS D. PUBLIC SYNONYM Self Test Answers 14. All database data is stored in: A. TABLES B. TABLES and VIEWS C. TABLES, VIEWS, SEQUENCES, and SYNONYMS D. None of the above. 15. A database object that is defined by a SELECT statement but contains no data is a: A. VIEW B. SYNONYM C. SEQUENCE D. Not possible 165 166 Chapter 4: Retrieving Data Using the SQL S ELECT Statement Self Test Answers Execute a Basic SELECT Statement 1. ˛ B. The lack of the optional WHERE clause indicates that the SELECT will return all of the rows in the table. ˝ A, C, and D are incorrect. The query doesn’t require the inclusion of the ENGINE_ID column, nor any particular column. The fact that the ENGINE_NAME column is included has no bearing on the rows that may or may not be returned. If it just so happens that the rows returned have no values for the ENGINE_NAME column, then so be it—the two issues are unrelated as far as the SELECT statement is concerned. 2. ˛ B and C. The UPDATE reserved word cannot be used in this context. It can only be used in the UPDATE statement. Also, the comma at the end of the expression list on line 2 is incorrect. ˝ A and D are incorrect. The single digit 1 is allowed. It is a numeric literal in this context, not the name of a table column, and besides, no table would let a column be created with a name consisting of the single digit 1 anyway. Also, the comma at the beginning of line 2 is fine; all of the components of the SELECT statement can be included on a single line or spread across multiple consecutive lines; it doesn’t matter—the same is true for all SQL statements. 3. ˛ B. A column name is not required—you could use a literal value or some other expression, considering that expressions may include column names but are not required to include a column name. ˝ A, C, and D are incorrect. The reserved words SELECT and FROM are required, as is the name of a valid database table or view. 4. ˛ B and C. WHERE is the clause in which you can spell out the criteria by which data in the table is analyzed. For each row in the table, the WHERE condition is either true or false. If true, the row is displayed; if not true, the row is not included in the SELECT statement’s output. The WHERE clause is optional. ˝ A and D are incorrect. WHERE does not determine which columns can be returned in a SELECT statement—the SELECT statement’s select list can do that. The ORDER BY performs a very different function—it sorts the rows returned by the WHERE clause according to the criteria spelled out in the ORDER BY clause. Self Test Answers 167 List the Capabilities of SQL SELECT Statements 5. ˛ A, B, and C. The first example uses the asterisk, which is a shorthand way of referencing every available column in the database table. The second answer is fine—even though the columns are listed in an order that is different from how they are structured in the table, it doesn’t matter—you can list the columns in any order you wish. ˝ D is incorrect. The phrase “ALL THE COLUMNS” is not a valid clause for the SELECT statement. 6. ˛ A and D. Answer A is missing the select list, also known as the expression list. Answer D uses parentheses incorrectly. Both will produce a syntax error. ˝ B and C are incorrect. In other words, both are valid SELECT statements. Answer B selects two valid expressions and a column name. Answer C selects the same column name several times, which might seem odd, but it’s perfectly valid syntactically. 7. ˛ B. The DISTINCT clause applies the requirement for unique information across all the columns chosen in the SELECT statement. In this case, the combination of LAST_NAME and FIRST_NAME, together, must be unique across the rows that are returned, and of the five rows of data, two have the same values for LAST_NAME and FIRST_NAME: the rows for CUSTOMER_ID of 1 and 5. Therefore these two rows will be represented by a single row in the output of this particular SELECT statement, and each of the remaining rows will be displayed for LAST_NAME and FIRST_NAME. ˝ A, C, and D are incorrect. 8. ˛ C. You cannot use the asterisk together with any other column in the SELECT statement. The asterisk can only be used by itself. ˝ A, B, and D are incorrect. If it weren’t for the syntax error that results from the combination of the asterisk and a column reference—or in this particular case, a pseudocolumn reference—then the correct answer might have been B, which is that the ROWNUM would display, but with numbers assigned to the rows before ORDER BY changed the order of the rows, and along with that, the order of the ROWNUM values as well. 9. ˛ C. Remember that the orders of operator precedence require that the multiplication be performed first. That means the first action will be to multiply 4 times 1.10, resulting in 4.40. The result of that will be added to 3, thus: 7.40. ˝ A, B, and D are incorrect. You might get 13.2 if you multiply 3 times 4, and then multiply the result times 1.10. But the first two numbers have an operator for addition, not multiplication. And you might get 7.70 if you add 3 plus 4 and then multiply the results by 1.10, but that is not what SQL will do here; instead, SQL will first do the multiplication and then do the addition—see the explanation for the correct answer, C. 168 Chapter 4: Retrieving Data Using the SQL S ELECT Statement 10. ˛ D. Parentheses are placed at the top of the order of operator precedence, meaning that anything you enclose in parentheses will be evaluated before anything else. ˝ A, B, and C are incorrect. Uh—no. Just—no. 11. ˛ B. Joining is the act of relating two tables—or more—and connecting their output by way of identifying common information to produce one combined set of rows. A SELECT statement that performs this feature is often referred to as a “join”. ˝ A, C, and D are incorrect. Projecting isn’t really the word, but “projection” refers to the act of choosing a subset of columns from the available set of columns in a given table. Provisioning isn’t really a concept in Oracle SQL. Linking isn’t relevant here, either. Describe How Schema Objects Work 12. ˛ B. The INDEX stores data for speeding up querying. ˝ A, C, and D are incorrect. ROWID is a pseudocolumn, and not a database object. A VIEW names a SELECT statement. LOOKUP is something I made up; it’s not a reserved word in Oracle as best as I know. 13. ˛ D. The answer is that you would create a PUBLIC SYNONYM. ˝ A, B, and C are incorrect. A public table is not a particular type of object in Oracle SQL, although you could create a table that essentially serves the purpose, as we’ll explore when we look at privileges. A SYNONYM is close but not quite the right answer—yes, a SYNONYM is an alias for another database object, but a synonym is not, by default, available to the entire database, although it’s possible to make it so, but it’s far better to create a PUBLIC SYNONYM for that purpose. And there is no formal object known as ALIAS. 14. ˛ A. All data is stored in tables. Even data about the tables you create is stored automatically by Oracle SQL in a set of system-defined and system-maintained tables. ˝ B, C, and D are incorrect. 15. ˛ A. A VIEW is created by naming a SELECT statement. ˝ B, C, and D are incorrect. A SYNONYM is created by associating an alias with another database object name. A SEQUENCE is a number counter. 5 Restricting and Sorting Data Certification Objectives 5.01 Limit the Rows That Are Retrieved by a Query 5.02 Sort the Rows That Are Retrieved by a Query 3 Q&A Two-Minute Drill Self Test 170 Chapter 5: Restricting and Sorting Data T his chapter looks at two clauses of the SELECT statement: the WHERE clause and the ORDER BY clause. The WHERE clause specifies the criteria that are required for a row to be included in a SQL statement. Without it, all rows in a given table are retrieved, but with it, a SQL statement can selectively target particular rows for processing. The ORDER BY clause sorts the retrieved rows. It’s very flexible: it can sort rows in ascending or descending order, or it can sort by expression lists or take advantage of other powerful features. A working knowledge of both of these clauses is necessary in order to pass the exam. Let’s get started. Certification Objective 5.01 Limit the Rows That Are Retrieved by a Query When building a SELECT statement, your first task is to identify which database table (or tables or views) contains the data you need. You also need to look at the table’s structure to choose the columns that will be included in the select list of your SELECT statement. But rarely do you stop there. Most of the time you’ll want to limit the rows you’ll retrieve to a particular few, based on some sort of business rules. That task is accomplished with the SELECT statement’s WHERE clause. This section will look at the WHERE clause and its usage. The WHERE Clause The WHERE clause is one of the more important clauses of three different SQL statements: SELECT, UPDATE, and DELETE. The purpose of the WHERE clause is to identify rows that you wish to include in your SQL statement. If you’re working with a SELECT, then your WHERE clause chooses which rows will be included in your SELECT output. If it’s an UPDATE you’re working with, the WHERE clause defines which rows will be updated. If a DELETE, the WHERE clause defines which rows will be deleted. Within any SQL statement, the WHERE clause, if included, always follows the FROM clause. WHERE is optional; it is never required in order to form a complete SQL statement, but if included, it must follow the FROM clause. Limit the Rows That Are Retrieved by a Query 171 The WHERE clause starts with the reserved word WHERE, which is followed by the WHERE condition. The WHERE condition consists of one or more comparisons of expressions. The ultimate goal of the WHERE condition is to determine a value of true or false for each row in the tables (and/or views) identified in the FROM clause. If the WHERE condition returns a true for a given row, that row is included in the SQL statement. If it returns a false for a given row, that row is ignored for the SQL statement. Let’s look at a simple example: 01 02 03 SELECT EMPLOYEE_ID FROM WORK_HISTORY WHERE SHIP_ID = 3; In this example, the WHERE clause on line 3 compares two expressions: n The first expression is the table column SHIP_ID. n Next is the comparison operator, which in this case is the equal sign. n Finally we have the expression consisting of the literal value 3. The WHERE clause will consider each row in the tables (and/or views) identified in the FROM clause. For this WHERE clause, each row’s SHIP_ID value is analyzed to determine if its value equals 3. For each row that contains a value of 3 in the SHIP_ID column, the WHERE condition returns a value of “true” for that row, and that row is included in the SQL statement. All other rows are ignored. Note that the SELECT statement’s select list doesn’t include SHIP_ID. The WHERE clause does not need to include any of the columns that are being displayed—any column in the table is available to the WHERE clause. In this particular example, the issue of whether to include a row is based on data that won’t be included in the final results of the SELECT statement, and that’s fine. If you leave the WHERE clause out of a SELECT statement, then all rows of the table (or tables) are retrieved. Here is another example of a WHERE clause: 01 02 03 SELECT PORT_NAME, CAPACITY FROM PORTS WHERE CAPACITY >= 5; This example shows a complete WHERE clause on line 3. In this example, the SELECT statement will show the values for PORT_NAME and CAPACITY for all rows with a value in the CAPACITY column that is greater than or equal to 5. In the next section we’ll examine expressions in WHERE clauses. 172 Chapter 5: Restricting and Sorting Data Comparing Expressions The WHERE clause uses a series of comparisons, each of which evaluates for each row to either true or false. Each comparison involves two expressions evaluated by a comparison operator. The expressions are first evaluated, then compared. Here is an example: on the left is an expression that consists solely of the column named SALARY. On the right is an expression that multiplies two numbers together: SALARY >= 50899 * 1.12 In this example, if the value in SALARY is greater than or equal to the result of the math equation 50899 times 1.12, the result is true. Otherwise, it’s false. The examples you’ve seen so far have shown column names on the left, but that’s not required—any valid expression may be placed on either side—or both sides—of the comparison operator. Ideally one of the expressions should include data from the table; otherwise, what’s the point? But in terms of syntax, that is not required—all that is required is a valid expression on both sides of the comparison operator. Let’s look at another example: START_DATE < END_DATE If the value in the column titled START_DATE is less than the value in the column titled END_DATE, the expression is true; otherwise, it’s false. (Note that when SQL compares dates, “less than” means “earlier than”. For example, January 1 is less than January 2 of the same year. More on this issue in a bit.) You’ve already seen expressions in Chapter 4. The WHERE clause uses “comparison operators” to compare two expressions to each other. See Table 5-1 for a full list of the comparison operators. The operators are relatively self-explanatory, except for IN, LIKE, and IS, all of which we’ll discuss in upcoming sections. Table 5-1 Operator Description Comparison Operators = Equal >= Greater than or equal to > Greater than <= Less than or equal to < Less than != Not equal Limit the Rows That Are Retrieved by a Query 173 Table 5-1 Operator Description Comparison Operators (Continued) <> Not equal ^= Not equal IN Compares one value on the left side of the operator to a set of one or more values on the right side of the operator. The set of values must be enclosed in parentheses. If the values are presented as constants, they are separated by commas, as in (‘Maple’, ‘Elm’, ‘Main’) or (2009, 2010, 2011). A query may also be used, as in (SELECT PORT_NAME FROM PORTS)—this is called a “subquery” and we’ll discuss much more on that topic in Chapter 9. LIKE Enables wildcard characters. There are two wildcard characters: _ The underscore is a wildcard character representing a single character. % The percent sign is a wildcard character representing zero or more characters. IS Used with NULL or NOT NULL Comparing Datatypes Within a single comparison, both expressions should be the same datatype in order for the comparison to work. There are essentially three general categories of datatypes to consider when performing comparisons—numeric, character string, and date. The rules for comparing datatypes are listed in Table 5-2. Table 5-2 Datetype Comparison Rules Rules for Datatype Comparisons Numeric Smaller numbers are less than larger numbers. 1 is less than 10. –3 is less than –1. The number 0 is greater than any negative number. Character ‘A’ is less than ‘Z’. ‘Z’ is less than ‘a’, meaning that uppercase letters are less than lowercase letters. Be careful of situations where numbers are treated as characters. For example, the string ‘2’ is considered to be greater than the string ‘10’, because character strings are treated as text, not numbers, unless SQL is given explicit instructions otherwise— something we’ll address later, when we discuss functions that perform datatype conversions. Comparisons are case sensitive by default. Dates Yesterday is less than tomorrow. Earlier dates are less than later dates. 174 Chapter 5: Restricting and Sorting Data You may have noticed that I said datatypes “should” be the same for two expressions that are compared to each other. I say “should” because this isn’t an absolute rule. Sometimes you can get away with comparing expressions of different datatypes provided that SQL has enough information to perform an automatic datatype conversion and therefore treat both sides of the comparison as though they were the same datatype, even though they are not. While this can work, it’s not recommended. The results of such automatic datatype conversions can be a bit tricky and relatively unpredictable, so it’s best to avoid such situations. When we discuss SQL functions later, you’ll see some functions that can be used to perform explicit datatype conversions, which is the better choice for the SQL professional. In the meantime, don’t depend on Oracle SQL’s automatic datatype conversion capabilities unless you love to live dangerously and don’t mind if the rest of us laugh at you. Here’s an example that compares string values: SELECT * FROM EMPLOYEES WHERE LAST_NAME = 'Smith'; This sample will show all columns in all the rows in the EMPLOYEES table where the value for the LAST_NAME column is the character string ‘Smith’. Note that text searches are case sensitive by default. In other words, this is a different query: SELECT * FROM EMPLOYEES WHERE LAST_NAME = 'SMITH'; The search for employees with a value in the LAST_NAME column of ‘SMITH’ will not find the same rows that have a LAST_NAME value of ‘Smith’. If you wish to do a search on both possibilities, see Chapter 6, where we’ll discuss how to handle such situations using SQL functions. When comparing dates, I always like to remember the rhyme: “later” dates are “greater” dates.That’s my trick for remembering how the rules of date comparison work. LIKE The LIKE comparison operator is useful for performing wildcard searches on character data. It uses wildcard characters that you can embed within a text string. Limit the Rows That Are Retrieved by a Query 175 LIKE works with columns of datatype CHAR and VARCHAR2. Technically it doesn’t really work on DATE, but on a practical level it does—it performs an automatic datatype conversion of the DATE values involved before performing the comparison. The two wildcard symbols are n The underscore (_), representing a single character n The percent sign (%), representing zero or more characters The underscore is used when you are looking for a query in which you are allowing a fixed number of characters. Underscores can be repeated as required. For example, this query is looking for values in the PORT_NAME column that start with the string ‘San’, followed by a blank space, followed by any four characters: 01 02 03 SELECT PORT_NAME FROM PORTS WHERE PORT_NAME LIKE 'San ____'; In case you can’t tell, that’s four underscores after ‘San ’ in the preceding query. If you were to run this query against rows with these values: San Diego San Francisco San Juan the query will only return this value: San Juan That’s because of the four underscores in the query (line 3), which specifically ask for four unknown characters after ‘San ’. No more, no less. If you wish to indicate any number of unknown characters, ranging from zero to infinity, then use the percent sign. This query, SELECT PORT_NAME FROM PORTS WHERE PORT_NAME LIKE 'San%'; will find all three rows in the previous example: San Diego San Francisco San Juan 176 Chapter 5: Restricting and Sorting Data The percent sign, combined with LIKE, indicates that any number of characters are sought. Underscores and percent signs may be used in any combination, in any order, in any location within the pattern. For example: SELECT PORT_NAME FROM PORTS WHERE PORT_NAME LIKE '_o%'; This query is looking for values in PORT_NAME with any one random character in the first position, followed by the lower case letter ‘o’ in the second position, followed by anywhere from zero to an infinite number of characters after the letter ‘o’. The following rows match the request: Los Angeles Honolulu When working with LIKE, you put the wildcard character (or characters) within a string enclosed in single quotes. The string must occur after the reserved word LIKE, not before. In other words, the following is syntactically correct but doesn’t perform as you might think it should: SELECT PORT_NAME FROM PORTS WHERE 'G_and%' LIKE PORT_NAME; This query is asking if the string literal ‘G_and%’ happens to match the value contained within PORT_NAME. This probably isn’t what was intended. The point here is that the wildcard characters are only “activated” if the pattern containing them is on the right side of the LIKE reserved word. This is the query that was probably intended: SELECT PORT_NAME FROM PORTS WHERE PORT_NAME LIKE 'G_and%'; This query would find a row containing a PORT_NAME value such as this: Grand Cayman So remember: place the pattern after LIKE, not before. Oracle won’t complain if you screw it up. But your output probably won’t be what you’re intending. Limit the Rows That Are Retrieved by a Query 177 Boolean Logic The WHERE clause includes support for Boolean logic, whereby multiple expressions can be connected together with a series of Boolean operators. This section looks at those operators, what they are, how they are used, and their order of precedence. AND, OR Most WHERE conditions involve more than just one comparison of two expressions. Most WHERE clauses contain several such comparisons. This is where the Boolean operators come in. Two or more comparisons of expressions can be connected together by using various combinations of the Boolean operators AND and OR. There’s also a third operator—NOT—and it can be used to invert an AND or OR condition. Boolean operators evaluate multiple comparison expressions and produce a single true or false conclusion from the series of comparisons. For example: 01 02 03 04 05 SELECT EMPLOYEE_ID FROM WORK_HISTORY WHERE SHIP_ID = 3 AND STATUS = 'Pending'; Let’s break this down the way Oracle SQL does. Consider the following data listing: WORK_HISTORY_ID --------------10 11 12 EMPLOYEE_ID ----------3 4 7 SHIP_ID ------1 4 3 STATUS -----Pending Active Pending For each row, the WHERE condition will do the following: n Determine if the SHIP_ID value equals 3 n Determine if the STATUS value is equal to the string ‘Pending’ The results for each row are as follows: WORK_HISTORY_ID --------------10 11 12 EMPLOYEE_ID ----------3 4 7 SHIP_ID ------1 4 3 STATUS ------Pending Active Pending SHIP_ID=3? ---------FALSE FALSE TRUE STATUS='Pending'? ----------------TRUE FALSE TRUE 178 Chapter 5: Restricting and Sorting Data Now let’s apply the AND operator to each row: WORK_HISTORY_ID --------------10 11 12 SHIP_ID=3? ---------FALSE FALSE TRUE AND AND AND STATUS='Pending'? ----------------TRUE FALSE TRUE RESULT -------FALSE FALSE TRUE The rules of Boolean operator evaluation are the same as they are in conventional mathematics. See Table 5-3 for a listing of all the possible results of Boolean operator expressions. The rules for Booleans are: n For AND, both expressions must be true for the combination to be true. Otherwise, the answer is false. n For OR, at least one expression needs to be true for the combination to evaluate to true. Otherwise, the answer is false. The basic syntax for a SELECT statement with a WHERE clause that includes Booleans is as follows: 01 02 03 04 05 06 07 SELECT select_list FROM from_table WHERE expression comparison_operator expression Boolean_operator expression comparison_operator expression termination_character Lines 4 and 6 represent the same thing—a comparison of two expressions. Table 5-3 Boolean Expression Result Boolean Expression Combinations and Results TRUE AND TRUE TRUE TRUE AND FALSE FALSE FALSE AND TRUE FALSE FALSE AND FALSE FALSE TRUE OR TRUE TRUE TRUE OR FALSE TRUE FALSE OR TRUE TRUE FALSE OR FALSE FALSE Limit the Rows That Are Retrieved by a Query 179 A single WHERE clause may include as many of these comparisons as are required, indicated on line 4, and also on line 6—provided they are each separated by a Boolean operator. NOT The reserved word NOT is part of the set of Boolean operators. It can be placed in front of an expression to reverse its conclusion from true to false, or vice versa. For example, let’s modify a SELECT statement you saw earlier: 01 02 03 04 05 SELECT EMPLOYEE_ID FROM WORK_HISTORY WHERE SHIP_ID = 3 AND NOT STATUS = 'Pending'; In this SELECT, we’ve added the reserved word NOT on line 5 to reverse the findings of the comparison of the string ‘Pending’ to the values in the column STATUS. If you were to run this version of the SELECT against the same three rows you used earlier, you’d get a very different result: WORK_HISTORY_ID --------------10 11 12 EMPLOYEE_ID ----------3 4 7 SHIP_ID ------1 4 3 STATUS ------Pending Active Pending SHIP_ID=3? ---------FALSE FALSE TRUE NOT STATUS='Pending'? --------------------FALSE TRUE FALSE With an AND operator still in use here, now our SELECT statement will return no rows, since AND requires both sides to be true, and in this case none are. Let’s look at another example: 01 02 03 SELECT EMPLOYEE_ID FROM WORK_HISTORY WHERE NOT SHIP_ID = 3; As you can see from this example, NOT can be used without any other Boolean operators. If you’re an experienced 3GL programmer and have used languages such as Oracle’s PL/SQL, this section may have you wondering where the BOOLEAN datatype fits in to SQL. It doesn’t.There is no BOOLEAN datatype in SQL. There is in PL/SQL, but not in SQL. Instead, expressions are compared to each other in order to determine a Boolean condition of TRUE or FALSE, and the Boolean operators compare them to determine an answer.The concepts of TRUE and FALSE are significant throughout SQL, as we see with the WHERE condition. But there are no specific datatypes that represent Boolean values. 180 Chapter 5: Restricting and Sorting Data Operator Precedence Just as there is a set of rules regarding the order of evaluating arithmetic operators within expressions, so too are there rules for evaluating Boolean operators. It’s very important that you remember the order in which SQL evaluates Boolean operators. The bottom line: NOT is evaluated first. After that, AND is evaluated before OR. For example, consider the following data listing for a table called SHIP_CABINS: ROOM_NUMBER ----------102 103 104 105 106 STYLE --------Suite Stateroom Suite Stateroom Suite WINDOW --------Ocean Ocean None Ocean None Now consider this SQL statement against the data listing: SELECT FROM WHERE OR AND ROOM_NUMBER SHIP_CABINS STYLE = 'Suite' STYLE = 'Stateroom' WINDOW = 'Ocean'; How many rows do you think this query will retrieve? Are you thinking . . . three rows, by any chance? If you are, you’re not alone; most people tend to. But . . . you’ll really get five rows. Why? Because of the rules of Boolean operator precedence. An English-speaking person might read that query as asking for all rows with a STYLE value of either ‘Suite’ or ‘Stateroom’ and also with a value for WINDOW of ‘Ocean’. But SQL sees this differently—it first evaluates the AND expression. SQL is looking for all the rows where STYLE is ‘Stateroom’ and WINDOW is ‘Ocean’ . . . OR . . . . any row with a STYLE value of ‘Suite’, regardless of its value for WINDOW. In other words, it’s doing this: ROOM_NUMBER ----------102 103 104 105 106 STYLE --------Suite Stateroom Suite Stateroom Suite WINDOW --------Ocean Ocean None Ocean None Stateroom AND Ocean? -------------------FALSE TRUE FALSE TRUE FALSE OR OR OR OR OR Suite? -----TRUE FALSE TRUE FALSE TRUE Remember, only one side in an OR must be TRUE. And given this criterion, all five rows will evaluate to true. Limit the Rows That Are Retrieved by a Query 181 You can use parentheses to override the rules of Boolean operator precedence, like this: SELECT FROM WHERE OR AND ROOM_NUMBER SHIP_CABINS (STYLE = 'Suite' STYLE = 'Stateroom') WINDOW = 'Ocean'; That query will retrieve three rows. Additional WHERE Clause Features The WHERE clause offers some options to streamline the readability of your code. This section describes features that are important to advanced WHERE clause usage. IN Sometimes you’ll find yourself comparing a single column to a series of various values. For example: SELECT PORT_NAME FROM PORTS WHERE COUNTRY = 'UK' OR COUNTRY = 'USA' OR COUNTRY = 'Bahamas'; That query is correct, but in such situations, you have the option of choosing a different style. You may choose to use the reserved word IN as an alternative. For example: SELECT PORT_NAME FROM PORTS WHERE COUNTRY IN ('UK', 'USA', 'Bahamas'); The rules that govern the use of the IN operator include the following: n IN can be used with dates, numbers, or text expressions. n The list of expressions must be enclosed in a set of parentheses. n The list of expressions must be of the same datatype—or be similar enough that Oracle can perform automatic datatype conversion to make them all the same. n The list can include anywhere from one expression to several, each separated by commas. 182 Chapter 5: Restricting and Sorting Data In addition, the Boolean operator NOT may precede the IN operator, as follows: SELECT PORT_NAME FROM PORTS WHERE COUNTRY NOT IN ('UK', 'USA', 'Bahamas'); The use of NOT will identify rows as true if they do not contain a value from the list. You’ll see later that the reserved word IN is particularly important in the WHERE clause when we’re using subqueries, which we’ll discuss in Chapter 9. BETWEEN In addition to the formats we’ve seen so far, the WHERE clause also supports a feature that can compare a single expression to a range of values. This technique involves the reserved word BETWEEN. Here’s an example: SELECT PORT_NAME FROM PORTS WHERE CAPACITY BETWEEN 3 AND 4; This is the equivalent of the following statement: SELECT FROM WHERE AND PORT_NAME PORTS CAPACITY >= 3 CAPACITY <= 4; Notice that BETWEEN is inclusive. In other words, it doesn’t simply look for values “between” the two comparison expressions but also includes values that are equal to the comparison expressions. The range can be specified using any valid expression. The range should be from lowest to highest. If you specify the higher value first, and the lower value second, your code will be accepted syntactically but will always return zero rows. The NOT keyword may also be combined with BETWEEN. The following are valid statements: SELECT PORT_NAME FROM PORTS WHERE CAPACITY NOT BETWEEN 3 AND 4; SELECT PORT_NAME FROM PORTS WHERE NOT CAPACITY BETWEEN 3 AND 4; These two examples are equivalent to each other. Limit the Rows That Are Retrieved by a Query 183 IS NULL, IS NOT NULL Remember that the NULL value represents an unknown value. NULL is the equivalent of “I don’t know”. Any value that’s compared to “I don’t know” is going to produce an unknown result—i.e., NULL. For example: SELECT PORT_NAME FROM PORTS WHERE CAPACITY = NULL; This SQL statement will never retrieve any rows, never ever, never ever ever. Don’t believe me? Try it, I’ll wait. Told you. It will not ever retrieve any rows, not even if the value for CAPACITY is NULL within a given row. The reason is that this is asking SQL to compare CAPACITY to a value of “I don’t know”. But what if the value of CAPACITY in the database table is actually NULL? Shouldn’t this work then? Shouldn’t you be able to ask if CAPACITY = NULL? Why isn’t the expression “NULL = NULL” true? Well—let me ask you this: I’m thinking of two numbers, and I’m not going to tell you what either one of them are. Instead I’m just going to ask you this: are these two numbers equal to each other? Well? Are they? Of course you can’t possibly know. I think you’d have to say the answer is “I don’t know”, or NULL. And NULL, in terms of Boolean logic, is always assumed to be FALSE. So any time you create a WHERE condition that ends up as “anything = NULL”, the answer will always be FALSE, and you’ll never get a row—even if the “anything” is NULL itself. But what do you do when you really need to test the value of something like CAPACITY to determine if it is NULL or not? There is an answer, and it’s the SQL comparison condition IS NULL, and its companion IS NOT NULL. Let’s redo our SELECT statement: SELECT PORT_NAME FROM PORTS WHERE CAPACITY IS NULL; Now you’re asking for rows from the PORTS table where the value for CAPACITY is unknown in the database—which is what IS NULL asks for. That’s a very different query than asking if CAPACITY happens to be identical to some number that we haven’t identified yet—which is what “= NULL” asks. The opposite of the IS NULL comparison operator is IS NOT NULL, like this: SELECT PORT_NAME FROM PORTS WHERE CAPACITY IS NOT NULL; 184 Chapter 5: Restricting and Sorting Data In this query, you’re asking for all rows in which the CAPACITY value is identified in the database, i.e., wherever it is not NULL. These concepts are very important. This is yet another example of one of the many ways in which SQL code might appear to be correct, might execute without any syntax or execution errors, and yet can be totally wrong. Be sure you get this right. Don’t screw it up. If you do, the problems will be subtle and potentially disastrous, and might only become apparent months later after bad data and incorrect reports have been circulated. So remember: Never use this: = NULL There is never a good reason to use that, ever. Always use this instead: IS NULL Got it? Additional Concepts There are more ways to customize a WHERE clause than what has been presented here. Upcoming topics that will be addressed in this book—and tested on the exam—include the following: n Subqueries n Set operators These and other issues are important to the WHERE clause and important to the exam. They will be covered on their own in upcoming chapters. Certification Objective 5.02 Sort the Rows That Are Retrieved by a Query This section looks at another clause in the SELECT statement, the ORDER BY clause. ORDER BY is used to sort the rows that are retrieved by a SELECT statement. It sorts by specifying expressions for each row in the table. Sorting can be performed in either ascending or descending order. SQL will sort according to the datatype of the expression that is identified in the ORDER BY. You can include Sort the Rows That Are Retrieved by a Query 185 more than one expression. The first expression is given sorting priority, the second is given second-position priority, and so on. ORDER BY is always the final clause in a SELECT statement. It is only used in SELECT; contrary to the WHERE clause, which can also be used in UPDATE and DELETE, the ORDER BY clause is unique to the SELECT statement and is not used in the other SQL statements. (Note: in Chapter 9 we’ll examine how you may embed a SELECT statement as a subquery within an INSERT, UPDATE, or DELETE statement—so in that regard, it is theoretically possible that an ORDER BY clause might be included in a SELECT statement that is embedded within, for example, an INSERT statement. But that is a separate issue.) ORDER BY does not change data as it is stored in the table. Data in a table remains unchanged as a result of the ORDER BY. ORDER BY is part of the SELECT statement, and the SELECT statement is incapable of changing data in the database. Note, however, that when SELECT is embedded within other SQL statements like INSERT or UPDATE, changes to the database can result, but not because of SELECT alone. You’ll see how that works in Chapter 9. ORDER BY sorts the output of a SELECT statement for display purposes only. It is always the last step in a SELECT statement, and performs its sort after all the data has been retrieved and processed by the SELECT statement. Reference by Name Let’s look at an example of ORDER BY in action. Consider the following data listing from a table ADDRESSES. ADDRESS_ID ---------1 2 3 4 5 6 7 8 9 10 11 12 STREET_ADDRESS ------------------350 Oracle Parkway 1600 Amphitheatre Parkway 1 Dell Way 29 E Ohio St 5788 Roswell Rd NE 10103 100 St NW 1221 Avenue of the Americas 239 Baker Street 1 rue des Carrieres 2041 S Harbor Blvd 600 N Michigan Ave 1515 Sheridan Rd CITY ------------Redwood City Mountain View Round Rock Chicago Atlanta Edmonton New York London Quebec City Anaheim Chicago Wilmette ST -CA CA TX IL GA AB NY QC CA IL IL COUNTRY -----USA USA USA USA USA Canada USA UK Canada USA USA USA 186 Chapter 5: Restricting and Sorting Data We can select this data and sort it by specifying the column name (or names) in the ORDER BY clause of the SQL statement, as follows: SELECT ADDRESS_ID, STREET_ADDRESS, CITY, STATE, COUNTRY FROM ADDRESSES ORDER BY STATE; The results are shown in Figure 5-1. Notice in the figure that the rows are sorted in alphabetical order according to the value in the STATE column. Note that the row with a NULL value for STATE is last. The NULL value is considered the “highest” value. As we review the output, it becomes clear that we might also wish to alphabetize our information by city for each state. We can do that by modifying our ORDER BY clause ever so slightly: SELECT ADDRESS_ID, STREET_ADDRESS, CITY, STATE, COUNTRY FROM ADDRESSES ORDER BY STATE, CITY; In the modified version of our ORDER BY, we add a second column to the ORDER BY clause by which we wish to sort. The results of this SELECT statement are displayed in Figure 5-2. The rows have been sorted first by STATE, and then by the CITY value for each STATE. Note that the choice of columns we include in the ORDER BY clause does not influence which columns we choose to display in the SELECT expression list. It would probably be easier to read if we put the same columns used in the ORDER BY in the same positions as the SELECT expression list. In other words, this query would probably produce a more readable output: SELECT STATE, CITY, ADDRESS_ID, STREET_ADDRESS, COUNTRY FROM ADDRESSES ORDER BY STATE, CITY; The output of this SELECT would draw attention to our intent, which is to sort data by STATE first, then CITY. But while this might be considered preferential design in certain circumstances, it is by no means required within the syntax of the SQL statement. We’re not even required to include the ORDER BY columns in the SELECT statement’s expression list at all. This is another perfectly valid SELECT statement: SELECT ADDRESS_ID, STREET_ADDRESS, COUNTRY FROM ADDRESSES ORDER BY STATE, CITY; Sort the Rows That Are Retrieved by a Query 187 Figure 5-1 Results of SELECT with ORDER BY STATE Figure 5-2 Results of SELECT with ORDER BY STATE, CITY Notice that we’re sorting by columns that aren’t included in the SELECT statement’s expression list. Without an ORDER BY clause, there is no guarantee regarding the sequence in which rows will be displayed in a SELECT statement’s output. The rows may be produced in a different order from one query to another. The only way to ensure consistency to the output is to include an ORDER BY clause. 188 Chapter 5: Restricting and Sorting Data ASC and DESC There are two reserved words that specify the direction of sorting on a given column of the ORDER BY clause. Those reserved words are ASC and DESC. n ASC is short for “ascending” and indicates that values will be sorted in ascending order. In other words, the lowest, or least, value will be listed first, followed by values of higher, or greater, value. ASC is the default choice and as such does not need to be specified when desired but may be specified for clarity. n DESC is short for “descending” and indicates that values will be sorted in descending order. In other words, the highest, or greatest, value will be listed first, and values will continue to be listed in decreasing, or lesser, value. As just stated, the default is ASC. You don’t need to specify ASC. The ORDER BY examples you’ve seen so far have defaulted to ASC without our having to specify it. But you can specify ASC if you wish: SELECT SHIP_ID, PROJECT_COST, PROJECT_NAME, DAYS FROM PROJECTS ORDER BY SHIP_ID ASC; Here’s a variation on the preceding SELECT statement that uses a combination of ASC and DESC: SELECT SHIP_ID, PROJECT_COST, PROJECT_NAME, DAYS FROM PROJECTS ORDER BY SHIP_ID ASC, PROJECT_COST DESC; The results of this SELECT are displayed in Figure 5-3. Notice that the SHIP_ID values are listed in ascending order, but that for each ship, the PROJECT_COST values are shown from the highest to the lowest values. ASC and DESC each operate on the individual ORDER BY expressions. There is no way to assign the ASC or DESC to all the ORDER BY expressions collectively; instead, you must place your choice after each individual ORDER BY expression, remembering that ASC is the default and therefore does not need to be specified. Sort the Rows That Are Retrieved by a Query 189 Figure 5-3 PROJECTS table with ORDER BY ASC and DESC Expressions Note that the expressions you can include in an ORDER BY clause are not limited to columns in a table. Any expression may be used. In order to be useful, the expression should include a value in the table; otherwise, the value may not change and there won’t be any meaningful effect on the rows in the table. For example, here’s a data listing for the PROJECTS table: PROJECT_ID ---------1 2 3 4 5 6 SHIP_ID ------2 2 3 1 1 1 PROJECT_NAME -----------------------Hull Cleaning Deck Resurfacing Lifeboat Inspection Clean Pools Replace Lobby Carpeting Major Engine Service PROJECT_COST -----------340000 964000 12000 37000 137000 837000 DAYS ---20 10 3 5 5 15 This data listing shows a series of projects. For each project, we see the SHIP_ID for which the project is intended, the project’s total cost, and the estimated number of days it will take to complete each project. Looking at the values for PROJECT_COST and DAYS, we see enough information to compute the average cost per day for each project. In other words: PROJECT_COST / DAYS For example, the per-day cost for the three-day “Lifeboat Inspection” will turn out to be 4000, or 12000 divided by 3. 190 Chapter 5: Restricting and Sorting Data What if we want to sort these rows according to the computed value of the PROJECT_COST / DAYS? No problem: SELECT * FROM PROJECTS ORDER BY PROJECT_COST / DAYS; That query will achieve the result we’re after. Let’s vary it a bit in order to see more of what it is we’re calculating and sorting: SELECT PROJECT_ID, PROJECT_NAME, PROJECT_COST, DAYS, PROJECT_ COST/DAYS FROM PROJECTS ORDER BY PROJECT_COST/DAYS; The results of this query are shown in Figure 5-4. Note that the rows are ordered by a value that doesn’t exist in the table, but rather a value that is the result of an expression that draws values from the table. The Column Alias As you’ve already seen, a SELECT statement can include expressions in the select list. For example: SELECT PROJECT_ID, PROJECT_NAME, PROJECT_COST, DAYS, PROJECT_COST/DAYS FROM PROJECTS ORDER BY PROJECT_COST/DAYS; Notice the output in Figure 5-4, and the default title of the fifth column. SQL has used the expression as the title of the column. Figure 5-4 PROJECTS sorted by PROJECT_ COST / DAYS Sort the Rows That Are Retrieved by a Query 191 We could have used a SQL feature called the “column alias”. Here is the same query with a column alias: 01 02 03 04 SELECT PROJECT_ID, PROJECT_NAME, PROJECT_COST, DAYS, PROJECT_COST/DAYS AS PER_DAY_COST FROM PROJECTS ORDER BY PER_DAY_COST; Notice the PER_DAY_COST column alias at the end of line 2. The column alias is a name you make up and place just after the column you wish to alias, separated by the optional keyword AS. In this example, the column with the column alias is the final column in the select list. Once the column alias is used, you can reference it from within the ORDER BY clause, as we do on line 4. The rules for using a column alias include the following: n Each expression in the SELECT list may optionally be followed by a column alias. n A column alias is placed after the expression in the select list, separated by the optional keyword AS and a required space. n If the column alias is enclosed in double quotes, it can include spaces and other special characters. n If the column alias is not enclosed in double quotes, it is named according to the standard rules for naming database objects. n The column alias exists within the SQL statement and does not exist outside of the SQL statement. n The column alias will become the new header in the output of the SQL statement. n The column alias can be referenced within the ORDER BY clause, but nowhere else—such as WHERE, GROUP BY, or HAVING. Here’s an example of a column alias that uses the double quotation marks. Notice the inclusion of a space in the alias. 01 02 03 04 SELECT PROJECT_ID, PROJECT_NAME, PROJECT_COST, DAYS, PROJECT_COST/DAYS "Cost Per Day" FROM PROJECTS ORDER BY "Cost Per Day"; See the output of this query in Figure 5-5. Notice the column heading for the aliased column—the alias becomes the new heading in the SQL output. 192 Chapter 5: Restricting and Sorting Data Figure 5-5 SELECT output with column alias The point of bringing up the alias here, in this discussion about ORDER BY, is this: you can use the column alias when referencing any column with ORDER BY, and it’s particularly useful when trying to use ORDER BY with an expression from within the SELECT statement’s expression list. Reference by Position Another way the ORDER BY clause can identify columns to be sorted is via the “reference by position” method. This only works if the intent of the ORDER BY is to sort rows according to information that is included in the SELECT list. For example: SELECT PROJECT_ID, PROJECT_NAME, PROJECT_COST, DAYS, PROJECT_COST/DAYS FROM PROJECTS ORDER BY 5; Notice that we choose to ORDER BY 5 in this SQL statement. The number 5 in this context is referencing the fifth item in the SELECT statement’s select list, which is the expression “PROJECT_COST/DAYS”. Any expression in the SELECT list can be referenced using its numeric position. The first expression is considered number 1, the second is number 2, and so on. Any attempt to reference a position that doesn’t exist will produce a SQL error; for example, this is invalid: SELECT PROJECT_ID, PROJECT_COST/DAYS FROM PROJECTS ORDER BY 5; This statement will not execute. The ORDER BY clause must identify a number that corresponds to an item that is in the SELECT list. Sort the Rows That Are Retrieved by a Query 193 Combinations ORDER BY can combine the various techniques of reference by name, reference by column alias, and reference by position, for example: SELECT SHIP_ID, PROJECT_COST, PROJECT_NAME "The Project", DAYS FROM PROJECTS ORDER BY SHIP_ID DESC, "The Project", 2; This example is a valid statement. It sorts rows by n The value of SHIP_ID, in descending order n The value in the PROJECT_NAME column, which has a column alias in this SQL statement of “The Project” n The value in the PROJECT_COST column, which is the second item in the SELECT list The output of this query is shown in Figure 5-6. Remember that ordering a select statement by position is extremely useful in many situations that involve complex SELECT statements. Later you’ll see some interesting combinations of Figure 5-6 PROJECTS sorted by multiple techniques multiple SELECT statements—such as the section that looks at using set operators that combine multiple SELECT statements into one—and in those situations, you can always reference an ORDER BY column by position. 194 Chapter 5: Restricting and Sorting Data ORDER BY and NULL When SELECT performs a sort using ORDER BY, it treats any values that it might find to be NULL as “greater than” any other value. In other words, when you sort by a numeric datatype column, and that column contains NULL values, the NULL values will sort as being greater than all NOT NULL values in the list. The same is true for character datatypes and date datatypes. Certification Summary The WHERE clause is part of the SQL statements SELECT, UPDATE, and DELETE. It is used to identify the rows that will be affected by the SQL statement. For the SELECT statement, WHERE determines which rows are retrieved. For the UPDATE statement, it determines which rows will be updated. For the DELETE statement, it determines which rows will be deleted. The WHERE clause concerns itself with entire rows, not just the columns that are the subject of the particular SQL statement of which it is a part. The WHERE clause can reference columns that are not in the SELECT list. The WHERE clause is optional. If included in a SELECT statement, it must follow the FROM clause. The WHERE clause compares two expressions and determines if the result of the comparison is true or false. At least one of the two expressions should include a column from whatever table the SQL statement is intended to address, so that the WHERE clause is relevant to the SQL statement. The expressions are compared using comparison operators. Examples include the equal sign, the not-equal sign, and the greater-than and less-than signs. A series of comparisons can be connected together using the Boolean operators AND and OR. The NOT operator can also be included. Together, these expressions can form complex WHERE clauses. The LIKE operator can activate the wildcard characters. The two wildcard characters are the underscore (_) and the percent sign (%). The IN operator can compare a single value to a set of values. An expression using the IN operator will evaluate to true if that single value matches any of the values in the expression list. When using the WHERE clause to locate rows that have a NULL value, never use the “= NULL” comparison, instead always use the IS NULL or IS NOT NULL comparison operators. Sort the Rows That Are Retrieved by a Query 195 The ORDER BY clause of the SELECT statement is the method for sorting the rows of output returned by the SELECT statement. The ORDER BY clause is optional, but if included in a SELECT statement, it is always the final clause of the SELECT statement. ORDER BY specifies one or more expressions. Each expression is used by ORDER BY to sort each row in the result set. Output rows are sorted first by the first expression, and for any rows that share the same value for the first expression, those rows will be sub-sorted for expression two, and so on. Expressions for ORDER BY follow the same rules as expressions in the SELECT statement’s select list and the WHERE clause. Each expression should ideally reference a column in the table, but this isn’t required. The ASC and DESC reserved words can be used in an ORDER BY clause to determine the direction of sorting for each individual expression. ASC will sort values in ascending order, and DESC will sort in descending order. ASC is the default and need not be specified. The specification of ASC or DESC should follow each expression with a space separating them. ORDER BY sorts values according to datatypes. With numeric datatypes, low numbers are low, and high numbers are high; with dates, yesterday is lower than tomorrow, and next week is higher than last month; with characters, ‘Z’ is less than ‘a’, and the character string ‘10’ is less than the character string ‘3’. ORDER BY can specify expressions in the SELECT statement’s select list by referencing the column alias, if one was created within the SELECT list. ORDER BY can also identify expressions in the SELECT list by the number corresponding to the position of the item in the SELECT list; for instance, “ORDER BY 1” will sort by the first item in the SELECT list. ORDER BY can combine all of these features into one series of order items. A column alias, if specified in the select list, is not recognized in the WHERE, GROUP BY, or HAVING clause. 196 Chapter 5: 3 Restricting and Sorting Data Two-Minute Drill Limit the Rows That Are Retrieved by a Query q The WHERE clause comes after the FROM clause. q WHERE identifies which rows are to be included in the SQL statement. q WHERE is used by SELECT, UPDATE, and DELETE. q WHERE is an optional clause. q Expressions form the building blocks of the WHERE clause. q Expressions may include column names, literal values, and as you’ll see in Chapter 6. The WHERE clause compares expressions to each other using comparison operators and determines if the comparisons are true or false. q Boolean operators may separate each comparison to create a complex series of evaluations. Collectively, the final result for each row in the table will either be true or false; if true, the row is returned; if false, it is ignored. q The Boolean operators are AND, OR, and NOT. q The rules of Boolean operator precedence require that NOT be evaluated first, then AND, and then OR. q Parentheses can override any Boolean operator precedence. q When comparing date datatypes: earlier date values are considered “less” than later dates, so anything in January will be “less than” anything in December of the same year. q When comparing character datatypes, the letter ‘a’ is less than the letter ‘z’, upper case letters are “lower than” lower case letters, and the character representation of ‘3’ is greater than the character representation of ‘22’, even though the results would be different if they were numeric datatypes. q LIKE can be used to activate wildcard searches. q IN can be used to compare a single expression to a set of one or more expressions. q BETWEEN can be used to see if a particular expression’s value is within a range of values. BETWEEN is inclusive, not exclusive, so that BETWEEN 2 and 3 includes the numbers 2 and 3 as part of the range. q Use IS NULL or IS NOT NULL when testing a column to see if its value is NULL. Two-Minute Drill 197 Sort the Rows That Are Retrieved by a Query q ORDER BY is an optional clause used to sort the rows retrieved in a SELECT statement. q If used, ORDER BY is always the last clause in the SELECT statement. q ORDER BY uses expressions to direct the sorting order of the result set of the SELECT statement. q Each expression is evaluated in order, so that the first item in the ORDER BY will do the initial sort of output rows, the second item listed will sort any rows that share identical data for the first ORDER BY element, and so on. q ORDER BY can sort by columns in the table, regardless of whether the columns appear in the SELECT statement’s select list or not. q ORDER BY can also sort by expressions of any kind, following the same rules of expressions that you’ve seen with the WHERE clause and the select list. q Numeric data is sorted by default in ascending order, from lower numbers to higher. q Character data is sorted by default in ascending order, from ‘A’ to ‘Z’. q Date data is sorted by default in ascending order, from prior dates to later dates. q All sorts default to ascending order, which can be specified with the optional keyword ASC. q Sort order can be changed to descending order with the keyword DESC. q ORDER BY can identify columns by column alias, or by position within the SELECT list. 198 Chapter 5: Restricting and Sorting Data Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Limit the Rows That Are Retrieved by a Query 1. Consider the following SELECT statement: SELECT PORT_ID FROM PORTS WHERE 1=2; Which of the following is true of the SELECT statement? A. It will produce a syntax error because the WHERE condition does not refer to any columns in the table. B. It will produce a syntax error because the WHERE condition returns a FALSE value. C. It will execute and return all of the rows in the table. D. It will execute and return none of the rows in the table. 2. Review the information in this exhibit: PORT_ID ------1 2 3 4 5 6 PORT_NAME -------------------Galveston San Diego San Francisco Los Angeles San Juan Grand Cayman COUNTRY -------USA USA USA USA USA UK CAPACITY -------4 4 3 4 3 3 Now consider the following SELECT statement: SELECT FROM WHERE OR AND * PORTS PORT_NAME LIKE 'San%' PORT_NAME LIKE 'Grand%' CAPACITY = 4; How many rows from the data in the exhibit will be returned by the preceding query? A. None B. 1 C. 3 D. 6 Self Test 199 3. Review the table listing from this PROJECTS table: PROJECT_NAME --------------------------Repair Hallway on Lido Deck Fix broken window cabin 12 COST -----500.00 129.45 Next, review this SQL statement: SELECT PROJECT_NAME FROM PROJECTS WHERE COST ^= 500; How many rows will the SELECT statement return? A. None, because the WHERE condition only wants rows with a cost greater than 500. B. None, because of the syntax error in the expression “COST ^= 500”. C. 1 D. 2 4. Which of the following statements is true of Boolean operators? For this question, ignore the role of parentheses. (Choose two.) A. AND is evaluated before NOT. B. NOT is evaluated last. C. OR is evaluated after AND. D. NOT is evaluated first. 5. Review the following data listing for a table VENDORS: VENDOR_ID --------1 2 CATEGORY --------------Supplier Teaming Partner Now review the following SQL statement: SELECT VENDOR_ID FROM VENDORS WHERE CATEGORY IN ('Supplier','Subcontractor','%Partner'); How many rows will the SELECT statement return? A. 2 B. 1 C. 0 D. None—it will fail due to a syntax error 200 Chapter 5: Restricting and Sorting Data 6. Review the following data listing for a table called SHIP_CABINS: ROOM_NUMBER ----------102 103 104 STYLE --------Suite WINDOW --------Ocean Ocean The blank values are NULL. Now review the following SQL statement (line numbers are added for readability): 01 02 03 SELECT ROOM_NUMBER FROM SHIP_CABINS WHERE (STYLE = NULL) OR (WINDOW = NULL); How many rows will the SQL statement retrieve? A. 0 B. 1 C. 2 D. None because you cannot use parentheses in line 3 to surround the expressions 7. Review the following data listing for a table SHIPS: SHIP_ID ------1 2 SHIP_NAME ------------Codd Crystal Codd Elegance CAPACITY -------2052 2974 LENGTH -----855 952 LIFEBOATS --------80 95 In the SHIPS table, SHIP_NAME has a datatype of VARCHAR2(20). All other columns are NUMBER. Now consider the following query (note—line numbers added for readability): 01 02 03 04 05 SELECT FROM WHERE AND AND SHIP_ID SHIPS CAPACITY BETWEEN 2052 AND 3000 LENGTH IN ('100','855') SHIP_NAME LIKE 'Codd_%'; How many rows will the SELECT statement return? A. None, because of a syntax error resulting from a datatype conflict in line 4 B. None, because line 5 is asking for SHIP names that contain an underscore after the string ‘Codd’, and none do C. 2 D. 1 Self Test 201 8. Assume all table name and column name references in the SQL statement that follows are valid. That being said—what is wrong with the syntax of the following SQL statement? SELECT SHIP_ID FROM SHIPS WHERE ((2*LIFEBOATS)+57) - CAPACITY IN (LIFEBOATS*20, LIFEBOATS+LENGTH); A. B. C. D. In the WHERE clause there is a syntax error before the word CAPACITY. It needs to have either an equal sign or a not-equal sign. In the WHERE clause there is a syntax error after the word IN. There is nothing wrong with the syntax. 9. Review the following data listing for the SHIPS table: SHIP_ID ------1 2 SHIP_NAME ------------Codd Crystal Codd Elegance CAPACITY -------2052 2974 LENGTH -----855 952 LIFEBOATS --------80 95 Now review the following SQL statement (line numbers are added for readability): 01 02 03 04 05 SELECT WHERE OR OR AND SHIP_ID FROM SHIPS SHIP_NAME IN ('Codd Elegance','Codd Victorious') (LIFEBOATS >= 80 LIFEBOATS <= 100) CAPACITY / LIFEBOATS > 25; Which of the following statements is true about this SELECT statement? A. The syntax is correct. B. The syntax on lines 3 and 4 is incorrect. C. Lines 3 and 4 have correct syntax but could be replaced with OR LIFEBOATS BETWEEN 80 AND 100. D. Line 5 is missing parentheses. Sort the Rows That Are Retrieved by a Query 10. Review this SELECT statement: SELECT SHIP_NAME FROM SHIPS ORDER BY SHIP_ID, CAPACITY DESC; Assume that all table and column references exist within the database. What can be said of this SELECT statement? 202 Chapter 5: Restricting and Sorting Data A. The rows will sort in order by SHIP_ID and then by CAPACITY. All rows will sort in descending order. B. The rows will sort in order by SHIP_ID in ascending order, and then by CAPACITY in descending order. C. The statement will fail to execute because the ORDER BY list includes a column that is not in the select list. D. The statement will fail to execute because there is no WHERE clause. 11. Review this SELECT statement: SELECT FROM WHERE ORDER BY PRODUCT_ID, PRODUCT_NAME, UNIT_PRICE, SHIPPING PRODUCTS (UNIT_PRICE + SHIPPING) * TAX_RATE > 5 LIKE PRODUCT_NAME; Assume all table and column references exist in the database. What can be said of this SELECT statement? A. The statement will execute successfully and as intended. B. The statement will execute but not sort because the ORDER BY clause is wrong. C. The statement will fail to execute because the ORDER BY clause includes the word LIKE. D. None of the above. 12. Which if the following is true of the ORDER BY clause? (Choose two.) A. It is optional. B. It can be used in the UPDATE statement as well as SELECT and DELETE. C. It can sort rows based on data that isn’t displayed as part of the SELECT statement. D. If the list of ORDER BY expressions uses the “by position” form, then all expressions in the ORDER BY must use the “by position” form. 13. If you are using an ORDER BY to sort values in descending order, in which order will they appear? A. If the datatype is numeric, the value 400 will appear first before the value 800. B. If the datatype is character, the value ‘Michael’ will appear first before the value ‘Jackson’. C. If the datatype is date, the value for June 25, 2010 will appear before the value for August 29, 2010. D. If the datatype is character, the value ‘130’ will appear first before ‘75’. 14. Consider the following data listing for a table called BRANCH_OFFICE_ACCOUNTS: ACCOUNT_ID ---------1 2 3 4 CRUISE_NAME ----------Hawaii Hawaii Mexico Mexico START_DATE ---------11-JUL-11 10-OCT-11 04-OCT-11 06-DEC-11 END_DATE -------24-JUL-11 23-OCT-11 17-OCT-11 19-DEC-11 Self Test 203 The CRUISE_NAME column is a VARCHAR2 column, and the START_DATE column is of the DATE datatype. Now review the following SELECT statement: SELECT ACCOUNT_ID, CRUISE_NAME, START_DATE, END_DATE FROM BRANCH_OFFICE_ACCOUNTS ORDER BY CRUISE_NAME DESC, START_DATE ASC; What will be the value in the ACCOUNT_ID column for the first row displayed as a result of this query? A. 1 B. 2 C. 3 D. 4 15. Consider the following data listing for a table called PAY_HISTORY: PAY_HISTORY_ID -------------1 2 3 4 SALARY ------73922 47000 37450 91379 START_DATE ---------04-JUN-11 04-JUN-11 04-JUN-11 05-FEB-12 END_DATE -------- 08-APR-15 The START_DATE and END_DATE columns are of the DATE datatype. Assume that blank values are NULL. Now review the following SELECT statement: SELECT PAY_HISTORY_ID, SALARY, START_DATE, END_DATE FROM PAY_HISTORY ORDER BY END_DATE DESC, START_DATE, SALARY; What will be the value in the PAY_HISTORY_ID column for the first row displayed as a result of this query? A. 1 B. 2 C. 3 D. 4 204 Chapter 5: Restricting and Sorting Data Self Test Answers Limit the Rows That Are Retrieved by a Query 1. ˛ D. Syntactically the expression in the WHERE clause is correct. But since 1 is not equal to 2, the result will be FALSE for every row in the table, no matter how many rows may exist in the table. ˝ A, B, and C are incorrect. There’s nothing wrong with the syntax; the expression will evaluate. If the expression were, say, 1=1, then it would be TRUE for all rows and return every row in the table. But it’s FALSE, so nothing is returned. 2. ˛ C. The only rows returned will be those that start with the ‘San’ string. The issue here is comparison operator precedence. AND is evaluated before OR. The latter portion of the WHERE clause is “PORT_NAME LIKE ‘Grand%’ AND CAPACITY = 4”, and this is evaluated first, and it finds no rows at all. Then the results of that portion of the WHERE are compared to “PORT_NAME LIKE ‘San%’”, which returns three rows, leaving the final result as three rows. ˝ A, B, and D are incorrect. 3. ˛ C. The operator in the expression is a valid operator for the “not equals” comparison. One row has a COST value that is not equal to 500. ˝ A, B, and D are incorrect. The symbol “^=” does not indicate greater than; that is the operator “>”. It is not a syntax error, but rather a valid symbol for the “not equals” comparison. 4. ˛ C and D. NOT is evaluated first, then AND, and then OR. ˝ A and B are incorrect. 5. ˛ B. The SELECT will return one row, for VENDOR_ID 1 where the CATEGORY equals ‘Supplier’. ˝ A, C, and D are incorrect. The second row will be ignored because even though the set of expressions within the IN clause includes a value for ‘%Partner’ and uses the “percent sign” wildcard character at the beginning, the wildcard isn’t activated, because LIKE isn’t present in the expression. Therefore, the string is treated as a literal. Had there been a value in CATEGORY of ‘%Partner’, the row would have been returned. The failure to include LIKE is not a syntax error per se; it’s just incorrect design of the SELECT statement. One way to change this query into something that is more likely the intended form would be this: SELECT VENDOR_ID FROM VENDORS WHERE CATEGORY IN (‘Supplier’, ‘Subcontractor’) OR CATEGORY LIKE ‘%Partner’; That approach would produce two rows and perform the query that was probably intended. Self Test Answers 205 6. ˛ A. This query will always retrieve zero rows, no matter what they look like. The use of the “= NULL” expression within the WHERE clause guarantees that fact. Nothing will ever be retrieved, because no SQL engine is capable of confirming that any value is equal to “I don’t know”. ˝ B, C, and D are incorrect. If line three had used “IS NULL”, as in “WHERE STYLE IS NULL OR WINDOW IS NULL”, then the answer would have been C, or two rows. Also if the IS NULL were used and the OR had been AND instead, then one row would have been returned. Regardless, the parentheses are correct here; you are allowed to enclose complete expressions within parentheses within a WHERE clause. 7. ˛ D. The query returns the row with a value of SHIP_ID = 1, and no more. The BETWEEN range is inclusive, so the number 2052 is part of the range. ˝ A, B, and C are incorrect. The LENGTH value is numeric, and the set of expressions inside of IN are strings. However, Oracle SQL will perform an automatic datatype conversion, since the strings all contain numeric data within them anyway, and the operation will succeed. It’s not the best design, but it works, and you’ll need to be aware of this for the exam. Also, line 5 uses the LIKE operator to activate wildcard characters within the string, and both of the available wildcards are used—the single-character underscore and the multicharacter percent sign. These combine to indicate that any row with a SHIP_NAME that starts with the string ‘Codd’, followed by at least one character, followed by anywhere from zero to an infinite number of additional characters, will be accepted. 8. ˛ D. There is nothing wrong with the syntax. ˝ A, B, and C are incorrect. The pair of nested parentheses before the word CAPACITY is a valid expression that multiplies the value of the LIFEBOATS column and adds the number 57 to the end of it. Then the entire result is subtracted by whatever the value for CAPACITY might be. The result of that expression will then be compared to whatever is contained in the series of expressions after the IN clause. There are two expressions there: one multiplies the LIFEBOATS value times 20; the second adds the values of the columns named LIFEBOAT and LENGTH. All of these expressions are syntactically valid. 9. ˛ A. The syntax is correct. However, there are some issues involving the logic—such as the expression on lines 3 and 4, which don’t really do anything—any non-NULL value for LIFEBOATS will be found with these expressions, because of the OR operator on line 4. It would make more sense for that operator to be AND, but regardless, it is syntactically correct. ˝ B, C, and D are incorrect. Lines 3 and 4 have accurate syntax, but the OR at the beginning of line 4 should probably be an AND. Since it is not, then BETWEEN would not be an equivalent substitute here, since BETWEEN can only test for a range and essentially serves as a replacement of the AND combination, as in “LIFEBOATS >= 80 AND LIFEBOATS <= 100”. Line 5 doesn’t need any parentheses. They wouldn’t hurt anything, necessarily; they just aren’t required. 206 Chapter 5: Restricting and Sorting Data Sort the Rows That Are Retrieved by a Query 10. ˛ B. The ORDER BY clause will default to ascending order for SHIP_ID, but CAPACITY is explicitly directed to sort in descending order. ˝ A, C, and D are incorrect. The DESC directive only applies to the CAPACITY column in the ORDER BY clause, not both items. The fact that the ORDER BY clause references columns that are not in the select list is irrelevant; it’s okay to do that. The WHERE clause is not required; it’s an optional clause, as is the ORDER BY clause. 11. ˛ C. The LIKE operator is meaningless in ORDER BY. ˝ A, B, and D are incorrect. The statement will certainly not execute; it will fail to parse due to the syntax error of the LIKE operator in the wrong place. Given that it won’t even parse due to syntax errors, it certainly won’t execute. 12. ˛ A and C. ORDER BY is optional; it is not required. It is able to sort rows in the table based on any criteria that are meaningful to the row, and when sorted, any columns may be displayed from those rows in the select list, regardless of the ORDER BY criteria. ˝ B and D are incorrect. It is unique to the SELECT statement and does not appear as an option or otherwise in any other SQL statement. Ordering by position is available to each individual ORDER BY expression and does not depend nor require the same format from other ORDER BY expressions. 13. ˛ B. If the values are character, then ‘A’ is less than ‘Z’, and if we’re listing rows in descending order, then the greater value is shown first. That means the values later in the alphabet are shown first. In comparing the character strings ‘Michael’ and ‘Jackson’, the string ‘Michael’ is greater and will show first in the listing before ‘Jackson’. ˝ A, C, and D are incorrect. If the values are numeric, then 400 is less than 800. That means in a descending order listing, where the higher value is listed first, 800 would be listed before 400. With regard to date datatypes, later dates are greater, and August 29, 2010 should list before June 25, 2010. Finally, with regard to numeric values treated as strings, you have to think about how they would appear in the dictionary—the first character is the most important, and in this case, the ‘7’ in ‘75’ indicates that character string is higher than ‘130’, so in a descending pattern, the ‘75’ would be listed before ‘130’. If those values were treated as numeric values, it might be a different situation. But we’re explicitly directed to treat them as character strings. 14. ˛ C. The row with an ACCOUNT_ID value of 3 will appear first. The ORDER BY clause sorts by CRUISE_NAME first, in descending order, which places values for Mexico before values for Hawaii, since CRUISE_NAME is a character string, and M is “greater than” H, and descending order places values that are “greater than” the others in the first position. Now, we have two rows with a CRUISE_NAME value of ‘Mexico’, so the next ORDER BY expression becomes important. That second expression looks at the START_DATE value and sorts in Self Test Answers 207 ascending order, which is the default for all ORDER BY expressions. For dates, this means that “earlier” dates will precede “later” dates. For the two rows with a CRUISE_NAME of ‘Mexico’, the START_DATE values are ‘04-OCT-11’ and ‘06-DEC-11’. The October date is “earlier”, so that row will appear first—and its value for ACCOUNT_ID is 3. ˝ A, B, and D are incorrect. 15. ˛ B. In the first expression of the ORDER BY, we sort by END_DATE in descending order. Of the four rows, only one has a value for END_DATE; the other rows have NULL values. NULLs are treated as “greater than” the defined values, and since we’re sorting in descending order, that places the three rows with NULL values for END_DATE at the top. So we turn our attention to the second item in the ORDER BY clause, which is the START_DATE. This is sorted in ascending order, and that places the two rows with a START_DATE of ‘04-JUN-11’ and a NULL value for END_DATE up at the top of our list. To resolve the conflict about which will be our first row, we turn to the third expression in the ORDER BY, which calls for sorting by SALARY, and in the default ascending order. The two remaining salaries are 73922 and 47000. Of these, the second one is the lowest, and that pushes this row to the top. This row has a PAY_HISTORY_ID value of 2. ˝ A, C, and D are incorrect. This page intentionally left blank 6 Using SingleRow Functions to Customize Output Certification Objectives 6.01 Describe Various Types of Functions That Are Available in SQL 6.02 Use Character, Number, and Date Functions in SELECT Statements 6.03 Describe the Use of Conversion Functions 6.04 3 Q&A Manage Data in Different Time Zones— Use Various Datetime Functions Two-Minute Drill Self Test 210 Chapter 6: Using Single-Row Functions to Customize Output T his chapter looks at the topic of SQL functions. Functions perform unique tasks that boost the capabilities of SQL. There are many SQL functions, and it is important that the certified Oracle Database SQL Expert be familiar with them all, and understand when they will be relevant for use in a particular professional setting. This chapter looks exclusively at single-row functions, which are also known as scalar functions. You’ll study the topic of aggregate functions later in Chapter 7, when you study the GROUP BY clause of the SELECT statement. Certification Objective 6.01 Describe Various Types of Functions That Are Available in SQL Functions have the following three characteristics: n They accept incoming values, or parameters (Note: a few functions take no parameters). n They incorporate data from the parameters into some sort of process; in other words, they perform some sort of task on the incoming data, such as a calculation or some other activity. n They return one single answer as a result. For example, here is a SQL statement that uses a function called INITCAP, which takes a single parameter: SELECT LASTNAME, INITCAP(LASTNAME) FROM ONLINE_SUBSCRIBERS; In this example, for each row that the SELECT statement processes, the SQL built-in function INITCAP takes the column LASTNAME and transforms the text contained within so that the first letter is displayed as a capital letter (initial capital, INITCAP, get it?), and the rest of the text is in lowercase letters. The result of the function is displayed in place of the value for the LASTNAME column. See Figure 6-1 for an example of its output. Describe Various Types of Functions That Are Available in SQL 211 Figure 6-1 Output of SELECT with INITCAP As you can see, a function like INITCAP isn’t foolproof—notice how it does a nice transformation on the first two rows but doesn’t necessarily produce a desirable result in the third row, where the third letter L should still be capitalized. But INITCAP performs its task; it’s up to us as developers to know where best to apply it. When a function is used in a SQL statement, it’s often said that it’s called or invoked from the statement. Functions can be called from anyplace that an expression can be called. In other words, you can invoke a function from: n A SELECT statement’s select list and WHERE clause n An INSERT statement’s list of values n An UPDATE statement’s SET clause and WHERE clause n A DELETE statement’s WHERE clause . . . and more. There are a variety of functions available in SQL. The two major types are “builtin” and “user-defined”. Built-in functions are those that are part of the SQL language itself. They are available with every standard implementation of SQL. User-defined functions are those that are created by users, much the same way a user would create a software application. They are written with features that go beyond the capabilities of SQL, using languages such as PL/SQL. Their construction is beyond the scope of the exam, and therefore this book. This book—and exam— will only deal with built-in functions. There are a great many built-in functions, and they fall into several categories. It’s not important for the exam that you know which category a function is in. 212 Chapter 6: Using Single-Row Functions to Customize Output Categories merely serve to make a discussion about functions a little easier to manage. The categories included here are character, number, date, conversion, and other. Character Functions Character functions are used to manipulate text. They can be used to perform many jobs on a given string: analyze its length (LENGTH), pad it with extra characters (RPAD, LPAD), trim off unwanted characters (RTRIM, LTRIM, TRIM), locate a given string within a larger string (INSTR), extract a smaller string from a larger string (SUBSTR), and replace text within a string (REPLACE). It’s even possible to search for strings that aren’t necessarily spelled the same but that sound alike (SOUNDEX), and more. When these are combined together, the possibilities are theoretically endless. Number Functions Number functions can perform mathematical analysis. SQL comes with many functions for determining sin (SIN, ASIN, SINH), cosine (COS, ACOS, COSH), and tangent (TAN, ATAN, ATAN2, TANH). You can determine absolute value (ABS), or determine if a given number is positive or negative (SIGN). A function can round off values (ROUND) and otherwise abbreviate numbers (TRUNC). Number functions can be incorporated into expressions, and as you’ve already seen, expressions provide support for standard arithmetic operations of addition (+), subtraction (–), multiplication (*), and division (/). These operators are not functions but are, well, operators. The point here is that you can combine the operators with number functions to produce powerful SQL statements. Date Functions The set of available SQL functions includes powerful features for DATE manipulation. You can obtain the current date and time (SYSDATE, SYSTIMESTAMP), “round” off dates to varying degrees of detail (ROUND), and otherwise abbreviate them (TRUNC). You can calculate the differences between two or more dates in many ways. Describe Various Types of Functions That Are Available in SQL 213 Simple arithmetic operators will help determine the differences between two dates in terms of days, meaning that if you subtract one date from another, the resulting answer will be a number representing the difference in terms of days. But what if you want something else, like—the difference in terms of months? (The answer is MONTHS_BETWEEN.) There are functions that will assist in managing such tasks. You can add or subtract an entire month and account for spans of time that encompass years (ADD_MONTHS). What if you have a particular date and wish to know if that date falls on, say, a Saturday or not? This sort of feature can be accomplished with “conversion” functions, which we discuss in the next section. Conversion Functions Conversion functions perform many tasks on data of all datatypes. Conversion functions are used primarily to convert values from one datatype to another. They can, for example, convert any numeric value to a text string. They can convert a text string that contains numeric data into a proper numeric datatype. They can take text representations of dates and convert them to a formal DATE datatype. But conversion functions can do more than this. They are often used to convert data of any datatype into a text string that includes formatting information. For example, if you have a DATE datatype that contains raw information about hours, minutes, seconds, and the date on the calendar, you can transform that into a text string that spells out the entire date in detail, such as “Thursday, July the Fourth, Seventeen Seventy-Six”. Conversion functions can transform raw numeric data into financial formats that include dollar signs and symbols for other international currency, proper placement for commas and periods according to various international formats, and more. Other Functions There are some functions that don’t quite fit into the categories listed here. USER is a great example—that’s a standard function that takes no parameters and simply returns the value showing the name of the current user account. Other functions support advanced features, such as hierarchical queries. We’ll look at those functions as we discuss various advanced features throughout the book. 214 Chapter 6: Using Single-Row Functions to Customize Output Certification Objective 6.02 Use Character, Number, and Date Functions in SELECT Statements This section looks in detail at many of the SQL functions. You’ll learn how they work, and you’ll see examples of how many of them can be used. For each function discussed here, we address n The function’s list of parameters n Whether each parameter is required or optional n What task the function performs n The output from the function Rather than present an alphabetical listing of them, the SQL functions presented in this section are listed logically, and related functions are described together. This is not an exhaustive analysis of all the functions available in SQL, but is nevertheless rather comprehensive, focusing primarily on the functions that are most commonly used. Remember: functions are an exam objective. It’s important to be familiar with how the major functions work. This section describes the most commonly used functions that are likely to be on the exam. The DUAL Table Before we get started, I need to mention the DUAL table, which is something that isn’t a function issue per se but is helpful to our purposes here. It is not a “SQL” thing, nor is it necessarily a “function” thing, but it’s an “Oracle” thing you should know before we continue. The DUAL table is present in every Oracle database. This special table contains just one column. The column is named DUMMY, and it has a datatype of VARCHAR2(1). The DUAL table contains only one row. That row has a value in DUMMY of ‘X’. The purpose of DUAL is simple—to have something to run a SELECT statement against when you don’t wish to retrieve any data in particular but instead simply wish to run a SELECT statement to get some other task accomplished. For example, you’ll soon see in this section that there’s an Oracle SQL function called SYSDATE Use Character, Number, and Date Functions in SELECT Statements 215 that displays the current date according to the operating system of the server on which the Oracle database is installed. If you wish to get the value of SYSDATE without wading through a bunch of table data from your application, you can simply execute the following SQL statement: SELECT SYSDATE FROM DUAL; The result: you’ll get one response for the current value of SYSDATE, since you know the DUAL table only has one row. We’ll use the DUAL table from time to time throughout the rest of this chapter as we go through examples of the various SQL functions. Character Manipulation This section looks in detail at the more commonly used character functions. Character functions do not necessarily deal exclusively with character data—some of these functions have numeric parameters and even numeric output, like INSTR. But the overall spirit and intent of these functions is to perform the sort of data processing typically associated with text manipulation. UPPER, LOWER Syntax: UPPER(s1), LOWER(s1) Parameters: s1, a required character string. Process: Transforms s1 into uppercase letters (UPPER) or lowercase letters (LOWER). Output: Character string. Example: UPPER can be useful when you are doing a text search and aren’t sure whether the data in the table is in uppercase, lowercase, or both. You can use UPPER to force a conversion of all data in the table, then compare that result to an uppercase literal value, thus eliminating any chance of missing mixed case text in the table. For example: SELECT EMPLOYEE_ID FROM EMPLOYEES WHERE UPPER(LAST_NAME) = 'MCGILLICUTTY'; The previous query will return rows from the EMPLOYEES table where the LAST_ NAME is ‘McGillicutty’, ‘mcgillicutty’, or any other combination of upper- and lowercase letters that equals the letters in the string. 216 Chapter 6: Using Single-Row Functions to Customize Output INITCAP Syntax: INITCAP(s1) Parameters: s1, a required character string. Process: Transforms s1 into a mixed-case string, where the first letter of each word is capitalized, and each following character is in lowercase letters. Output: Character string. Example: Below is a SQL statement that invokes INITCAP three times. The first example passes in the string “napoleon”, which is translated into mixed-case letters. The second example takes the string “Red O’Brien” as input. Notice that we need to include the single quote escape character within the string in order for a single quote character to be recognized—since the single quote mark is also the string delimiter, we need to type two single quotes in succession, which is how you instruct SQL to treat a single The escape character quote as an actual character within the string, that activates, or enables, a single quote and not the string delimiter. Finally, the third character to be displayed is a single quote. example does the same thing with the string “McDonald’s”, but notice the result—the results of INITCAP are less than desirable—the first “d” in “McDonald’s” is converted to lowercase, and the “s” at the end of “McDonald’s” is converted to uppercase—INITCAP interprets the “s” as the start of a new word. SELECT INITCAP('napoleon'), INITCAP('RED O''BRIEN'), INITCAP('McDonald''s') FROM DUAL; INITCAP('NAPOLEON') INITCAP('REDO''BRIEN') INITCAP('MCDONALD''S') ------------------- ---------------------- ---------------------Napoleon Red O'Brien Mcdonald'S CONCAT, || Syntax: CONCAT(s1, s2), s1 || s2 Parameters: s1, s2. Both are character strings; both are required. Process: Concatenates s1 and s2 together into one string. Output: Character string. Example: SELECT CONCAT('Hello, ', 'world!') FROM DUAL; Use Character, Number, and Date Functions in SELECT Statements 217 The equivalent using the double vertical bars: SELECT 'Hello, ' || 'world!' FROM DUAL; While CONCAT takes only two parameters, the double vertical bar syntax can be repeated as often as is necessary. For example, this approach creates one string: SELECT 'Hello, ' || 'world!' || ' Great to ' || 'see you.' FROM DUAL; 'HELLO,'||'WORLD!'||'GREATTO'||'SEEYOU.' ---------------------------------------Hello, world! Great to see you. Note that the result here is one single string. Another example: SELECT FIRST_NAME || ' ' || LAST_NAME || ' of ship number ' || SHIP_ID || '.' FROM EMPLOYEES WHERE LAST_NAME = 'West'; FIRST_NAME||''||LAST_NAME||'OFSHIPNUMBER'||SHIP_ID||'.' -------------------------------------------------------Mike West of ship number 4. Trish West of ship number 2. LPAD, RPAD Syntax: LPAD(s1, n, s2), RPAD(s1, n, s2). Parameters: s1 (character string—required); n (number—required); s2 (character string—optional—s2 defaults to a single blank space if omitted). Process: Pad the left of character string s1 (LPAD) or right of character string s1 (RPAD) with character string s2, so that s1 is n characters long. Output: Character string. Example: Take a string literal ‘Chapter One—I Am Born’ and pad it to the right with 40 occurrences of a single period. SELECT RPAD('Chapter One - I Am Born',40,'.') FROM DUAL; RPAD('CHAPTERONE-IAMBORN',40,'.') ---------------------------------------Chapter One - I Am Born................. 218 Chapter 6: Using Single-Row Functions to Customize Output Many SQL functions are useful in and of themselves, but many become more useful when combined with each other. For example, here’s a combination of RPAD and LPAD with the concatenation operators, executed against a table called BOOK_CONTENTS: SELECT RPAD(CHAPTER_TITLE || ' ',30,'.') || LPAD(' ' || PAGE_NUMBER,30,'.') "Table of Contents" FROM BOOK_CONTENTS ORDER BY PAGE_NUMBER; Table of Contents -----------------------------------------------------------Introduction ............................................. 1 Chapter 1 ................................................ 5 Chapter 2 ............................................... 23 Chapter 3 ............................................... 57 Index ................................................... 79 Notice this example also includes three uses of the concatenation operator: • Once to append a single blank after the CHAPTER_TITLE value • Once to put a single blank in front of the PAGE_NUMBER value • Once to combine the output of RPAD and LPAD Also note the use of the column alias “Table of Contents”, and the ORDER BY to ensure that the rows sort according to PAGE_NUMBER. If the “On the Job” code sample showing LPAD and RPAD combined with string concatenation is a mystery to you, then stop and study it.The exam may include questions about several functions combined and nested within each other, like the BOOK_CONTENTS sample shown in the sample. LTRIM, RTRIM Syntax: LTRIM(s1, s2), RTRIM(s1, s2) Parameters: s1, s2—both are character strings. s1 is required, s2 is optional—if omitted, it defaults to a single blank space. Use Character, Number, and Date Functions in SELECT Statements 219 Process: Removes occurrences of the s2 characters from the s1 string, from either the left side of s1 (LTRIM) or the right side of s1 (RTRIM) exclusively. Output: Character string. Notes: Ideal for stripping out unnecessary blanks or periods or ellipses, etc. Example: SELECT RTRIM('Seven thousand--------','-') FROM DUAL; RTRIM('SEVENTHOUSAND--------','-') ---------------------------------Seven thousand TRIM Syntax: TRIM(trim_info trim_char FROM trim_source) Parameters: trim_info is one of these keywords: LEADING, TRAILING, BOTH—if omitted, defaults to BOTH. trim_char is a single character to be trimmed—if omitted, assumed to be a blank. trim_source is the source string—if omitted, the TRIM function will return a NULL. Process: Same as LTRIM and RTRIM, with a slightly different syntax. Output: Character string. Example: Trim off the dashes at the end of the string ‘Seven thousand--------’. SELECT TRIM(TRAILING '-' FROM 'Seven thousand--------') FROM DUAL; TRIM(TRAILING'-'FROM'SEVENTHOUSAND--------') -------------------------------------------Seven thousand LENGTH Syntax: LENGTH(s) Parameters: s is the source string (required). Process: Identifies the length of a given string. 220 Chapter 6: Using Single-Row Functions to Customize Output Output: Numeric. Example: Determine the length of a really long and famous word: SELECT LENGTH('Supercalifragilisticexpialidocious') FROM DUAL; LENGTH('SUPERCALIFRAGILISTICEXPIALIDOCIOUS') -------------------------------------------34 INSTR Syntax: INSTR(s1, s2, pos, n) Parameters: s1 is the source string (required); s2 is the substring (required); pos is the starting position in s1 to start looking for occurrences of s2 (optional, default is 1); n is the occurrence of s2 to locate (optional, default is 1). If pos is negative, the search in s1 for occurrences of s2 starts at the end of the string and moves backward. Process: Locates a string within another string (e.g., IN STRing). Output: Numeric. Example: Look for the string ‘is’ within ‘Mississippi’, starting at the first character position but looking for the second occurrence of ‘is’. SELECT INSTR('Mississippi','is',1,2) FROM DUAL; INSTR('MISSISSIPPI','IS',1,2) ----------------------------5 The INSTR function is telling us that the second occurrence of ‘is’ starts at the fifth character in ‘Mississippi’. SUBSTR Syntax: SUBSTR(s, pos, len) Parameters: s = a character string, required; pos = a number, required; len = a number, optional. Process: Extracts a substring from s, starting at the pos character of s, and continuing for len number of characters. If len is omitted, then the substring starts Use Character, Number, and Date Functions in SELECT Statements 221 as pos and runs through the end of s. If pos is negative, then the function starts at the end of the string and moves backward. Output: Character string. Example: Starting with a source string of ‘Name: MARK KENNEDY’, extract a substring out of it, beginning at the seventh position and running to the end of the string. SELECT SUBSTR('Name: MARK KENNEDY', 7) FROM DUAL; SUBSTR('NAME:MARKKENNEDY',7) ---------------------------MARK KENNEDY SOUNDEX Syntax: SOUNDEX(s) Parameters: s = the source string, required. Process: Translates a source string into its SOUNDEX code. Output: Character string. Notes: SOUNDEX is a coding scheme for translating English words into sound-alike patterns. A single SOUNDEX value is relatively worthless. But two combined together can be surprisingly helpful. The reason is that similarsounding words tend to generate the same SOUNDEX pattern. To generate a SOUNDEX translation for any word, the first letter remains unchanged. The next series of letters are translated into a numeric code according to the rules shown in Table 6-1. Translation is performed for each letter until three digits are generated. If any letters exist beyond that, they are ignored. For example: The last name “Worthington” has a SOUNDEX pattern of W635: the first letter ‘W’ remains unchanged; the second letter “o” is ignored per the bottom row of the Table 6-1; the third letter “r” translates into 6 according to Table 6-1; the fourth letter “t” translates into a 3; the fifth letter “h” is ignored—again, according to Table 6-1, which also tells us to ignore the letter “i”; the letter “n” translates into 5, and now that we have one letter “W” and three numbers “635”, we are done, and the remaining letters in “Worthington” are ignored. Thus, the SOUNDEX code is W635. 222 Chapter 6: Using Single-Row Functions to Customize Output Table 6-1 Letter SOUNDEX Code SOUNDEX Translation Table B, F, P, V 1 C, G, J, K, Q, S, X, Z 2 D, T 3 L 4 M, N 5 R 6 All other letters (A, E, H, I, O, U, W, Y) Ignored So two words that sound alike, for example, “Worthington” and “Wurthinden”, while spelled differently, will nevertheless generate the same SOUNDEX pattern. Here’s an example: SELECT SOUNDEX('Worthington'), SOUNDEX('Worthen') FROM DUAL; SOUNDEX('WORTHINGTON') SOUNDEX('WORTHEN') ---------------------- -----------------W635 W635 Notice how the two different words produce the same SOUNDEX pattern. That means we can do queries like this: SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME FROM EMPLOYEES WHERE SOUNDEX(LAST_NAME) = SOUNDEX('Worthen'); EMPLOYEE_ID FIRST_NAME LAST_NAME ---------------------- -------------------- -----------------7 Buffy Worthington Notice that SOUNDEX is used twice in the WHERE clause. Using it once would probably be useless. This query will find customers with the last name of ‘Worthington’, ‘Wurthinden’, ‘Worthan’, and even ‘Wirthen’. SOUNDEX has something of a bias toward English. For example, the popular Vietnamese name “Nguyen” is pronounced “Nwen”, but the SOUNDEX patterns for those two words—“Nguyen” and “Nwen”—are rather different. So SOUNDEX is not perfect, but rather useful nonetheless. Use Character, Number, and Date Functions in SELECT Statements 223 Mathematical Processing This section describes functions that deal with numeric values. Some numeric functions are pretty simple—such as ABS, which takes a single numeric value and returns its absolute value. There’s also SQRT, which takes a single numeric value and returns its square root. Not all of the input parameters to numeric functions are necessarily numeric, but the overall intent of these functions is to perform numeric analysis and perform the sort of tasks typically associated with numeric data processing. ROUND—Number Syntax: ROUND(n, i) Parameters: n is required, is any number, and can include decimal points. i is an integer, and is optional—if omitted, it will default to 0. Process: n is rounded depending on the value of i. If i is zero, n is rounded off to the nearest whole number, i.e., zero decimal points. If i is a positive number, n is rounded to i places to the right of the decimal point. If i is a negative number, n is rounded to i places to the left of the decimal point. The number 5 is rounded away from zero. Output: If i is omitted, ROUND returns a value in the same numeric datatype as n. If i is specified, ROUND returns a datatype of NUMBER. Example: Round off 12.355143 to two significant digits to the right of the decimal, and also round off 259.99 to the nearest “tens”—i.e., one digit to the left of the decimal: SELECT ROUND(12.355143, 2), ROUND(259.99,-1) FROM DUAL; ROUND(12.355143,2) ROUND(259.99,-1) ---------------------- ---------------------12.36 260 TRUNC—Number Syntax: TRUNC(n, i) Parameters: n is required, is any number, and can include decimal points. i is an integer and is optional—if omitted, it will default to 0. Process: TRUNC “rounds” toward zero—i.e., it truncates the numbers. Output: If i is omitted, TRUNC returns a value in the same numeric datatype as n. If i is specified, TRUNC returns a datatype of NUMBER. 224 Chapter 6: Using Single-Row Functions to Customize Output Example: Using the same numbers we just used with the ROUND example, truncate them instead: SELECT TRUNC(12.355143, 2), TRUNC(259.99,-1) FROM DUAL; TRUNC(12.355143,2) TRUNC(259.99,-1) ---------------------- ---------------------12.35 250 REMAINDER Syntax: REMAINDER(n1, n2) Parameters: n1 and n2 are numbers. Both are required. Process: Identifies the multiple of n2 that is nearest to n1, and returns the difference between those two values. Output: Numeric. Example: Test REMAINDER using three sequential numbers: 9, 10, and 11, and compare each against the number 3. Since the first number (9) is a multiple of 3, there is no remainder, so the answer will be 0. The second number (10) represents one more number than the multiple, so the remainder is 1. Notice what happens with the third number (11)—the function doesn’t return a 2 as you might expect. Instead, it returns a negative 1, because the nearest integer that’s divisible by 3 is 12, which is closer to the 11 than the 9. In other words, REMAINDER identifies the closest multiple of n2. If the multiple is higher, REMAINDER returns a negative number to indicate that the closest multiple of n2 is higher than n1. SELECT REMAINDER(9,3), REMAINDER(10,3), REMAINDER(11,3) FROM DUAL; REMAINDER(9,3) REMAINDER(10,3) REMAINDER(11,3) -------------------- -------------------- ---------------------0 1 -1 MOD Syntax: MOD(n1, n2) Parameters: n1 and n2 are numbers. Both are required. Process: Performs the same task as REMAINDER, except MOD uses FLOOR instead of ROUND in its equation. Output: Numeric. Use Character, Number, and Date Functions in SELECT Statements 225 Example: Get the MOD of the same three number pairs we tested with REMAINDER. Note the results in the third example—this might be what you would’ve expected with REMAINDER, and didn’t get—but you do get it with MOD. SELECT MOD(9,3), MOD(10,3), MOD(11,3) FROM DUAL; MOD(9,3) MOD(10,3) MOD(11,3) ---------------------- ---------------------- ---------------------0 1 2 Working with Dates The following section looks at functions that work primarily with DATE datatypes. SYSDATE Parameters: None Process: Returns the current date and time according to the operating system on which the Oracle database server is installed. In other words, if your SQL statement is running on an Oracle server instance from a remote location, then regardless of the location of you or your client, SYSDATE will return the date and time of the operating system on which the server resides. Time information is contained within SYSDATE but doesn’t display by default; however, it can be extracted by way of the TO_CHAR conversion function. (Note: it can also be altered by changing the NLS_DATE_FORMAT session parameter.) Output: Date. Example: Show the current date according to the operating system where the Oracle server is installed: SELECT SYSDATE FROM DUAL; SYSDATE ------------------------06-JUL-09 ROUND—Date Syntax: ROUND(d, i) Parameters: d is a date (required); i is a format model (optional). 226 Chapter 6: Using Single-Row Functions to Customize Output Process: d is rounded off to the nearest date value, at a level of detail specified by i. d is required and specifies a value of the DATE datatype. i is a format model, and specifies the level of detail to which the DATE value will be rounded—i.e., to the nearest day, nearest hour, nearest year, etc. i is optional. Values are biased toward rounding up—for example, when rounding off time, twelve noon rounds up to the next day. Format models are covered in the upcoming section about the TO_CHAR conversion function. But we’ll include one in the example that follows to give you an idea of what a format model is. Output: Date. Example: This example shows a SELECT statement with three expressions in the select list. The first is SYSDATE, which returns the current date. The second is the same date, rounded to the nearest month, as specified by the ‘MM’ format model. The third is the same date rounded to the nearest year, as specified by the ‘RR’ format model. SELECT SYSDATE TODAY, ROUND(SYSDATE,'MM') ROUNDED_MONTH, ROUND(SYSDATE,'RR') ROUNDED_YEAR FROM DUAL; TODAY ROUNDED_MONTH ROUNDED_YEAR --------------------- --------------------- -------------------27-JUL-09 01-AUG-09 01-JAN-10 If the optional second parameter is omitted, the DATE value will be rounded to the nearest hour. (Note: we’ll explore more about how DATE values and format models work when we discuss the TO_CHAR conversion function. That’s where you’ll see how to display the hours for a given DATE value.) TRUNC—Date Syntax: TRUNC(d, i) Parameters: d is a date (required); i is a format model (required). Process: Performs the same task as ROUND for dates, except TRUNC always rounds down. Output: Date. Example: Use Character, Number, and Date Functions in SELECT Statements 227 SELECT SYSDATE TODAY, TRUNC(SYSDATE,'MM') TRUNCATED_MONTH, TRUNC(SYSDATE,'RR') TRUNCATED_YEAR FROM DUAL; TODAY TRUNCATED_MONTH TRUNCATED_YEAR -------------------- --------------------- --------------------27-JUL-09 01-JUL-09 01-JAN-09 NEXT_DAY Syntax: NEXT_DAY(d, c) Parameters: d is a date, required; c is a text reference to a day of the week, required. Process: Returns a valid date representing the first occurrence of the c day following the date represented in d. Output: Date. Example: Show the first occurrence of a Saturday following the 31st of May, 2011. SELECT NEXT_DAY('31-MAY-11','Saturday') FROM DUAL; NEXT_DAY('31-MAY-11','SATURDAY') ------------------------04-JUN-11 LAST_DAY Syntax: LAST_DAY(d) Parameters: d is a date, required. Process: Returns the last day of the month in which d falls. Output: Date. Example: Show the last days of February in 2011 and 2012. SELECT LAST_DAY('14-FEB-11'), LAST_DAY('20-FEB-12') FROM DUAL; LAST_DAY('14-FEB-11') LAST_DAY('20-FEB-12') ------------------------- ------------------------28-FEB-11 29-FEB-12 228 Chapter 6: Using Single-Row Functions to Customize Output ADD_MONTHS Syntax: ADD_MONTHS(d, n) Parameters: d is a date, required; n is a whole number, required. Process: Adds n months to d, and returns a valid date value for the result. Output: Date. Example: Add four months to November 1, 2011. SELECT ADD_MONTHS('31-JAN-11',1), ADD_MONTHS('01-NOV-11',4) FROM DUAL; ADD_MONTHS('31-JAN-11',1) ADD_MONTHS('01-NOV-11',4) ------------------------- ------------------------28-FEB-11 01-MAR-12 There is no “SUBTRACT_MONTHS” function. Instead—use ADD_MONTHS to add a negative number of months, and you’ll subtract them instead. MONTHS_BETWEEN Syntax: MONTHS_BETWEEN(d1, d2) Parameters: d1 and d2 are dates, required. Process: Determines the number of months between the two dates. The result does not round off automatically—if the result is a partial month, MONTHS_ BETWEEN shows a real number result. Whole months are counted according to the calendar months involved—if the time spans, say, a February that has 29 days, then the one month time span for that time period will be 29 days. In other words: MONTHS_BETWEEN('01-JAN-12', '01-FEB-12') = -1= MONTHS_BETWEEN('01-JAN-12', '01-MAR-12') = -2= MONTHS_BETWEEN('10-AUG-14', '10-JUL-14') = 1= Note that the answer may be opposite of what you would expect. The first parameter is expected to be the greater value; the second is expected to be the lesser. But that’s not required, and as you can see from these examples, either approach works, but notice the sign of the result—if the second parameter is the greater value, the result is a negative number. Use Character, Number, and Date Functions in SELECT Statements 229 Output: Number. Example: Display the number of months between June 12, 2014, and October 3, 2013. SELECT MONTHS_BETWEEN('12-JUN-14','03-OCT-13') FROM DUAL; MONTHS_BETWEEN('12-JUN-14','03-OCT-13') --------------------------------------8.29032258064516129032258064516129032258 NUMTOYMINTERVAL Syntax: NUMTOYMINTERVAL (n, interval_unit) Parameters: n = number (required). interval_unit = one of the following values: ‘YEAR’ or ‘MONTH’. Process: Transform the number n into a value that represents the interval_unit amount of time. Output: A value in the INTERVAL YEAR TO MONTH datatype. Example: The following example takes the number 27 and transforms it into a value representing a time interval of 27 months, which equates to 2 years and 3 months, in the INTERVAL YEAR TO MONTH datatype. The “2-3” value shows 2 years, 3 months is the amount of time that results. SELECT NUMTOYMINTERVAL(27,'MONTH') FROM DUAL; NUMTOYMINTERVAL(27,'MONTH') --------------------------2-3 NUMTODSINTERVAL Syntax: NUMTODSINTERVAL (n, interval_unit) Parameters: n = number (required). interval_unit = one of the following: ‘DAY’, ‘HOUR’, ‘MINUTE’, or ‘SECOND’. Process: Converts the numeric value into an interval of time according to the value of interval_unit. Output: A value of the datatype INTERVAL DAY TO SECOND. 230 Chapter 6: Using Single-Row Functions to Customize Output Example: The following example translates 36 hours into its formal representation of 1 day, 12 hours in the datatype INTERVAL DAY TO SECOND, which displays a single number for day, followed by hours, minutes, seconds, and fractional seconds. SELECT NUMTODSINTERVAL(36,'HOUR') FROM DUAL; NUMTODSINTERVAL(36,'HOUR') -------------------------1 12:0:0.0 Other Functions This section looks at some additional commonly used functions. NVL Syntax: NVL(e1, e2) Parameters: e1 and e2 are expressions, both are required, and both should be of the same datatype, but automatic datatype conversion applies here, so values may be different as long as they are capable of being converted to the same datatype automatically. Process: If e1 has a value of NULL, then NVL returns the value for e2. Otherwise it returns e1. The intent of NVL is to use it in a query where multiple rows are being returned, and you expect that perhaps some of the rows might be NULL. There’s nothing wrong with that in and of itself, but what if you are performing some sort of processing that can’t take a value of NULL? For example, a single NULL value within a mathematical calculation will automatically make the answer NULL. You can use NVL to substitute something meaningful in the place of NULL—such as a zero—in order to satisfy the outer function. Output: If e1 has a character datatype, the output will be VARCHAR2. If e1 is numeric, the output will be numeric. If the output is NULL, then it’s NULL. Example: Note that we have three expressions in the SELECT list that follows. The first simply shows that we’re using NVL to replace the literal value for NULL with a zero. Useless by itself but it proves the point of what the NVL function does. The second expression shows an equation in which we add 14 to NULL and subtract 4 from the result. But what is 14 plus NULL? It’s NULL. So is NULL minus 4. So in the third expression, we use NVL to replace NULL with a 0, and we get an answer of 10. Use Character, Number, and Date Functions in SELECT Statements 231 SELECT NVL(NULL,0) FIRST_ANSWER, 14+NULL-4 SECOND_ANSWER, 14+NVL(NULL,0)-4 THIRD_ANSWER FROM DUAL; FIRST_ANSWER SECOND_ANSWER THIRD_ANSWER ---------------------- ---------------------- ---------------------0 10 The purpose of the preceding example is to show what you can do with NVL. A more likely scenario would be something like this: SELECT SQ_FT + NVL(BALCONY_SQ_FT,0) FROM SHIP_CABINS; This SQL code adds the square feet of a ship’s cabin with the square feet of its balcony. But what if there isn’t a balcony, and a NULL value is returned for BALCONY_SQ_FT? The entire result would be NULL, unless we use the NVL function as we do in the preceding example. DECODE Syntax: DECODE(e, search_expression, d) Parameters: e, search_expression, and d are all expressions. The first two are required; the third is optional. Process: e is a required expression; search_expression is a series of pairs of expressions, se1 and se2, each separated by commas; if e equals se1, then DECODE should return se2. Otherwise, it should return d. If d is omitted, DECODE will return NULL. In DECODE, two NULL values are considered to be equivalent. NULL compared to NULL will produce a TRUE result and send the corresponding value back if required. Output: If the datatypes of e and the first occurrence of se1 are character, DECODE will return a value of datatype VARCHAR2. If the datatypes of e and the first occurrence of se1 are numeric, DECODE will return a value of numeric datatype. Example: In the example that follows, we select rows from ADDRESSES by looking at the STATE column value as is, and then also using DECODE to translate the values in STATE according to the search_expression in DECODE, which in this case only looks at two state values but could have easily been expanded to translate, or decode, all of the state values. The final item in 232 Chapter 6: Using Single-Row Functions to Customize Output DECODE is ‘Other’, which is assigned to all values of STATE that aren’t found in our search_expression list—including the NULL value for STATE. SELECT STATE, DECODE(STATE,'CA', 'California', 'IL','Illinois', 'Other') AS DECODED_STATE FROM ADDRESSES; STATE ----CA TX IL AB NY QC DECODED_STATE ------------California Other Illinois Other Other Other Other The DECODE function is often referred to as the “IF-THEN-ELSE” of Oracle SQL. CASE Syntax: CASE expression1 WHEN condition1 THEN result1 WHEN condition2 THEN result2 . . . ELSE resultfinal END Parameters: expression1 can be a column in a SELECT statement’s select list, or any other valid expression; required. If expression1 evaluates to a value that is equal to condition1, then the function returns result1. Additional WHEN/THEN comparison pairs may be included. The first pair is required; additional pairs are optional. An optional ELSE at the end will return the value of resultfinal if no WHEN/THEN comparison pair matched. Process: Compare all the pairs to determine which value will be returned. If no values match, resultfinal is returned. If no values match and no ELSE clause is included, NULL is returned. Example: SELECT CASE 'option1' WHEN 'option1' THEN 'found it' WHEN 'option2' THEN 'did not find it' END AS "Answer" FROM DUAL; Answer ---------------found it Use Character, Number, and Date Functions in SELECT Statements 233 The function starts with the keyword CASE and ends with the keyword END. The CASE expression may include a column name, like this: SELECT SHIP_NAME, CAPACITY, CASE CAPACITY WHEN 2052 THEN 'MEDIUM' WHEN 2974 THEN 'LARGE' END AS "SIZE" FROM SHIPS WHERE SHIP_ID <= 4; SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Champion Codd Victorious CAPACITY ---------------------2052 2974 2974 2974 SIZE -----MEDIUM LARGE LARGE LARGE Note that in this example, the CASE function takes in a numeric value and returns a text string. NULLIF Syntax: NULLIF(e1, e2) Parameters: e1 and e2 are both expressions; required. Must be the same datatype. Process: If e1 and e2 are the same, NULLIF returns NULL. Otherwise, it returns e1. Output: An expression matching the datatypes of the input parameters. Example: NULLIF is good for comparing multiple rows wherein an older and newer version of a particular value lies, and you wish to cull out those that are either still not updated, or have been already. For example: SELECT TEST_SCORE, UPDATED_TEST_SCORE, NULLIF(UPDATED_TEST_SCORE,TEST_SCORE) REVISION_ONLY FROM SCORES; TEST_SCORE ---------95 55 83 UPDATED_TEST_SCORE REVISION_ONLY ------------------ ------------95 75 75 83 In the preceding example, the column UPDATED_TEST_SCORE represents a set of values that includes older TEST_SCORE values and those that have been revised for some reason. The NULLIF function helps filter out only those values that 234 Chapter 6: Using Single-Row Functions to Customize Output represent changes to the older original values, as evidenced in the third SELECT column with the column alias of REVISION_ONLY. Nesting Functions When a function is placed within an expression in such a way that its output becomes the parameter for another function, it is said to be “nested”. When one function is “nested” within another, the nested function executes first. The nested function is also considered the “inner” function, as opposed to the “outer” function, which receives the output of the inner function as an input parameter. Here’s an example that nests one function within another. The combination of SUBSTR and INSTR can be very helpful in locating strings whose position varies within a string but There are many more varies relative to a fixed distance to another functions that exist in SQL than are string. The classic example is common in described in this book. Space limitations address information, when you are looking for prevent me from showing descriptions and the two-letter state abbreviation that is often examples of all of them. Yet any of the found after the comma plus one blank space. many functions may appear on the exam. See Figure 6-2 for an example. The first column Be sure to review the Oracle Database shows the column ADDRESS2 unchanged. SQL Language Reference Manual and Notice, however, that each string contains a review the lengthy description of all of two-letter state abbreviation, and that each the SQL functions before taking the state is after a comma plus one blank space. exam. Pay particular attention to the We can use that consistent pattern to our input parameters of each function, as advantage. The second column shows how we well as the datatype of each function’s can use the INSTR function to find the exact returned value. location of that comma in each individual row of ADDRESS2. Finally, the third column shows how we can nest the output of each row’s INSTR result within a SUBSTR function. By adding 2 to the results of INSTR (one for the comma, one for the space), we locate the precise start of the two-letter state abbreviation within each occurrence of ADDRESS2 and thus are able to extract the value for the third column, STATE. Finally, note that we order the output by the findings of the third column. Pretty interesting that we can sort rows of data by a substring of a column whose position changes within each row of the table—but it’s entirely possible through the use of nested functions. Describe the Use of Conversion Functions 235 Figure 6-2 SUBSTR and INSTR combined together Certification Objective 6.03 Describe the Use of Conversion Functions Conversion functions convert the datatype of an expression from one datatype to another. Some will also transform the format of the data at the same time. Conversion functions are not necessarily required in all situations—many automatic datatype conversions are performed by SQL without prompting. However, automatic conversions are not always performed, and explicit datatype conversions are always considered to be good design. Here is an example—this is an INSERT statement that attempts to store data into two columns. The CALL_ID column is of the NUMBER datatype. The CALL_DATE_TZ column is of the datatype TIMESTAMP WITH TIME ZONE. Here’s an attempt to INSERT data into that table: INSERT INTO CALLS (CALL_ID, CALL_DATE_TZ) VALUES (1, '24-MAY-12 10:15:30'); Error starting at line 1 in command: INSERT INTO CALLS (CALL_ID, CALL_DATE_TZ) VALUES (1, '24-MAY-12 10:15:30') Error report: SQL Error: ORA-01840: input value not long enough for date format 01840. 00000 - "input value not long enough for date format" 236 Chapter 6: Using Single-Row Functions to Customize Output Now let’s try that same INSERT statement with a conversion function: INSERT INTO CALLS (CALL_ID, CALL_DATE_TZ) VALUES (1, TO_TIMESTAMP_TZ('24-MAY-12 10:15:30', 'DD-MON-RR HH24:MI:SS') ); 1 rows inserted In this example, the TO_TIMESTAMP_TZ conversion function is used to send the same data we used in our previous INSERT. This particular conversion function uses a “format model” that describes the format of the data to the database. The format model in this instance is ‘DD-MON-RR HH24:MI:SS’. This helps to ensure that the input data is recognized correctly. The next section describes many conversion functions with examples of their use. Conversion Functions There are a number of functions intended to convert values of one datatype to another datatype. They are discussed in this section. Some of the most commonly used are TO_NUMBER, TO_CHAR, and TO_DATE. In addition, TO_TIMESTAMP is useful for situations involving the use of fractional seconds, and TO_DSINTERVAL and TO_YMINTERVAL deal with the datatypes of time intervals. TO_NUMBER Syntax: TO_NUMBER(e1, format_model, nls_parms) Parameters: e1 is an expression (required). format_model is the optional format model. See Table 6-2 for a complete list of elements that make up the format model. There is an optional third parameter representing NLS settings. It allows you to identify any of the three NLS parameters defined in Table 6-3. If included, the third parameter for TO_NUMBER consists of a single string that encompasses any one or more of those three NLS parameters. For example, the following is one example of the nls_parms parameter that provides a specification of two of the NLS parameters: ' nls_currency = ''USD'' nls_numeric_characters = '',.'' ' Note that since the values are enclosed in single quotes, yet include single quotes themselves, then each occurrence of the single quotes within the string must be preceded by the escape character—which is a single quote—in order to clarify Describe the Use of Conversion Functions 237 that the value is in fact a single quote as part of the string, rather than the end of the overall string literal value. These values can be used to declare non-standard NLS parameter values within the incoming e1 parameter. Process: Transform e1 from an expression, perhaps a character string, into a numeric value, using format_model to determine what format e1 may take, and where to extract the numeric values from among the formatting information. Output: Numeric. Example: In the example that follows, our starting value is a string, ‘$17,000.23’. This isn’t a numeric datatype but a character string containing a dollar sign and a comma. The format model here explains that the dollar sign is a symbol, and the format model makes it clear where the significant numeric data can be found in the source column. The “9” element below is not a literal number 9, but rather an element of the format model that indicates the presence of any digit. It is repeated to indicate the upper bound of acceptable values. Finally the output is displayed—a raw numeric value extracted from the character string ‘$17,000.23’. SELECT TO_NUMBER('$17,000.23','$999,999.99') FROM DUAL; TO_NUMBER('$17,000.23','$999,999.99') -----------------------------------17000.23 Here is a similar example showing the use of the nls_parms parameter. SELECT TO_NUMBER('17.000,23', '999G999D99', 'nls_numeric_characters='',.'' ') REFORMATTED_NUMBER FROM DUAL; REFORMATTED_NUMBER ---------------------17000.23 In this example, the incoming value shows a decimal point to mark “thousands” and the comma to mark the decimal point. The nls_parms value clarifies this to the TO_NUMBER function, along with the format mask, and the incoming value is interpreted and translated, as shown in the displayed output. See Table 6-2 for a complete list of the elements that can be included in a numeric format model. 238 Chapter 6: Using Single-Row Functions to Customize Output Table 6-2 Element Example Description Number Format Elements ,. 9,999.99 Commas and decimal points will pass through wherever they are included. Warning: only one period allowed per format mask. $ $999.99 Leading dollar sign. 0 0099.99 Leading or trailing 0. 9 999 Any digit. B B999 Leading blank for integers. C C999 The ISO currency symbol as defined in the NLS_ISO_ CURRENCY parameter. D 999D99 Returns the current decimal character as defined by the NLS_NUMERIC_CHARACTERS parameter. The default value is a period. EEEE 9.9EEE Returns a value in scientific notation. G 9G999 Returns the group separator (e.g., a comma). L L999 Returns the local currency symbol. MI 999MI Returns negative value with trailing minus sign; returns positive value with a trailing blank. PR 999PR Returns negative values in angle brackets. RN rn RN Returns values in Roman numerals, uppercase. Put RN in lowercase, as “rn”, for Roman numerals in lowercase. S (prefix) S9999 Returns negative values with a leading minus sign, positive values with a leading positive sign. Note: Can only appear in the first or last position of a format mask. S (suffix) 9999S Returns negative values with a trailing minus sign, positive values with a trailing positive sign. Note: Can only appear in the first or last position of a format mask. TM TM The text minimum number format model returns the smallest number of characters possible. U U999 Returns the Euro currency symbol or whatever is indicated by the NLS_DUAL_CURRENCY parameter. V 999V99 Returns a value multiplied by 10n, where n is the number of 9s after the V. X XXXX Returns the hexadecimal value. Describe the Use of Conversion Functions 239 Table 6-3 NLS Parameter Description The NLS Parameters NLS_NUMERIC_CHARACTERS = ‘dg’ d = decimal character—see D in Table 6-2. g = group separator—see G in Table 6-2. NLS_CURRENCY = ‘text’ text = local currency symbol—see L in Table 6-2. NLS_ISO_CURRENCY = ‘currency’ currency = international currency symbol— see C in Table 6-2. TO_CHAR The TO_CHAR function converts data from various datatypes to character data. There are actually three different TO_CHAR functions. They are, in the most technical of terms, three “overloaded” functions. An “overloaded” function is one that shares a name with another function, but where each is differentiated by their respective parameter lists. Each parameter list represents a different function. There are three versions of TO_CHAR: one whose first parameter is a character string, another whose first parameter is a date, and another whose first parameter is numeric. The following sections describe each of the three TO_CHAR functions. TO_CHAR—CHARACTER Syntax: TO_CHAR(c) Parameters: c is either an NCHAR, an NVARCHAR2, a CLOB, or an NCLOB. Process: Transforms the incoming parameter into a VARCHAR2. Output: VARCHAR2. Example: SELECT TO_CHAR('Hello') FROM DUAL; TO_CHAR('HELLO') ---------------Hello There are situations where you’ll work with datatypes that cannot accept, for example, CLOB data, but can accept the output of TO_CHAR—such as a VARCHAR2 datatype. 240 Chapter 6: Using Single-Row Functions to Customize Output TO_CHAR—NUMBER Syntax: TO_CHAR(n, format_model, nls_parms) Parameters: n is a number (required). Format_model is optional. A format model consists of one or more format elements, which we saw earlier listed in Table 6-2. The nls_parms value is the same parameter we saw earlier with the TO_NUMBER function. Process: Transforms n into a character string, using the optional format model for guidance as to how to format the output with any special characters that may be desired, such as dollar signs or other financial symbols, special handling of negative numbers, etc. Output: Character. Example: Format the number 198 with a dollar sign and penny specification. SELECT TO_CHAR(198,'$999.99') FROM DUAL; TO_CHAR(198,'$999.99') ---------------------$198.00 TO_CHAR—DATE Syntax: TO_CHAR(d, format_model, nls_parms) Parameters: d is a date or a date interval (required). Format_model is optional and can be used to format data in a variety of ways. See Table 6-4 for details on format models for date datatypes. The nls_parms parameter is the same we saw earlier, for the TO_NUMBER function. Output: Character. Example: Here’s an example of the use of a date format model as described in Table 6-4: SELECT TO_CHAR(SYSDATE,'DAY, "THE" DD "OF" MONTH, RRRR') FROM DUAL; TO_CHAR(SYSDATE,'DAY,"THE"DD"OF"MONTH,RRRR') -------------------------------------------THURSDAY , THE 02 OF JULY , 2009 The “FM” code is a format mask that cleans up all of the trailing blanks, as follows: SELECT TO_CHAR(SYSDATE,'FMDAY, "THE" DD "OF" MONTH, RRRR') FROM DUAL; Describe the Use of Conversion Functions 241 TO_CHAR(SYSDATE,'FMDAY,"THE"DD"OF"MONTH,RRRR') ---------------------------------------------THURSDAY, THE 2 OF JULY, 2009 Changing the format masks to mixed case sends an implied message to mix-case the output as well: SELECT TO_CHAR(SYSDATE,'FMDay, "the" Dd "of" Month, RRRR') FROM DUAL; TO_CHAR(SYSDATE,'FMDAY,"THE"DD"OF"MONTH,RRRR') ---------------------------------------------Thursday, the 2 of July, 2009 Adding the “th” indicator introduces an additional improvement. The inclusion of “th” will append whatever is appropriate after the date—for 1, you’ll get “1st”, for 2, you’ll get “2nd”, etc. For example, SELECT TO_CHAR(SYSDATE,'FMDay, "the" Ddth "of" Month, RRRR') FROM DUAL; TO_CHAR(SYSDATE,'FMDAY,"THE"DDTH"OF"MONTH,RRRR') -----------------------------------------------Thursday, the 2nd of July, 2009 The format model is the secret to extracting the time values from SYSDATE. For example, SELECT TO_CHAR(SYSDATE,'HH24:MI:SS AM') FROM DUAL; TO_CHAR(SYSDATE,'HH24:MI:SSAM') ------------------------------17:48:16 PM Notice in this example we can use either AM or PM to indicate where we want the morning/afternoon indicator to be located, and whether we want it to include periods or not. Whether we use AM or PM makes no difference; the appropriate indicator will appear wherever the format model directs, as shown in the preceding example. The SYSDATE function displays the date by default. But buried inside of it is also the time of day, in hours, minutes, and seconds. The full set of data can be extracted from SYSDATE with the format model parameters of the TO_CHAR function, 242 Chapter 6: Using Single-Row Functions to Customize Output as shown in Table 6-4. But beware, there is danger here . . . and it’s yet another example of how tricky SQL can be. Take a look at this SQL statement: SELECT TO_CHAR(SYSDATE, 'DD-MON-RRRR HH:MM:SS') "Today's Date And Time" FROM DUAL; See anything wrong with it? Perhaps not. Most developers don’t; this can trip up even the most experienced and seasoned of SQL professionals. Try it on any database instance, and it will work, and the output will probably appear to be correct. But look closely at the value displayed for that portion of the format model represented by the MM. Then look at Table 6-4. MM is not “minutes”; it is “months”. If you want minutes, you need to use “MI”, as in “HH:MI:SS”. Watch this one, folks; it’s very tricky—the syntax is technically correct, the execution will be successful, and the test data looks correct at a glance. But it’s still wrong. The sharp eye of a certified Oracle Database SQL Expert should flag this. Table 6-4 Element Description Date Format Elements AD / A.D. BC / B.C. Anno Domini or Before Christ indicator, with or without periods AM / A.M. PM / P.M. Morning or afternoon hours, with or without periods CC / SCC Century D Day of the week, 1 through 7 DAY The name of the day spelled out DD Day of the month, 1 through 31 DDD Day of the year, 1 through 366 DL Long date format, as determined by the NLS_DATE_FORMAT parameter. Appearance is determined by NLS_TERRITORY and NLS_LANGUAGE parameters. Sample AMERICAN_AMERICA output is ‘Monday, July 27, 2009’ DS Short date format. Appearance is determined by NLS_ TERRITORY and NLS_LANGUAGE parameters. Sample AMERICAN_AMERICA output is ‘7/27/2009’ DY Abbreviated name of day. SUN, MON, TUE, etc. E Abbreviated era name EE Full era name Describe the Use of Conversion Functions 243 Table 6-4 Element Description Date Format Elements (Continued) FF Fractional seconds FM Used in combination with other elements to direct the suppression of leading or trailing blanks FX Exact matching between the character data and the format model HH, HH12 Hour of the day, 1 through 12 (both are identical) HH24 Hour of day, 1 through 24 IW Week of the year, 1 through 53 I IY IYY Last 1, 2, or 3 digits of the ISO year J Julian day, counted as the number of days since January 1, 4712 B.C. MI Minute. 0 through 59 MM Month in double digits, 01 through 12 MON Abbreviated name of month, e.g., JAN, FEB, MAR MONTH Name of month spelled out PR If negative, numbers are enclosed within angle brackets (<>). If positive, returned with leading and trailing spaces. PR follows specification, for example: 9999PR Q Quarter of year RM Roman numeral month RR Accepts twentieth-century dates in the twenty-first century using only two digits. 00 through 49 is interpreted as 2000 through 2049. 50 through 99 is interpreted as 1950 through 1999 RRRR The four-digit year. If provided a two-digit year, it returns the same value as RR SS Seconds, 0 through 59 SSSS Seconds past midnight, 0 through 86399 TS The short time format. Only allowable when specified with the DL or DS format model element, separated by white space TZD Abbreviated time zone with Daylight Saving Time. Only valid in timestamp and interval formats. Examples: ‘EST’, ‘CMT’ TZH Time zone hour. Not valid in DATE datatypes; only valid in timestamp and interval formats. ‘00’ through ‘12’ (Continued) 244 Chapter 6: Using Single-Row Functions to Customize Output Table 6-4 Element Description Date Format Elements (Continued) TZM Time zone minute. Only valid in timestamp and interval formats. ‘00’ through ‘59’ TZR Time zone region information. Not valid in DATE datatypes; only valid in timestamp and interval formats. Example: ‘America/ Los_Angeles’ WW The week of the year, 1 through 53. Week 1 starts on the first day of the year and ends on the seventh day of the year W The week of the month, 1 through 5. Week 1 starts on the first day of the month and ends on the seventh day of the month X Local radix character Y,YYY The year with the comma in position YEAR, SYEAR The year spelled out in English. The S version causes BC dates to display with a minus sign prefix YYYY, SYYYY The four-digit year. The S version causes BC dates to display with a minus sign prefix YYY, YY, Y The last 3, 2, or 1 digits of the year -/,.;: Punctuation that is accepted in place and passed through as is “text” Literal value. Display as is. TO_DATE Syntax: TO_DATE(c, format_model, nls_parms) Parameters: c = a character string (required); format_model is a format model according to Table 6-4. The nls_parms value is the same parameter you saw earlier with the TO_NUMBER function. Process: Transform the value contained within c into a valid DATE datatype by structuring format_model to describe how the character string is formed, identifying the date information accordingly. Output: Date. Example: Convert a non-standard date representation to the default format. SELECT TO_DATE('2009-01-31','RRRR-MM-DD') FROM DUAL; TO_DATE('2009-01-31','RRRR-MM-DD') ------------------------31-JAN-09 Describe the Use of Conversion Functions 245 TO_TIMESTAMP Syntax: TO_TIMESTAMP (c, format_model, nls_parms) Parameters: c is a character datatype (required); format_model must define the format of c corresponding to TIMESTAMP format model elements—optional, the default requirement is that c must be in the TIMESTAMP format. The nls_parms value is the same parameter you saw earlier with the TO_NUMBER function. Process: Converts c data to the TIMESTAMP datatype, which differs from DATE in that it includes fractional seconds. The format_model defines the pattern of c’s date information to the function so the various elements of TIMESTAMP are identified—information for year, month, day, hours, minutes, seconds, and fractional seconds. Output: A value in the TIMESTAMP datatype. Example: Here is a character representation of a date. The format model is included to define the pattern and inform the TIMESTAMP function where the DD information is, where the MON information is, etc. SELECT TO_TIMESTAMP('2020-JAN-01 13:34:00:093423', 'RRRR-MON-DD HH24:MI:SS:FF') EVENT_TIME FROM DUAL; EVENT_TIME ------------------------01-JAN-20 01.34.00.093423000 PM TO_DSINTERVAL Syntax: TO_DSINTERVAL (sql_format, nls_parms) Parameters: sql_format is a character string in the format required for a INTERVAL DAY TO SECOND datatype, which is ‘DAYS HH24:MI:SS.FF’. For example, ‘15 14:05:10.001’ is the INTERVAL DAY TO SECOND representation for 15 days, 14 hours, 5 minutes, and 10.001 seconds. The nls_parms value is the same parameter you saw earlier with the TO_NUMBER function. Process: Transforms the incoming value represented in sql_format to a value of INTERVAL DAY TO SECOND datatype. Output: A value in the INTERVAL DAY TO SECOND datatype. 246 Chapter 6: Using Single-Row Functions to Customize Output Example: The following converts a value representing 40 days, 8 hours, 30 minutes, and 0.03225 seconds into the INTERVAL DAY TO SECOND datatype. SELECT TO_DSINTERVAL('40 08:30:00.03225') EVENT_TIME FROM DUAL; EVENT_TIME ----------40 8:30:0.032250000 TO_YMINTERVAL Syntax: TO_YMINTERVAL (‘y-m’) Parameters: y and m are numbers contained within a string, required. Process: Tranforms y and m into the years and months in a format of the datatype INTERVAL YEAR TO MONTHS. Output: A value in the INTERVAL YEAR TO MONTHS datatype. Example: Convert the character expression showing 4 years and 6 months into the datatype INTERVAL YEAR TO MONTHS. SELECT TO_YMINTERVAL('04-06') EVENT_TIME FROM DUAL; EVENT_TIME ----------4-6 Automatic Datatype Conversions This section would be remiss if we didn’t at least mention the concept of automatic datatype conversions. We’ve mentioned them before, but it’s worth pointing out here that some datatype conversions occur automatically in the database. For example: SELECT 'Chapter ' || 1 || ' . . . I am born.' FROM DUAL; 'CHAPTER'||1||'...IAMBORN.' --------------------------Chapter 1 . . . I am born. Manage Data in Different Time Zones—Use Various Datetime Functions 247 In this sample, we concatenate three expressions into one. The center expression is a numeric literal—and yet, the concatenation operators are only intended to connect string values together. But SQL is smart enough to recognize what is happening, and it performs an automatic datatype conversion of the numeric 1 into a character ‘1’ and then completes the concatenation. Another example (line numbers added): 01 02 03 04 05 06 07 08 SELECT SYSDATE, ADD_MONTHS(SYSDATE, SUBSTR('plus 3 months',6,1)) PLUS_THREE FROM DUAL; SYSDATE PLUS_THREE ------------------------- ------------------------28-JUL-09 28-OCT-09 In this example, the SUBSTR function in line 3 returns a string value of ‘3’, which is automatically converted to a numeric datatype, since a numeric is what is required for the ADD_MONTHS function in lines 2 and 3. As I’ve stated before, the general rule of thumb is this: automatic datatype conversions can and do happen wherever they can be done without losing data precision. However, good software does not depend on them but instead is written with explicit datatype conversions—using the conversion functions discussed here—wherever required. Certification Objective 6.04 Manage Data in Different Time Zones—Use Various Datetime Functions Oracle SQL contains a number of features to support the management of local and remote time zones. For example, a help desk that is located in one time zone that takes phone calls from one or more additional time zones must be able to track the times of incoming phone calls and associated responses, and be able to do so in such a way that all the different time zones will fully understand the information. 248 Chapter 6: Using Single-Row Functions to Customize Output For any given transaction, there are three time zones to be concerned with: n The UTC time, which is the absolute universal standard against which all other times are based n The database time zone, which is the time zone of the location where the database is installed (accessible by the function DBTIMEZONE) n The session time zone, which is the time zone of the user (accessible by the function SESSIONTIMEZONE) Oracle recommends setting the database time to UTC time. That way you simplify the overall process, as well as speed performance by eliminating an extra time offset. However, such a configuration step is not required, nor necessarily desired, depending on your particular business rule requirements. Note that the DATE and TIMESTAMP datatypes do not support time zone differences. However, there are two datatypes that do work with time zones. They are called TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE. See Table 6-5 for a comparison of these datatypes with DATE and TIMESTAMP and their different features. The TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE datatypes differ in the way they handle time zones. Both datatypes store the source data’s date and time. The former—TIMESTAMP WITH TIME ZONE—also stores the time zone. The latter—TIMESTAMP WITH LOCAL TIME ZONE—does not store the time zone but stores the time normalized to UTC time. When queried, it presents its data in the user’s local time zone. It uses an offset from UTC time. In the next few sections, we’ll look into the details of how this works. If you are working with an application in which the time zone for a given event is important, use TIMESTAMP WITH TIME ZONE. But if you require a system in which that isn’t necessary—a system that is more concerned with multiple users across multiple time zones who should be able to each see data displayed in terms of their own local time as defined by their own local client machine—use TIMESTAMP WITH LOCAL TIME ZONE. However, note that web-based applications often show time according to the time on the web server, rather than the local client, so unless special steps are taken with regard to web browser interfaces, the TIMESTAMP WITH LOCAL TIME ZONE may provide no benefit to such an application. Manage Data in Different Time Zones—Use Various Datetime Functions Table 6-5 Datatype Fractional Seconds Time Zone Datetime Datatypes and Time Zones DATE No No TIMESTAMP Yes No TIMESTAMP WITH TIME ZONE Yes Explicit TIMESTAMP WITH LOCAL TIME ZONE Yes Relative 249 Database Time vs. Session Time Two system variables that track times are important for our purposes here: n The database time zone, as defined by the function DBTIMEZONE n The session time zone, as defined by the function SESSIONTIMEZONE SELECT DBTIMEZONE, SESSIONTIMEZONE FROM DUAL; DBTIMEZONE SESSIONTIMEZONE ---------- ---------------+00:00 America/New_York According to this example, the database time zone is UTC+0, which is to say that it’s set to UTC. The session time zone is ‘America/New_York’. To change the database time zone: ALTER DATABASE SET TIME_ZONE = 'Europe/Zurich'; Note: you cannot change the database time zone if the database already contains any tables with columns of the TIMESTAMP WITH LOCAL TIME ZONE datatype. To change the session time zone: ALTER SESSION SET TIME_ZONE = 'America/Los_Angeles'; If you are trying to change the database time zone and find that you cannot because you already have tables with the TIMESTAMP WITH LOCAL TIME ZONE datatype, you can easily locate those tables by querying the data 250 Chapter 6: Using Single-Row Functions to Customize Output dictionary, which I discuss in Chapter 14. For now, know that this query will locate those table names for you, along with their owners: SELECT FROM WHERE ORDER BY OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE DBA_TAB_COLUMNS DATA_TYPE LIKE '%LOCAL TIME_ZONE%' OWNER, TABLE_NAME, COLUMN_NAME; Coordinated Universal Time (UTC) The Coordinated Universal Time, or UTC, is the new name for Greenwich Mean Time (GMT). It is the universal standard for measuring time internationally. Technically there are differences between UTC and GMT, but for our purposes those differences are irrelevant. The primary issue for us to be aware of is that UTC measures time as it exists at the Royal Observatory in Greenwich, London. (Generally that’s true. There are exceptions, but they go beyond the scope of our discussion here.) All other time around the world is measured as an offset of time relative to that location. In other words, the American east coast is 5 hours “behind” the time in Greenwich, London, so New York, for example, is considered –5:00 UTC. (This is with Standard Time in force.) This and all other times are defined in terms of their difference from Greenwich, i.e., plus or minus UTC. In the world of SQL, the UTC time is the top authority. The second-level authority is the database server. The third authority is the client system. Time on the database server is measured relative to UTC. In an application that deals with multiple time zones and the associated datatypes, it’s not uncommon to set the time zone for the database server to be identical to UTC, regardless of its actual location. Time Zone Datatypes There are two special datatypes for managing time across multiple time zones, described here. They are: n TIMESTAMP WITH TIME ZONE n TIMESTAMP WITH LOCAL TIME ZONE To understand them, you must first understand the concepts of the time zone region name and time zone offset. Let’s discuss time zone region names and then review the TIMESTAMP datatype (which does not store time zone data), after which we’ll discuss the two time zone datatypes. Manage Data in Different Time Zones—Use Various Datetime Functions 251 Time Zone Region Name Time Zone Region Names are text descriptions of the various time zones available as part of the UTC system. Each text description has a name and an abbreviation. Examples include those listed in Table 6-6. Notice in the table that time zone names have more than one associated abbreviation. That’s because the abbreviations refer to something other than the particular geographical location for the time zone. For example, ‘America/Chicago’ includes the abbreviations CDT, CST, and others. These refer to n Central Daylight Time (UTC-5) n Central Standard Time (UTC-6) n Eastern Standard Time (UTC-5) n Local Mean Time (UTC-6) The list of available time zone region names in any given database is available in the data dictionary. The data dictionary is a topic we’ll cover in some detail later in the book. For now, it’s worth noting simply that you can issue the Table 6-6 Name Abbreviation Examples of Time Zone Names and Abbreviations America/Chicago CDT America/Chicago CST America/Chicago EST America/Chicago LMT Asia/Macau CST Asia/Macau LMT Asia/Macau MOST Asia/Macau MOT Australia/Brisbane EST Australia/Brisbane LMT Europe/Vienna CEST Europe/Vienna CET Europe/Vienna LMT 252 Chapter 6: Using Single-Row Functions to Customize Output following query from any user account and obtain a list of the available time zones in your database: SELECT TZABBREV, TZNAME FROM V$TIMEZONE_NAMES ORDER BY TZABBREV, TZNAME; This query lists the time zone abbreviations, along with the many time zone names that exist within each one, alphabetized. The advantage to using time zone region names in the database is that any changes affecting Daylight Saving Time are automatically managed, which is not true when time zone information is stored according to time zone offset. Time Zone Offset A time zone offset takes the following format: +/- TZH:TZM The TZH and TZM format models were listed in Table 6-4. An example of a time zone offset is -05:00 This example represents a time zone offset of “minus five hours”. The New York time zone has an offset of “-05:00” from UTC when Daylight Standard Time (also known as Standard Time) is in effect, and “-4:00” when Daylight Saving Time is in effect. Note, however, than if you store time zone information in the “time zone offset” format, your data won’t be adjusted for changes between Standard Time and Daylight Saving Time. Time zone information stored in the “time zone region name” format will reflect such changes. As a reminder, the TIMESTAMP datatype is the same as DATE, but with fractional seconds included. The time zone datatypes build on the TIMESTAMP datatype, as described next. TIMESTAMP WITH TIME ZONE Datatype The TIMESTAMP WITH TIME ZONE datatype is an Oracle SQL datatype that is similar to the TIMESTAMP datatype, but it adds the following fields: TIMEZONE_ HOUR, TIMEZONE_MINUTE, TIMEZONE_REGION, TIMEZONE_ABBR. The time zone is stored in one of two ways: Manage Data in Different Time Zones—Use Various Datetime Functions 253 n A time zone region name, or n A time zone offset from UTC The time zone region name is a text representation describing one of the many approved time zone regions. The time zone offset is the interval between the local time and the UTC. As we’ve stated, Oracle officially recommends that you store time zone information using the time zone region name rather than the time zone offset from the UTC, so that adjustments involving Daylight Saving Time (DST) will be automatically taken into account by the system when you use the time zone region name. TIMESTAMP WITH LOCAL TIME ZONE Datatype TIMESTAMP WITH LOCAL TIME ZONE is a datatype that is also similar to the TIMESTAMP datatype, but it stores the time normalized to the database time zone. In other words, no information is stored about the time zone of the data. However, when a user queries data of the TIMESTAMP WITH LOCAL TIME ZONE type, the data is presented in terms of the user’s local time zone. Time Zone Functions Time zone functions are those functions that work with the datatypes and data objects that support the management of time within a database whose user base spans multiple time zones. DBTIMEZONE Syntax: DBTIMEZONE Parameters: None. Process: Returns the time zone for the database. Output: Character. Example: Here’s a database whose time is set to UTC exactly, no offset. SELECT DBTIMEZONE FROM DUAL; DBTIMEZONE ---------+00:00 Oracle officially recommends that the database time zone be set to UTC, in order to speed performance by avoiding unnecessary time zone calculations. 254 Chapter 6: Using Single-Row Functions to Customize Output SESSIONTIMEZONE Syntax: SESSIONTIMEZONE Parameters: None. Process: Returns the time zone for the current session. The format of the output is dependent on the most recent execution of the ALTER SESSION statement. The options are: (a) time zone offset, (b) time zone regional name. The better choice is (b), time zone regional name, if you want the database to perform adjustments to support Standard Time and Daylight Saving Time changes automatically. Output: Character. Example: Obtain the session time: SELECT SESSIONTIMEZONE FROM DUAL; SESSIONTIMEZONE ---------------America/New_York CURRENT_DATE, CURRENT_TIMESTAMP Syntax: CURRENT_DATE, CURRENT_TIMESTAMP(t) Parameters: None for CURRENT_DATE. For CURRENT_TIMESTAMP, t = local time zone’s fractional second precision. Ranges between 0 and 9. Optional; defaults to 6. Process: Returns the current date and current timestamp within the session time zone. Output: CURRENT_DATE returns a value of the DATE datatype; CURRENT_ TIMESTAMP returns a value of the TIMESTAMP WITH TIME ZONE datatype. Example: Here is an example: SELECT CURRENT_DATE, CURRENT_TIMESTAMP FROM DUAL; CURRENT_DATE CURRENT_TIMESTAMP ------------------------- ----------------08-JUL-09 08-JUL-09 03.03.50.843000000 PM AMERICA/NEW_YORK Note the first part of the value returned by CURRENT_TIMESTAMP. It’s the same as the CURRENT_DATE function, plus additional information showing time. DATE datatype values actually store information for hours, minutes, and Manage Data in Different Time Zones—Use Various Datetime Functions 255 seconds; the TO_CHAR conversion function is capable of displaying that detail. But DATE datatypes do not store fractional seconds; TIMESTAMP does. The local time zone information shown with the TIMESTAMP output is not stored within the TIMESTAMP but reflects the local time zone defined by SESSIONTIMEZONE. LOCALTIMESTAMP Syntax: LOCALTIMESTAMP(t) Parameters: t = local time zone’s fractional second precision. Ranges between 0 and 9. Optional; defaults to 6. Process: Displays the user session’s local time, as opposed to the database time zone, which may be different. The value is displayed including year, month, day, hours, minutes, and seconds, including fractional seconds. Output: A value of datatype TIMESTAMP. Example: Show the local time to a fractional-second precision of four digits to the right of the decimal point. SELECT LOCALTIMESTAMP(4) FROM DUAL; LOCALTIMESTAMP(4) ------------------------09-JUL-09 12.18.20.031300000 AM SYSTIMESTAMP Syntax: SYSTIMESTAMP Parameters: None. Process: Returns the system date, including fractional seconds, of the operating system on which the database is installed. This is the TIMESTAMP equivalent to the SYSDATE function. Output: The system date in the TIMESTAMP WITH TIME ZONE datatype. Example: Show the database’s operating system date and time with fractional seconds included. SELECT SYSTIMESTAMP FROM DUAL; SYSTIMESTAMP ------------09-JUL-09 12.21.27.437000000 AM -04:00 256 Chapter 6: Using Single-Row Functions to Customize Output NEW_TIME Syntax: NEW_TIME(d, t1, t2) Parameters: d is a DATE datatype and is required. t1 and t2 are time zone indications taken from Table 6-7. Process: For a given value of d, NEW_TIME translates the time d according to the offset specified between t1 and t2. In other words, t1 is assumed to be the time zone in which d is recorded, so NEW_TIME will convert that time into the t2 time zone. Output: A value in DATE datatype. Example: SELECT TO_CHAR( NEW_TIME( TO_DATE('1983-JAN-03 14:30:56','RRRR-MON-DD HH24:MI:SS'), 'AST', 'HST') ,'DD-MON-RR HH:MI:SS') NEW_DATE FROM DUAL; NEW_DATE -----------------03-JAN-83 08:30:56 Table 6-7 Time Zones Standard Time Daylight Saving Time Time Zone Values for the NEW_ TIME Function Atlantic AST ADT Bering BST BDT Central CST CDT Eastern EST EDT Greenwich UTC Alaska-Hawaii HST HDT Mountain MST MDT Newfoundland NST Pacific PST PDT Yukon YST YDT Manage Data in Different Time Zones—Use Various Datetime Functions 257 Time Zone Conversion Functions The following section describes functions that convert time zone datatypes. FROM_TZ Syntax: FROM_TZ(ts, tz) Parameters: ts is a TIMESTAMP value (required); tz is a time zone reference (required). Process: Transforms ts, a TIMESTAMP value, and tz, a character value representing the time zone, into a value of the datatype TIMESTAMP WITH TIME ZONE. The second parameter, tz, can be in one of two formats: either the format of ‘TZH:TZM’, where TZH and TZM are time zone hours and time zone minutes, as described in Table 6-4; or the format of a character expression that results in a string in the TZR with optional TZD format, also as described in Table 6-4. Output: A value of the TIMESTAMP WITH TIME ZONE datatype. Example: Starting with the character string ‘2012-10-12 07:45:30’, convert it to the TIMESTAMP datatype, and then convert it to the TIMESTAMP WITH TIME ZONE by included a corresponding time zone offset value of ‘7:30’. SELECT FROM_TZ( TIMESTAMP '2012-10-12 07:45:30', '+07:30') FROM DUAL; FROM_TZ(TIMESTAMP'2012-10-1207:45:30','+07:30') ----------------------------------------------12-OCT-12 07.45.30.000000000 AM +07:30 TO_TIMESTAMP_TZ Syntax: TO_TIMESTAMP_TZ(c, format_model, nls_parms) Parameters: c is a character string (required). The format_model must define the format of c corresponding to TIMESTAMP WITH TIME ZONE format model elements—optional, the default requirement is that c must be in the TIMESTAMP format. The optional nls_parms value is the same parameter you saw earlier with the TO_NUMBER function. 258 Chapter 6: Using Single-Row Functions to Customize Output Process: Transforms c into a value of TIMESTAMP WITH TIME ZONE, where format_model defines the format in which c stores the TIMESTAMP WITH TIME ZONE information. The time zone will default to that defined by the SESSION parameter. Output: A value in the TIMESTAMP WITH TIME ZONE datatype. Example: Convert the character string ‘17-04-2013 16:45:30’ to a datatype of TIMESTAMP WITH TIME ZONE by providing a format mask. SELECT TO_TIMESTAMP_TZ('17-04-2013 16:45:30','DD-MM-RRRR HH24:MI:SS') "Time" FROM DUAL; Time ------------17-APR-13 04.45.30.000000000 PM AMERICA/NEW_YORK Note that there isn’t a conversion function that specifically converts values into the TIMESTAMP WITH LOCAL TIME ZONE datatype. For that, use CAST—see the next description. CAST Syntax: CAST(e AS d) Parameters: e is an expression; d is a datatype. Process: Converts e to d. Particularly useful for converting text representations of datetime information into datetime formats, particularly TIMESTAMP WITH LOCAL TIME ZONE. Output: A value in the d datatype. Example: In the following, we convert a value in the default timestamp format, presented as a literal value: SELECT CAST('19-JAN-10 11:35:30' AS TIMESTAMP WITH LOCAL TIME ZONE) "Converted LTZ" FROM DUAL; Manage Data in Different Time Zones—Use Various Datetime Functions 259 Converted LTZ ------------19-JAN-10 11.35.30.000000000 AM If we wish to use a format mask for any reason, we can nest a call to, for example, the TO_TIMESTAMP conversion function, as follows: SELECT CAST(TO_TIMESTAMP('19-JAN-10 14:35:30','DD-MON-RR HH24:MI:SS') AS TIMESTAMP WITH LOCAL TIME ZONE) "Converted LTZ" FROM DUAL; Converted LTZ ------------19-JAN-10 02.35.30.000000000 PM EXTRACT Syntax: EXTRACT( fm FROM e) Parameters: fm is a format model element from Table 6-8 (required); e is a timestamp expression. Process: Extracts the value indicated by fm from e, where fm is one of the following keywords: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, TIMEZONE_HOUR, TIMEZONE_MINUTE, TIMEZONE_REGION, TIMEZONE_ABBR; and e is an expression representing a datetime datatype. Output: Character if you extract TIMEZONE_REGION or TIMEZONE_ABBR data; numeric for all other extractions. Example: SELECT EXTRACT(MINUTE FROM TO_TIMESTAMP('2009-10-11 12:13:14', 'RRRR-MM-DD HH24:MI:SS')) "Minute" FROM DUAL; Minute ---------------------13 260 Chapter 6: Table 6-8 Using Single-Row Functions to Customize Output Format Elements and the EXTRACT Function Keyword DATE TIME STAMP TIME STAMP WITH TIME ZONE TIME INTERVAL STAMP YEAR TO WITH MONTH LOCAL TIME ZONE INTERVAL DAY TO SECOND YEAR X X X X X — MONTH X X X X X — DAY X X X X — X HOUR — X X X — X MINUTE — X X X — X SECOND — X X X — X TIMEZONE_ HOUR — — X * X — — TIMEZONE_ MINUTE — — X X* — — TIMEZONE_ REGION — — X X* — — TIMEZONE_ ABBR — — X X* — — Note that the TIMESTAMP WITH LOCAL TIME ZONE only stores—and therefore only returns—local session time zone data. * SYS_EXTRACT_UTC Syntax: SYS_EXTRACT_UTC(dtz) Parameters: dtz is any datetime value with a time zone included. Process: Extracts the UTC from a datetime value. Output: A value of datatype TIMESTAMP. Example: The sample that follows passes in a date of March 25, 2012, 9:55 a.m., as a TIMESTAMP converted value with an offset of –4 hours. The datetime value is normalized for UTC and the UTC time is displayed as output. SELECT SYS_EXTRACT_UTC(TIMESTAMP '2012-03-25 09:55:00 -04:00') "HQ" FROM DUAL; Manage Data in Different Time Zones—Use Various Datetime Functions 261 HQ ------------------------25-MAR-12 01.55.00.000000000 PM AT TIME ZONE, AT LOCAL The datetime datatypes have some additional support for converting among datatypes that we’ll list here. Expression AT TIME ZONE The best way to understand the concept of the AT TIME ZONE conversion expression is with an example. First, let’s look at our system value for DBTIMEZONE and SESSIONTIMEZONE: SELECT DBTIMEZONE, SESSIONTIMEZONE FROM DUAL; DBTIMEZONE SESSIONTIMEZONE ---------- --------------------------+00:00 America/New_York So you can see that our DBTIMEZONE is set to UTC, since its UTC offset is zero. Meanwhile, our local session is in the New York time zone. Now, armed with that information, let’s take a character string that defines a particular datetime value in the TIMESTAMP datatype. We’ll use the TO_ TIMESTAMP conversion function to do this, and then we’ll transform it to be AT TIME ZONE DBTIMEZONE, giving the output a column alias of “DB Time”. This code shows how (line numbers added): 01 02 03 04 05 06 07 SELECT TO_TIMESTAMP('2012-MAY-24 02:00:00','RRRR-MON-DD HH24:MI:SS') AT TIME ZONE DBTIMEZONE "DB Time" FROM DUAL; DB Time ------------24-MAY-12 06.00.00.000000000 AM +00:00 Note that the end of line 2 is an optional column alias, specified after the AT TIME ZONE expression. The SQL statement includes the TO_TIMESTAMP function to define a value in the TIMESTAMP datatype, which is then followed by the “AT TIME ZONE” 262 Chapter 6: Using Single-Row Functions to Customize Output keywords, which are setting up the value to be transformed into its equivalent in another time zone. In this example, the target time zone is the value for DBTIMEZONE, but in its place we could use any of the following: n SESSIONTIMEZONE n A valid time zone name, such as ‘America/Chicago’ n A time zone offset in the ‘hh:mm’ format, such as ‘+04:00’ (since Daylight Saving Time is in effect at this time, the UTF offset to New York is only 4 hours) n An expression that produces any of the preceding values The AT TIME ZONE keywords can be preceded by the datatypes: n TIMESTAMP n TIMESTAMP WITH TIME ZONE n TIMESTAMP WITH LOCAL TIME ZONE . . . but not the DATE datatype. The returned value represents the original time translated into the time zone as specified in the AT TIME ZONE expression. Expression AT LOCAL The AT LOCAL expression converts the source data into the local time equivalent, as shown in this code (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 SELECT FROM_TZ( CAST( TO_DATE('1999-12-01 11:00:00', 'RRRR-MM-DD HH:MI:SS') AS TIMESTAMP ), 'America/Los_Angeles' ) AT LOCAL "East Coast Time" FROM DUAL; East Coast Time --------------01-DEC-99 02.00.00.000000000 PM AMERICA/NEW_YORK Note the column alias at the end of line 6, specified after the AT LOCAL expression. Certification Summary 263 The AT LOCAL expression takes no value but simply converts the source value to whatever the session time zone indicates, which in this example is America/ New_York time, as indicated by the translated value shown in line 11, the output of the query. Certification Summary SQL functions perform a wide variety of tasks, ranging from mathematical calculations to text analysis and date conversions. Functions can be called from almost any SQL statement, and from a variety of locations within various SQL statements. SQL functions can be called from the SELECT statement’s select list and WHERE clause; from the INSERT statement’s value list; from the UPDATE statement’s SET clause and WHERE clause; and from the DELETE statement’s WHERE clause. Function takes anywhere from zero to multiple input parameter values. Each function does some sort of processing that incorporates the input parameters, and perhaps some other data as well. Each function sends back exactly one result. Character functions perform tasks associated with string manipulation and text analysis. Character functions include UPPER, LOWER, INITCAP, CONCAT, LPAD, RPAD, LENGTH, INSTR, SUBSTR, and others. Character functions accept input parameters that may be character data and may include other datatypes, such as numeric parameters. And while each character function returns exactly one value, as do all functions, the character functions do not necessarily return character data as their return value. For example, LENGTH returns a number indicating the length of a given character string. But each performs a task associated with character strings. Number functions, also referred to as numeric functions, perform analysis on numbers. They include ROUND, REMAINDER, MOD, and others. Date functions work with date and datetime information. Date functions include SYSDATE, ROUND (for dates), TRUNC (for dates), NEXT_DAY, LAST_DAY, ADD_MONTHS, MONTHS_BETWEEN, NUMTOYMINTERVAL, NUMTODSINTERVAL, and others. Other functions perform tasks that may or may not perform processing on one or more datatype. Other functions include NVL, DECODE, and NULLIF. Functions may be nested within each other, so that the output of one function serves as the input parameter of another. Conversion functions include TO_NUMBER, TO_CHAR, TO_DATE, TO_ TIMESTAMP, TO_DSINTERVAL, TO_YMINTERVAL, and others. 264 Chapter 6: Using Single-Row Functions to Customize Output Multiple time zones can be handled in a variety of ways. There is a central system-wide value that stores the time zone for the database, called DBTIMEZONE. This can be set to the UTC time or to an offset of it. Local sessions, in turn, can be in different time zones. Each session’s time zone can be analyzed individually by way of the SESSIONTIMEZONE function. The time zone data can be stored in the TIMESTAMP and TIMESTAMP WITH TIME ZONE datatypes. TIMESTAMP WITH LOCAL TIME ZONE stores data in the time zone of the database server, yet displays the date data in the local session time zone of the end user. Functions that can support time zone management include DBTIMEZONE, SESSIONTIMEZONE, CURRENT_DATE, CURRENT_TIMESTAMP, LOCALTIMESTAMP, SYSTIMESTAMP, NEW_TIME, and others. Time zone conversion functions include FROM_TZ, TO_TIMESTAMP_TZ, CAST, EXTRACT, and SYS_EXTRACT_UTC. Two-Minute Drill 3 265 Two-Minute Drill Describe Various Types of Functions That Are Available in SQL q SQL functions accept one or more input parameters. A few take no parameters. q Each function returns one value; no more, no less. q SQL functions perform tasks of various kinds. q Functions can be included anywhere a SQL expression can be included, provided that the rules of datatypes are respected. q Functions can be included in the WHERE clause of the SELECT, UPDATE, and DELETE statements. q Functions can be included in the SELECT expression list, INSERT value list, and UPDATE SET clause. Use Character, Number, and Date Functions in SELECT Statements q Character functions include text cleanup and conversion functions. q UPPER, LOWER, and INITCAP can manage the case of a string. q LPAD and RPAD can pad a string with specified characters. q INSTR, SUBSTR, CONCAT, and LENGTH can be used to divide up and put together different strings. q Numeric functions perform analysis and calculations. q TRUNC always rounds toward zero. q REMAINDER and MOD are variations on division and leftover values. q Date functions offer a variety of features to support the tracking of centuries, decades, years, quarters, months, weeks, days, hours, minutes, seconds, and fractions of seconds, as well as times across different time zones. q Other functions include LEAST, GREATEST, NVL, NVL2, DECODE, and NULLIF. 266 Chapter 6: Using Single-Row Functions to Customize Output Describe the Use of Conversion Functions q Conversion functions include TO_NUMBER, TO_CHAR, and TO_DATE. q TO_CHAR can convert from character, date, or numeric data, and into character data. q The conversion function TO_TIMESTAMP can convert to the TIMESTAMP datatype, which is the same as DATE but adds fractional seconds. q The functions TO_DSINTERVAL and TO_YMINTERVAL convert to interval datatypes INTERVAL DAY TO SECOND and INTERVAL YEAR TO MONTH. Manage Data in Different Time Zones—Use Various Datetime Functions q Time zone management can be performed with datatypes like TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL TIME ZONE. q The DBTIMEZONE returns the value of the database server’s time zone as an offset to UTC. q The SESSIONTIMEZONE returns the value of the particular user session’s local time zone. q The conversion function TO_TIMESTAMP_TZ converts to TIMESTAMP WITH TIME ZONE, which is the same as TIMESTAMP but with time zone information. Self Test 267 Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Describe Various Types of Functions That Are Available in SQL 1. Which of the following is true of functions? A. They never return a value. B. They often return a value. C. They always return a value. D. There is no consistent answer to whether they return a value or not. 2. Which of the following is true of character functions? A. They always accept characters as parameters and nothing else. B. They always return a character value. C. They are generally used to process text data. D. They generally have the letters CHAR somewhere in the function name. 3. Built-in SQL functions: (Choose three.) A. Can be invoked from a DELETE statement’s WHERE clause. B. Are written by SQL developers and also known as “user-defined” functions. C. Are available for use from the UPDATE statement. D. Are available for use within a SELECT statement’s WHERE clause, as well as the SELECT statement’s expression list. Use Character, Number, and Date Functions in SELECT Statements 4. Review this SQL statement: SELECT SUBSTR('2009',1,2) || LTRIM('1124','1') FROM DUAL; What will be the result of the SQL statement? A. 2024 B. 221 C. 20124 D. A syntax error 268 Chapter 6: Using Single-Row Functions to Customize Output 5. Review this SQL statement: SELECT TRUNC(ROUND(ABS(-1.7),2)) FROM DUAL; What will be the result of the SQL statement? A. 1 B. 2 C. 3 D. 4 6. Review this SQL statement: SELECT LASTNAME FROM CUSTOMERS WHERE LASTNAME = SOUNDEX('Franklin'); What are some possible results for the query? A. Franklyn B. Phrankline C. None of the above D. There’s not enough information present to know the answer 7. Review this SQL statement: SELECT MONTHS_BETWEEN(LAST_DAY('15-JAN-12')+1,'01-APR-12')FROM DUAL; What will result from the query above? A. 2 B. 3 C. –2 D. –3 Describe the Use of Conversion Functions 8. If you wish to display a numeric value with dollar signs and commas, which of the following is the best approach to take? A. The TO_NUMBER function with a format model B. The TO_CHAR function with a format model C. A combination of string literals that contain commas and dollar signs, along with the CONCAT function D. The MONEY datatype Self Test 269 9. Which of the following SQL statements will display the current time, in hours, minutes, and seconds, as determined by the operating system on which the database server resides? A. SELECT TO_CHAR(SYSDATE) FROM DUAL; B. SELECT TO_CHAR(SYSDATE, ‘HR:MI:SE’) FROM DUAL; C. SELECT TO_CHAR(SYSDATE, ‘HH:MI:SS’) FROM DUAL; D. SELECT TO_CHAR(SYSDATE, ‘HH:MM:SS’) FROM DUAL; 10. Which query returns an expression of the datatype INTERVAL YEAR TO MONTHS representing an interval of 1 year and 3 months? A. SELECT TO_YMINTERVAL(‘01:03’) FROM DUAL; B. SELECT TO_YMINTERVAL(‘01-03’) FROM DUAL; C. SELECT TO_INTERVALYM(‘01:03’) FROM DUAL; D. SELECT TO_INTERVALYM(‘01-03’) FROM DUAL; Manage Data in Different Time Zones—Use Various Datetime Functions 11. Which of the following SQL datatypes cannot store fractional seconds? A. DATE B. TIMESTAMP WITH LOCAL TIME ZONE C. TIMESTAMP D. INTERVAL DAY TO SECOND 12. Your database server is in Beijing, China. You are supporting an application with user sessions originating out of Beijing and Atlanta. You wish to ensure that your application stores dates in such a way that if your Beijing team stores datetime data, such as “9 PM Beijing”, your Atlanta users will see “9 PM Beijing” instead of the equivalent time in Atlanta. Which datatype is the best choice? A. TIMESTAMP B. TIMESTAMP WITH TIME ZONE C. TIMESTAMP WITH LOCAL TIME ZONE D. It cannot be done 13. Pacific Standard Time is abbreviated PST. PST is an example of which format model element? A. TZD B. TZH C. TZM D. TZR 270 Chapter 6: Using Single-Row Functions to Customize Output 14. Review the following code: CREATE TABLE EMAIL_RESPONSE ( EMAIL_RESPONSE_ID NUMBER, EMAIL_SENT TIMESTAMP WITH LOCAL TIME ZONE, EMAIL_RECEIVED TIMESTAMP WITH TIME ZONE); ALTER SESSION SET TIME_ZONE = 'America/Los_Angeles'; INSERT INTO EMAIL_RESPONSE VALUES (1,SYSDATE,SYSDATE); ALTER SESSION SET TIME_ZONE = 'America/Chicago'; SELECT EMAIL_SENT FROM EMAIL_RESPONSE; If this code is executed at ‘01-DEC-11 02:00:00.000000000’ in the ‘America/Los_Angeles’ time zone, and the offset between Los Angeles and Chicago is +02:00, then what time value is displayed as a result of the SELECT statement? A. ‘01-DEC-11 02:00:00.000000000’ B. ‘01-DEC-11 04:00:00.000000000’ C. ‘01-DEC-11 02:02:00.000000000’ D. None of the above 15. Examine the code displayed in 14, and consider the result of this SQL statement if it were executed after that code: SELECT EXTRACT(TIMEZONE_REGION FROM EMAIL_RECEIVED) "Region" FROM EMAIL_RESPONSE; Which of the following is the most likely response to the preceding SQL statement? (Choose the one best answer.) A. ‘America/Los_Angeles’ B. ‘America/Chicago’ C. +02:00 D. ‘01-DEC-11’ Self Test Answers 271 Self Test Answers Describe Various Types of Functions That Are Available in SQL 1. ˛ C. They always return a single value. ˝ A, B, and D are incorrect. 2. ˛ C. They are generally used to process text data. ˝ A, B, and D are incorrect. They do not all accept characters as input parameters—some, such as SUBSTR, take numeric input parameters. They do not always return a character value—LENGTH does not. And they do not all have CHAR in their function name. 3. ˛ A, C, and D. The functions that are reviewed in this chapter are known as built-in functions and are available to be used anywhere in SQL where an expression can be used. That includes a SELECT statement’s expression list, an UPDATE statement’s SET clauses, an INSERT statement’s list of input values, and the WHERE clause of any SQL statement— SELECT, UPDATE, and DELETE. ˝ B is incorrect. Built-in functions and user-defined functions are separate categories. Both can be invoked from the same places—such as a SELECT statement’s WHERE clause—but user-defined functions are written in languages such as PL/SQL. This chapter only looked at built-in functions. Use Character, Number, and Date Functions in SELECT Statements 4. ˛ A. The SUBSTR function will extract data from the string (‘2009’) starting at the first position (1), and lasting for 2 characters (2), resulting in an answer of ‘20’. The LTRIM function will trim off all occurrences of the ‘1’ from the left side of ‘1124’, resulting in ‘24’. The two results are concatenated together for a final result of ‘2024’. ˝ B, C, and D are incorrect. There is no syntax error present in the code. Even though the values evaluated by both functions include data that consists of numerals, both are enclosed in single quotes and therefore are treated as character data. Even if they were not enclosed in single quotes, SQL would perform an automatic datatype conversion anyway. 5. ˛ A. The result will be 1. The ABS function determines absolute value. As the innermost function, it will be evaluated first, resulting in an answer of 1.7. The ROUND function will process the value of 1.7 and round it to the nearest two digits to the right of the decimal point, and the result will still be 1.7. Finally, TRUNC will truncate the value down to a one. ˝ B, C, and D are incorrect. 272 Chapter 6: Using Single-Row Functions to Customize Output 6. ˛ C. None of the above is correct. ˝ A, B, and D are incorrect. SOUNDEX is only used on the right side of the WHERE clause comparison, and that means the value for FRANKLIN will be converted to its SOUNDEX code and then compared to the actual last names in the table. Without looking at the SOUNDEX lookup table, we can tell that the SOUNDEX code will be a single letter F followed by some three numbers. Therefore it cannot possibly be either A or B. And there’s certainly enough information presented in the scenario to recognize that the answer cannot be either A nor B. 7. ˛ C. The answer will be –2. First, the LAST_DAY function will transform the value of ‘15-JAN-12’ to ‘31-JAN-12’, and then the result of that will be added to 1, so that the first of February will result: ‘01-FEB-12’. The difference between that date and ‘01-APR-12’ will be a negative 2. ˝ A, B, and D are incorrect. Describe the Use of Conversion Functions 8. ˛ B. The TO_CHAR function would work, along with a format model, such as TO_ CHAR(rawNumber, ‘$999,999.99’). ˝ A, C, and D are incorrect. The TO_NUMBER function works with format masks, but it converts from characters to numeric values, not the other way around. You may be able to use a combination of concatenation and string literals, but it would be painstakingly difficult, particularly in a dynamic environment where the significant numbers involved could fluctuate. There is no MONEY datatype in Oracle SQL. 9. ˛ C. The correct format mask is ‘HH:MI:SS’. ˝ A, B, and D are incorrect. TO_CHAR with no format mask executes successfully but does nothing and shows the date alone. There is no ‘SE’ format mask. Answer D is tricky—it works, and it produces output, but the ‘MM’ format mask indicates months, not minutes, and is logically incorrect. 10. ˛ B. The TO_YMINTERVAL function is correct, with the single parameter of a string containing two numbers, separated by a dash, where the first represents years in the interval, and the second represents the number of months in the interval. ˝ A, C, and D are incorrect. There is no TO_INTERVALYM function. And the use of a colon is inappropriate in the TO_YMINTERVAL function. Manage Data in Different Time Zones—Use Various Datetime Functions 11. ˛ A. DATE cannot store fractional seconds. It can store year, month, day, hours, minutes, and seconds. But not fractional seconds. Self Test Answers 273 ˝ B, C, and D are incorrect. Both the TIMESTAMP WITH LOCAL TIME ZONE and TIMESTAMP datatypes have the ability to store fractional seconds. So can TIMESTAMP WITH TIME ZONE. INTERVAL DAY TO SECOND also can store fractional seconds. 12. ˛ B. TIMESTAMP WITH TIME ZONE will record the time as is, and any future query will retrieve it as is, regardless of the origination of the query. ˝ A, C, and D are incorrect. TIMESTAMP cannot store time zone information. TIMESTAMP WITH LOCAL TIME ZONE will translate time data into the user session’s time zone. 13. ˛ A. TZD means a time zone with Daylight Saving Time built in. Other examples include EDT, EST, CST, and PDT. ˝ B, C, and D are incorrect. TZH is time zone hours. TZM is time zone minutes. TZR is time zone region. 14. ˛ B. The TIMESTAMP WITH LOCAL TIME ZONE datatype ensures that datetime data stored at a particular time will adjust when the session time zone changes. In this case, we moved our session time zone to an alternative with a plus two hour time difference. That means that if we stored our data at 2 a.m. local time in Los Angeles, then at the same time it’s 4 a.m. in Chicago. ˝ A, C, and D are incorrect. 15. ˛ A. ‘America/Los_Angeles’ is the time zone region for the EMAIL_RECEIVED column, and since the datatype is TIMESTAMP WITH TIME ZONE, the time zone is stored within the value and extracted, regardless of the location of the end user executing the query—who, in this instance, is executing the query from a local session that’s been set to ‘America/Chicago’. ˝ B, C, and D are incorrect. The TIMESTAMP WITH TIME ZONE retains the time zone of the value, as opposed to ‘America/Chicago’, which is the time zone of the local session. +02:00 is the offset, not a value for TIMEZONE_REGION. ‘01-DEC-11’ is a date literal. This page intentionally left blank 7 Reporting Aggregated Data Using the Group Functions Certification Objectives 7.01 Identify the Available Group Functions 7.02 Describe the Use of Group Functions 7.03 Group Data by Using the GROUP BY Clause 7.04 3 Q&A Include or Exclude Grouped Rows by Using the HAVING Clause Two-Minute Drill Self Test 276 Chapter 7: Reporting Aggregated Data Using the Group Functions T his chapter reviews the features in SQL that identify individual rows in a given table and aggregate summary information about them. We’ll look at aggregate functions, and also at two new clauses in the SELECT statement: the GROUP BY clause and its companion, the HAVING clause.You will need to fully understand these capabilities in order to pass the exam. Certification Objective 7.01 Identify the Available Group Functions The functions we reviewed in the last chapter are referred to as single-row functions. The term “single-row” means that each function returns one value for each one row it encounters. Another term for “single-row” function is scalar function. There is a second category of functions that is referred to as group functions. A group function returns one value for each set of zero or more rows it encounters. Another term for group function is multirow or aggregate function. Aggregate functions are typically used with a SELECT statement that selects many rows, where the aggregate function scans a set of rows and returns a single answer for all of them. Table 7-1 shows a summary list of some of the more commonly used aggregate functions available in SQL. Table 7-1 Function(s) Description Commonly Used Aggregate Functions— Overview COUNT, SUM, MIN, MAX, AVG, MEDIAN The more commonly used aggregate functions VARIANCE, VAR_POP, VAR_SAMP, COVAR_POP, COVAR_SAMP, STDDEV, STDDEV_POP, STDDEV_SAMP Variance and standard deviation, with options for population standard deviation and cumulative standard deviation RANK, DENSE_RANK, PERCENT_RANK PERCENTILE_CONT, PERCENTILE_DISC, CUME_DIST, FIRST, LAST Ranking functions and associated keywords GROUP_ID, GROUPING, GROUPING_ID Grouping features for use with GROUP BY . . . ROLLUP and CUBE Describe the Use of Group Functions 277 The first thing to recognize about aggregate functions is that they n Process data from zero or more rows. n Return one—and only one—row’s worth of data as their result. Aggregate functions can work with different datatypes. While numeric aggregate functions are the most common, some aggregates process data with character and date datatypes. Aggregate functions must be treated separately from scalar functions because they behave differently and impose a variety of requirements on any SELECT statement that might invoke them. For example, since only one value is returned for any set of zero or more rows, then a typical single SELECT statement cannot mix aggregate and scalar functions in the same select list—after all, if single-row expressions return one value per row, but multirow functions return only one value, then how can tabular output be structured? There are limited exceptions to this, which we’ll study in this chapter. But for now, note that you cannot mix scalar and aggregate functions using what we’ve reviewed so far in this book. We’ll review the detailed functionality of some of the more commonly used aggregate functions in the next section. Certification Objective 7.02 Describe the Use of Group Functions Aggregate functions can be called from four places in a SELECT statement: the select list, the ORDER BY clause, and either of two new clauses we’ll look at in this chapter: the GROUP BY clause and the HAVING clause. Both the GROUP BY and HAVING clauses are unique to the SELECT statement; they do not exist in other SQL statements. The major aggregate functions are described in detail in the following sections. COUNT Syntax: COUNT(e1) Parameters: e1 is an expression. e1 can be any datatype. The COUNT function determines the number of occurrences of non-NULL values. It considers the value of an expression and determines if that value is NOT NULL for each row it encounters. 278 Chapter 7: Reporting Aggregated Data Using the Group Functions Figure 7-1 The VENDORS table For example, let’s work with the VENDORS table, shown in Figure 7-1. Let’s look at all the rows in the VENDORS table: SELECT VENDOR_NAME, STATUS, CATEGORY FROM VENDORS; Here’s the output, showing that we have two rows in the table: VENDOR_NAME STATUS CATEGORY -------------------- ---------------------- ---------Acme Steaks 17 Acme Poker Chips We haven’t selected every column here, and we don’t need to for our purposes. But assume that the blank entries in the output are NULL values, and not blank spaces—so that the STATUS column contains only one value, and CATEGORY has none. Now let’s look at the following SELECT statement that tries to count occurrences of data in each of these columns: SELECT COUNT(VENDOR_NAME), COUNT(STATUS), COUNT(CATEGORY) FROM VENDORS; COUNT(VENDOR_NAME) COUNT(STATUS) COUNT(CATEGORY) ---------------------- ---------------------- ---------------------2 1 0 Notice that COUNT ignores any and all values that are NULL. Finally, we can simply count the number of rows in the entire table: SELECT COUNT(*) FROM VENDORS; COUNT(*) ---------------------2 Describe the Use of Group Functions 279 COUNT will only return the value of non-NULL values in columns. Recall that “SELECT * FROM table” is the shorthand way of asking to SELECT all the columns in a given table. The COUNT function is often used with the asterisk in this fashion to get a quick count on all the rows in a given table using COUNT(*). We could have mixed these functions in various combinations: SELECT COUNT(*), COUNT(VENDOR_NAME) FROM VENDORS; COUNT(*) COUNT(VENDOR_NAME) ---------------------- ---------------------2 2 Note that a COUNT of the asterisk is asking for a count of all rows. In the rare situation where a row contains nothing but NULL values, COUNT(*) will still count that row. It’s worth noting that COUNT will never return a NULL value. If it encounters no values at all, it will at least return a value of 0 (zero).This is not the case with all of the aggregates, but it’s true with COUNT. This becomes important when working with subqueries, which we’ll study in Chapter 9. The DISTINCT and ALL operators can be used with aggregate functions. For example, here is an example showing DISTINCT and ALL used within a COUNT function: SELECT COUNT(DISTINCT LAST_NAME), COUNT(ALL LAST_NAME) FROM EMPLOYEES; COUNT(DISTINCTLAST_NAME) COUNT(ALLLAST_NAME) ------------------------ ---------------------5 7 The COUNT function counts occurrences of data, not NULL values. But when combined with the asterisk, as in “SELECT COUNT(*) FROM VENDORS”, it counts occurrences of rows—and will include rows with all NULL values in the results. This example tells us that the table called EMPLOYEES has seven rows with values for LAST_NAME, of which five are unique values for LAST_NAME, so two are duplicates. Also remember that DISTINCT and/or ALL cannot be used with the asterisk. 280 Chapter 7: SUM Reporting Aggregated Data Using the Group Functions Syntax: SUM(e1) Parameters: e1 is an expression whose datatype is numeric. The SUM function adds numeric values in a given column. It only takes numeric data as input. SUM adds all the values in all the rows and returns a single answer. For example: SELECT SUM(SUBTOTAL) FROM ORDERS; Such a query will add up all of the values for SUBTOTAL in the ORDERS table and produce a single result. Another example: SELECT SUM(SUBTOTAL) FROM ORDERS WHERE ORDER_DATE = SYSDATE; This query will find any and all rows for which ORDER_DATE is equal to the system’s date for today, and then add up all of the values in the SUBTOTAL column and produce a single answer. MIN, MAX Syntax: MIN(e1); MAX(e1) Parameters: e1 is an expression with a datatype of character, date, or number. For a given set of rows identified by a SELECT statement, MIN returns the single minimum value, and MAX returns the single maximum value. MIN and MAX can work with numeric, date, and character data, and they use the same basic logic that ORDER BY uses for the different datatypes: n Numeric n Data Low numbers are MIN; high numbers are MAX. Earlier dates are MIN; later dates are MAX. ‘A’ is less than ‘Z’; ‘Z’ is less than ‘a’. The string value ‘2’ is greater than the string value ‘100’. The character ‘1’ is less than the characters ‘10’. Earlier dates are less than later dates. n Character For example, consider the following list of data from the table EMPLOYEES: LAST_NAME -----------------------------Hoddlestein Smith Describe the Use of Group Functions 281 Lindon West Worthington Now let’s identify MIN and MAX values: SELECT MIN(LAST_NAME), MAX(LAST_NAME) FROM EMPLOYEES; MIN(LAST_NAME) MAX(LAST_NAME) ------------------------------ -----------------------------Hoddlestein Worthington Note that “Hoddlestein” is alphabetically the first value from the list of LAST_ NAME values. Even though the data returned by MIN and MAX represents the data found within a single row in the list, do not be tricked into thinking that this represents a “singlerow” answer—it does not. SQL sees each response of MIN and MAX as an “aggregate” answer, meaning that the individual value is the answer representing the full set of rows. AVG Syntax: AVG(e1) Parameters: e1 is an expression with a numeric datatype. The AVG function computes the average value for a set of rows. AVG only works with numeric data. It ignores NULL values. For example, let’s look at the PAY_HISTORY table; after that, we’ll ask for the average value of all the values within the SALARY column. SELECT PAY_HISTORY_ID, SALARY FROM PAY_HISTORY; PAY_HISTORY_ID ---------------------1 2 3 4 5 6 SALARY ---------------------73922 47000 58000 37450 91379 45500 SELECT AVG(SALARY) FROM PAY_HISTORY; AVG(SALARY) ---------------------58875.1666666666666666666666666666666667 282 Chapter 7: Reporting Aggregated Data Using the Group Functions While we’re at it, we can nest the results of this query within the scalar function ROUND, like so: SELECT ROUND(AVG(SALARY),2) FROM PAY_HISTORY; ROUND(AVG(SALARY),2) ---------------------58875.17 We can get really fancy and format the data using the TO_CHAR function and a format model: SELECT TO_CHAR(ROUND(AVG(SALARY),2),'$999,999.99') FROM PAY_HISTORY; TO_CHAR(ROUND(AVG(SALARY),2),'$999,999.99') ------------------------------------------$58,875.17 In these last few examples of SELECT statements, we’ve nested a single aggregate function within two scalar, or single-row, functions. You can incorporate a single aggregate function within as many nested scalar functions as you wish. The aggregate function need not be the innermost function—you can include one aggregate function with any number of scalar functions in a nested combination, provided that all of the parameter datatypes are respected. But if you wish to include two aggregate functions within a nested combination, hold off—we’ll address that issue later in this chapter. It’s more complex than it might appear. DISTINCT and ALL are available for use with AVG. In the event that a table’s data listing includes some repeated values, the use of DISTINCT will transform the results so that the average is computed only on unique occurrences of each value. MEDIAN Syntax: MEDIAN(e1) Parameters: e1 is an expression with a numeric or date datatype. MEDIAN can operate on numeric or data datatypes. It ignores NULL values. The MEDIAN function is somewhat related to AVG. MEDIAN performs as you might expect: from a set of data, MEDIAN returns either the middle value or, if that isn’t easily identified, then an interpolated value from within the middle. In other words, MEDIAN will sort the values, and if there is an odd number of values, it will identify the value in the middle of the list; otherwise, if there an even number of values, it will locate the two values in the middle of the list and perform linear interpolation between them to locate a result. Describe the Use of Group Functions 283 Here’s an example—if you were to execute the following SQL statements: CREATE INSERT INSERT INSERT SELECT TABLE TEST_MEDIAN(A NUMBER(3)); INTO TEST_MEDIAN VALUES (1); INTO TEST_MEDIAN VALUES (10); INTO TEST_MEDIAN VALUES (3); MEDIAN(A) FROM TEST_MEDIAN; The value returned by the SELECT statement would be 3. RANK Syntax: RANK(c1) WITHIN GROUP (ORDER BY e1) Parameters: c1 is a constant; e1 is an expression with a datatype matching the corresponding c1 datatype. Numeric and character pairs are allowed. In this format, the parameters can be repeated in such a way that for each c1, you can have a corresponding e1, for each c2 (if included), there must be a corresponding e2, etc. Each successive parameter is separated from the previous parameter by a comma, as in RANK(c1, c2, c3) WITHIN GROUP (ORDER BY e1, e2, e3) Also, the datatype of c1 must match the datatype of e1, and the datatype of c2 (if included) must match the datatype of e2, etc. The RANK function calculates the rank of a value within a group of values. Ranks may not be consecutive numbers, since SQL counts tied rows individually, so if three rows are tied for first, they will each be ranked 1, 1, and 1, and the next row will be ranked 4. For example: SELECT FROM RANK(300) WITHIN GROUP (ORDER BY SQ_FT) SHIP_CABINS; RANK(300)WITHINGROUP(ORDERBYSQ_FT) ---------------------------------6 This answer of 6 is telling us when we sort the rows of the SHIP_CABINS table, and then consider the literal value 300 and compare it to the values in the SQ_FT column, that the value 300, if inserted into the table, and if sorted with the existing rows, would be the sixth row in the listing. In other words, there are five rows with a SQ_FT value less than 300. 284 Chapter 7: Reporting Aggregated Data Using the Group Functions FIRST, LAST Syntax: aggregate_function KEEP (DENSE_RANK FIRST ORDER BY e1) aggregate_function KEEP (DENSE_RANK LAST ORDER BY e1) Parameters: e1 is an expression with a numeric or character datatype. The aggregate functions FIRST and LAST are similar. For a given range of sorted values, they return either the first value (FIRST) or the last value (LAST) of the population of rows defining e1, in the sorted order. For example: SELECT FROM MAX(SQ_FT) KEEP (DENSE_RANK FIRST ORDER BY GUESTS) "Largest" SHIP_CABINS; Largest ---------------------225 In this example, we are doing the following: n First, we’re sorting all the rows in the SHIP_CABINS table according to the value in the GUESTS column, and identifying the FIRST value in that sort order, which is a complex way of saying that we’re identifying the lowest value for the GUESTS column. n For all rows with a GUEST value that matches the lowest value we just found, determine the MAX value for SQ_FT. In others, display the highest number of square feet for any and all cabins that accommodate the lowest number of guests according to the GUESTS column. Experienced professionals might recognize that FIRST and LAST perform tasks that can also be done with certain usages of self-joins or views, which we examine in later chapters. While self-joins and views are beneficial for a variety of reasons, the use of FIRST or LAST as shown above will achieve performance improvements over the alternative approaches. GROUPING The aggregate function GROUPING is discussed in detail in its own section in Chapter 13. Group Data by Using the GROUP BY Clause 285 Others There are more aggregate functions than are described in this section. They include functions to work with nested tables, functions to perform linear regression analysis, and various forms of statistical analysis. These functions aren’t specifically referenced in the certification exam guide objectives, so we won’t review them all here. But you can find full descriptions of them in Oracle Corporation’s SQL Language Reference Manual. Certification Objective 7.03 Group Data by Using the GROUP BY Clause The GROUP BY clause is an optional clause within the SELECT statement. Its purpose is to group sets of rows together and treat each individual set as a whole. In other words, GROUP BY identifies subsets of rows within the larger set of rows being considered by the SELECT statement. In this way, it’s sort of like creating a series of “mini-select” statements within the larger SELECT statement. Let’s take another look at the SHIP_CABINS table, which now has some new columns since the last time we worked with it (see Figure 7-2). Figure 7-2 The SHIP_CABINS table 286 Chapter 7: Reporting Aggregated Data Using the Group Functions Let’s run this SELECT statement against the table, looking only at rows where SHIP_ID = 1: SELECT FROM WHERE SHIP_CABIN_ID, ROOM_NUMBER, ROOM_STYLE, ROOM_TYPE, WINDOW, GUESTS, SQ_FT SHIP_CABINS SHIP_ID = 1; The results are shown here: SHIP_CABIN_ID ------------1 2 3 4 5 6 7 8 9 10 11 12 ROOM_NUMBER ----------102 103 104 105 106 107 108 109 110 702 703 704 ROOM_STYLE ---------Suite Stateroom Suite Stateroom Suite Suite Stateroom Stateroom Stateroom Suite Suite Suite ROOM_TYPE ---------------Standard Standard Standard Standard Standard Royal Large Standard Large Presidential Royal Skyloft WINDOW -----Ocean Ocean None Ocean None Ocean None None None None Ocean Ocean GUESTS -------4 2 4 3 6 5 2 2 2 5 5 8 SQ_FT -------533 160 533 205 586 1524 211 180 225 1142 1745 722 This data listing shows several rows of data. Take a look at the column called SQ_FT, showing the number of square feet of each room on the ship. Let’s compute the average square feet for rooms and round off the answer: SELECT FROM WHERE ROUND(AVG(SQ_FT),2) SHIP_CABINS SHIP_ID = 1; The result: ROUND(AVG(SQ_FT),2) ---------------------647.17 That’s the average for all of the cabins on the ship. But look at the data listing, and you’ll see that each of the ship’s cabins seems to fall into one of two different categories according to the data in the ROOM_STYLE column. Each room is either a ‘Suite’ or a ‘Stateroom’. Group Data by Using the GROUP BY Clause 287 If we wanted to look at the average for the two individual values for ROOM_ STYLE, we could run two individual queries, like this: SELECT FROM WHERE ROUND(AVG(SQ_FT),2) SHIP_CABINS SHIP_ID = 1 AND ROOM_STYLE = 'Stateroom'; ROUND(AVG(SQ_FT),2) ---------------------196.2 SELECT FROM WHERE ROUND(AVG(SQ_FT),2) SHIP_CABINS SHIP_ID = 1 AND ROOM_STYLE = 'Suite'; ROUND(AVG(SQ_FT),2) ---------------------969.29 That is useful information, but a relatively cumbersome way to get it. Using this approach, we have to (a) identify the individual values for ROOM_STYLE and type them carefully into our queries, (b) run multiple queries, and (c) obtain our output via multiple queries. The better way to get this done is with the GROUP BY clause. We can get the same information by telling SQL to “group” the rows according to their values for ROOM_STYLE, whatever they may be. Here’s the query: SELECT FROM WHERE GROUP BY ROOM_STYLE, ROUND(AVG(SQ_FT),2) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE; ROOM_STYLE ---------Suite Stateroom ROUND(AVG(SQ_FT),2) ---------------------969.29 196.2 In this particular example, we add the GROUP BY clause to tell SQL to “group” the rows that have the same value for ROOM_STYLE, and then compute the AVG function for each group, rather than for all of the rows in the table. Note that we’re still using the WHERE clause, so we only address rows with a SHIP_ID value of 1. 288 Chapter 7: Reporting Aggregated Data Using the Group Functions To get an idea of what SQL does with this query, let’s first sort the rows according to ROOM_STYLE and highlight the two different groups of rows. SHIP_CABIN_ID ------------1 3 5 6 10 11 12 2 4 7 8 9 ROOM_NUMBER ----------102 104 106 107 702 703 704 103 105 108 109 110 ROOM_STYLE ---------Suite Suite Suite Suite Suite Suite Suite Stateroom Stateroom Stateroom Stateroom Stateroom ROOM_TYPE ---------------Standard Standard Standard Royal Presidential Royal Skyloft Standard Standard Large Standard Large WINDOW -----Ocean None None Ocean None Ocean Ocean Ocean Ocean None None None GUESTS -------4 4 6 5 5 5 8 2 3 2 2 2 SQ_FT -------533 533 586 1524 1142 1745 722 160 205 211 180 225 Our GROUP BY query didn’t include an ORDER BY clause, but we chose to sort these rows to highlight the fact that there are two groups of rows. Note the values in the column ROOM_STYLE. Note that the rows with a ROOM_STYLE of ‘Suite’ are italicized and those with a ROOM_STYLE of ‘Stateroom’ are in bold. Now go back and look at our SELECT statement. Did we specify anything about ‘Suite’ or ‘Stateroom’? Not specifically. We didn’t have to. The directive to GROUP BY ROOM_STYLE tells SQL to “group” each set of rows that share the same value for ROOM_STYLE, whatever that may be. We could have included multiple aggregate functions in this query’s select list if we wanted to, for example: SELECT ROOM_STYLE, ROUND(AVG(SQ_FT),2) "Average SQ FT", MIN(GUESTS) "Minimum # of Guests", COUNT(SHIP_CABIN_ID) "Total # of cabins" FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_STYLE; ROOM_STYLE ---------Suite Stateroom Average SQ FT ---------------------969.29 196.2 Minimum # of Guests ---------------------4 2 Total # of cabins ---------------------7 5 Group Data by Using the GROUP BY Clause 289 The rules for forming a GROUP BY clause are as follows: n The GROUP BY can specify any number of valid expressions, including columns of the table. n Generally the GROUP BY is used to specify columns in the table that will contain common data, in order to “group” rows together for performing some sort of aggregate function on the set of rows. n The only items allowed in the select list of a SELECT that includes a GROUP BY clause are n Expressions that are specified in the GROUP BY n Aggregate functions n Expressions that are specified in the GROUP BY do not have to be included in the SELECT statement’s select list. Let’s try grouping this same set of rows by something else. In this query, we’ll group by the ROOM_TYPE column instead. We’ll add a few other features as well: SELECT ROOM_TYPE, TO_CHAR(ROUND(AVG(SQ_FT),2),'999,999.99') "Average SQ FT", MAX(GUESTS) "Maximum # of Guests", COUNT(SHIP_CABIN_ID) "Total # of cabins" FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_TYPE ORDER BY 2 DESC; ROOM_TYPE Average SQ FT -------------------- ------------Royal 1,634.50 Presidential 1,142.00 Skyloft 722.00 Standard 366.17 Large 218.00 Maximum # of Guests ---------------------5 5 8 6 2 Total # of cabins ---------------------2 1 1 6 2 Notice the following changes to our query: n As we stated, we chose to GROUP BY the ROOM_TYPE column. We also put ROOM_TYPE in the select list. n We added an ORDER BY clause that is sorting on the second column from the select list, which in this case is the AVG of the SQ_FT column. 290 Chapter 7: Reporting Aggregated Data Using the Group Functions n We replaced the MIN function with the MAX function, just for fun. n Unrelated to the GROUP BY functionality, we chose to put a format model with the AVG output to clean it up a little. n We also added a column alias for each of the last three expressions, omitting the optional keyword AS for each alias. Notice the results of our modified SELECT with GROUP BY clause: n The values for ROOM_TYPE are automatically listed, and in this case, five values were found—so we have five rows in our output, each representing a set of rows in the source table. n The aggregate functions of AVG, MIN, and COUNT are all calculated for each individual group. That last point is important. It’s the entire purpose of the GROUP BY function. If you don’t understand it, then try this—look at the output of the first row, which is for the ROOM_TYPE value of ‘Royal’, and consider that the individual row you are seeing in the output is the same data you would get if you ran this query alone, without the GROUP BY clause: SELECT TO_CHAR(ROUND(AVG(SQ_FT),2),'999,999.99') "Average SQ FT", MAX(GUESTS) "Maximum # of Guests", COUNT(SHIP_CABIN_ID) "Total # of cabins" FROM SHIP_CABINS WHERE SHIP_ID = 1 AND ROOM_TYPE = 'Royal' ORDER BY 1 DESC; Average SQ FT Maximum # of Guests Total # of cabins ------------- ---------------------- ---------------------1,634.50 5 2 In the preceding query, we’ve eliminated the GROUP BY clause and introduced a WHERE clause to only look at ROOM_TYPE = ‘Royal’. The result is the same data we find in the first row of the GROUP BY we ran earlier, except for the text value of ‘Royal’, which we can’t include in this SELECT. The reason we can’t include it: a SELECT can only include expressions in the select list that are defined at the same level of detail as each other. The aggregate functions AVG, MAX, and COUNT—and all other aggregate functions—have the effect of defining a single value representing all of the rows in the SELECT statement. This is why they are called “aggregate” functions: they represent the “aggregate” of all the rows. A single column value cannot do that—ah, that is, unless we specify that column within a GROUP BY clause. Putting a scalar (single-row) value in a GROUP BY clause has Group Data by Using the GROUP BY Clause 291 the effect of transforming the reference to that column into an aggregate value, thus transforming it to the level where its value represents the aggregate of rows, just like an aggregate function. Grouping by a particular column essentially transforms that column into an aggregate value—if only temporarily for the purpose of the query. Multiple Columns You can use GROUP BY with multiple columns: SELECT ROOM_STYLE, ROOM_TYPE, TO_CHAR(MIN(SQ_FT),'9,999') "Min", TO_CHAR(MAX(SQ_FT),'9,999') "Max", TO_CHAR(MIN(SQ_FT)-MAX(SQ_FT),'9,999') "Diff" FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_STYLE, ROOM_TYPE ORDER BY 3; ROOM_STYLE ---------Stateroom Stateroom Suite Suite Suite Suite ROOM_TYPE Min Max Diff -------------------- ------ ------ -----Standard 160 205 -45 Large 211 225 -14 Standard 533 586 -53 Skyloft 722 722 0 Presidential 1,142 1,142 0 Royal 1,524 1,745 -221 In the preceding example, note the following: n The GROUP BY clause includes two columns from the table: ROOM_STYLE and ROOM_TYPE. This tells SQL to group all rows that share the same value for both the ROOM_STYLE and the ROOM_TYPE columns, and apparently there are six such groups, according to the output. n The SELECT statement’s select list happens to include the ROOM_STYLE and ROOM_TYPE columns in the same positions as they are in the GROUP BY clause; this is not required, but it makes the output listing easy to read. n The ORDER BY clause tells SQL to sort the rows based on the value in the third item in the select list, which is the MIN aggregate function. n Each of the aggregate functions is formatted with the TO_CHAR format model, to include commas where appropriate and narrow the columns to a reasonable width. 292 Chapter 7: Reporting Aggregated Data Using the Group Functions n The final column in our select list is an expression that calculates the MIN and MAX values and determines the difference between them, and formats the results. Clearly there’s a lot going on in this SELECT statement, but it’s a great example of a GROUP BY in action. ORDER BY Revisited When a GROUP BY is used in a SELECT statement, then if there is an ORDER BY clause included as well, its use will be somewhat restricted. The list of columns and/or expressions in an ORDER BY that is part of a SELECT statement that uses GROUP BY is limited to the following: n Expressions specified in the GROUP BY clause n Expressions specified in the select list, referenced by position, name, or alias n Aggregate functions, regardless of whether the aggregate function is specified elsewhere in the SELECT statement n The functions USER, SYSDATE, and UID A single SELECT statement can produce output at just one level of aggregation.This is why a SELECT statement cannot mix scalar and aggregate values in a select list. One thing you cannot include in the ORDER BY is this: columns in the table that aren’t specified in the GROUP BY clause. That’s not the case for SELECT statements in general—in a scalar SELECT you can ORDER BY columns in the table whether they are included in the SELECT or not. But that’s not true when a GROUP BY is involved. ORDER BY is more limited. Nesting Functions You might recall from our examples that we’ve nested functions in some of our SQL statements. The concept of nesting functions refers to the practice of positioning a function in such a way that the value it returns becomes the input parameter for another function. For example: SELECT TO_CHAR(MEDIAN(SQ_FT),'999.99') FROM SHIP_CABINS; Group Data by Using the GROUP BY Clause 293 In this example, the MEDIAN aggregate function is “nested” within the TO_CHAR function. Thus the MEDIAN function, in this example, is the “inner” function, and it returns a value that becomes an input parameter to the TO_CHAR conversion function, which is the “outer” function. As long as the datatypes match up, nesting is allowed. In this instance, MEDIAN can only be used like this if it is returning a value of the datatype that TO_CHAR can accept. Now, remember that there are two general types of functions: single-row, or scalar, functions; and multirow, or aggregate, functions. Scalar functions return one value for each row encountered by the SQL statement in which the scalar function is applied. Aggregate functions return one value for every zero or more rows encountered by the SQL statement. The rules for nesting functions differ, depending on whether you are nesting aggregate or scalar functions. Scalar functions can be nested multiple times, as long as the datatypes match. The reason is that scalar functions all operate on the same level of detail within the rows—for every one row, a scalar function returns one value. Aggregate functions, on the other hand, behave differently than scalar functions when it comes to nesting. The reason is that aggregates combine data from multiple rows into a single row. Once that has been accomplished, your resulting value no longer represents the same level of detail you were originally dealing with. For example, let’s look again at the SHIP_CABINS table and consider a simple SELECT statement with a GROUP BY clause: SELECT FROM WHERE GROUP BY ROOM_STYLE, ROOM_TYPE, MAX(SQ_FT) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE; ROOM_STYLE ---------Stateroom Suite Stateroom Suite Suite Suite ROOM_TYPE -------------------Standard Standard Large Skyloft Royal Presidential MAX(SQ_FT) ---------------------205 586 225 722 1745 1142 This SELECT groups rows according to ROOM_STYLE and ROOM_TYPE, as we’ve seen, and displays the MAX value for SQ_FT within each group. The result is six rows, which tells us that we have six unique groups for ROOM_STYLE and ROOM_TYPE. It tells us nothing about the number of rows that might be found 294 Chapter 7: Reporting Aggregated Data Using the Group Functions within the source data—but just so you know, it’s the same data list we saw earlier in this chapter, which consisted of twelve rows. Now let’s try to compute the AVG value of these six MAX values: SELECT FROM WHERE GROUP BY ROOM_STYLE, ROOM_TYPE, AVG(MAX(SQ_FT)) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE; If we try to execute this SELECT statement, this will be the result: Error starting at line 1 in command: SELECT ROOM_STYLE, ROOM_TYPE, AVG(MAX(SQ_FT)) FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_STYLE, ROOM_TYPE Error at Command Line:1 Column:9 Error report: SQL Error: ORA-00937: not a single-group group function 00937. 00000 - "not a single-group group function" Why are we getting this error? The reason is simple: by introducing AVG into the SELECT statement’s expression list, we are moving up the level of aggregation a higher degree, and we are informing SQL that we simply want one answer for all of those grouped rows. The problem: our GROUP BY is trying to display only one answer for all the rows, but there are six different ROOM_STYLE and ROOM_ TYPE values for those rows—there is no single answer that can represent all six of those rows. One solution is to modify our SELECT statement by removing items from the select list that are at inconsistent levels of detail, like this: SELECT FROM WHERE GROUP BY AVG(MAX(SQ_FT)) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE; AVG(MAX(SQ_FT)) ---------------------770.833333333333333333333333333333333333 Now we get an answer, and we can see the result displays in just one row, which in turn represents the six rows from the previous query, which itself represented twelve rows. So we have aggregated 12 rows into 6, and then 6 into 1—all with one Group Data by Using the GROUP BY Clause 295 query. In other words, this latest SELECT statement and its AVG result represents an aggregation of an aggregation. Let’s try a third level of nested aggregate: SELECT FROM WHERE GROUP BY COUNT(AVG(MAX(SQ_FT))) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE; Error starting at line 1 in command: SELECT COUNT(AVG(MAX(SQ_FT))) FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_STYLE, ROOM_TYPE Error at Command Line:1 Column:19 Error report: SQL Error: ORA-00935: group function is nested too deeply 00935. 00000 - "group function is nested too deeply" It can’t be done. Two levels deep is the furthest you can go with nested aggregate functions. However—we are allowed to introduce nested scalar functions at any time. For example: SELECT FROM WHERE GROUP BY ROUND(AVG(MAX(SQ_FT))) SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE; ROUND(AVG(MAX(SQ_FT))) ---------------------771 To sum up: n You are allowed to nest aggregate functions up to two levels deep. n Each time you introduce an aggregate function, you are “rolling up” lower- level data into higher-level summary data. n Your SELECT statement’s select list must always respect the level of aggregation and can only include expressions that are all at the same level of aggregation. And finally—remember that scalar functions can be nested at any time and have no effect on modifying the levels of row aggregation. 296 Chapter 7: Reporting Aggregated Data Using the Group Functions Certification Objective 7.04 Include or Exclude Grouped Rows by Using the HAVING Clause The HAVING clause can exclude specific groups of rows defined in the GROUP BY clause. In other words, it performs the same task as the WHERE clause does for the rest of the SELECT statement. The difference is that WHERE deals with individual rows, while HAVING deals with groups of rows as defined in the GROUP BY clause. The HAVING clause does not define the groups of rows themselves; those groups must already be defined by the GROUP BY clause. HAVING defines the criteria upon which each of the GROUP BY groups will either be included or excluded. The HAVING clause can only be invoked in a SELECT statement where the GROUP BY clause is present. If it is included, GROUP BY and HAVING must follow WHERE (if included) and precede ORDER BY (if included). Table 7-2 shows these relationships. The HAVING function can be used like the WHERE clause to determine which rows will be included—or excluded—from your query. HAVING deals with the groups of rows identified in the GROUP BY clause. Any group that is identified in GROUP BY can be referenced by HAVING to be included in or excluded from the SQL statement. Table 7-2 Sequence Clause Required / Optional? Clauses in a SELECT Statement 1 SELECT Required 2 FROM Required 3 WHERE Optional 4 GROUP BY Optional 4 HAVING Optional 6 ORDER BY Optional Note HAVING is only allowed with a GROUP BY clause. HAVING and GROUP BY may occur in either order. Include or Exclude Grouped Rows by Using the HAVING Clause 297 For example: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 SELECT ROOM_STYLE, ROOM_TYPE, TO_CHAR(MIN(SQ_FT),'9,999') "Min" FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROOM_STYLE, ROOM_TYPE HAVING ROOM_TYPE IN ('Standard', 'Large') OR MIN(SQ_FT) > 1200 ORDER BY 3; ROOM_STYLE ---------Stateroom Stateroom Suite Suite ROOM_TYPE Min -------------------- -----Standard 160 Large 211 Standard 533 Royal 1,524 In this example, we’ve added the HAVING clause, which is on lines 7 and 8. The output starts on line 11. In this example, the HAVING clause consists of 07 08 HAVING OR ROOM_TYPE IN ('Standard', 'Large') MIN(SQ_FT) > 1200 This HAVING restricts the groups identified in the GROUP BY clause to only those rows where ROOM_TYPE = ‘Standard’ or ROOM_TYPE = ‘Large’, OR the value for MIN(SQ_FT) is greater than 1200. As the preceding example shows, HAVING can use the same Boolean operators that WHERE does—AND, OR, and NOT. The only restrictions on HAVING: n It can only be used in SELECT statements that have a GROUP BY clause. n It can only compare expressions that reference groups as defined in the GROUP BY clause, and aggregate functions. HAVING can include scalar functions as long as these restrictions are respected. In other words, a scalar function can be incorporated into a larger expression that references a GROUP BY group or an aggregate function. Just remember that HAVING deals with groups of rows, not individual rows. 298 Chapter 7: Reporting Aggregated Data Using the Group Functions Certification Summary Multirow functions differ from single-row functions in that they return one value for a group of rows, whereas single-row functions return one answer for each individual row. Single-row functions are also referred to as “scalar” functions; multirow functions are also referred to as “aggregate” functions. The available aggregate functions in SQL include the commonly used functions COUNT, SUM, MIN, MAX, AVG, and MEDIAN. There are functions to support standard deviation and variance, ranking, linear regression analysis, grouping with ROLLUP and CUBE, XML support, and working with nested tables. Aggregate functions can be called from four places in a SELECT statement: the select list, the GROUP BY clause, the HAVING clause, and the ORDER BY clause. If an aggregate function appears in the select list of the SELECT statement, then all other expressions must be at the same level of aggregation. You cannot mix scalar and aggregate values together in the select list. The GROUP BY clause specifies one or more expressions that SQL is to use to group rows together. Any values displayed in the SELECT output must be displayed once for each group. In this fashion, the GROUP BY can transform a single column reference into an “aggregate” reference by specifying that column as a GROUP BY item. Any column or expression specified in the GROUP BY clause can also be included in the SELECT statement’s select list. However, this is not required. The HAVING clause can be used to filter out groups that have been specified with the GROUP BY clause. HAVING works much like the WHERE clause does: while the WHERE clause filters out individual rows, HAVING does the same thing for groups of rows. HAVING is only allowed if the GROUP BY clause is also present. If HAVING and GROUP BY are included in a SELECT statement, they must follow the WHERE clause (if used) and precede the ORDER BY clause (if used). GROUP BY often precedes HAVING, but the two can occur in either order in the SELECT statement’s syntax. Two-Minute Drill 3 299 Two-Minute Drill Identify the Available Group Functions q Group functions are also known as aggregate, or multirow, functions. q Multirow functions return one value for every set of zero or more rows considered within a SELECT statement. q There are group functions to determine minimum and maximum values, calculate averages, and more. q Group functions can be used to determine rank within a group of rows. Describe the Use of Group Functions q Aggregate and scalar data cannot be included in the same SELECT statement’s select list. q The COUNT function counts occurrences of data, as opposed to the SUM function, which adds up numeric values. q The MIN and MAX functions can operate on date, character, or numeric data. q The AVG and MEDIAN functions can perform average and median calculations, and they can ignore NULL values in their computations. q Some functions such as RANK use the keywords ‘WITHIN GROUP (ORDER BY)’ to process a value and identify its ranking within the overall set of rows in the data set. Group Data by Using the GROUP BY Clause q The GROUP BY clause is an optional clause in the SELECT statement in which you can specify how to group rows together in order to process them as a group. q The row groups identified by GROUP BY can have aggregate functions a pplied to them, so that the final result of the SELECT is not a single aggregate value, but a series of aggregate function results, one per group. q GROUP BY can specify columns in a table, which will have the effect of grouping rows in the SELECT that share the same values in those columns. 300 Chapter 7: Reporting Aggregated Data Using the Group Functions q Whatever you specify in the GROUP BY may also be included in the SELECT statement’s select list—but this is not required. q The effect of GROUP BY on a column is to change that column into an “aggregate” value; in other words, by grouping rows that have common data for a given column, and by specifying the column in the GROUP BY, you elevate the information in the column from “scalar” to “aggregate” for the purposes of that SELECT statement. q GROUP BY can specify one or more expressions. Include or Exclude Grouped Rows by Using the HAVING Clause q The HAVING clause is an optional clause for the SELECT statement that works in coordination with GROUP BY. q You cannot use HAVING unless GROUP BY is present. q HAVING specifies groups of rows that will be included in the output of the SELECT statement. q HAVING performs the same function for GROUP BY that WHERE performs for the rest of the SELECT statement. q HAVING specifies groups using the same expression logic and syntax that WHERE would use. q The GROUP BY and HAVING clauses are not required, but if used, they must follow the WHERE clause and precede the ORDER BY clause. q While GROUP BY typically precedes HAVING in common practice, this is not required, and they can appear in either order. Self Test 301 Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Identify the Available Group Functions 1. Aggregate functions: (Choose two.) A. Return one value for each group of rows specified in a SELECT statement. B. Are also called group functions. C. Must be used in SELECT statements that select multiple rows. D. Can only operate with numeric data. 2. Review the following illustration: Now review this SQL statement: SELECT CRUISE_ORDER_ID, COUNT(ORDER_DATE) FROM CRUISE_ORDERS; What can be said of this statement? A. It will fail to execute because ORDER_DATE is a date datatype, and no aggregate function can work with a date datatype. B. It will fail to execute because it mixes scalar and aggregate data in the select list. C. It will execute successfully but not produce any meaningful output. D. There is nothing wrong with the SQL statement. Describe the Use of Group Functions 3. Which of the following aggregate functions can be used on character data? (Choose two.) A. COUNT B. MIN C. AVG D. MEDIAN 302 Chapter 7: Reporting Aggregated Data Using the Group Functions 4. Examine the following data listing of a table called PERMITS: PERMIT_ID --------1 2 3 FILED_DATE ---------05-DEC-09 12-DEC-09 14-DEC-09 VENDOR_ID --------101 310903 101 Which one of the following aggregate functions could be used to determine how many permits have been filed by VENDOR_ID 101? A. SUM B. COUNT C. MEDIAN D. HAVING 5. Review the illustration from question 2, and then review the following SQL statement: SELECT AVG(CRUISE_ORDER_ID), MIN(ORDER_DATE) FROM CRUISE_ORDERS; What will result from an attempt to execute this SQL statement on the CRUISE_ORDERS table? A. It will fail with an execution error, because you cannot use the AVG function on a PRIMARY KEY column. B. It will fail with an execution error, because you cannot use the MIN function on a DATE datatype. C. It will fail with an execution error if the table contains only one row. D. It will execute and perform as intended. 6. Review the following data listing from a table SCORES: SCORE_ID -------1 2 3 TEST_SCORE ---------95 85 Now consider the following query: SELECT TO_CHAR(AVG(TEST_SCORE),'999,999.99') FROM SCORES; What will be the result of this query? Self Test A. B. C. D. 303 It will result in a syntax error because of the TO_CHAR function. It will result in an execution error. 90.00. 60.00. 7. Review the following illustration: Which of the following SQL statements will execute correctly? A. SELECT RANK(100000) WITHIN GROUP (ORDER BY PROJECT_COST) FROM PROJECTS; B. SELECT RANK(100,000) WITHIN GROUP (ORDER BY PROJECT_COST) FROM PROJECTS; C. SELECT RANK(7500000) GROUP BY (ORDER BY PROJECT_COST) FROM PROJECTS; D. SELECT RANK('Upgrade') WITHIN GROUP (ORDER BY PROJECT_COST) FROM PROJECTS; 8. Which of the following aggregate functions ignores NULL values in its calculations? (Choose all that apply.) A. MEDIAN B. AVG C. SUM D. MAX 9. An aggregate function can be called from: (Choose two.) A. The HAVING clause of an INSERT statement B. The ORDER BY clause of a SELECT statement C. The expression list of a DELETE statement D. The select list of a SELECT statement 304 Chapter 7: Reporting Aggregated Data Using the Group Functions Group Data by Using the GROUP BY Clause 10. Review the illustration from question 7. Your task is to define a SELECT statement that groups rows according to their value for PURPOSE, and for each purpose, computes the total number of DAYS. Which one of the following queries will perform this task? A. SELECT SUM(DAYS), PURPOSE FROM PROJECTS GROUP BY PURPOSE; B. SELECT SUM(DAYS), PURPOSE FROM PROJECTS GROUP BY PURPOSE, SUM(DAYS); C. SELECT PURPOSE, COUNT(DAYS) FROM PROJECTS GROUP BY PURPOSE; D. SELECT PURPOSE, RANK(DAYS) ON (ORDER BY) FROM PROJECTS GROUP BY PURPOSE; 11. Review the illustration from question 2, and then look at the SQL code that follows (line numbers are added): 01 02 03 04 SELECT FROM WHERE GROUP BY TO_CHAR(ORDER_DATE,'Q') "Quarter", COUNT(*) CRUISE_ORDERS TO_CHAR(ORDER_DATE,'YYYY') = '2009' TO_CHAR(ORDER_DATE,'Q'); Recall that the ‘Q’ format model is for quarter, so that TO_CHAR using a DATE datatype with the ‘Q’ format mask is translating the date into the quarter in which it falls—1, 2, 3, or 4. Given that, which of the following statements is true of the SQL statement? A. It will fail because of a syntax error in line 4, since you cannot use the TO_CHAR function in the GROUP BY clause. B. It will fail because of a syntax error in line 1, since you cannot use the TO_CHAR function with the COUNT aggregate function. C. It will execute and show the number of orders in the CRUISE_ORDERS table for each quarter in the year 2009. D. None of the above. Self Test 305 12. Review the illustration from question 7, and then look at the SQL code that follows (line numbers are added): 01 02 03 SELECT COUNT(COUNT(PROJECT_COST)) FROM PROJECTS GROUP BY PURPOSE; What will happen if you try to execute this query on the PROJECTS table? A. It will fail with a syntax error because line 1 is not correct. B. It will fail with an execution error because you cannot use a VARCHAR2 column in a GROUP BY clause. C. It will succeed and display one row for each different value in the PURPOSE column. D. It will succeed and display one row. Include or Exclude Grouped Rows by Using the HAVING Clause 13. Which of the following statements is true about HAVING? (Choose two.) A. It can be used only in the SELECT statement. B. It must occur after the GROUP BY clause. C. It must occur after the WHERE clause. D. It cannot reference an expression unless that expression is first referenced in the GROUP BY clause. 14. Review the illustration from question 7, and review the SQL statement that follows (line numbers added): 01 02 03 04 SELECT FROM GROUP BY HAVING SHIP_ID, MAX(DAYS) PROJECTS SHIP_ID AVG(PROJECT_COST) < 500000; Which of the following statements is true for this SQL statement? A. It will fail to execute due to a syntax error on line 4. B. It will include only those rows with a PROJECT_COST value of less than 500000. C. It will include only those groups of rows for a given SHIP_ID with an average value of PROJECT_COST less than 500000. D. It will fail to execute because of a syntax error on line 1. 306 Chapter 7: Reporting Aggregated Data Using the Group Functions 15. Review the illustration from question 7. Your assignment: create a SELECT statement that queries the PROJECTS table, to show the average project cost for each PURPOSE. You know there are only two values for PURPOSE in the table: ‘Upgrade’ or ‘Maintenance’. You want to restrict output to those rows where the DAYS are greater than 3. Which of the following SELECT statements will perform this task? A. SELECT PURPOSE, AVG(PROJECT_COST) FROM PROJECTS WHERE DAYS > 3 GROUP BY PURPOSE; B. SELECT PURPOSE, AVG(PROJECT_COST) FROM PROJECTS GROUP BY PURPOSE HAVING DAYS > 3; C. SELECT PURPOSE, AVG(PROJECT_COST) FROM PROJECTS GROUP BY PURPOSE, (DAYS > 3); D. SELECT PURPOSE, AVG(PROJECT_COST) FROM PROJECTS WHERE DAYS > 3 GROUP BY PURPOSE, DAYS HAVING DAYS > 3; Self Test Answers 307 Self Test Answers Identify the Available Group Functions 1. ˛ A and B. Aggregate functions return one value for each group of rows in the SELECT statement. They are also referred to as “group” functions, or “multirow” functions. ˝ C and D are incorrect. A SELECT statement may return zero rows, or one row, or multiple rows, without being required to use an aggregate function. Some aggregate functions operate on character and date datatypes; they are not restricted to numeric data. 2. ˛ B. It mixes scalar data—the CRUISE_ORDER_ID column—and aggregate data—the COUNT function applied to the ORDER_DATE column. This is not possible without a GROUP BY clause. The GROUP BY clause could be used to transform the CRUISE_ORDER_ ID column into an aggregate value by specifying “GROUP BY CRUISE_ORDER_ID” at the end of the statement before the semicolon termination character. ˝ A, C, and D are incorrect. Some aggregate functions can work with the date datatype, and COUNT is one of them. Describe the Use of Group Functions 3. ˛ A and B. COUNT numbers occurrences of data. That data can include character, date, or numeric datatypes. MIN determines the minimum value but will work with character data to determine the value representing the value that would appear first in an alphabetic sorting of the candidate values. ˝ C and D are incorrect. AVG and MEDIAN work with numeric data only. 4. ˛ B. COUNT will determine the occurrences of VENDOR_ID in the data listing. ˝ A, C, and D are incorrect. SUM adds numbers, which is not desired here. MEDIAN determines an average value. HAVING is not an aggregate function, it is a clause of the SELECT statement. 5. ˛ D. It will execute. The statement is syntactically correct. ˝ A, B, and C are incorrect. You can use AVG with a PRIMARY KEY column. It might not produce any useful information, but it’s allowed. You can also use MIN with DATE datatypes, as well as character strings. It doesn’t matter if the table has only one row; the statement will still work. You are allowed to use an aggregate function on zero, one, or more rows. 6. ˛ C. The AVG will compute by ignoring the NULL value and averaging the remaining values, resulting in an answer of 90.00. ˝ A, B, and D are incorrect. There is no syntax error here; the TO_CHAR function correctly formats the output to include commas if necessary. There will be no execution 308 Chapter 7: Reporting Aggregated Data Using the Group Functions error, either. If the AVG function included NULL values, and, say, treated them as zeros, then the answer would be 60.00. That could be accomplished with the NVL function, as in AVG(NVL(TEST_SCORE,0)). But that’s not included as an option here. 7. ˛ A. The request to RANK the literal numeric value of 100000 within the set of values for PROJECT_COST asks SQL to establish a numeric ranking for the value 100000 within the set of rows, and indicate where a row containing a value of 100000 for PROJECT_COST would fall within the sorted list, if there were such a row. ˝ B, C, and D are incorrect. The numeric literal value cannot include a comma—in other words, within the arguments for RANK, the value of “100,000” (without quotes) is not seen as one hundred thousand, but instead is seen as one hundred, followed by a second parameter of three zeros. Two parameters cannot be accepted by RANK unless there are two corresponding WITHIN GROUP expressions; there is only one in the answer provided. In answer C, the GROUP BY is misplaced. In answer D, ‘Upgrade’ represents an invalid datatype because the datatypes of both RANK and ORDER BY must match, and in this example, PROJECT_COST is a numeric datatype, as we see in the accompanying exhibit. 8. ˛ A, B, C, and D. All of the functions mentioned ignore null values. MAX in particular is worth emphasizing—remember that NULL values sort higher than NOT NULL values when ORDER BY sorts on a column containing NULL values. However, while that is true, only NOT NULL values are considered by the MAX function. The same is true for the other functions listed in the question. ˝ None are incorrect. 9. ˛ B and D. The SELECT statement allows an aggregate function to be called from the ORDER BY clause and the select list. If you specify an aggregate function from within an ORDER BY clause when a GROUP BY clause is present, the ORDER BY will sort the aggregate rows that each represent a group of rows. ˝ A and C are incorrect. There is no HAVING clause in an INSERT statement. There is no expression list in a DELETE statement. Group Data by Using the GROUP BY Clause 10. ˛ A. Some might prefer to place the PURPOSE column before the SUM(DAYS) expression in the SELECT expression list, but that is not required. ˝ B, C, and D are incorrect. Answer B is syntactically incorrect, since you cannot put an aggregate function within a GROUP BY clause. Answer C is incorrect because the COUNT function is used instead of SUM. COUNT would count the occurrences of data, rather than sum up the values. Answer D is just a random combination of reserved words and nonsense. Self Test Answers 309 11. ˛ C. The statement is syntactically correct and will execute. ˝ A, B, and D are incorrect. The TO_CHAR function is a scalar function and, as such, is not subject to the same restrictions that any aggregate function is. For example, the TO_CHAR used in the GROUP BY clause is fine. And by using the TO_CHAR expression in the GROUP BY, it can also be used in the SELECT expression list in line 1, along with the aggregate function COUNT. 12. ˛ D. It will succeed and display one row. The reason you know this is because line 1 shows an aggregate of an aggregate with a GROUP BY clause. ˝ A, B, and C are incorrect. Line 1 is correct; you are allowed to nest one aggregate within one other aggregate function. You can GROUP BY any datatype; there is no restriction on grouping by character data. If you were to use only one aggregate function, the result would display one row for each unique value of PURPOSE. But by nesting COUNT within COUNT, you are adding up all of those rows and displaying one aggregate answer. Include or Exclude Grouped Rows by Using the HAVING Clause 13. ˛ A and C. HAVING is only valid in the SELECT statement, not the other SQL statements. HAVING must occur after the WHERE clause. ˝ B and D are incorrect. HAVING cannot be used without GROUP BY, but it is not required to follow GROUP BY. HAVING is not limited to expressions identified in the GROUP BY clause; instead, it is limited to any valid expression that addresses the groups established within the GROUP BY clause. In other words, aggregate functions can be invoked from within HAVING, whether they are called by GROUP BY or not. 14. ˛ C. The statement is syntactically correct and will produce a series of rows of data. Each row will represent all values for each SHIP_ID value in the table. Each row representing each SHIP_ID will have one maximum value for DAYS. Any set of rows for SHIP_ID whose average value of PROJECT_COST is less than 500000 will be included; all others will be excluded. ˝ A, B, and D are incorrect. There is no syntax error on line 4. The HAVING clause is not required to reference anything in the GROUP BY. HAVING can reference aggregate functions; its only limitation is that it cannot directly reference columns in the table if those columns have not been included in the GROUP BY clause. (Columns omitted from GROUP BY may be incorporated in certain expressions in HAVING but cannot be directly referenced as standalone columns.) Answer B could only be true if the WHERE clause were present and filtering rows as answer B describes—the HAVING clause doesn’t include or exclude rows on an individual basis but instead includes or excludes groups of rows as defined by the GROUP BY clause and the HAVING clause. 310 Chapter 7: Reporting Aggregated Data Using the Group Functions 15. ˛ A. One of the most important aspects of understanding HAVING is to know when not to use it, and this is a great example of that—nothing in this question says anything about restricting groups of data, and that is the only reason why you would use HAVING. The WHERE clause achieves the task of ensuring that only rows where DAYS are greater than three will be considered. ˝ B, C, and D are incorrect. The task defined by the question doesn’t require HAVING. There is no description in the question that asks for anything about the GROUPS to be excluded. Answer B is syntactically incorrect because HAVING can only reference aggregate functions or columns that are identified in the GROUP BY, and this does neither. Answer C is syntactically incorrect because you cannot enclose the final expression in parentheses by itself. Answer D is syntactically correct but does not produce the answer that is described in the question—it will instead group all the rows by both PURPOSE and DAYS, which is not what was asked for—such a query can potentially produce many more rows than just the two expected. In other words, instead of getting one group of rows per value in PURPOSE, you’ll get a finer division of detail with each set of rows containing a unique combination of both PURPOSE and DAYS, and that is something different. 8 Displaying Data from Multiple Tables Certification Objectives 8.01 8.02 Write SELECT Statements to Access Data from More Than One Table Using Equijoins and Non-Equijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins Join a Table to Itself by Using a Self-Join 8.03 3 Q&A Generate a Cartesian Product of All Rows from Two or More Tables Two-Minute Drill Self Test 312 Chapter 8: Displaying Data from Multiple Tables T his chapter reviews various types of joins. A join is a SELECT statement that retrieves data from two or more tables and connects that data together to produce a combined set of output. The SELECT statement specifies data in one table that is identical to data in another table. Tables that share common data elements that support joins are said to be “related” to each other. This is why a SQL database is called a “relational database management system”; joining tables is the whole purpose of SQL database systems. This chapter will look at n Equijoins, which use the equality operator n Non-equijoins, which do not use the equality operator n INNER joins n OUTER joins n NATURAL joins n Cross-joins (also known as Cartesian products) n Self-joins We’ll discuss the syntax of all of these forms of joins, and look at the use of table aliases, as well as a number of examples. Certification Objective 8.01 Write SELECT Statements to Access Data from More Than One Table Using Equijoins and NonEquijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins There are several types of joins in SQL. The most common is the equijoin. Another is the non-equijoin. We’ll discuss both in this section. Before that, however, let’s discuss some concepts that will help us during our discussion about joining tables— let’s revisit PRIMARY KEY and FOREIGN KEY constraints. Write SELECT Statements to Access Data from More Than One Table . . . 313 KEY Relationships We’ve already seen how tables have PRIMARY KEYS and FOREIGN KEYS. Just to review: n The PRIMARY KEY is a unique identifier in a particular table. n The FOREIGN KEY is a copy of some (or all) of one table’s PRIMARY KEY data in a second table, so that the second table can relate back to the first. For example, see Figure 8-1. The PORTS and SHIPS tables both have their own primary key columns. For PORTS, it’s the PORT_ID column. For SHIPS, it’s the SHIP_ID column. And incidentally—we’re choosing to name our primary key columns with the “_ID” suffix, but that’s not required in SQL. Notice that the SHIPS table also has something called the HOME_PORT_ID column. The intent of this column is to contain values that are also found in the PORTS table’s PORT_ID column. How can you tell this is the case? Well . . . because I’m telling you now, really, there’s nothing inherent in the table structures alone that guarantees that this is the intent. The fact that the phrase PORT_ID is found in the HOME_PORT_ID column name is a clue, but not a guarantee. However, note the diagram in Figure 8-1, and the crow’s foot line in the center of the diagram that connects the two tables together. Figure 8-1 is a simple entity relationship diagram (ERD). The crow’s foot line shows you the relationship between the two entities, or tables, of SHIPS and PORTS. The line is a clue that there’s a FOREIGN KEY on the SHIPS table that relates to the PORTS table. The “F” in the SHIPS entity to the left of the HOME_PORT_ID column name indicates Figure 8-1 The PORTS and SHIPS tables 314 Chapter 8: Displaying Data from Multiple Tables that the FOREIGN KEY in SHIPS is a constraint on the HOME_PORT_ID column. However, nothing in this particular ERD indicates which column in the PORTS table is the referenced column of the FOREIGN KEY constraint. As we’ll see later in this chapter, it’s the PORT_ID column of SHIPS. This FOREIGN KEY helps to ensure that no data entered into the HOME_PORT_ID column of SHIPS will be accepted unless that data is already present in the PORT_ID column of the PORTS table. We saw earlier how to create foreign key constraints that do precisely this task. The ERD shows the crow’s foot pointing toward the SHIPS entity. This means that for every one row in PORTS, there could theoretically be many rows in SHIPS. This Entity relationship is because you can add as many rows to the diagrams (ERDs) are not mentioned in SHIPS table as you wish for any one PORT_ID the certification objectives, nor does the value, by simply repeating that value in each exam contains any questions specifically row’s HOME_PORT_ID column. But for any about ERDs per se. However, many of given SHIP table row, there can only be one the questions will ask you to consult corresponding PORT table row. The relationship an “exhibit” that will feature an ERD, between these two tables is said to be “one-toand then ask you a SQL question based many”, meaning that there can only be one row on the tables presented in the ERD. In in PORT for any number of rows in SHIPS. other words, the exam assumes you The crow’s foot points one line in the can read simple ERDs. Our self-tests direction of the “one” side of that relationship, increasingly do the same as we progress and points the “many” lines—three lines to be through the book, and our practice exams precise—in the direction of the “many” side of use the same approach as the official that relationship. certification exam. The “one-to-many” relationship does not require there to be many rows in the SHIPS table that correspond to any given row in the PORTS table. It merely allows for the possibility. The reason for including this paragraph in this chapter is to remind you why those PRIMARY KEY and FOREIGN KEY constraints exist—to support the type of joining we’re about to do in this chapter. But there’s an important point to be made here: you can join tables without the presence of PRIMARY KEY and FOREIGN KEY constraints. There is no official connection in the database between key constraints and table joins. Key constraints are helpful to provide data integrity and increase the odds of success and meaningful results from table joins. But they are not required. So—with that point established—let’s start joining tables. Write SELECT Statements to Access Data from More Than One Table . . . 315 Types of Joins Joins are characterized in many ways. One way a join is defined is in terms of whether it is an inner join or an outer join. Another issue is that of equijoins and non-equijoins. These descriptions are not mutually exclusive descriptions. Inner Versus Outer Joins There are two major categories of syntax for creating joins in Oracle SQL: n Inner joins connect rows in two or more tables if and only if there are matched rows in all the tables being joined. n Outer joins connect rows in two or more tables in a way that is more inclusive—if data exists in one table that has no matching values in another, the unmatched row will still be included in the output. Equijoins Versus Non-Equijoins Separate from the issue of inner and outer joins is the issue of equijoin versus non-equijoin: n Equijoins connect data in two or more tables by looking for common data among the tables’ columns. In other words, an equijoin looks for an exact match of data. n Non-equijoins connect data by looking for relationships that don’t involve equality, such as “less than” or “greater than” relationships, or situations where data in one table is within a range of values in another. Most of the joins we’ll work with will be equijoins, but we’ll look at non-equijoins as well. Other Joins There are other joins that we’ll review in this chapter, such as self, cross-, and natural joins. These descriptions include joins that fall into the categories we’ve already seen of “equijoin” and “non-equijoin”, or “inner” and “outer” join. We’ll review each separately. 316 Chapter 8: Displaying Data from Multiple Tables Inner Joins The first type of join we’ll review is an inner join. An inner join connects rows between two or more tables if and only if there are matched rows in all joined tables. If there isn’t a match in all tables, then none of the data for that row is included in the inner join’s output. For example, let’s connect two tables with an inner join—look again at Figure 8-1. Every ship in the SHIPS table can be assigned a home port in the PORTS table. This is recorded in the database by assigning a HOME_PORT_ID to each record in the SHIPS table. This is why the SHIPS table includes a column called HOME_PORT_ID, which is designated a FOREIGN KEY. The FOREIGN KEY constraint points to the PORT_ID column in the PORTS table, so that any entry in the SHIPS table’s HOME_PORT_ID will represent a value that already exists in the PORTS table’s PORT_ID column. Let’s look at our sample data in these tables. First the PORTS table: PORT_ID ---------------------1 2 3 4 PORT_NAME -------------------Baltimore Charleston Tampa Miami Next, the SHIPS table: SHIP_ID ---------------------1 2 3 4 5 6 SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Champion Codd Victorious Codd Grandeur Codd Prince HOME_PORT_ID ------------------1 3 3 2 2 As you can see from these data listings, many ships have a HOME_PORT_ID that matches a PORT_ID in the PORTS table. If you were to identify the home port for, say, the ‘Codd Elegance’, you would see that it’s PORT_ID 3, which is Tampa. And what you just saw in making that connection is what you have to spell out to SQL so that SQL can do the same thing. In other words, to join these tables together, we can n Identify both tables in the FROM clause, separated by the keywords INNER JOIN. n Define the column from each table that is being used to join the data in the ON condition. Write SELECT Statements to Access Data from More Than One Table . . . 317 Here’s the code for an inner join: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS INNER JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; The ORDER BY is something we added; it’s not required for the join. Note that the keyword INNER is not required; we can eliminate it and go with this approach: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; This query is the same as the INNER JOIN query with one variation: we removed the optional keyword INNER from line 2. Everything else is the same. Whichever syntax we use—with or without the keyword INNER—the result is the same: SHIP_ID ---------------------1 2 4 5 6 SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Victorious Codd Grandeur Codd Prince PORT_NAME -------------------Baltimore Tampa Tampa Charleston Charleston That’s the output from our inner join. Note that we can add additional WHERE clause criteria to our join. Let’s say we wanted to restrict our output so that only the ‘Charleston’ rows were included. Let’s modify the INNER JOIN syntax: 01 02 03 04 05 SELECT FROM ON WHERE ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS INNER JOIN PORTS HOME_PORT_ID = PORT_ID PORT_NAME = 'Charleston' SHIP_ID; The result will be to limit our results to only those ships that are ported in Charleston. Now go back before we added the WHERE clause, and look at our original output from the first inner join. Do you see something missing? Look for the ‘Codd Champion’—it isn’t in the output. The reason is because the ‘Codd Champion’, 318 Chapter 8: Displaying Data from Multiple Tables aka SHIP_ID 3, has no assigned value for HOME_PORT_ID. As a result, there is no matching row in the PORTS table, and since we used an “inner join” format, we only produce output if there are matched rows in all joined tables. The result: ‘Codd Champion’ is omitted. And that’s not all—we also don’t see any value for the PORT_ID 4, ‘Miami’. The reason is the same—there is no ship assigned to Miami as a home port. This is why our join is an “inner join”. It only shows records that have matched rows in both tables. But if you want to show data from rows that aren’t necessarily matched in all tables, then you want to use the “outer join” format. Older Inner Join Syntax Before we move on to outer joins, let’s review an old variation to the syntax we just reviewed for an inner join. Here it is: 01 02 03 04 SELECT FROM WHERE ORDER BY S.SHIP_ID, S.SHIP_NAME, P.PORT_NAME SHIPS S, PORTS P S.HOME_PORT_ID = P.PORT_ID S.SHIP_ID; In this form, the join is accomplished in lines 2 and 3, where we list the joined tables in the FROM clause, and also identify the join criterion in line 3 with an equal sign. In this syntax, there is no keyword JOIN or ON. The WHERE clause can include additional criteria as any WHERE clause might, for example: 01 02 03 04 05 SELECT FROM WHERE AND ORDER BY S.SHIP_ID, S.SHIP_NAME, P.PORT_NAME SHIPS S, PORTS P S.HOME_PORT_ID = P.PORT_ID PORT_NAME = 'Charleston' S.SHIP_ID; This is the older form of an inner join that Oracle has used, and it still works. But the version we reviewed earlier—the version that uses the JOIN and ON keywords—is preferred and is consistent with the ANSI standard for SQL joins. Outer Joins An outer join is a join that displays data from the same rows an inner join does, but also adds data from rows that don’t necessarily have matches in all the tables that are joined together. There are three types of outer joins—LEFT, RIGHT, and FULL. Each is described here. Write SELECT Statements to Access Data from More Than One Table . . . 319 LEFT OUTER JOIN To see one type of outer join in action, let’s continue with our example and modify our query just a little to make it an outer join: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS LEFT OUTER JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; Notice the addition of the keyword LEFT in line 2. The resulting output of this code is SHIP_ID ---------------------1 2 3 4 5 6 SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Champion Codd Victorious Codd Grandeur Codd Prince PORT_NAME -------------------Baltimore Tampa Tampa Charleston Charleston By changing our FROM clause from a JOIN to a LEFT OUTER JOIN, we have changed the query from an inner join to an outer join. (Remember that JOIN defaults to INNER JOIN.) And notice that our output now includes data for SHIP_ ID 3. Also notice that the row for SHIP_ID 3 shows no value for PORT_NAME, which is correct—no HOME_PORT_ID value was assigned to it. Also note: the OUTER keyword is optional. In other words, this is just as good: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS LEFT JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; In this example, OUTER is omitted, but the effect is the same. RIGHT OUTER JOIN But we still don’t see our PORT_NAME of ‘Miami’. So let’s change our query again: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS RIGHT OUTER JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; 320 Chapter 8: Displaying Data from Multiple Tables Note that we’ve replaced the keyword LEFT with the keyword RIGHT in line 2. The result: SHIP_ID ---------------------1 2 4 5 6 SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Victorious Codd Grandeur Codd Prince PORT_NAME -------------------Baltimore Tampa Tampa Charleston Charleston Miami We’ve now included the row for ‘Miami’. But we lost our row with the ‘Codd Champion’. That’s because this RIGHT OUTER JOIN favors unmatched rows on the right side of the join, which is the PORTS table (see line 2 of the SELECT statement), but we took away our LEFT OUTER JOIN to SHIPS. As before, OUTER is optional. RIGHT JOIN will do the same thing as RIGHT OUTER JOIN. FULL OUTER JOIN If we want to combine the effects of a RIGHT OUTER JOIN and LEFT OUTER JOIN together, we can use the FULL OUTER JOIN: 01 02 03 04 SELECT FROM ON ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS FULL OUTER JOIN PORTS HOME_PORT_ID = PORT_ID SHIP_ID; Line 2 shows the use of the keywords FULL OUTER JOIN, and the output is: SHIP_ID ---------------------1 2 3 4 5 6 SHIP_NAME -------------------Codd Crystal Codd Elegance Codd Champion Codd Victorious Codd Grandeur Codd Prince PORT_NAME -------------------Baltimore Tampa Tampa Charleston Charleston Miami And here we have all of our records, matched or not. And as before—you guessed it—the keyword OUTER is optional. Write SELECT Statements to Access Data from More Than One Table . . . 321 Deprecated Outer Join Syntax: (+) And now a word to my fellow longtime veteran Oracle professionals. If you’ve been looking for the plus sign somewhere in the syntax for our discussion on inner and outer joins, you’re out of luck. The famous—or infamous—plus sign, a longtime friend of many veteran Oracle professionals, is on its way out the door. It still works. But Oracle Corporation is in the process of kicking it to the curb. Oracle Corporation has officially declared it deprecated. This is what I mean: if you were to go back to the LEFT OUTER JOIN example, and translate it back into the old form of Oracle table joins, the SELECT statement would look like this: 01 02 03 04 SELECT FROM WHERE ORDER BY SHIP_ID, SHIP_NAME, PORT_NAME SHIPS, PORTS HOME_PORT_ID = PORT_ID(+) SHIP_ID; Note the special characters at the end of line 3. The plus sign in parentheses defines this query as a left outer join. The plus sign is on the right side in order to define a left outer join. This is the old syntax, and it still works. But it’s not on the exam. It was never ANSI standard anyway. Furthermore, Oracle Corporation formally recommends that you avoid using it from now on and stick with the keywords INNER JOIN, OUTER JOIN, and all the other related keywords. The old format still works. But you won’t be tested on it—you’ll be tested on the new format. Using Table Aliases In our examples so far, we’ve joined tables using columns that have had different column names. This isn’t always the case, however. For example, look at the two tables in Figure 8-2. The EMPLOYEES table and the ADDRESSES table both have a column called EMPLOYEE_ID. That column is the PRIMARY KEY in EMPLOYEES, and it’s the FOREIGN KEY in ADDRESSES. Using what we’ve seen so far, we might try this syntax: 01 02 03 SELECT FROM ON EMPLOYEE_ID, LAST_NAME, STREET_ADDRESS EMPLOYEES INNER JOIN ADDRESSES EMPLOYEE_ID = EMPLOYEE_ID; 322 Chapter 8: Displaying Data from Multiple Tables Figure 8-2 The EMPLOYEES and ADDRESSES tables There’s a problem with this syntax. Look at line 1. The first item in our SELECT statement’s select list is EMPLOYEE_ID, but which table’s EMPLOYEE_ID are we intending here? Chances are it won’t make that much of a difference with regard to data display, since both columns contain the same data—unless we use a form of OUTER JOIN, in which case there may be a difference. Regardless, that’s no help to us here, because SQL will reject this statement anyway due to the ambiguous column reference. One solution is to use the full table name as a prefix to the column: 01 02 03 SELECT FROM ON EMPLOYEES.EMPLOYEE_ID, LAST_NAME, STREET_ADDRESS EMPLOYEES INNER JOIN ADDRESSES EMPLOYEES.EMPLOYEE_ID = ADDRESSES.EMPLOYEE_ID; We’ve added the full table name in front of each reference to EMPLOYEE_ID, separated by a period, to clarify our intent. Note that we needed to make these changes three times—once on line 1, and twice on line 3. This is perfectly acceptable and represents clear and thorough design. Write SELECT Statements to Access Data from More Than One Table . . . 323 There’s an alternative, however, and it’s the table alias. Here’s an example of the table alias in action: 01 02 03 SELECT FROM ON EM.EMPLOYEE_ID, LAST_NAME, STREET_ADDRESS EMPLOYEES EM INNER JOIN ADDRESSES AD EM.EMPLOYEE_ID = AD.EMPLOYEE_ID; First look at line 2. After each table referenced in the FROM clause, we left a space, followed by a name we specify. The name needs to match the rules for naming database objects. For EMPLOYEES we chose EM, and for ADDRESSES we chose AD. We could have chosen anything within the rules of naming database objects. Since we chose to create table aliases, we were also able to use the table alias as prefixes on lines 1 and 3. The result is a more easily readable query. There’s no right or wrong answer as to which approach you should choose—either the full table name prefix or the table alias prefix. Either way, you should consider the following points: n When writing any query in which a column reference is ambiguous, you must do something to identify the column clearly to the SQL statement. Otherwise, you’ll get an error message and the SQL statement won’t execute. n The use of table prefixes and table aliases is on the exam. The table alias is more commonly used, in my ever-so-humble opinion. But both work. Also note: table aliases can be used in INSERT, UPDATE, and DELETE statements, as well as SELECT. NATURAL Joins So far, many of the examples we’ve seen have joined tables using columns of different names—such as HOME_PORT_ID and PORT_ID. It’s more common, however, for such columns to be named with the same name. In other words, when database designers create two tables and intend to link them together, it’s good design to give identical names to any columns that will be linked. That’s not to say the opposite is true—it’s not necessarily bad design to do otherwise—it all depends on readability and intent. But the point for our discussion here is that you will often work with tables that share identical column names, and it will be these columns upon which your joins will probably be built. For example, review Figure 8-2 again. As we saw in the last section, the two tables shown both have a column called EMPLOYEE_ID. This column is a FOREIGN KEY in the ADDRESSES table, and the PRIMARY KEY of the EMPLOYEES table. 324 Chapter 8: Displaying Data from Multiple Tables The natural join approach tells SQL to locate any columns in the two tables with a common name, and use them to join the tables. Here’s an example: 01 02 SELECT FROM EMPLOYEE_ID, LAST_NAME, STREET_ADDRESS EMPLOYEES NATURAL JOIN ADDRESSES; Notice the use of the keywords NATURAL JOIN in line 2. Also notice that there’s no keyword ON anywhere, and nowhere that we establish the join between the two common columns—which in these two tables are EMPLOYEES.EMPLOYEE_ID and ADDRESSES.EMPLOYEE_ID. The NATURAL JOIN doesn’t require an explicit declaration of these columns, provided that the column names are identical. Also notice something else: see the reference to EMPLOYEE_ID in line 1? Remember that there are two EMPLOYEE_ID columns—one in EMPLOYEES and one in ADDRESSES. Normally such a reference in a join would require a table alias. But the natural join forbids such table prefixes on join column names. Their use would result in a syntax error. However, table prefixes are allowed on other columns—but not the join columns in a natural join. Finally, a natural join is an inner join. This is why the NATURAL JOIN syntax can get away without a table alias in line 1 above—by restricting itself to an inner join, the EMPLOYEE_ID column will always have the same value, regardless of which table’s EMPLOYEE_ID is intended. Unmatched rows are omitted in an inner join. You cannot perform an outer join with the NATURAL keyword. But there’s something similar that will support outer joins, and it’s the USING keyword— that’s next. USING The keyword USING is similar to the natural join, in the sense that its use depends on the presence of identically named columns in the JOIN. However, USING can be used with both inner and outer joins. For example: 01 02 03 SELECT FROM EMPLOYEE_ID, LAST_NAME, STREET_ADDRESS EMPLOYEES LEFT JOIN ADDRESSES USING (EMPLOYEE_ID); Note the syntax here—we’re using a LEFT JOIN on two tables that share the same column name EMPLOYEE_ID. As we’ve already seen, this is a variation of an outer join. The keyword OUTER is optional and omitted from this example. Notice the keyword USING on line 3. USING is followed by a column name enclosed in parentheses. No table name prefix is allowed before the column name, not here, and not elsewhere in the statement—such as line 1. Write SELECT Statements to Access Data from More Than One Table . . . 325 Since the table name prefix is not allowed in line 1, how do you know which table’s EMPLOYEE_ID is intended in the select list in line 1? The answer is that it may be one or the other, depending on the row. In an outer join, which is also an equijoin, the values in both tables for EMPLOYEE_ID will either be identical to each other, or will include one NULL value in one of the two table’s columns. The output, therefore, will show a value if any is present in either table; otherwise, a NULL value will display. The reason this works is that the values will never conflict in an outer join —the join condition, by definition, will reject conflicting values and exclude rows with conflicting values for the join condition. The result is this: if you include the join column in the select list—such as the EMPLOYEE_ID column in line 1 of the example—then the output of an outer join’s “join column” specified with the USING clause will show a value wherever a value is present in either table’s join column; otherwise, it will display a NULL value. The USING keyword does basically the same thing as the natural join in the sense that the connection between the joined tables is performed automatically. The difference is that USING lets us perform an outer join as well as an inner join. Multitable Joins So far we’ve only looked at joins that connect two tables. But joins can connect two, three, or more tables. For example, see Figure 8-3. These three tables can be joined together in a SELECT statement like this: 01 02 03 SELECT FROM P.PORT_NAME, S.SHIP_NAME, SC.ROOM_NUMBER PORTS P JOIN SHIPS S ON P.PORT_ID = S.HOME_PORT_ID JOIN SHIP_CABINS SC ON S.SHIP_ID = SC.SHIP_ID; Notice the syntax for this SELECT statement that joins three tables: n The FROM keyword appears once. n After line 2, when the original two-table join completes, line 3 opens with the keyword JOIN. n Line 3 continues with the third table name, followed by a table alias, followed by the explicitly defined join criteria. Line 3 in the preceding SELECT statement can be repeated and edited as required in order to join additional tables beyond these three. 326 Chapter 8: Displaying Data from Multiple Tables Figure 8-3 PORTS, SHIPS, and SHIP_CABINS tables Non-Equijoins So far, all the joins we’ve seen have been equijoins. In other words, the joins have used columns containing common data values among the join tables, and joined rows in the tables based on finding equal values in the join columns. Non-equijoins relate one row to another by way of non-equal comparisons, such as comparisons of greater or lesser value, or perhaps comparisons that look for a range of values. Such joins are unusual but important. And they are part of the certification exam criteria. Let’s look at an example. See Figure 8-4. Write SELECT Statements to Access Data from More Than One Table . . . 327 Figure 8-4 The SCORES and GRADING tables Note that these tables do not have a FOREIGN KEY relationship. As we’ve already noted, that is not required in order to join tables. Let’s look at some data in these tables. First, SCORES: SCORE_ID ---------------------1 2 3 TEST_SCORE ---------95 55 83 Next, GRADING: GRADING_ID ---------------------1 2 3 4 5 GRADE ----A B C D E SCORE_MIN ---------------------90 80 70 60 50 SCORE_MAX -----------100 89 79 69 59 The idea here is that the SCORES table lists some actual scores on exams, and the GRADING table contains information about grading criteria. In the SCORES table, we have a row of data showing that the test identified with a SCORE_ID of 1 received a score of 95. According to the GRADING table, that should be a grade of A. Let’s create a SELECT statement that joins these tables together to determine each test score’s grades (line numbers added): 01 02 03 SELECT S.SCORE_ID, S.TEST_SCORE, G.GRADE FROM SCORES S JOIN GRADING G ON S.TEST_SCORE BETWEEN G.SCORE_MIN AND G.SCORE_MAX; 328 Chapter 8: Displaying Data from Multiple Tables Note the syntax of this join. On line 2 we have a typical JOIN syntax, but on line 3, instead of the equijoin, we connect the two tables by comparing the value in the TEST_SCORE column of SCORES and see if it’s BETWEEN the values for the GRADING table’s SCORE_MIN and SCORE_MAX columns. Here is the output: SCORE_ID ---------------------1 3 2 TEST_SCORE ---------95 83 55 GRADE ----A B E This is an example of a non-equijoin. The syntax of the ON condition in a non-equijoin is similar to the syntax for the WHERE clause in the SELECT, in that you can use comparison expressions, the ‘greater than’ or ‘less than’ operators, SQL functions, and Boolean operators to connect a series of comparisons together. Certification Objective 8.02 Join a Table to Itself by Using a Self-Join A self-join is a table that is joined to itself. A self-join connects a column in a table with a column—often a different column—in the same table. (Note: Syntactically you can join a column to itself in the same table, as opposed to a different column in the same table. It doesn’t do much logically, but the syntax will execute.) Self-joins can use all the same variations on join criteria that any other table join can use. In other words, self-joins can be inner joins or outer joins, equijoins or nonequijoins, etc. Let’s write a self-joining SELECT statement. For starters, see Figure 8-5. The POSITIONS table lists job titles within our Codd Cruises organization. Here’s a listing of some of the columns in the POSITIONS table: POSITION_ID ---------------------1 2 3 4 5 POSITION -------------------Captain Director Manager Crew Chief Crew REPORTS_TO ---------------1 2 2 4 Join a Table to Itself by Using a Self-Join 329 Figure 8-5 The POSITIONS table Note the column REPORTS_TO. It indicates that, for example, the ‘Crew Chief’ reports to the position of POSITION_ID 2, which is ‘Director’. Self-Referencing Foreign Keys The POSITIONS table is supported with a foreign key that points to itself, which is created with this SQL statement: ALTER TABLE POSITIONS ADD CONSTRAINT FK_PO_PO FOREIGN KEY (REPORTS_TO) REFERENCES POSITIONS (POSITION_ID); Note that a foreign key is advised, but not required in order to perform the self-join. Self-Join Syntax Now that we have our table, our data, and our optional foreign key constraint, let’s look at a query that will connect all of this together. To create the self-join, we need to do the following: n Identify the table twice in the FROM clause. n Define our join criteria—which in this case will be an OUTER join so that we can include the highest-level position that doesn’t have a REPORTS_TO value—and therefore isn’t “matched” with anything. n Apply a table alias to all appropriate references, being careful to join the REPORTS_TO column in the first table reference to the POSITION_ID column in the second table reference. 330 Chapter 8: Displaying Data from Multiple Tables Here’s the query: SELECT FROM ON ORDER BY A.POSITION_ID, A.POSITION, B.POSITION BOSS POSITIONS A LEFT OUTER JOIN POSITIONS B A.REPORTS_TO = B.POSITION_ID A.POSITION_ID; And here’s the output: POSITION_ID ---------------------1 2 3 4 5 POSITION -------------------Captain Director Manager Crew Chief Crew Be sure you have a solid command of the join syntax for all forms of joins. That should include NATURAL, USING, and the various inner joins and outer joins. All forms are fair game on the exam. BOSS -------------------Captain Director Director Crew Chief The result: a listing of positions, and the supervisor each reports to. All of this data is found in the one table POSITIONS. You can see that in the SELECT statement’s output, both the POSITION column and the BOSS column contain data that is found in the POSITION column of the POSITIONS table. But the self-join produces a meaningful output display. Certification Objective 8.03 Generate a Cartesian Product of All Rows from Two or More Tables A Cartesian product occurs when two or more tables are included in a SELECT statement without a join condition. When a SELECT statement references two or more tables in the FROM clause without a JOIN, SQL will still execute the statement, connecting each row in one table with every row in the other. A Cartesian product is also known as a cross-join. Generate a Cartesian Product of All Rows from Two or More Tables 331 For example, consider the following data listing from table VENDORS: VENDOR_ID --------1 2 VENDOR_NAME ----------Acme Steaks Acme Poker Chips Now consider the data listing of a table ONLINE_SUBSCRIBERS: ONLINE_SUBSCRIBER_ID -------------------1 2 3 LASTNAME -------KLINE bryant McLean Finally, let’s create a Cartesian product on these two tables: SELECT * FROM VENDORS, ONLINE_SUBSCRIBERS; That’s it. The output is as follows: VENDOR_ID ---------------------1 1 1 2 2 2 VENDOR_NAME -------------------Acme Steaks Acme Steaks Acme Steaks Acme Poker Chips Acme Poker Chips Acme Poker Chips ONLINE_SUBSCRIBER_ID ---------------------1 2 3 1 2 3 LASTNAME ----------KLINE bryant McLean KLINE bryant McLean Note the result: each row of VENDORS is joined to every row of ONLINE_ SUBSCRIBERS. Another way to perform the same cross join is this: SELECT * FROM VENDORS CROSS JOIN ONLINE_SUBSCRIBERS; Note the use of the keywords CROSS and JOIN. Is this useful? I don’t think so. Even the Oracle Corporation’s SQL Language Reference Manual refers to a Cartesian product as “rarely useful”. (See the SQL Language Reference Manual, for Oracle Database Release 11.1, pages 9–11—of all things.) The most important take-away on this topic is simple: always be sure to include a join condition in your queries. If you don’t, Oracle won’t complain; it will just deluge you with exponentially many more rows of output than you probably anticipated. So watch it. 332 Chapter 8: Displaying Data from Multiple Tables A few things to consider with Cartesian products: n They are mentioned in the certification exam objectives. n There are generally considered to be a “mistake” in professional applications. n If you ever find a reasonable use for one, please let me know at soh@corbinian.com. The first person to notify me of such an application will win $10 in cash from me. That being said, they are on the exam, so know the term and the functionality. Certification Summary There are several ways to join tables in SQL. The inner join compares common values in rows of two or more tables and returns data from a row only if that row has a match in the joined table. The outer join will show a row as output whether that row has a joined row in another table or not. Some joins are equijoins, which means that they join rows in one table with rows in another table by looking for values in both rows that are equal to each other. Non-equijoins look for values that have some relationship other than equality, such as greater than, less than, or in between a range of values. Primary key and foreign key relationships help to protect the integrity of data in columns that are intended to join tables, but their presence is not required in order to create a successful join. When two or more tables are joined, any of their columns may be included in the SELECT statement’s select list. However, a syntax error may result if the two tables have columns that share the same name. In such situations, the table name can be placed in front of the column name as a prefix to eliminate any ambiguity. As an alternative, the table can be assigned an alias name that will last only long enough for the SELECT statement to execute. The alias can then be used as a prefix in front of any column name, and it may be required in front of the otherwise ambiguous column names. A natural join does not specify which columns are being used to connect two or more tables together, relying instead on the assumption that the columns to form the join have the same name as each other. Natural joins are inner joins. The USING keyword can do something similar to NATURAL, but for other forms of joins, including outer joins. USING can name the common column one Certification Summary 333 time, and the SELECT statement will complete the join based on that column, as well as eliminating the need for a table prefix or alias in front of the key column. Multi-table joins can be performed with any join. Non-equijoins use comparison operators, Boolean logic, and anything else to establish comparison logic between two or more tables in a join. A self-join occurs when a table is joined to itself. Typically one column in the table is joined to a different column in the same table. A Cartesian product results when two tables are listed in the FROM clause of a SELECT statement, but no join criteria are provided. SQL will accept the statement and execute it, joining each row in one table with every row in the other table. The results are rarely useful. 334 Chapter 8: 3 Displaying Data from Multiple Tables Two-Minute Drill Write SELECT Statements to Access Data from More Than One Table Using Equijoins and Non-Equijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins q A join is any SELECT statement that selects from two or more tables. q A join will connect rows in one table with rows in another table. q The equijoin identifies a particular column in one table’s rows, and relates that column to another table’s rows, and looks for equal values in order to join pairs of rows together. q The non-equijoin differs from the equijoin in that it doesn’t look for exact matches but instead looks for relative matches, such as one table’s value that is between two values in the second table. q The inner join compares a row in one table to rows in another table and only produces output from the first row if a matching row in the second table is found. q The outer join compares rows in two tables and produces output whether there is a matching row or not—the left outer join shows all the rows in one table and only the matching rows in the second; the right outer join does the same thing in reverse; the full outer join shows all rows in both tables one way or the other—either as a matched rowset or as a standalone row. q The table alias only exists for the duration of the SQL statement in which it is declared. q Table aliases are necessary to eliminate ambiguity in referring to columns of the same name in a join. q The natural join does not name the connecting column but assumes that two or more tables have columns with identical names, and that these are intended to be the connecting, or joining, columns. q The USING keyword can empower an inner, outer, or other join to connect based on a set of commonly named columns, in much the same fashion as a natural join. q Joins can connect two, three, or more tables. Two-Minute Drill 335 Join a Table to Itself by Using a Self-Join q The self-join connects a table to itself. q Self-joins typically connect a column in a table with another column in the same table. q Self-joins can also be referred to as recursive joins. q Self-joins can otherwise behave as equijoins, non-equijoins, inner joins, and outer joins. Generate a Cartesian Product of All Rows from Two or More Tables q The Cartesian product is also known as a cross-join. q The cross-join connects every row in one table with every row in the other table. q It is created by selecting from two or more tables without a join condition of any kind. q The Cartesian product is rarely useful. 336 Chapter 8: Displaying Data from Multiple Tables Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose all the correct answers for each question. Write SELECT Statements to Access Data from More Than One Table Using Equijoins and Non-Equijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins 1. Review the INVOICES and VENDORS tables: Which of the following is a syntactically correct outer join query? (Choose two.) A. SELECT VENDOR_NAME, INVOICE_DATE FROM ON VENDORS LEFT JOIN INVOICES VENDORS.VENDOR_ID = INVOICES.VENDOR_ID; B. SELECT VENDOR_NAME, INVOICE_DATE FROM ON VENDORS OUTER JOIN INVOICES VENDORS.VENDOR_ID = INVOICES.VENDOR_ID; C. SELECT VENDOR_NAME, INVOICE_DATE FROM ON VENDORS RIGHT OUTER JOIN INVOICES VENDORS.VENDOR_ID = INVOICES.VENDOR_ID; D. SELECT VENDOR_NAME, INVOICE_DATE FROM ON VENDORS FULL OUTER INVOICES VENDORS.VENDOR_ID = INVOICES.VENDOR_ID; Self Test 337 2. You have two tables. One table is called CUSTOMERS. Another is called PURCHASES, and it records a list of customer transactions. Your goal is to create a SELECT statement that will show all customers by last name in alphabetical order, along with any purchases they may have made in the past two weeks as recorded in the PURCHASES table. It’s possible that many customers have made no purchases in the past two weeks, but you still want them included in the output. Both tables contain a column called CUSTOMER_ID. Which of the following will be true of the SELECT statement you’ll need to create? (Choose two.) A. It will be an inner join. B. It will be an outer join. C. It will be a cross-join. D. It will be an equijoin. 3. Review the SQL statement: SELECT FROM ON V.VENDOR_ID, INV.INVOICE_DATE VENDORS V INNER JOIN INVOICES INV V.VENDOR_ID = INV.VENDOR_ID; Which one of the following keywords in this statement is optional? A. JOIN B. INNER C. ON D. All are required 4. Review the illustration from question 1 and then review the SQL statement (line numbers added): 01 02 03 SELECT VENDOR_ID, INVOICE_DATE, TOTAL_PRICE FROM VENDORS JOIN INVOICES USING (VENDOR_ID); Which of the following statements is true for the SQL statement? A. It will execute successfully. B. It will fail with a syntax error because there is no ON clause. C. It will fail with a syntax error on line 1 because VENDOR_ID is ambiguous. D. It will fail with a syntax error on line 3 because of the parentheses around VENDOR_ID. 5. Review the illustration from question 1 and then review the SQL statement (line numbers added): 01 02 03 SELECT VENDOR_ID, INVOICE_DATE, TOTAL_PRICE FROM VENDORS JOIN INVOICES USING (VENDOR_ID); 338 Chapter 8: Displaying Data from Multiple Tables What kind of join is this? (Choose two.) A. INNER B. OUTER C. NATURAL D. Equijoin 6. A table alias: (Choose two.) A. Renames a table in the database so that future joins can use the new name. B. Is the same thing as a SYNONYM. C. Exists only for the SQL statement that declared it. D. Can be used to clear up ambiguity in the query. 7. Review the POSITIONS, EMPLOYEES, and PAY_HISTORY tables: Self Test 339 Review the following SQL statement: SELECT LAST_NAME, POSITION, SALARY FROM POSITIONS P JOIN EMPLOYEES E ON P.POSITION_ID = E.POSITION_ID JOIN PAY_HISTORY PH ON E.EMPLOYEE_ID = PH.EMPLOYEE_ID; Which of the following is true for the SQL statement: (Choose two.) A. It will fail because there are no table aliases. B. It will execute successfully. C. It is an outer join. D. It connects three tables. 8. Review the illustration from question 7 and then review the following SQL statement (line numbers added): 01 02 03 SELECT A.EMPLOYEE_ID, B.POSITION FROM PAY_HISTORY A JOIN POSITIONS B ON A.SALARY < B.MAX_SALARY AND A.SALARY > B.MIN_SALARY; Which of the following statements accurately describe the SQL statement? (Choose two.) A. It contains a syntax error on line 3. B. It is an inner join. C. It is a non-equijoin. D. It contains a syntax error on line 2, and should have an additional keyword with the JOIN keyword. 9. How many tables can be included in a JOIN? A. Only two B. As many as you like, provided they are all constrained with PRIMARY KEY and FOREIGN KEY constraints to ensure that the join condition will work C. Two, three, or more D. No more than seven 10. The difference between an INNER and an OUTER join is: A. The INNER join relates a table to itself; the OUTER join relates a table to other tables. B. The INNER join displays rows that match in all joined tables; the OUTER join shows data that doesn’t necessarily match. C. The OUTER join relates a table to tables in other user accounts; the INNER does not. D. The INNER runs on data inside the table; the OUTER runs on data outside of the table. 340 Chapter 8: Displaying Data from Multiple Tables Join a Table to Itself by Using a Self-Join 11. A self-join is: (Choose two.) A. A SELECT statement that specifies one table once in the FROM clause B. A SELECT statement that specifies one table twice in the FROM clause C. A SELECT statement that joins a table to itself by connecting a column in the table to a different column in the same table D. A SELECT statement that uses the SELF JOIN keywords 12. Review the illustration from question 7. Which of the following is a valid self-join statement? (Choose all that apply.) A. SELECT P1.POSITION_ID, P1.MIN_SALARY, P1.MAX_SALARY FROM ON POSITIONS P1 JOIN POSITIONS P2 P1.REPORTS_TO = P2.POSITION_ID; B. SELECT P1.POSITION_ID, P1.MIN_SALARY, P1.MAX_SALARY FROM ON POSITIONS P1 SELF JOIN POSITIONS P2 P1.REPORTS_TO = P2.POSITION_ID; C. SELECT P1.POSITION_ID, P1.MIN_SALARY, P1.MAX_SALARY FROM ON POSITIONS P1 INNER JOIN POSITIONS P2 P1.REPORTS_TO = P2.POSITION_ID; D. SELECT P1.POSITION_ID, P1.MIN_SALARY, P1.MAX_SALARY FROM ON POSITIONS P1 RIGHT OUTER JOIN POSITIONS P2 P1.REPORTS_TO = P2.POSITION_ID; Generate a Cartesian Product of All Rows from Two or More Tables 13. Review the following SQL statement: SELECT * FROM INSTRUCTORS CROSS JOIN SCORES; The INSTRUCTORS table contains a total of three rows. The SCORES table contains a total of four rows. How many rows will the SELECT statement return? A. 3 B. 4 C. 12 D. There is not enough information to determine the answer Self Test 341 14. Review the illustration from question 1 and the following SELECT statement: SELECT VEN.VENDOR_ID, INV.INVOICE_ID, VEN.VENDOR_NAME FROM VENDORS VEN, INVOICES INV; Which of the following best describes the syntax of the SELECT statement? A. It is a natural join. B. It is rarely useful. C. It will not execute due to a syntax error. D. It will not execute due to a logic error. 15. What is the defining aspect of a SELECT statement that produces a Cartesian product? (Choose the best answer.) A. The lack of any JOIN criteria B. The keyword CARTESIAN C. A FROM statement that mentions two or more tables, but with no presence elsewhere of the keywords INNER or OUTER D. None of the above 342 Chapter 8: Displaying Data from Multiple Tables Self Test Answers Write SELECT Statements to Access Data from More Than One Table Using Equijoins and Non-Equijoins/View Data That Generally Does Not Meet a Join Condition by Using Outer Joins 1. ˛ A and C. The LEFT JOIN . . . ON syntax is correct. So is the RIGHT OUTER JOIN . . . ON syntax. Remember that the keyword OUTER is optional. ˝ B and D are incorrect. The OUTER . . . ON syntax is incorrect; there is no OUTER by itself. The FULL OUTER . . . ON syntax is also incorrect. In neither of these is the required keyword JOIN present. 2. ˛ B and D. The SELECT will have to be an outer join in order to include all records in the CUSTOMERS table whether or not they have a corresponding row in the PURCHASES table in the last two weeks. Also, since both tables contain a CUSTOMER_ID, you’ll use an equijoin to locate exact matches between the two tables. ˝ A and C are incorrect. The query cannot be an inner join, because if it were, it would only show customers who have made purchases in the past two weeks. It cannot be a cross-join, which is a Cartesian product, because all that would do is connect every customer with every purchase without any regard for whether the customer actually made the purchase, or if someone else did. 3. ˛ B. INNER is optional. When creating an INNER JOIN, you can just use the term JOIN without the reserved word INNER, and the join will be assumed to be INNER. ˝ A, C, and D are incorrect. JOIN is required. So is ON. 4. ˛ A. It will execute successfully. ˝ B, C, and D are incorrect. Even though this is a JOIN, the presence of USING eliminates the need for an ON clause. With USING, a table alias is not required, nor is one allowed in the select list. The parentheses around VENDOR_ID on line 3 are fine. 5. ˛ A and D. The INNER keyword is optional, but that is what this is by default. It’s also an equijoin, in that the two tables are joined by defining values that match equally in the VENDOR_ID column—this is specified by use of the USING clause on line 3, which is equivalent to ON VENDORS.VENDOR_ID = INVOICES.VENDOR_ID. ˝ B and C are incorrect. It is not an OUTER join; if it were, it would say so. It is not a NATURAL join for the same reason—if it were, it would say so. 6. ˛ C and D. The table alias goes away after the query is over. It can be used to clear up confusion in the syntax of a statement by adding it as a prefix at the beginning of any column that shares the same name with another column in a joined table. ˝ A and B are incorrect. The table alias is not the same as a SYNONYM. The table alias only survives within the SQL statement that calls it; after that, it goes away. Self Test Answers 343 7. ˛ B and D. It will execute successfully, and it connects three tables. ˝ A and C are incorrect. It does not require table aliases. It is an inner join, not an outer join. 8. ˛ B and C. The query is an inner join. The keyword INNER is optional and omitted in this instance. The query is a non-equijoin, wherein the ON condition compares the PAY_ HISTORY table’s SALARY column of values to the MAX_SALARY and MIN_SALARY of the POSITIONS table. ˝ A and D are incorrect. The statement contains no syntax errors. 9. ˛ C. You can join as many tables as you wish. ˝ A, B, and D are incorrect. You are not limited to two tables, nor are you required to only join tables that have constraints on them. You are not limited to seven tables. 10. ˛ B. The INNER shows only data when there’s a row-to-row match between tables, whereas OUTER can show data for rows in one table that don’t match the rows in the joined table. ˝ A, C, and D are incorrect. Wrong, wrong, wrong. Join a Table to Itself by Using a Self-Join 11. ˛ B and C. In a self-join, the table name is repeated twice in the FROM clause, and perhaps more than twice. A self-join is most commonly used to join a column in a table to a different column within the same table. ˝ A and D are incorrect. The self-join syntax names the same name twice—or more—in the FROM clause. There is no syntax in Oracle SQL involving the keywords SELF JOIN. 12. ˛ A, C, and D. All of these are valid SQL statements. The first is a typical inner join. Answer C spells out the optional word INNER for the same result as Answer A. Answer D defines a valid outer join yet is still a self-join. ˝ B is incorrect. There is no keyword SELF, as in SELF JOIN. Generate a Cartesian Product of All Rows from Two or More Tables 13. ˛ C. The SELECT statement is a cross-join, which forms a Cartesian product, since it joins two tables without providing any join criteria. Therefore it will connect each row in the first table with every row in the second table. In other words, the first of the three rows in INSTRUCTORS will be connected with every one of the four rows in SCORES, for a total of four rows. This will be repeated for all three INSTRUCTOR rows, until there are 12 rows of output (3 × 4). ˝ A, B, and D are incorrect. 344 Chapter 8: Displaying Data from Multiple Tables 14. ˛ B. The SQL statement is a Cartesian product, since no join condition is specified. Oracle’s documentation publishes commentary that specifically describes this form of a join as “rarely useful”. That being said—Cartesian products are included on the exam. ˝ A, C, and D are incorrect. The syntax is correct and the statement will execute. It is not a natural join—a natural join uses reserved words such as NATURAL. 15. ˛ A. The lack of any JOIN criteria will do it. ˝ B, C, and D are incorrect. There is no keyword CARTESIAN. The lack of keywords INNER or OUTER has no bearing on whether a query produces a Cartesian product or not. 9 Retrieving Data Using Subqueries Certification Objectives 9.01 Define Subqueries 9.07 9.02 Describe the Types of Problems That Subqueries Can Solve Solve Problems with Correlated Subqueries 9.08 Update and Delete Rows Using Correlated Subqueries 9.09 Use the EXISTS and NOT EXISTS Operators 9.10 Use the WITH Clause 9.03 List the Types of Subqueries 9.04 Write Single-Row and Multiple-Row Subqueries 9.05 Write a Multiple-Column Subquery 9.06 Use Scalar Subqueries in SQL 3 Q&A Two-Minute Drill Self Test 346 Chapter 9: Retrieving Data Using Subqueries T his chapter looks at subqueries. A subquery is a SELECT statement within a larger SQL statement. The subquery concept builds on many of the features we’ve already looked at, and expands on them in a powerful mechanism that expands the capabilities of SQL. Subqueries introduce some complexities that are important to master. They are an important part of the certification exam. Certification Objective 9.01 Define Subqueries As we’ve already seen, a query is a SELECT statement. Give that, a subquery is a SELECT statement that exists within another SQL statement—sort of a “sub” SQL statement. SQL statements that accept subqueries include SELECT, INSERT, UPDATE, and DELETE. Subqueries are not limited to DML—they can also be used in a CREATE TABLE or CREATE VIEW statement as well. Most subqueries are syntactically autonomous, meaning that you could execute the subquery successfully on its own, separate from the parent query. However, some subqueries are not standalone queries but instead are “correlated” to the larger parent query in a way that ties the two queries together. A subquery is a SELECT statement that may return one or more columns in one or more rows. A SQL statement that includes a subquery as part of its code is considered the “parent” to the subquery. A parent SQL statement may include one or more subqueries in its syntax. Subqueries may have their own subqueries. In other words, a SQL statement may have a subquery, which in turn may have another subquery within it, and on and on. The starting SQL statement in such a situation is the “toplevel” query, and any subsequent subquery that contains a subquery within it is a “parent” to its subquery. A “parent” query may also be referred to as an “outer” query. Any valid SELECT statement can qualify as a subquery of another statement. The sort of SELECT statements that can be made into a subquery include those that retrieve data from one or more tables or views, those that use complex expressions or scalar or aggregate functions, and those that include the WHERE and GROUP BY clauses, HAVING clauses, joins, or any of the other features available to SELECT statements. Describe the Types of Problems That Subqueries Can Solve 347 A subquery is not restricted to retrieving data from the same table or tables as the parent query. In fact, subqueries often retrieve data from tables other than those specified in the parent query. The tables of the subquery are not required to have any key relationship or join or other logical relationship to the tables of the parent query. But such a relationship may exist between the parent and the subquery—it’s just not required. Some subqueries can be tied into the parent query. Known as “correlated” subqueries, such statements can achieve single-statement results that cannot otherwise be accomplished by a single statement. Certification Objective 9.02 Describe the Types of Problems That Subqueries Can Solve Subqueries can be used to solve a variety of problems. Some are listed here: Subqueries can find answers to questions and then use those answers to ask new questions. In other words, in a single SELECT statement’s WHERE clause, a subquery can find data based on some criteria, then use that answer to identify a secondary answer, and then pass that answer on to the parent query, all in the same SQL statement. This can be repeated within multiple stages in ways that a standalone parent query cannot do without the use of a subquery. n Complex multistage queries A subquery can be incorporated into a CREATE TABLE statement to quickly create and populate a table from an existing data source at the time the table is created. n Creating populated tables Subqueries can be incorporated into an INSERT or UPDATE statement to move large amounts of data and insert or update many rows of information by moving data from one source into another in a single SQL statement. n Large data set manipulation A subquery is used to create view objects at the time of creation. This topic is explored in Chapter 10 in which we create views. n Creating named views 348 Chapter 9: Retrieving Data Using Subqueries A subquery can be used to replace a table reference in a FROM clause. This form of subquery, also known as an inline view, is discussed in Chapter 10. n Dynamic view definition There’s a particular form of subquery that will only return one column’s worth of data in one row—which is to say, it will return a single value. Such a subquery can be used in almost any place in a SQL statement where an expression can be used. n Dynamic expression definition with scalar subqueries As you can see, subqueries are powerful, can do a wide variety of tasks, and can occur in almost any SQL statement in almost any clause. This chapter will explore many examples of these usages of subqueries. Certification Objective 9.03 List the Types of Subqueries There are many different types of subqueries. Here are the major types: A single-row subquery returns a single row’s worth of data in its result. Single-row subqueries may include multiple columns’ worth of data, or a single column’s worth of data. n Single-row subqueries A multiple-row subquery returns zero, one, or more rows in its result. It is not guaranteed to return multiple rows, but it may do so, and thus the parent query should be structured to receive multiple rows just in case. For example, if the parent query uses an equal sign to compare its own value with the returned value of the multiple-row subquery, then the parent query (and therefore the query as a whole) may fail with an execution error—it depends on whether the multiple-row subquery actually returns multiple rows. It might not, but it certainly can at any time. Therefore the parent query to a multirow subquery typically uses a comparison operator that allows for multiple rows of values to be returned. n Multiple-row subqueries Multiple-column subqueries return more than one column in their result. This requires the parent query to receive multiple n Multiple-column subqueries Write Single-Row and Multiple-Row Subqueries 349 columns from the subquery and involves special syntax considerations. A multiple-column subquery can be either a single-row or multiple-row subquery. A correlated subquery is a subquery that specifies columns that belong to tables that are also referenced by the parent query. In a multilevel series of subqueries and sub-subqueries, the correlated parent query can be any number of levels higher than the subquery. The correlation involves more than the subquery merely accessing the same tables and columns through its own direct call to the table; rather, the correlated subquery performs row-by-row analysis in cooperation with the parent query, accessing data, and referencing that data in its own expressions, in order to coordinate row processing together with the correlated parent. Correlated subqueries can exist in SELECT, UPDATE, and DELETE statements. A correlated subquery may also be a single-row, multiple-row, or multiplecolumn subquery. n Correlated subqueries If a single-row subquery consists of only one column’s worth of output, then it is known as a scalar subquery. Scalar subqueries can be used in almost any location that an expression can be used, which is not true for other forms Note that the different of subquery. A scalar subquery can also be types of subqueries aren’t mutually correlated. exclusive. A single type of subquery may fall into multiple categories of subqueries As you can see, there are many different described in this chapter. types of subqueries. Let’s begin looking at them n Scalar subqueries in detail. Certification Objective 9.04 Write Single-Row and Multiple-Row Subqueries In this section, we’ll create subqueries that return one expression in either a singlerow or multiple-row answer. 350 Chapter 9: Retrieving Data Using Subqueries Single-Row Subqueries A single-row subquery is a SELECT statement within another SQL statement. One of its benefits is the ability to perform multiple-step queries in a single SQL statement. For example, let’s say you’re tasked with the job of identifying the names of employees of our fictional company, Codd Cruise Lines. You’re tasked to look for employees who are assigned to the same ship as an employee named Al Smith. See Figure 9-1 for the ERD of the table we’ll work with. You could perform this task in two steps. Step one: find the SHIP_ID of the ship on which Al Smith is assigned, like this: SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith' AND FIRST_NAME = 'Al'; SHIP_ID ---------------------1 Step two: use the SHIP_ID value to locate other employees on the same ship. SELECT FROM WHERE AND EMPLOYEE_ID, LAST_NAME, FIRST_NAME EMPLOYEES SHIP_ID = 1 NOT (LAST_NAME = 'Smith' AND FIRST_NAME = 'Al'); EMPLOYEE_ID ---------------------1 7 Figure 9-1 The EMPLOYEES table LAST_NAME -----------------------------Hoddlestein Worthington FIRST_NAME -------------------Howard Buffy Write Single-Row and Multiple-Row Subqueries 351 There’s an answer—in two steps. Not bad. But a subquery could have discovered the answer in one step, like this (line numbers added): 01 02 03 04 05 06 07 SELECT EMPLOYEE_ID, LAST_NAME, FIRST_NAME FROM EMPLOYEES WHERE SHIP_ID = (SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith' AND FIRST_NAME = 'Al') AND NOT (LAST_NAME = 'Smith' AND FIRST_NAME = 'Al'); This one query achieves the same thing as the previous two queries. Note what we’ve done here—we’ve edited the second of the previous two queries by replacing ‘SHIP_ID = 1’ with ‘SHIP_ID = ’ and the subquery on lines 3 through 6. We’ve literally placed the first of the previous two queries within the second of those two queries. There is an inherent risk with this particular syntax. Notice the equal sign on line 3. That’s the parent query’s way of saying that it is expecting one—and only one—row from the subquery. In other words, it is expecting this query to be a singlerow subquery. Here’s the problem: what happens if that subquery returns more than one row? What if there is more than one Al Smith in the EMPLOYEES table? Let’s find out—let try searching for employees who work on the same ship as anyone whose last name is ‘Smith’, regardless of first name: 01 02 03 04 05 06 SELECT EMPLOYEE_ID, LAST_NAME, FIRST_NAME FROM EMPLOYEES WHERE SHIP_ID = (SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith') AND NOT (LAST_NAME = 'Smith'); Error starting at line 1 in command: Error report: SQL Error: ORA-01427: single-row subquery returns more than one row 01427. 00000 - "single-row subquery returns more than one row" Notice the text of the error message: “single-row subquery returns more than one row”. In other words, we apparently do have more than one person in the EMPLOYEES table with a last name of ‘Smith’. 352 Chapter 9: Retrieving Data Using Subqueries This creates a problem. Our query has an equal sign on line 3, and that’s why our subquery is expected to be a “single-row” query. There are a few alternatives we could take here. If we wish to retain the integrity of the single-row subquery, then we need to edit that subquery to ensure that it will return one, and only one, row. There are many ways to guarantee a one-row response. For example, a subquery that uses a WHERE criterion based on a primary key or some other unique value will return only one value, like this: SELECT SHIP_ID FROM EMPLOYEES WHERE EMPLOYEE_ID = 5; Of course, that assumes you know the value for the appropriate EMPLOYEE_ID. Another example would be a subquery that returns an aggregate function without a GROUP BY clause, like this: SELECT MIN(SHIP_ID) FROM EMPLOYEES WHERE LAST_NAME = 'Smith'; Aggregate functions always return a single row, as long as no GROUP BY is involved. Logically, though, this isn’t always an option to solve the particular business challenge you might be facing. Still another example would be a subquery that uses the ROWNUM feature to limit the number of rows in the response, like this: SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith' AND ROWNUM < 2; Remember that the ROWNUM pseudocolumn assigns row numbers to the query’s output (before processing the ORDER BY clause) and can be effective in limiting output. In this example, it ensures that we only receive a one-row response. But again—this may not logically support the original intent of your query. These are examples of ways in which you might limit the subquery to one row of output. The moral of the story: use the single-row subquery when you know the result will be one row. Otherwise, you’d better use something other than the single-row subquery format, or else you’ll run the risk of an execution error. Also—if the subquery returns no rows at all, then no error will result. The query will execute, but the subquery will return a NULL value to the parent query. Keep in mind—a failed execution attempt in SQL isn’t necessarily a bad thing. Sometimes it’s a good idea to create a single-row subquery in situations where you want to deliberately fail the parent query if multiple rows are Write Single-Row and Multiple-Row Subqueries 353 found in the subquery.This can be a useful feature that can help flag bigger problems elsewhere in the database, such as the failure of a unique identifying mechanism like a primary key, or some other logical error beyond your immediate SQL code. When your SQL statements are embedded within some other programs that have the capabilities of handling failures, or “exceptions” as Oracle PL/SQL calls them, you can program those systems to take evasive or corrective actions and address what might be a much bigger problem. You can use multiple subqueries within a single WHERE clause. Here’s a SQL statement with more than one subquery (line numbers added): 01 02 03 04 05 06 07 SELECT EMPLOYEE_ID, LAST_NAME, FIRST_NAME FROM EMPLOYEES WHERE SHIP_ID = (SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith' AND FIRST_NAME = 'Al') AND NOT (LAST_NAME = 'Smith' AND FIRST_NAME = 'Al') AND SSN = (SELECT SOCIAL_NUMBER FROM EMP_BENEFITS WHERE EMP_BENEFITS_ID = 17); Notice in the example what is happening on line 6. In that portion of the query, we are comparing a parent column named SSN to the subquery column called SOCIAL_NUMBER. Subqueries do not have to share the same column name with the parent query. The only thing that is required is that the datatypes for SSN and SOCIAL_NUMBER be the same. If the datatypes match up, the comparison is valid. The comparison conditions available for use with single-row subqueries are listed in Table 9-1. Table 9-1 Single-Row Subquery Comparison Conditions Comparison Conditions Description = Equal <> Not equal != Not equal ^= Not equal > Greater than >= Greater than or equal to < Less than (Continued) 354 Chapter 9: Table 9-1 Single-Row Subquery Comparison Conditions (Continued) Retrieving Data Using Subqueries Comparison Conditions Description <= Less than or equal to LIKE Enables wildcard characters. There are two wildcard characters: _ The underscore is a wildcard character representing a single character. % The percent sign is a wildcard character representing one or more values. IN Compares one value on the left side of the operator to a set of one or more values on the right side of the operator. The set of values must be enclosed in parentheses. If the values are presented as constants, they are separated by commas, as in (‘Maple’, ‘Elm’, ‘Main’) or (2009, 2010, 2011). A query may also be used, as in (SELECT PORT_NAME FROM PORTS). The keyword IN deserves special attention. When the keyword IN is used, the parent query sees the subquery as potentially a multiple-row subquery, which we’ll discuss in the next section. So—single-row subqueries are very useful for performing multistep queries when you can guarantee that the subquery will return a single row. But when your subquery returns multiple rows, you need to take a different approach—let’s look at that next. Multiple-Row Subqueries A multiple-row subquery returns more than one row of answers to the parent query. For example, we saw in our earlier example that there is apparently more than one employee in our EMPLOYEES table with a last name of ‘Smith’. Because of that fact, we couldn’t use the single-row query format with a subquery that searched for rows with a LAST_NAME value of ‘Smith’. But we can use that subquery in the multiple-row format, as shown here (line numbers added): 01 02 03 04 SELECT FROM WHERE ORDER BY SHIP_ID, LAST_NAME, FIRST_NAME EMPLOYEES SHIP_ID IN (SELECT SHIP_ID FROM EMPLOYEES WHERE LAST_NAME = 'Smith') SHIP_ID, LAST_NAME; Now our query is asking to list the employees who work on a ship with anyone named ‘Smith’, and list the Smiths themselves. But for our purposes, note line 3, Write Single-Row and Multiple-Row Subqueries 355 where we replaced the equal sign with the reserved word IN. As a result of that one change, we no longer get an error message but instead get this: SHIP_ID ---------------------1 1 1 3 3 LAST_NAME -----------------------------Hoddlestein Smith Worthington Lindon Smith FIRST_NAME -------------------Howard Al Buffy Alice Joe Remember from our discussion of the WHERE clause and the set of comparison operators that the keyword IN allows the WHERE clause to compare one value to a set of values. The same dynamic is at work here. IN allows the subquery to return multiple rows. The presence of the keyword IN directs the parent query to allow the subquery to be a multiple-row subquery. Note that the subquery doesn’t have to return multiple rows. The presence of IN simply allows for the possibility. Notice we didn’t get an execution error this time. Instead we obtained output and can now see that we have an employee named ‘Smith’ assigned to SHIP_ID 1, and another on SHIP_ID 3. The comparison operators that can be used with a multirow subquery are listed in Table 9-2. Table 9-2 Multirow Subquery Comparison Conditions Comparison Conditions Description IN Compares a subject value to a set of values. Returns TRUE if the subject value equals any of the values in the set. Returns FALSE if the subquery returns no rows. NOT Used with IN to reverse the result. Returns TRUE if the subquery returns no rows. ANY Used in combination with single-row comparison conditions (such as = or >) to compare a subject value with a multirow subquery. Returns TRUE if the subject value finds a match consistent with the comparison operator in any of the rows returned by the subquery. Returns FALSE if the subquery returns no rows. SOME Same as ANY. (Continued) 356 Chapter 9: Table 9-2 Multirow Subquery Comparison Conditions (Continued) Retrieving Data Using Subqueries Comparison Conditions Description ALL Used in combination with single-row comparison conditions to compare a subject value with a multirow subquery. Returns TRUE if the subject value finds a match consistent with the comparison operator in all of the rows returned by the subquery. Returns TRUE if the subquery returns no rows. Example: Find all products with a price that’s greater than all of the products in the ‘Luxury’ category: SELECT * FROM PRODUCTS WHERE PRICE > ALL (SELECT PRICE FROM PRODUCTS WHERE CATEGORY = ‘Luxury’); The use of greater-than or lesser-than comparison conditions does not support multirow subqueries unless combined with ALL, ANY, or SOME. By themselves, they are used with single-row subqueries. The keywords shown in Table 9-2 indicate that the parent query is expecting the subquery to be a multirow subquery. A multirow subquery may return anywhere from zero to multiple rows of answers. Certification Objective 9.05 Write a Multiple-Column Subquery The subqueries we’ve looked at so far compare one value in the parent query with one column’s worth of data from a subquery. But it is possible to compare multiple columns at once, as we’ll see in this section. Here’s an example of a multiple-column subquery (line numbers added): 01 02 03 04 05 06 SELECT EMPLOYEE_ID FROM EMPLOYEES WHERE (FIRST_NAME, LAST_NAME) IN (SELECT FIRST_NAME, LAST_NAME FROM CRUISE_CUSTOMERS) AND SHIP_ID = 1; Write a Multiple-Column Subquery 357 In this example, we are querying the EMPLOYEES table and looking for the EMPLOYEE_ID of anyone with a first name and last name that matches a customer in the CRUISE_CUSTOMERS table. Notice the syntax: n The multiple-column list of the parent query is enclosed in parentheses (line 3). n The columns are separated by commas (line 3). n The datatypes of the columns must match—meaning that the columns on line 3 must match the datatypes of the columns identified on line 4. Other than that, everything else is standard. This particular example happens to allow for a multirow subquery (note the IN at the end of line 3) but that is not required for a multiple-column subquery. The columns in our preceding example share the same name in both the parent query and the subquery. This, however, is not required. All that is required is that the datatypes of the columns match. For example, see the tables in Figure 9-2, and then review this query: 01 02 03 04 05 06 Figure 9-2 The INVOICES and PAY_ HISTORY tables SELECT INVOICE_ID FROM INVOICES WHERE (INVOICE_DATE, (SELECT FROM WHERE TOTAL_PRICE) = START_DATE, SALARY PAY_HISTORY PAY_HISTORY_ID = 4); 358 Chapter 9: Retrieving Data Using Subqueries In this query, we compare the values of the INVOICES table’s INVOICE_DATE and TOTAL_PRICE columns with the START_DATE and SALARY columns in the A correlated subquery PAY_HISTORY table. The column names don’t can include multiple expressions in the match, but the datatypes do. select list, as long as the parent query As we’ve seen, a multiple-column subquery compares its results to the same number can compare two or more columns at once. The of expressions, each of which must have a comparisons are subject to the same rules and matching datatype. restrictions involving single-row and multiplerow subqueries. The column names involved don’t need to have the same names, but they do need to have the same datatypes, or comparable datatypes such that automatic datatype conversion is capable of making them the same datatypes. Certification Objective 9.06 Use Scalar Subqueries in SQL A scalar subquery returns one row with one column. In other words, it returns one column of data within one row, all the time. The scalar subquery is a single-row, single-column subquery. We can use this sort of a subquery in a WHERE clause, and we’ve already seen how that works. But we can also use this particular type of subquery in many other locations. You can use a scalar subquery within most any place that you can use any valid expression. For example, recall the VENDORS and INVOICES tables from Chapter 8’s Self Test. Let’s create a SELECT statement that demonstrates one of the uses of a scalar subquery: SELECT VENDOR_NAME, (SELECT TERMS_OF_DISCOUNT FROM INVOICES WHERE INVOICE_ID = 1) AS DISCOUNT FROM VENDORS ORDER BY VENDOR_NAME; VENDOR_NAME -------------------Acme Poker Chips Acme Steaks DISCOUNT -------------------2 pct on 30 2 pct on 30 Use Scalar Subqueries in SQL 359 In this example, we’ve placed the scalar subquery as a second expression within the SELECT statement’s select list. We’ve also chosen to give a column alias to this second item in the select list. Notice the output—the data under the DISCOUNT column heading is the result of our scalar subquery. Scalar subqueries must always be enclosed in parentheses. If the parent query in which it is being included already has a set of parentheses present, the scalar subquery will still require its own set of parentheses—they are an integral part of the scalar subquery’s syntax. Scalar subquery expressions cannot be used in the following locations: n In CHECK constraints n In GROUP BY clauses n In HAVING clauses n In a function-based index (which is coming up in Chapter 11) n As a DEFAULT value for a column n In the RETURNING clause of any DML statement n In the WHEN conditions of CASE n In the START WITH and CONNECT BY clauses, which we discuss in Chapter 16. Other than that, they can be used anywhere you would use an expression. Heads up—the topic of scalar subqueries is featured on the exam. You should be comfortable with all the various places in which the scalar subquery can be used—and cannot be used. Get familiar with the syntax and usage, and you’ll improve your odds of success on the exam. Scalar subqueries are not limited to SELECT statements. Here’s an example of a scalar subquery within an INSERT statement (line numbers added): 01 02 03 04 05 06 07 INSERT INTO EMPLOYEES ( EMPLOYEE_ID, SHIP_ID) VALUES ( SEQ_EMPLOYEE_ID.NEXTVAL, (SELECT SHIP_ID FROM SHIPS WHERE SHIP_NAME = 'Codd Champion') ); 360 Chapter 9: Retrieving Data Using Subqueries In this SQL statement, a scalar subquery is used at line 6 to extract a value from the table SHIPS to include in the INSERT statement for EMPLOYEES. Remember: anywhere a valid SQL expression can be used, a scalar subquery can probably be used as well, subject to the limitations just listed. Note that if a scalar subquery that returns no value—in other words, NULL—is used in an UPDATE or INSERT to assign value, it will assign NULL. Certification Objective 9.07 Solve Problems with Correlated Subqueries A correlated subquery is a query that is integrated with a parent query. Correlated subqueries include references to elements of a parent query, and thus, they do not exist as standalone queries, as do the examples we’ve seen so far. Up to now, any of the subqueries we’ve looked at could be executed on their own. That’s not the case with a correlated subquery. Let’s take a look at an example using the SHIP_CABINS table. Back in Chapter 7, we saw the SHIP_CABINS table in Figure 7-2, along with a data listing showing the 12 rows of information in our sample table. Each row in SHIP_ CABINS shows that a cabin is of ROOM_STYLE ‘Suite’ or ‘Stateroom’. Each individual room’s value for SQ_FT is shown, and they are not all the same. Our current challenge is to create a single query that lists all the cabins in the ship whose size—as measured by the SQ_FT column—is larger than the average cabin for its ROOM_STYLE. In other words, we need to n Identify the average square footage for each ROOM_STYLE in SHIP_ CABINS, and then use that value to n Display each ship cabin whose SQ_FT is greater than the average for its ROOM_STYLE. Without a correlated subquery, we’d be required to create separate queries to get this information. We would need n One query to get the averages n Another query—or queries—to compare the individual averages for each ROOM_STYLE Solve Problems with Correlated Subqueries 361 But with a correlated subquery, we can do it all at once. Here’s the SQL: 01 02 03 04 05 06 SELECT FROM WHERE A.SHIP_CABIN_ID, A.ROOM_STYLE, A.ROOM_NUMBER, A.SQ_FT SHIP_CABINS A A.SQ_FT > (SELECT AVG(SQ_FT) FROM SHIP_CABINS WHERE ROOM_STYLE = A.ROOM_STYLE) ORDER BY A.ROOM_NUMBER; Note the subquery that starts on line 3 and continues through and including line 5. In particular, note the second ROOM_STYLE at the end of line 5. See the table alias of ‘A’? That is a reference to a column of the parent query—not the subquery. See line 2 to confirm that the parent query’s table is aliased with the ‘A’ prefix. This is the “correlation” in this “correlated subquery”. This query is not executing as a standalone query and then passing back its result, as non-correlated subqueries do. Instead, the correlated subquery is executing once for each value that the parent query finds for each row, passing the value for the ROOM_STYLE column into the subquery and determining the average square footage for that particular ROOM_ STYLE. Finally, it uses the result of that query in line 3 to determine if the row in the parent query is greater than the average of SQ_FT for the ROOM_TYPE, or not. Here’s the output: SHIP_CABIN_ID ---------------------4 6 7 9 10 11 ROOM_STYLE ---------Stateroom Suite Stateroom Stateroom Suite Suite ROOM_NUMBER ----------105 107 108 110 702 703 SQ_FT ---------------------205 1524 211 225 1142 1745 One way to validate these results would be to get a list of each ROOM_STYLE and its average value for SQ_FT. Here’s a query to calculate that information: SELECT ROOM_STYLE, AVG(SQ_FT) FROM SHIP_CABINS GROUP BY ROOM_STYLE; ROOM_STYLE ---------Suite Stateroom AVG(SQ_FT) ---------------------969.285714285714285714285714285714285714 196.2 362 Chapter 9: Retrieving Data Using Subqueries This output confirms the average SQ_FT for each ROOM_STYLE, information we could use to go back and confirm that our correlated subquery only displayed room numbers whose individual SQ_FT values are higher than the average for the appropriate ROOM_STYLE. And they are. Correlated subqueries can exist in SELECT, UPDATE, and DELETE statements. They are “correlated” by way of a column reference from the parent query within the subquery. A table alias is not necessarily required in the subquery if no column name conflict exists. In our example, there was such a conflict, so we were required to use a table alias. But that’s not necessarily required in any correlated subquery. We could have just referenced any column from the parent query, and as long as there isn’t an identically named column in the subquery, no table alias is required. Its important to note that correlated subqueries may introduce performance degradation into a query. The process of correlating rows from one or more subqueries with the outer, or parent, query or queries may consume a significant amount of processing time. However, sometimes a correlated subquery can accomplish tasks that no other form of query may accomplish. Certification Objective 9.08 Update and Delete Rows Using Correlated Subqueries Let’s look at the use of correlated subqueries in an UPDATE statement and a DELETE statement. UPDATE with a Correlated Subquery An UPDATE statement can have a correlated subquery: n In the SET clause n In the WHERE clause As we saw in the preceding section, the correlated subquery will require some way to identify an expression as being from the parent query. The most common way to Update and Delete Rows Using Correlated Subqueries 363 do this is to assign a table alias to the table name in the UPDATE and then use that same table alias within the correlated subquery. Let’s look at an example. First, review the INVOICES table that we saw earlier, in Figure 9-2. Our task is to go back to our historical invoices and give a 10 percent discount to whoever placed our single biggest invoice for their respective quarter. So in the first quarter, we need to find the single biggest invoice and determine a 10 percent discount on that invoice, then do the same thing for the second quarter, and so on. To accomplish this feat, we’ll need to modify the invoice so that we change the value in the INVOICES table’s TERMS_OF_DISCOUNT column to the string ‘10 PCT’—and only for the appropriate invoice record. And we’ll need to n Identify the row with the highest value for TOTAL_PRICE for any given quarter, which we can identify using the TO_CHAR format mask ‘Q’ on the ORDER_DATE column. n Update an invoice only if it has the highest TOTAL_PRICE for the quarter. Here’s an UPDATE statement that does the trick: 01 02 03 04 05 06 UPDATE INVOICES INV SET TERMS_OF_DISCOUNT = '10 PCT' WHERE TOTAL_PRICE = (SELECT MAX(TOTAL_PRICE) FROM INVOICES WHERE TO_CHAR(INVOICE_DATE, 'RRRR-Q') = TO_CHAR(INV.INVOICE_DATE, 'RRRR-Q')); Notice the following items in the preceding query: n We choose to create a table alias “INV” which is declared at the end of line 1 and referenced in line 6. n The subquery starts in line 3 and runs through line 6. n The correlation occurs in lines 5 and 6, where the subquery’s reference to INVOICE_DATE is compared to the parent query’s INV.INVOICE_DATE. The comparison is performed by converting both dates to the ‘RRRR-Q’ format, which means the year and quarter, so that, for example, the date ‘31-MAY-11’ would convert to ‘2011-2’. n On line 3 is the comparison between the parent query and the subquery, which is an equal sign, indicating that the parent query is expecting a singlerow subquery. Given that the subquery is returning the aggregate value MAX for TOTAL_PRICE, and no GROUP BY is involved in the subquery, then the subquery will indeed return no more than one row. 364 Chapter 9: Retrieving Data Using Subqueries Here is an example of a correlated subquery used in the SET clause of an UPDATE statement: 01 02 03 04 05 06 07 UPDATE PORTS P SET CAPACITY = (SELECT COUNT(*) FROM SHIPS WHERE HOME_PORT_ID = P.PORT_ID) WHERE EXISTS (SELECT * FROM SHIPS WHERE HOME_PORT_ID = P.PORT_ID); In the preceding code, we do the following: Lines 5 through 7: We look for records in the PORTS table that any ship calls its home port, by way of the HOME_PORT_ID column. We use the keyword EXISTS, which we’ll review in the very next section, but for now—know that EXISTS tells us quite simply if there are any rows returned by the subquery at all. In other words, we’re simply asking if there are any rows in SHIPS that contain a value for HOME_PORT_ ID that corresponds to a given row in the parent UPDATE statement’s PORTS table. If yes, the subquery returns a TRUE. Lines 2 through 4: Then, if we find such PORTS, we update their capacity to equal the total number of ships in the SHIPS table currently calling that port home—this is accomplished in the correlated subquery that counts the number of records in SHIPS that share the same HOME_PORT_ID value with the parent UPDATE. Note that this example of an UPDATE uses two correlated subqueries—both of the subqueries are correlated, because both include the P.PORT_ID reference in their WHERE clauses, on lines 4 and 7. Note that a subquery of the form SELECT COUNT(*) FROM TABLE will always be a single-row subquery. If no rows are found, the subquery returns a single row with a value of zero. If multiple rows exist in the table, the subquery returns a single row with a value representing the number of rows found.This is true for queries using the COUNT function, but not for queries using other aggregates, such as AVG, MIN, MAN, or SUM.This is unique to COUNT. Next we’ll look at how we can use correlated subqueries in a DELETE statement. DELETE with a Correlated Subquery The DELETE statement can be used with a correlated subquery in the WHERE clause to determine which rows to delete from a given table. The syntax is similar to the correlated subquery syntax for SELECT and UPDATE statements. Use the EXISTS and NOT EXISTS Operators 365 Let’s take a look at a DELETE statement for the SHIP_CABINS table. This DELETE will remove those cabins with the smallest balcony square footage for each ROOM_TYPE and Correlated subqueries are ROOM_STYLE. In other words, for a given not limited to the SELECT statement— ROOM_TYPE of ‘Suite’ and a ROOM_STYLE they can also be used in UPDATE or of ‘Ocean View’, we’ll remove the row for the DELETE statements. cabin with the smallest balcony, and then we’ll move on and do the same for the ‘Stateroom’ with ‘Ocean View’ that has the smallest balcony, etc. Here’s the query (line numbers added): 01 02 03 04 05 06 DELETE FROM SHIP_CABINS S1 WHERE S1.BALCONY_SQ_FT = (SELECT MIN(BALCONY_SQ_FT) FROM SHIP_CABINS S2 WHERE S1.ROOM_TYPE = S2.ROOM_TYPE AND S1.ROOM_STYLE = S2.ROOM_STYLE); Notice that in this example, the correlation involves two columns, in lines 5 and 6. CertIFIcAtIon ObJectIVe 9.09 Use the EXISTS and NOT EXISTS Operators The EXISTS keyword tests for the existence of any rows in a subquery. If no rows are found, the answer is FALSE. Otherwise, the subquery returns TRUE. NOT EXISTS reverses the results. Let’s look at an example—the following query looks for PORTS that have any sort of record at all in the SHIPS table with a HOME_PORT_ID value that matches any of the PORT_ID values. Here’s the query: 01 02 03 04 05 SELECT PORT_ID, PORT_NAME FROM PORTS P1 WHERE EXISTS (SELECT * FROM SHIPS S1 WHERE P1.PORT_ID = S1.HOME_PORT_ID); 366 Chapter 9: Retrieving Data Using Subqueries EXISTS does not compare anything to the subquery.There is no “expression equals expression” format with EXISTS. Its syntax is simple: the keywords WHERE EXISTS and the subquery. Nothing more. Note the keyword EXISTS on line 3. The entire subquery is executed, even though EXISTS need only know whether or not the subquery returns any rows—so beware using EXISTS with subqueries that return large numbers of rows. It’s worth noting that this sort of query is sometimes referred to as a “semijoin”. A semijoin is a SELECT statement that uses the EXISTS keyword to compare rows in a table with rows in another table. CertIFIcAtIon ObJectIVe 9.10 Use the wITh Clause You can use the keyword WITH to assign a name to a subquery block. Once the name is assigned, you can reference the name from elsewhere in the query. WITH is considered a clause of the SELECT statement. Let’s look at an example—we’ll use WITH to declare two different subqueries. We’ll name one PORT_BOOKINGS and the other DENSEST_PORT (see the following listing, lines 2 and 8), and then invoke both of them by name in a SELECT statement (lines 12 through 14). Here’s the code (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 WITH PORT_BOOKINGS AS ( SELECT P.PORT_ID, P.PORT_NAME, COUNT(S.SHIP_ID) CT FROM PORTS P, SHIPS S WHERE P.PORT_ID = S.HOME_PORT_ID GROUP BY P.PORT_ID, P.PORT_NAME ), DENSEST_PORT AS ( SELECT MAX MAX_CT FROM PORT_BOOKINGS ) SELECT PORT_NAME FROM PORT_BOOKINGS WHERE CT = (SELECT MAX_CT FROM DENSEST_PORT); Certification Summary 367 Note that neither PORT_BOOKINGS nor DENSEST_PORT is a database object. They are the names of queries that exist solely within this WITH/SELECT statement. Also note the subqueries on lines 3 through 6, and on lines 9 through 10. Also note that The series of one or the only semicolon is at the end of the entire more subquery blocks defined before statement, not at the end of any individual SQL the SELECT statement is referred to as statement within the overall WITH statement. the subquery factoring clause. WITH can Internally, Oracle SQL treats a named query define one subquery factoring clause; within the WITH clause as a temporary table or it must be defined before the SELECT as an inline view. (We examine inline views in statement. Chapter 10.) The WITH clause can be used in the toplevel query of a SELECT statement and in many (but not all) subqueries of the SELECT statement, such as shown in line 14. If you use WITH to name a subquery, that name isn’t recognized within the subquery itself but is recognized in most every other location in the overall query. In other words, consider line 8, where we name and specify the subquery DENSEST_PORT. We couldn’t reference the name DENSEST_PORT in lines 9 through 10, but we can reference the name everywhere else. CertIFIcAtIon SummArY A subquery is a SELECT statement that exists within a larger SQL statement. Subqueries may be included in a SELECT, INSERT, UPDATE, or DELETE statement. Subqueries may also be used in a CREATE TABLE statement. Subqueries can be used in WHERE clauses of SELECT, UPDATE, and DELETE statements. They can be used in the UPDATE . . . SET clause, and the INSERT list of values. Depending on the type of subquery, it may be able to substitute for any expression almost anywhere an expression is accepted, including the select list of a SELECT statement. Subqueries can perform multiple-step queries in a single SQL statement. They can be used to reference lookup information from a given query. They can populate a table at the time of creation in a CREATE TABLE statement. They are used to create views. There are many types of subqueries, including single-row, multiple-row, multiplecolumn, scalar, and correlated. 368 Chapter 9: Retrieving Data Using Subqueries Single-row subqueries return one row of data to the parent query. Multiple-row subqueries can return anywhere from zero to one to more than one row. Multiplecolumn subqueries are compared to rows in the parent query using multiple columns at once. Scalar subqueries return one row and one column’s worth of data at all times. Correlated subqueries contain conditions in the subquery that connects rows of data with rows in the parent query, much as a join might do. Single-row subqueries use comparison conditions such as the equal sign or LIKE to compare their results to the parent query. Multiple-row subqueries use comparison conditions such as IN, NOT IN, ANY, and ALL. The EXISTS keyword can be used to test if a subquery contains any rows whatsoever. NOT EXISTS reverses the results. The WITH clause can assign names to subqueries temporarily within a given SELECT statement’s execution. Two-Minute Drill 3 369 Two-MInute DrIll Define Subqueries q A subquery is a SELECT statement contained within a SQL statement. q The outer SQL statement is called the parent. The outermost level is the top level. q A top-level SQL statement containing a subquery may be a SELECT, INSERT, UPDATE, or DELETE, or else a CREATE TABLE or CREATE VIEW. q Subqueries may be nested within other subqueries. q Many subqueries could function as standalone queries. Some are correlated, meaning that they contain references that tie them into their parent queries. Describe the Types of Problems That Subqueries Can Solve q A subquery can provide lookup data to assist a parent query in completing a WHERE clause or something comparable. q Subqueries can help combine multiple steps into a single query, reducing what otherwise might be several consecutive SQL statements into a single statement. q Subqueries in a CREATE TABLE or INSERT or UPDATE statement can draw from data from the database to populate database objects quickly. q Subqueries can name queries for subsequent reference. List the Types of Subqueries q A single-row subquery returns one row of data to the parent query. q A multiple-row subquery may return more than one row of data to the parent query. q Multiple-column subqueries return two or more columns worth of data at once to the parent query, which must test for all of the columns at once. q Correlated subqueries use data from a parent query to determine their own result. 370 Chapter 9: Retrieving Data Using Subqueries q Scalar subqueries always return one value, represented in one column of one row, every time. q The multiple-column subquery may be of the single-row or multiple-row type of subquery. q A correlated subquery might be a single-row, multiple-row, or multiple- column subquery. write Single-Row and Multiple-Row Subqueries q The results of a single-row subquery can be compared from within the parent using a scalar comparison operator, such as the equal sign, or the greater-than or less-than sign. q The column names are not required to match in such a comparison, but the datatypes must match, so that the parent query may compare columns of any name to subquery columns of any name, provided the datatypes match. q Multiple-row subqueries are compared differently to the parent query than single-row, using the multiple-row comparison conditions, such as IN, ANY, or ALL, in combination with single-row comparison operators such as >, to avoid getting an execution error message. write a Multiple-Column Subquery q Multiple-column subqueries return several columns’ worth of data to the parent query all at once. q The parent query must compare all of the columns together; the datatypes of each expression comparison much match between the parent and the subquery. q Multiple-column subqueries may return single-row or multiple-row answers. Use Scalar Subqueries in SQL q Scalar subqueries return data in the form of one value, in one column’s worth of one row. q Scalar subqueries may be used almost anywhere that any expression could be used. Two-Minute Drill 371 Solve Problems with Correlated Subqueries q Correlated subqueries use data from the parent in subquery predicates to determine what data to return to the parent query. q Correlated subqueries may present some performance degradation; however, they can perform tasks that could not otherwise be accomplished in a single query. Update and Delete Rows Using Correlated Subqueries q The UPDATE and DELETE statements can use correlated subqueries. q The UPDATE can use correlated subqueries in the SET or the WHERE clause. q The DELETE statement can use correlated subqueries in the WHERE clause. Use the EXISTS and NOT EXISTS Operators q The EXISTS operator can be used by a parent query to test a subquery and determine if it returns any rows at all. q NOT EXISTS reverses the findings of EXISTS. Use the wITh Clause q The WITH clause can dynamically name a subquery so that the SELECT statement following the WITH clause can reference that subquery by name, treating it as a dynamic table in real time. q Any subquery names assigned within the WITH clause are only good for that statement; they are not stored in the database. 372 Chapter 9: Retrieving Data Using Subqueries SelF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Define Subqueries 1. Which of the following forms of subquery never returns more than one row? A. Scalar B. Correlated C. Multiple-column D. None of the above Describe the Types of Problems That Subqueries Can Solve 2. Which of the following can be accomplished with a subquery? A. Populate a new table at the time it is created with new data. B. Populate a new table at the time it is created with data found elsewhere in the database. C. Populate an existing table with new data not curently in the database. D. None of the above. List the Types of Subqueries 3. Which of the following statements is true? (Choose two.) A. A single-row subquery can also be a multiple-row subquery. B. A single-row subquery can also be a multiple-column subquery. C. A scalar subquery can also be a multiple-column subquery. D. A correlated subquery can also be a single-row subquery. 4. A subquery that includes references back to the parent query, and thus cannot execute as a standalone query, is: (Choose the best answer.) A. A scalar subquery B. A correlated subquery C. A multiple-column subquery D. A referential subquery Self Test 373 write Single-Row and Multiple-Row Subqueries 5. Which of the following comparison operators may be used with a multiple-row subquery? (Choose two.) A. = B. >= ALL C. LIKE D. IN 6. Review the PORTS and SHIPS tables: Then review the following SQL code (line numbers added): 01 02 03 04 SELECT P.COUNTRY, P.CAPACITY FROM PORTS P WHERE P.PORT_ID > (SELECT S.HOME_PORT_ID FROM SHIPS S WHERE S.LENGTH > 900); You know that there are five rows in the SHIPS table with a length greater than 900. What will result from an attempt to execute this SQL statement? A. An execution error will result because the subquery will return more than one row and the parent query is expecting only one row from the subquery. B. A syntax error will result because PORT_ID and HOME_PORT_ID in line 3 have different column names. C. The statement will execute and produce output as intended. D. None of the above. 374 Chapter 9: Retrieving Data Using Subqueries write a Multiple-Column Subquery 7. Which of the following is true about the multiple-column subquery? A. Only two columns may be compared between the parent and the subquery. B. The names of the columns being compared must match. C. The datatypes of the columns being compared must match. D. A multiple-column subquery can also be a scalar subquery. Use Scalar Subqueries in SQL 8. A scalar subquery may not be used in which of the following clauses and/or SQL statements? A. The select list of a SELECT statement B. The VALUES list of an INSERT statement C. The SET clause of an UPDATE statement D. The GROUP BY clause of a SELECT statement Solve Problems with Correlated Subqueries 9. Review the WORK_HISTORY table: Your task is to create a query that will list—for each ship—all of the EMPLOYEE_ID values for all the employees who have the shortest work history for their ship. In other words, if there are two ships, you want to list all of the employees assigned to the first ship who have the shortest work history, and all of the employees assigned to the second ship who have the shortest work history, etc. Which of the following queries will accomplish this task? (Choose two.) Self Test 375 A. SELECT EMPLOYEE_ID FROM WORK_HISTORY W1 WHERE ABS(START_DATE - END_DATE) = (SELECT MIN(ABS(START_DATE - END_DATE)) FROM WORK_HISTORY WHERE SHIP_ID = W1.SHIP_ID); B. SELECT EMPLOYEE_ID FROM WORK_HISTORY W1 WHERE ABS(START_DATE - END_DATE) = (SELECT MIN(ABS(START_DATE - END_DATE)) FROM WORK_HISTORY); C. SELECT EMPLOYEE_ID FROM WORK_HISTORY W1 WHERE ABS(START_DATE - END_DATE) <= ALL (SELECT ABS(START_DATE - END_DATE) FROM WORK_HISTORY WHERE SHIP_ID = W1.SHIP_ID); D. SELECT EMPLOYEE_ID FROM WORK_HISTORY W1 WHERE ABS(START_DATE - END_DATE) < (SELECT MIN(ABS(START_DATE - END_DATE)) FROM WORK_HISTORY WHERE SHIP_ID = W1.SHIP_ID); 10. Review the illustration from question 6. Your team is tasked with the job of creating a list of the ships with the least capacity in each port. In other words, each ship has a home port. For each port that is a home port to ships, which of each port’s ships has the least capacity? Your team produces the following query in answer to this task (line numbers added): 01 02 03 04 05 06 07 SELECT S1.SHIP_NAME, (SELECT FROM WHERE FROM SHIPS S1 WHERE S1.CAPACITY = (SELECT FROM WHERE PORT_NAME PORTS PORT_ID = S1.HOME_PORT_ID) HOME_PORT MIN(CAPACITY) SHIPS S2 S2.HOME_PORT_ID = S1.HOME_PORT_ID); Which of the following statements is true about this SQL statement? A. The statement will fail with a syntax error because of the subquery on lines 1 through 3. B. The statement will fail with an execution error because of the subquery on lines 1 through 3. C. The statement will execute but will return meaningless information. D. The statement will execute successfully as intended. 376 Chapter 9: Retrieving Data Using Subqueries Update and Delete Rows Using Correlated Subqueries 11. A correlated subquery may be used in: (Choose three.) A. The SET clause of an UPDATE statement B. The WHERE clause of an UPDATE statement C. The WHERE clause of a DELETE statement D. The FROM clause of a DELETE statement 12. Review the illustration from question 6, and the following SQL code: 01 02 03 04 05 UPDATE PORTS P SET CAPACITY = CAPACITY + 1 WHERE EXISTS (SELECT * FROM SHIPS WHERE HOME_PORT_ID = P.PORT_ID); The PORTS table has 15 rows. The SHIPS table has 20 rows. Each row in PORTS has a unique value for PORT_ID. Each PORT_ID value is represented in the HOME_PORT_ID column of at least one row of the SHIPS table. What can be said of this UPDATE statement? A. The value for CAPACITY will increase once for each of the 15 rows in the PORTS table. B. The value for CAPACITY will increase by 20 for each of the 15 rows in the PORTS table. C. The value for CAPACITY will not increase. D. The statement will fail to execute due to an error in the syntax. Use the EXISTS and NOT EXISTS Operators 13. Another name for an EXISTS query is: A. Demijoin B. Multiple-column subquery C. Cross-join D. Semijoin 14. Review the illustration from question 6, and the following SQL code: 01 02 03 04 DELETE FROM PORTS P WHERE PORT_ID NOT EXISTS (SELECT PORT_ID FROM SHIPS WHERE HOME_PORT_ID = P.PORT_ID); Self Test 377 The code is attempting to delete any row in the PORTS table that is not a home port for any ship in the SHIPS table, as indicated by the HOME_PORT_ID column. In other words, only keep the PORTS that are currently the HOME_PORT_ID for a ship in the SHIPS table; get rid of all other PORT rows. That’s the intent of the SQL statement. What will result from an attempt to execute the preceding SQL statement? A. It will fail because of a syntax error on line 2. B. It will fail because of a syntax error on line 4. C. It will fail because of an execution error in the subquery. D. It will execute successfully and perform as intended. Use the wITh Clause 15. The WITH clause can be used to name a subquery, and: (Choose two.) A. The name of the subquery can be used in the SELECT statement following the WITH clause. B. The name of the subquery can be joined to other tables in the SELECT statement following the WITH clause. C. The name of the subquery is stored in the database by the WITH statement, and can be referenced by other SQL statements in later sessions. D. The name of the subquery can be invoked from within the subquery that is named. 378 Chapter 9: Retrieving Data Using Subqueries SelF Test Answers Define Subqueries 1. ˛ A. Scalar subqueries always return a single value, which is to say it returns one row’s worth of data, one column’s worth in that one row. ˝ B, C, and D are incorrect. A correlated subquery may or may not return multiple rows. Multiple-column subqueries may or may not return multiple rows. Describe the Types of Problems That Subqueries Can Solve 2. ˛ B. A subquery can be used in a CREATE TABLE statement to populate a new table with data already in existence in the database. ˝ A, C, and D are incorrect. You cannot use a subquery to add new data to the database. List the Types of Subqueries 3. ˛ B and D. A single-row subquery may consist of multiple columns in its single row. And it also may be correlated. ˝ A and C are incorrect. A single-row subquery cannot, by definition, also be a multiple-row subquery. Duh. A scalar subquery by definition can only be one column in one row, so it cannot be a multiple-column subquery. Double-duh. 4. ˛ B. A correlated subquery is the best answer. The name indicates that the subquery is correlated to the parent query. Technically, “scalar” and “multiple-column” subqueries may also be correlated, but we asked for the “best answer”, and clearly that is “correlated subquery”. ˝ A, C, and D are incorrect. Technically, a scalar subquery may also be a correlated subquery, which is why the question asked you to pick the “best answer”—the term “correlated” refers specifically to the concept of referring back to the parent query, whereas a scalar subquery refers specifically to a subquery’s return value as being a single value. The same is true for a multiplecolumn subquery—that may also be a correlated subquery, but the term “multiple-column” is intended to emphasize the fact that it returns multiple columns’ worth of results at once. Finally, a referential subquery isn’t anything; we just made that up. Self Test Answers 379 write Single-Row and Multiple-Row Subqueries 5. ˛ B and D. The “>=ALL” is “greater than all” of the values returned by the subquery, which is ideal for a multiple-row query. The “IN” comparison operator is also useful. ˝ A and C are incorrect. The “=” sign is restricted only to single-row subqueries. The LIKE operator is also limited to single-row subqueries. 6. ˛ A. The query will produce an execution error because the parent query is expecting a singlerow answer from the subquery—you know this because of the comparison operator in line 3, the greater-than sign is a single-row comparison operator. The better choice here might be “> ANY” or “> ALL”, depending on the situation. ˝ B, C, and D are incorrect. There is nothing wrong with PORT_ID and HOME_PORT_ID having different column names. As long as their datatypes match, all is well, and you know their datatypes match according to the illustration from question 6. write a Multiple-Column Subquery 7. ˛ C. The datatypes of the columns being compared must match. ˝ A, B, and D are incorrect. Multiple-column subqueries may involve two or more columns. The names of the columns do not have to match, just the datatypes. A multiple-column subquery cannot be a scalar subquery, since, by definition, scalar subqueries return a value of one row and one column, no more. Use Scalar Subqueries in SQL 8. ˛ D. Scalar subqueries may not be used in a GROUP BY clause. ˝ A, B, and C are incorrect. Scalar subqueries are allowed in all of the locations listed in these answers—a SELECT expression list, an INSERT values list, an UPDATE’s SET clause. Anywhere an expression can be used, a scalar expression can probably be used—subject to the limitations detailed in the chapter. Solve Problems with Correlated Subqueries 9. ˛ A and C. Answer A is a classic correlated subquery, connecting the subquery to the parent by way of the W1.SHIP_ID value. Answer C also works with the “<= ALL” comparison condition. ˝ B and D are incorrect. Answer B is missing the join in the subquery that connects the subquery with the parent query. Answer D compares the parent query’s WHERE clause value to the subquery with a less-than sign, which won’t work—the subquery is already selecting the minimum value from the subquery, so the parent query can’t find anything that will be less than the minimum. 380 Chapter 9: Retrieving Data Using Subqueries 10. ˛ D. The statement is syntactically fine. The SELECT includes two correlated subqueries. The first, in lines 1 through 3, is an expression in the SELECT statement’s select list. This subquery is correlated by way of the reference at the end of line 3. The second correlated subquery is in lines 5 through 7, and it obtains the minimum capacity value for ships belonging to each port. ˝ A, B, and C are incorrect. The statement will not fail, not with a syntax problem nor with an execution problem. The data it returns is exactly as requested. Update and Delete Rows Using Correlated Subqueries 11. ˛ A, B, and C. A correlated subquery may be used in any of these answers. ˝ D is incorrect. A correlated subquery cannot be used in the FROM clause of a DELETE statement. Note, however, that the question is asking specifically about correlated subqueries. While you cannot have a correlated subquery in the FROM clause of the DELETE, we’ll later see that an “inline view” can be used there, and an “inline view” is essentially a subquery—but not a correlated subquery. 12. ˛ A. The CAPACITY will increase once for each row processed by the UPDATE if that row is found in the subquery. ˝ B, C, and D are incorrect. Use the EXISTS and NOT EXISTS Operators 13. ˛ D. The semijoin is the correct answer. ˝ A, B, and C are incorrect. There is no such thing as a demijoin. A multiple-column subquery requires several columns on both sides of the comparison condition. A cross-join is a table join with no join criteria. 14. ˛ A. It will fail because of a syntax error on line 2—the first reference to PORT_ID should be removed. EXISTS does not compare the subquery to anything. In other words, line 2 should be “WHERE NOT EXISTS (SELECT *”, without the first PORT_ID reference. Other than that, everything else about the query is fine. ˝ B, C, and D are incorrect. Line 4 has no syntax errors. Nor does the subquery contain any execution errors. But neither will the SQL execute, for the reasons we described for the right answer. Use the wITh Clause 15. ˛ A and B. The name can be used in the SELECT following the WITH clause. ˝ C and D are incorrect. The name is not stored in the database by the WITH statement. It exists only for the WITH clause itself and is not recognized outside of the WITH clause. The one place within the WITH clause that does not recognize the subquery name is within the named subquery itself. 10 Creating Other Schema Objects CertIFIcAtIon ObJectIVes 10.01 Create and Use Simple and Complex Views 10.04 10.02 Create, Maintain, and Use Sequences Q&A 10.03 Create and Maintain Indexes 3 Create Private and Public Synonyms Two-Minute Drill Self Test 382 Chapter 10: Creating Other Schema Objects T his chapter introduces a number of other schema objects that are necessary to understand in order to create a complete application. These objects include the view, sequence, index, and synonym. Each is uniquely important in a variety of ways. CertIFIcAtIon ObJectIVe 10.01 Create and use Simple and Complex Views A view is a SELECT statement with a name, stored in the database, and accessible as though it were a table. Earlier you saw the WITH clause that can assign a name to a query within a single SELECT statement. The view object does the same thing in a more permanent manner, meaning that the view object resides in the database alongside tables and other database objects. Once you’ve created a view, you can refer to it in SELECT statements as though it were a table. Nothing about the SELECT is different—anyone looking at a given SELECT statement will not be able to determine from the SELECT statement alone if the FROM clause specifies a table or a view. Views are useful for a variety of reasons. One benefit is security. For example, consider a typical scenario where you have a large table that contains a combination of some sensitive information along with some information that is of a general interest. You might create a view that queries the general interest columns of the large table, then grant privileges on that view to the general population of users. Those users may now query the view, and get direct access to the general information without having access to more sensitive data that exists in the underlying table. Views are a great way to mask certain data while giving access to other data in the same table. Another benefit to views is their ability to make a complex query easier to work with. For example, you might create a view that is built on a complex join, so that the complexity is built into the view. The result is a view object that appears to be a single table, which you may now query as though it were a table. You can even join the view with other tables and other views. In this situation, a view can be used to simplify the complexity of a commonly used join. In the next section, we’ll create a view object. Create and Use Simple and Complex Views 383 Creating Views Let’s look at an example. First, review Figure 10-1. We’ll start with just the EMPLOYEES table—notice that it includes columns for employee ID, name, social security number, date of birth, and primary phone number. So here’s a problem: what if you wanted to give access to this table so that other people in the organization can get the phone numbers of employees? Think about that sensitive information, including social security numbers, and you might have second thoughts about having anybody query the EMPLOYEES table. One solution to this predicament is to use a view. Let’s create a view for the EMPLOYEES table: CREATE VIEW VW_EMPLOYEES AS SELECT EMPLOYEE_ID, LAST_NAME, FIRST_NAME, PRIMARY_PHONE FROM EMPLOYEES; If we execute this statement in SQL, we’ll get the following message: CREATE VIEW succeeded. (Note: this statement is the message displayed by SQL Developer. SQL*Plus will display “View created”.) FIGure 10-1 Diagrams for the EMPLOYEES and PAY_HISTORY tables 384 Chapter 10: Creating Other Schema Objects Now that we have this view, we can work with it just as if it were a table. For example, we can DESCRIBE it: DESC VW_EMPLOYEES; Name Null Type ------------------------------ -------- ------------EMPLOYEE_ID NOT NULL NUMBER LAST_NAME VARCHAR2(30) FIRST_NAME VARCHAR2(20) PRIMARY_PHONE VARCHAR2(20) Additionally, we can SELECT from it as if it were a table: SELECT * FROM VW_EMPLOYEES; SELECT FIRST_NAME || ' ' || LAST_NAME "Employee" FROM VW_EMPLOYEES ORDER BY PRIMARY_PHONE; The results will display just like any table. Anyone using VW_EMPLOYEES, running SELECT statements on it, describing its structure, doing anything they might wish using SQL commands—may not ever realize it’s not a table at all. The fact that it’s a view isn’t necessarily obvious. We chose to name it with a VW_ prefix for our own purposes, but we could have given it any name we wished. The syntax rules for creating a view are n The keywords CREATE VIEW n The optional keywords OR REPLACE n A name for the view, specified according to the rules for naming database objects n The keyword AS n Finally, a valid SELECT statement, with a few restrictions One of the requirements of the CREATE VIEW statement is this: the resulting VIEW must have valid column names. This means that if you choose a SELECT statement that incorporates any complex expressions within the select list, each expression must be assigned a column alias, or column names must be assigned by the CREATE VIEW statement itself. For example, let’s use the OR REPLACE option to create a new version of our VW_EMPLOYEES view (line numbers added): Create and Use Simple and Complex Views 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 385 CREATE OR REPLACE VIEW VW_EMPLOYEES AS SELECT EMPLOYEE_ID, LAST_NAME || ', ' || FIRST_NAME, PRIMARY_PHONE FROM EMPLOYEES; Error starting at line 1 in command: CREATE OR REPLACE VIEW VW_EMPLOYEES AS SELECT EMPLOYEE_ID, LAST_NAME || ', ' || FIRST_NAME, PRIMARY_PHONE FROM EMPLOYEES Error at Command Line:3 Column:33 Error report: SQL Error: ORA-00998: must name this expression with a column alias 00998. 00000 - "must name this expression with a column alias" What went wrong? The problem is on line 3, where we specify the expression that forms the second column in our SELECT expression list. Notice that it concatenates the columns LAST_NAME with a comma, a space, and then the FIRST_NAME column. Here’s the problem: what is the name of this column? There isn’t one assigned, but the CREATE VIEW statement requires one. Therefore—the attempted CREATE VIEW statement fails. To correct the problem, we can specify column names in the CREATE VIEW statement, like this (line numbers added): 01 02 03 04 05 CREATE OR REPLACE VIEW VW_EMPLOYEES (ID, NAME, PHONE) AS SELECT EMPLOYEE_ID, LAST_NAME || ', ' || FIRST_NAME EMP_NAME, PRIMARY_PHONE FROM EMPLOYEES; Now we’ll have a view consisting of three columns with the names ID, NAME, and PHONE. Alternatively, we could have used a column alias in the SELECT statement. You can use complex queries to create views. For example, let’s go back to Figure 10-1 and build a query that joins data from the PAY_HISTORY table into our view, as follows (line numbers added): 01 02 03 04 05 06 CREATE VIEW EMP_TREND AS SELECT EMP.SHIP_ID, MIN(SALARY) MIN_SALARY FROM EMPLOYEES EMP LEFT JOIN PAY_HISTORY PAY ON EMP.EMPLOYEE_ID = PAY.EMPLOYEE_ID WHERE END_DATE IS NULL GROUP BY EMP.SHIP_ID; 386 Chapter 10: Creating Other Schema Objects This statement uses a SELECT statement with a join, a GROUP BY, a WHERE clause, and aggregate functions; it creates a VIEW out of all of it. VIEW objects can be based on SELECT statements with subqueries, functions, and more. CREATE OR REPLACE VIEW SHIP_ONE_CABINS AS SELECT * FROM SHIP_CABINS WHERE SHIP_ID = 1; The view created with this statement will consist only of the rows in the SHIP_ CABINS table where the SHIP_ID value is equal to 1. The SHIP_CABINS table may contain more rows than those with a SHIP_ID of 1, but those rows won’t be found by way of any query on the SHIP_ONE_CABINS view. Also—take note again of the optional keywords OR REPLACE in the CREATE VIEW statement. These words don’t work with CREATE TABLE, but they do with CREATE VIEW. Be careful with them—when included, they will give you no warning if you are or are not overwriting some existing view. They will simply overwrite what may have gone before and replace it with the new view. It’s a convenient option that is very powerful—so be careful with it. You have been warned. Views and Constraints You can create constraints on a view in the same way you can create them on a table. HOWEVER: Oracle doesn’t enforce them without special configuration that’s available primarily to support certain data warehousing requirements. This subject is worth noting but not specifically addressed on the exam. updatable Views You’ve seen how we can SELECT from a view. But can we also use INSERT and UPDATE, and DELETE? The answer is: it depends. If the view contains enough information to satisfy all of the constraints in any underlying tables, then yes, you can use INSERT, UPDATE, or DELETE statements on the view. Otherwise no. Depending on the nature of the constraints, it may be possible to use some DML statements but not others on the view. For example, if the view fails to include any columns from the underlying table that have NOT NULL constraints, you will not be able to execute an INSERT statement, but you may be able to issue an UPDATE or DELETE statement. Create and Use Simple and Complex Views 387 For example, let’s revisit the EMPLOYEES table in Figure 10-1. Let’s make a new view on that table, like this: CREATE OR REPLACE VIEW EMP_PHONE_BOOK AS SELECT LAST_NAME, FIRST_NAME, PRIMARY_PHONE FROM EMPLOYEES; This view contains just enough information to print an employee phone book, including their names and phone numbers. Once we’ve created this view, we can select from it, like this: SELECT LAST_NAME, FIRST_NAME, PRIMARY_PHONE FROM EMP_PHONE_BOOK ORDER BY LAST_NAME, FIRST_NAME; Fantastic. But wait—we just hired someone new, her name is Sonia Sotogovernor, and we want to add her name to this view, let’s try it: INSERT INTO EMP_PHONE_BOOK (LAST_NAME, FIRST_NAME, PRIMARY_PHONE) VALUES ('Sotogovernor', 'Sonia', '212-555-1212'); Error starting at line 1 in command: INSERT INTO EMP_PHONE_BOOK (LAST_NAME, FIRST_NAME, PRIMARY_PHONE) VALUES ('Sotogovernor', 'Sonia', '212-555-1212') Error report: SQL Error: ORA-01400: cannot insert NULL into ("EFCODD"."EMPLOYEES"."EMPLOYEE_ID") 01400. 00000 - "cannot insert NULL into (%s)" Whoops. What’s wrong here? See the error message? Remember that our underlying table is the EMPLOYEES table, and it contains a PRIMARY KEY of EMPLOYEE_ID, as we see in Figure 10-1. But our view doesn’t include that column. As a result—there is no way for us to INSERT a value through the EMP_PHONE_ BOOK view so that it will provide a value for the required column of EMPLOYEE_ ID. We cannot execute an INSERT statement on this view. However, we can execute an UPDATE statement on the view. For example: UPDATE SET WHERE AND EMP_PHONE_BOOK PRIMARY_PHONE = '202-555-1212' LAST_NAME = 'Hoddlestein' FIRST_NAME = 'Howard'; This statement works perfectly fine on the view. The reason: the changes we’re making with this UPDATE statement do not violate any underlying constraints. 388 Chapter 10: Creating Other Schema Objects If there are any constraints on the underlying table that you cannot possibly honor when attempting to issue an INSERT, UPDATE, or DELETE on a VIEW, then the statement won’t work. The VIEW object must provide access to any of the underlying table’s columns in such a way that the constraints can be honored in order to satisfy those constraints and execute the statement successfully. Otherwise, the INSERT, UPDATE, or DELETE statement will fail. In addition, a view that is based on aggregate rows will not be updatable. You will be prevented from using INSERT, UPDATE, or DELETE if you create a view based on a SELECT statement that includes any of the following: n Omission of any required columns in that underlying table n GROUP BY or any other aggregation, such as set operators (which we discuss in Chapter 12) or hierarchical queries (discussed in Chapter 16) n DISTINCT n A FROM clause that references more than one table—that is, subqueries in the SELECT, or most joins Regarding that last item—it is technically possible to execute DML changes on joins where all updatable columns belong to a key-preserved table. The details go beyond the scope of this book. For the most part, you will not be able to issue DML changes to a VIEW object based on a join. As we’ve already seen, a view’s SELECT statement may include expressions as part of the columns in its formation, such as CREATE OR REPLACE VIEW EMP_PHONE_BOOK AS SELECT EMPLOYEE_ID, FIRST_NAME || ', ' || LAST_NAME EMP_NAME, PRIMARY_PHONE FROM EMPLOYEES; Note that the preceding query concatenates the FIRST_NAME and LAST_ NAME columns into one expression. As a result, the individual columns cannot be modified with an INSERT or UPDATE statement—there is no way to singularly refer to the individual columns, unless they are added as individual items in the select list. However, EMPLOYEE_ID, the required column, is included as an individual column, so this would be a satisfactory statement: INSERT INTO EMP_PHONE_BOOK (EMPLOYEE_ID, PRIMARY_PHONE) VALUES (102, '800-555-1212'); Create and Use Simple and Complex Views 389 That statement will successfully execute on our EMP_PHONE_BOOK view and add a new row to the underlying table—assuming the primary key value for EMPLOYEE_ID is accepted as a new unique entry. But we’re not able to INSERT a row through the VIEW using an INSERT statement that references the EMP_NAME column alias, nor its component columns FIRST_NAME and LAST_NAME. We simply have to omit any references to those columns in our DML statements for our DML to execute successfully. We may DELETE a row in this view. For example: DELETE FROM EMP_PHONE_BOOK WHERE EMPLOYEE_ID = 102; This statement will successfully delete the entire row for EMPLOYEE_ID of 102. If we issued a similar DELETE statement for any other existing value we can access— such as PRIMARY_PHONE or EMPLOYEE_ID—and the row were found, then the row—the entire row of the underlying table—would be deleted. That includes data in columns we can’t even see with the view. The whole row will delete. With regard to the general question of using INSERT, UPDATE, and/or DELETE on any given view, the general answer is really very simple: if the view provides rowlevel (not aggregated) access to one—and only one—table and includes the ability to access the required columns in that table, then you can use INSERT, UPDATE, and/or DELETE on the view to effect changes to the underlying table, in accordance with the restrictions we listed earlier. Otherwise, you may not be able to successfully execute a change to the view’s data. Note that the INSTEAD OF trigger in PL/SQL can be used to cause a nonupdatable view to behave as though it were updatable. But PL/SQL features are not addressed on the exam. Inline Views An inline view is a subquery that is contained within a larger SELECT statement in such a way that it replaces the FROM clause of a SQL statement. Here’s an example (line numbers added): 01 02 SELECT * FROM (SELECT * FROM DUAL); In this example, the inline view is included in the parentheses at the end of line 2. There is no limit to the number of inline views you can nest within inline views: SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM DUAL))); This “unlimited nesting” is different than the limit for typical subqueries, where the limit is 255 nested subqueries. 390 Chapter 10: Creating Other Schema Objects Inline views can be combined with various complex queries, such as those that use JOIN and GROUP BY clauses and more. For example: 01 02 03 04 05 06 07 08 09 SELECT A.SHIP_ID, A.COUNT_CABINS, B.COUNT_CRUISES FROM (SELECT SHIP_ID, COUNT(SHIP_CABIN_ID) COUNT_CABINS FROM SHIP_CABINS GROUP BY SHIP_ID) A JOIN (SELECT SHIP_ID, COUNT(CRUISE_ORDER_ID) COUNT_CRUISES FROM CRUISE_ORDERS GROUP BY SHIP_ID) B ON A.SHIP_ID = B.SHIP_ID; This statement is a single SELECT that pulls data from two inline views, one on lines 2 through 4, and the second on lines 6 through 8. Inline views can be any valid SELECT statement, placed into a SQL statement where the FROM clause would normally go. One great usage of an inline view is to address an issue involving the pseudocolumn ROWNUM. ROWNUM automatically assigns row numbers to each row in a table. The challenge with ROWNUM is that it assigns numbers before the ORDER BY clause is processed. As a result, you cannot sort rows and then use ROWNUM to number them—the results will be mixed up, since the ROWNUM is computed before the ORDER BY is processed. But you can move the ORDER BY clause into an inline view and then use the ROWNUM pseudocolumn on the outer query to display row numbers correctly. For example: SELECT ROWNUM, INVOICE_ID, ACCOUNT_NUMBER FROM (SELECT INVOICE_ID, ACCOUNT_NUMBER FROM INVOICES ORDER BY INVOICE_DATE) WHERE ROWNUM <= 3; ROWNUM ---------------------1 2 3 INVOICE_ID ---------------------2 3 4 ACCOUNT_NUMBER -----------------cre-kit-A1233-V01 ae-TRR INV-PR-0101 In this example, we use the ORDER BY in the inline view to sort our rows by INVOICE_DATE, and then we use ROWNUM in the outer query to limit our output to just the first three rows of data. We also include ROWNUM in our select list so that it appears in the output. Without the inline view, odds are that our ROWNUM values would be in an apparently random order, instead of sequential. Create and Use Simple and Complex Views 391 So why would you want to use an inline view? There are many reasons. As I’ve already demonstrated, inline views may be used to create complex joins built on aggregated queries. Another benefit has to do with the nature of dynamic SQL as it’s used with third-generation languages. Many popular web sites are built on web pages that are dynamically formed from a combination of Java, PL/SQL, or C++ code that pulls data from the database and merges the output with the languages used to form web pages. A full example of such a scenario is beyond the scope of this book, but it’s worth noting that such systems rely heavily on routines that create SQL code dynamically, during execution, in response to queries from end users. Such dynamic scenarios can benefit greatly from the ability to, for example, create a standard outer query in which the inline view can be substituted by dynamic code. An end user may perform a search that might draw data from any number of various sources, yet present the output through a fixed series of data elements.The inline view can support such a situation. Retrieving Data Retrieving data from a view is the same as retrieving data from a table. Views behave just like tables, and as such, they can be described, queried, joined, subqueried—in short, for all practical purposes, there is no difference between querying from a view versus querying from a table. ALTER VIEw The ALTER VIEW statement is used to accomplish any of the following tasks: n Create, modify, or drop constraints on a view. n Recompile an invalid view. The subject of constraints on a view is not something that is covered on the exam. Oracle does not enforce view constraints without special configuration (see DISABLE NOVALIDATE in Oracle’s documentation). Recompiling a view is a step you may wish to take if you’ve created a view and then later performed some sort of modification on the underlying table or tables upon which the view is created. Depending on the change you make to the view’s 392 Chapter 10: Creating Other Schema Objects source table, the view may be rendered invalid as a result. In Chapter 14 we’ll see how you can determine if a view is invalid or not, by querying the data dictionary. An invalid view cannot be used. If a view is invalid, it will require recompilation. Here is an example of a statement that recompiles a view: ALTER VIEW VW_EMPLOYEES COMPILE; You cannot change a view’s SELECT statement with the ALTER VIEW statement. Instead, you must drop and recreate the view. Once completed successfully, the view is back in working condition. If it does not compile, you know that the change to the underlying table may have fundamentally changed the nature of the VIEW’s structure. For example, if a view queries a particular named column from an underlying table, and that column is renamed or dropped, then the recompilation will not work and you may need to recreate the view and reassess your code. CertIFIcAtIon ObJectIVe 10.02 Create, Maintain, and use Sequences A sequence is an object that is predominantly used for one purpose: to generate data for primary key columns in tables. While that is the primary purpose of a sequence, there’s nothing inherent in the structure of a sequence to limit you to such a purpose. You can use a sequence to generate numeric sequences for any reason. But all a sequence does is issue sequentially increasing (or decreasing) numbers, according to the rules you define when you create the sequence. Creating Sequences Here’s a sample of the SQL statement to create a sequence: CREATE SEQUENCE SEQ_ORDER_ID; This example is a complete statement and represents the simplest form of a CREATE SEQUENCE statement. The syntax is as follows: Create, Maintain, and Use Sequences 393 n The required CREATE SEQUENCE keywords n The required name of the sequence that you specify, according to the rules of naming database objects Note that nothing in the code ties it to a particular table or other database object—nothing, that is, other than perhaps the choice of the name, which is a naming convention we use but is not required. Here’s the complete syntax for a sequence: CREATE SEQUENCE sequence_name sequence_options; There are several sequence_options that can each be specified, separated by spaces, as desired. Sequences can be set to start at any number and increment—or decrement— by any number. They can sequentially generate without ceasing or be given a range within which they continuously generate new numbers. They can be given a fixed series of numbers to generate, after which they cease generating numbers. The sequence options include the following: n INCREMENT BY integer Each new sequence number requested will increment by this number. A negative number indicates the sequence will descend. If omitted, the increment defaults to 1. n START WITH integer Specifies the first number that will start the sequence. If omitted, START WITH defaults to MINVALUE (which we discuss in a bit) for ascending sequences, or MAXVALUE for descending sequences, unless NOMINVALUE or NOMAXVALUE are specified either explicitly or implicitly (by default), in which case START WITH defaults to 1. n MAXVALUE integer Specifies the maximum number for the sequence. If omitted, then NOMAXVALUE is assumed. n NOMAXVALUE Specifies that there is no MAXVALUE specified. n MINVALUE integer Specifies the minimum number for the sequence. If omitted, NOMINVALUE is assumed, unless a MINVALUE is required by the presence of CYCLE, in which case the default is 1. n NOMINVALUE Specifies that there is no MINVALUE specified. When the sequence generator reaches one end of its range, restart at the other end. In other words, in an ascending sequence, once the generated value reaches the MAXVALUE, the next number generated will be the MINVALUE. In a descending sequence, once the generated value reaches the MINVALUE, the number generated will be the MAXVALUE. n CYCLE 394 Chapter 10: Creating Other Schema Objects When the sequence generator reaches the end of its range, stop generating numbers. NOCYCLE is the default. If no range is specified, NOCYCLE has no effect. n NOCYCLE Here’s another example of the CREATE SEQUENCE statement: CREATE SEQUENCE SEQ_ORDER_ID START WITH 1 INCREMENT BY 1; This SQL statement performs the same task as the earlier CREATE SEQUENCE statement you saw. This example explicitly specifies the default features. You can adjust those defaults if you wish, like this: CREATE SEQUENCE SEQ_ORDER_ID START WITH 10 INCREMENT BY 5; This statement will start with the number 10 and increment each successive number by 5. using Sequences Now that we’ve created a sequence, what do we do with it? Here’s an example: INSERT INTO ORDERS (ORDER_ID, ORDER_DATE, CUSTOMER_ID) VALUES (SEQ_ORDER_ID.NEXTVAL, SYSDATE, 28); In this sample INSERT statement, we insert a row into the ORDERS table that consists of three values. The first value is SEQ_ORDER_ID.NEXTVAL. This reference is to the sequence generator SEQ_ORDER_ID along with its pseudocolumn NEXTVAL, which performs the following two tasks: n Advances the sequence generator to the next available number. n Returns that value. If the sequence generator SEQ_ORDER_ID had just been created, and if it was created with the default values for the START WITH and INCREMENT BY, then the initial call to NEXTVAL will obtain the starting value of 1. If the next call to the sequence generator is also a call to the NEXTVAL pseudocolumn, then it will be advanced again by 1, to a value of 2. All sequence generators have two pseudocolumns: This increments the sequence to the next number, according to the sequence’s original CREATE SEQUENCE directives. It also returns the newly incremented number. n NEXTVAL Create, Maintain, and Use Sequences 395 This displays the current number that the sequence is holding. However, this call is only valid from within a session in which the NEXTVAL pseudocolumn has already been invoked. You cannot use CURRVAL in your initial call to any given sequence generator within a session. n CURRVAL The advantage to CURRVAL becomes apparent when working with a set of tables that involve PRIMARY KEY and FOREIGN KEY relationships. Consider the entity-relationship diagram (ERD) in Figure 10-2. Let’s create a couple of sequence generators for use with these tables: CREATE SEQUENCE SEQ_CRUISE_CUSTOMER_ID; CREATE SEQUENCE SEQ_CRUISE_ORDER_ID; Now—let’s insert some new rows into these tables (line numbers added): 01 02 03 04 05 06 07 08 09 INSERT INTO CRUISE_CUSTOMERS (CRUISE_CUSTOMER_ID, FIRST_NAME, LAST_NAME) VALUES (SEQ_CRUISE_CUSTOMER_ID.NEXTVAL, 'Joe', 'Schmoe'); INSERT INTO CRUISE_ORDERS (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID) VALUES (SEQ_CRUISE_ORDER_ID.NEXTVAL, SYSDATE, SEQ_CRUISE_CUSTOMER_ID.CURRVAL); FIGure 10-2 ERD diagram for the CRUISE_ CUSTOMERS and CRUISE_ ORDERS tables 396 Chapter 10: Creating Other Schema Objects There are three calls to our sequence generators in the preceding code: n In line 4 we call SEQ_CRUISE_CUSTOMER_ID.NEXTVAL to generate a new primary key. n At the end of line 9 we call the same sequence generator with the CURRVAL pseudocolumn. This directs the sequence generator to use the same value that was just assigned in the line 4 call—ensuring that our PRIMARY KEY– FOREIGN KEY relationship between these two tables will be respected. n At the beginning of line 9, we call SEQ_CRUISE_ORDER_ID.NEXTVAL to generate a new primary key for the CRUISE_ORDERS table. The result of these INSERT statements and uses of the sequence generators helps to ensure that we can join our tables to produce valid and meaningful output. A few important points to keep in mind about sequences: n You cannot invoke CURRVAL in your first reference to a sequence within a given session. NEXTVAL must be the first reference. n If you attempt to execute a statement, such as an INSERT, that includes the sequence reference NEXTVAL, the sequence generator will advance to the next number even if the INSERT statement fails. n You cannot invoke CURRVAL or NEXTVAL in the DEFAULT clause of a CREATE TABLE or ALTER TABLE statement. n You cannot invoke CURRVAL or NEXTVAL in the subquery of a CREATE VIEW statement, nor of a SELECT, UPDATE, or DELETE statement. n In a SELECT statement, you cannot combine CURRVAL or NEXTVAL with a DISTINCT operator. n You cannot invoke CURRVAL or NEXTVAL in the WHERE clause of a SELECT statement. n You cannot use CURRVAL or NEXTVAL in a CHECK constraint. n You cannot combine CURRVAL or NEXTVAL with the set operators UNION, INTERSECT, or MINUS. n You can call a sequence pseudocolumn from anywhere within a SQL statement that you can use any expression. That last point is important—a reference to a sequence must include its pseudocolumn, and such a reference is considered to be a valid expression, or a component of an expression. So assuming you’re working with a table PROJECTS Create and Maintain Indexes 397 that has a column PROJECT_COST, you could invoke a sequence SEQ_PROJ_ COST like this: SELECT PROJECT_COST / (3 * SEQ_PROJ_COST.NEXTVAL) FROM PROJECTS; That is valid syntax. Whether it’s useful or not is up to your business rules. But SQL recognizes this syntax and will execute it successfully. The bottom line: references to the pseudocolumns of sequences are valid expressions. Any SQL statement that is executed with a call to a sequence’s NEXTVAL pseudocolumn will advance the sequence, even if the SQL statement fails. CertIFIcAtIon ObJectIVe 10.03 Create and Maintain Indexes An INDEX is an object you can create in the database that supports faster queries on tables. For a given table, the INDEX stores a set of presorted data from one or more columns that you designate. Also stored in the INDEX is the address of data from the source table. SQL can use the INDEX object to speed up querying of WHERE and ORDER BY clauses. For example, if a WHERE clause references any indexed column (or columns), then SQL will automatically consider the index as it determines the optimal query strategy for the SQL statement. The result: queries may be significantly faster, depending on the amount of data involved, and also depending on the number of indexes that may be applied to a table. You cannot create an index on columns of LOB or RAW datatypes. Given that, you can create as many indexes as you wish on any given table. However, as you add additional indexes, you’ll eventually reach a point of diminishing returns—each index added to a table can potentially increase the workload on future INSERT, UPDATE, and DELETE statements. But let’s hold off on that discussion for a bit. For now, we just want to say that the SQL system will let you create as many indexes as you wish. 398 Chapter 10: Creating Other Schema Objects Remember that the WHERE clause can appear in a SELECT, UPDATE, or DELETE statement. Also note that a SELECT statement, in the form of a subquery, may appear within an INSERT statement or a variety of statements that CREATE objects such as the TABLE or VIEW. An INDEX object can potentially benefit any of these situations. Implicit Index Creation If you create a constraint on a table that is of type PRIMARY KEY or UNIQUE, then as part of the creation of the constraint, SQL will automatically create an index to support that constraint on the column or columns, if such an index does not already exist. For example, consider the following SQL statement: CREATE TABLE SEMINARS (SEMINAR_ID NUMBER(11) PRIMARY KEY, SEMINAR_NAME VARCHAR2(30) UNIQUE); This statement will create the table SEMINARS, two CONSTRAINTs, and two INDEX objects. These INDEX objects will be named automatically by the SQL system. Later in this section, you’ll see how to manually create these indexes. Also later, in Chapter 14, you’ll see how you can query the data dictionary to see these implicitly created indexes, but for now, here’s a query on the data dictionary that can confirm their creation: SELECT TABLE_NAME, INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'SEMINARS'; TABLE_NAME -----------------------------SEMINARS SEMINARS INDEX_NAME -----------------------------SYS_C009932 SYS_C009931 In the output of this example, you can see that the system assigned the names SYS_ C009932 and SYS_C009931 to the indexes. As an alternative, you can query elsewhere in the data dictionary to see the columns that are involved in the indexes: Create and Maintain Indexes 399 SELECT INDEX_NAME, COLUMN_NAME FROM USER_IND_COLUMNS WHERE TABLE_NAME = 'SEMINARS'; INDEX_NAME -----------------------------SYS_C009931 SYS_C009932 COLUMN_NAME --------------------------------SEMINAR_ID SEMINAR_NAME In these examples, we applied each constraint to a single column. Had we created a composite PRIMARY KEY, or a composite UNIQUE constraint, then all columns involved in the constraint would have also been indexed as a composite index, and the column names would be listed in the output of this second query on the data dictionary. Single Column Here is an example of a SQL statement that creates a single column index: CREATE INDEX IX_INV_INVOICE_DATE ON INVOICES(INVOICE_DATE); This SQL statement creates a simple index called IX_INV_INVOICE_DATE, on the column INVOICE_DATE in the table INVOICES. This will result in an object that sorts values in the INVOICE_DATE column of the INVOICES table. Once such an index exists, queries that reference INVOICE_DATE in the WHERE clause may return results significantly faster: SELECT * FROM INVOICES WHERE INVOICE_DATE = SYSDATE; This query may search the table by first searching in the index. The reason we say “may” is because of something called the “optimizer”. Optimizer All SQL statements use the Oracle Database optimizer . The optimizer processes all SQL statements to determine the best course of action in determining the result. For any SQL statement that needs to scan data in a table—such as a query with a WHERE clause or an ORDER BY clause—the optimizer will consider whether or not an available index on the queried table will contribute toward faster performance. The existence of an index does not guarantee its use. 400 Chapter 10: Creating Other Schema Objects For example, let’s consider the SELECT statement against the INVOICES table that we just reviewed. Whether or not an index is used for that query depends on the nature of the data found in the INVOICE_DATE column that is specified in the WHERE clause. If, for example, all of the rows in the INVOICES table have the same value for INVOICE_DATE, the index may not be used. On the other hand, if each row happens to have a unique INVOICE_DATE value, then the index most likely will be used. The difference has to do with the concept of selectivity. If a column tends to include data that is less repetitive and more unique, it is said to have a higher degree of selectivity, and an index on such a column would be attractive to the optimizer. But if data in a given column is relatively repetitive, it is said to have a lower degree of selectivity and will be less likely to be included in an index. In the sample SELECT you just looked at, if the SQL optimizer determines to use the index, and if evidence is found in the index that a row of INVOICES matches the desired result, the index points the query directly to the row(s) in the table, and the result is achieved—much faster than otherwise would have occurred. usage The Oracle Database optimizer will consider the use of an index in any query that specifies an indexed column in the WHERE clause or ORDER BY clause, depending on how the index column is specified. There are some guidelines for structuring your SQL statement so that the optimizer will be more likely to apply the index. The guidelines are as follows: n For best results, the indexed column should be specified in a comparison of equality. n A “greater than” or some other comparison may work. n A “not equals” will not invoke an index. n The LIKE comparison may invoke an index as long as the wildcard character is not in the leading position—in other words, the expression LIKE ‘%SMITH’ will not invoke an index, but LIKE ‘SMITH%’ may invoke an index. n A function on a column will prevent the use of an index—unless the index is a function-based index, which we’ll discuss in detail in Chapter 11. Furthermore, certain types of automated datatype conversions will eliminate the index. Create and Maintain Indexes 401 The design of an indexing scheme is something that falls under the general category of performance tuning. There is no single comprehensive approach to index design for a given database application. The approach you take depends upon a variety of factors, including the amount and selectivity of data expected, and the anticipated frequency and types of the various SQL statements you intend to execute on the database. A system that will not be queried much but will be heavily populated with INSERT statements would not benefit much from indexes, since each INSERT will be slower as it updates the tables and all associated INDEX objects. On such a database, infrequent queries may not justify the creation of INDEX objects and their associated performance trade-off. On the other hand, an application that involves a great deal of updating via UPDATE statements will benefit with thoughtfully designed indexes. There’s an old rule of thumb that recommends no more than five indexes on the average table in a transaction-based application. But that—again—depends on intended usage. The optimizer will do I’ve implemented applications in which some everything it can to use an index for a tables have had as many as nine indexes applied, given query if at all possible, and if the and the result was positive. That was a situation index is beneficial. It only avoids an index where queries on the table were not using if its use would be detrimental, such as in primary keys so much but instead used a variety the case of a table with a large number of of text-based lookups. rows with an indexed column that has low Performance tuning is the subject of many selectivity. books and is a topic that goes far beyond this book—and the exam. For the exam, it’s important to understand the syntax of creating indexes—both single column and composites—and their intended purpose and general usage. Maintenance Indexes are automatically maintained in the background by SQL and require no effort on your part to keep their lookup data consistent with the table. However, note that this means each future INSERT, UPDATE, and DELETE statement you issue will have to work harder. Each DML statement that modifies data in a table that is indexed will also perform index maintenance as required. In other words, each index you add to a table puts more workload on each DML statement that affects indexed data. 402 Chapter 10: Creating Other Schema Objects Build the indexes that contribute to your application’s overall performance, and don’t build indexes unless they are necessary. And plan to periodically review your index structures to determine which indexes may no longer be needed—an existing application burdened with unnecessary indexes may benefit from the removal of indexes. There are a number of performance tuning tools and techniques to assist with designing indexes. One is the EXPLAIN PLAN feature, which reveals the internal workings of a given SQL statement and provides insight into how SQL will optimize a given statement, including the use of indexes for a given SQL statement. It’s a great tool. And it’s not in the list of certification objectives for the exam, so we won’t get into it here. You may wish to explore one of the other books in the Oracle Press line to learn more about it. Composite A composite index is an index that is built on two or more columns of a table, like this: CREATE INDEX IX_INV_INVOICE_VENDOR_ID ON INVOICES(VENDOR_ID, INVOICE_DATE); In this example, the result is one single index that combines both columns. A composite index copies and sorts data from both columns into the composite index object. Its data is sorted first by the first position column, second by the second position column, and so on, for all of the columns that form the composite index. A WHERE clause that references all of the columns in a composite index will cause the SQL optimizer to consider using the composite index for processing the query. For example, this query would encourage the optimizer to use the composite index IX_INV_INVOICE_VENDOR_ID to maximum advantage: SELECT * FROM INVOICES WHERE VENDOR_ID = 10 AND INVOICE_DATE = SYSDATE; Note that the WHERE clause in the preceding example references the columns that make up the composite INDEX object. Next, consider this query: SELECT * FROM INVOICES WHERE VENDOR_ID = 10; This query, which references the first column in the composite index, also invokes the index. The reason: the composite index internally sorts data by the first column first, and the second column second. Given that, the internally copied and sorted data from the indexed table is comparable in structure to a single-column index based on—in this example—the VENDOR_ID column. Create and Maintain Indexes 403 But now consider this query: SELECT * FROM INVOICES WHERE INVOICE_DATE = SYSDATE; This query references the second column in the composite query, but not the first. The composite index structure is primarily sorted on the first column of its structure, which in the example we’re working with, is VENDOR_ID. But this query does not reference VENDOR_ID. Nevertheless, the SQL optimizer may still consider applying the index due to a feature known as “skip scanning”. Skip Scanning Thanks to skip scanning, a WHERE clause that references any columns within a composite index may invoke the index in its processing. However, the performance benefit is not identical. In skip scanning, SQL treats a composite index as a combination of several indexes. How many? That depends on the level of selectivity that results in the indexing of the first—or leading—column of the INDEX object. If the first column contains only a few unique values within a large number of rows, the index—if used—may be applied a relatively few number of times. On the other hand, if the leading column contains data that is relatively unique across the rows, then the index—if used—may be reviewed frequently. In other words, a skip scan will do an index scan once for each unique value in the first column. This isn’t quite as beneficial as a simple one-column index, and its benefit varies, depending on the uniqueness of values in the first column. But the WHERE clause gains some benefit anyway. The point is that a WHERE clause that references some, but not all, of the columns in a composite index may invoke the index, even if the leading column is not referenced in the WHERE clause. However, including the leading column may result in a more efficient application of the composite index and, therefore, a faster result to the query. unique A unique index is one that helps ensure that a column in a table will contain unique information. The syntax for creating a unique index is as follows: CREATE UNIQUE INDEX IX_EMP_SSN ON EMPLOYEES(SSN); This SQL statement creates an index that will ensure that data entered into the SSN column of the table EMPLOYEES is unique. 404 Chapter 10: Creating Other Schema Objects This is different from the UNIQUE constraint that you can apply to a column on a table. However, note that if you create a PRIMARY KEY or UNIQUE constraint on a table, a unique index will automatically be created along with the constraint. Note that the UNIQUE constraint is more self-documenting within the database. That being said, Oracle Corporation formally recommends the creation of unique indexes to enforce uniqueness in a column, for better results in query performance. Dropping You can drop an index with the DROP INDEX statement. For example, let’s drop our IX_INV_INVOICE_DATE index: DROP INDEX IX_INV_INVOICE_DATE; Note that if you drop a table upon which an index is based, the index is automatically dropped. If you re-create the table, you need to re-create the index. CertIFIcAtIon ObJectIVe 10.04 Create Private and Public Synonyms The SYNONYM object is a relatively simple object with a surprisingly important purpose. A SYNONYM consists of nothing more than an alternative name—an alias—for another object in the database that may—or may not—already exist. In other words, it’s an alternative name for some other database object. At first glance, the SYNONYM might not seem like a terribly useful feature, but it’s a critical component of a professional database application implementation, for reasons you’re about to see. You can create synonyms for tables, views, sequences, and other synonyms, as well as a number of other database objects that are included on the exam. When you create a synonym for another object, that object does not necessarily have to exist already. If it does exist, you are not required to have privileges on the object in order to successfully create a synonym for it. Obviously, however, for the synonym to eventually work, the object must eventually be created, and privileges must eventually be granted—but that can come after the synonym’s creation. First, there are two types of synonyms: private synonyms and public synonyms. In terms of SQL syntax, there really isn’t any such thing as a private synonym. There is instead a SYNONYM and a PUBLIC SYNONYM. You’ll look at both in detail next. Create Private and Public Synonyms 405 Private The SYNONYM (without the keyword PUBLIC) is often referred to as a private synonym. But there is no PRIVATE keyword that’s applicable in this context. Here’s an example of a SQL statement that creates a private synonym: CREATE OR REPLACE SYNONYM CO FOR CRUISE_ORDERS; This code creates an alternative name CO for an existing database object name CRUISE_ORDERS. The syntax is as follows: n The keyword CREATE is required. n The keywords OR REPLACE are optional—if included, then any preexisting synonym object with the same name will be dropped and re-created according to this statement’s directive. n The keyword SYNONYM is required. n Next comes the name you specify, according to the rules for naming database objects. n The keyword FOR is required. n Finally, include the name of the existing database object for which you wish to create an alias, optionally preceded by its schema name (which isn’t included in this example, but we’ll look at schema name prefixes in a bit). If the CRUISE_ORDERS object is a table, then you could now execute the following SQL statement: SELECT * FROM CO; In other words, once you’ve created a synonym for an object, you can reference that object with the synonym instead of its real name. In addition, the original name of the object is still good and available. A private synonym is owned by the user account that creates it, and by default is only visible within the user account, just as any other object owned by the user. As with any object owned by the user, the user must take steps to grant privileges on owned objects for other user accounts to get access to that object. In other words, a user may choose to make their private synonym visible to other users, but that requires an explicit effort on the user’s part to make that happen, as is true for tables, views, and many other objects—but not all objects. As you’ll see in the next section, the PUBLIC SYNONYM is automatically visible to all users. Let’s see how that works. 406 Chapter 10: Creating Other Schema Objects Public A public synonym is owned by a special system user account called PUBLIC. Every object owned by the PUBLIC account is automatically made visible to all users in the database. A public synonym, once created, is available to everyone in the database. Users who have been granted the appropriate system privilege may create a public synonym. We’ll discuss system privileges in Chapter 18, but for now, note that the system privilege required is the CREATE PUBLIC SYNONYM system privilege. Here’s an example of the statement that creates a public synonym: CREATE PUBLIC SYNONYM WH FOR WORK_HISTORY; It’s virtually identical to the syntax for creating a private synonym, with the only difference being the addition of the keyword PUBLIC. Once it is created, any user in the database can see the public synonym and reference it. However, that doesn’t necessarily guarantee that the user can get access to whatever object the synonym represents. In the preceding example, the public synonym WH is another name for the table WORK_HISTORY. Once created, any user can see the public synonym, but that doesn’t mean any user can access the WORK_HISTORY table—that requires privileges on the table itself, in addition to the creation of the public synonym. Object Privileges One of the most important usages of the public synonym is as an alias for a database object that has been made available by its owner to other users. Consider the table PORTS. Let’s say that PORTS is owned by a user called CODD, and that CODD wants other users to see this table. CODD decides to authorize another user account for this purpose; let’s call the other user account LARRY. CODD is going to let LARRY read data from the PORTS table. Later, in Chapter 18, we’ll look at the issues of user access, roles, and privileges. For now, know that this is the SQL statement that CODD can use to accomplish this. The statement will be this: GRANT SELECT ON PORTS TO LARRY; This statement, executed by CODD, gives user LARRY the ability to query the PORTS table owned by CODD. Once that’s been done, user LARRY will be able to query the PORTS table with a query like this: Create Private and Public Synonyms 407 SELECT * FROM CODD.PORTS; Notice that for LARRY to access the table PORTS that is owned by CODD, the user LARRY will have to prefix the table name with the user account name of CODD. This will be true for all queries issued by LARRY on the table PORTS. But what if CODD decides to turn over maintenance of the PORTS table to someone else? That means CODD will probably move the PORTS table to a different user account. That also means that somebody has to remember to let user LARRY know that he’s going to have to change his code in all his queries of the PORTS table, and edit out the CODD prefix, and put in something else. That’s really annoying, not to mention a maintenance headache that’s error-prone. But the public synonym can be used here to make life a lot easier. Here’s how: CREATE PUBLIC SYNONYM PORTS FOR CODD.PORTS; Now, assuming the SELECT privilege is still in force for user LARRY, any queries user LARRY makes on the PORTS table don’t need the schema prefix before the name of the database object PORTS. The following SELECT statement will work from user LARRY’s account: SELECT * FROM PORTS; This statement will be interpreted to be the same thing as SELECT * FROM CODD.PORTS; . . . thanks to the PUBLIC SYNONYM. Now, if user CODD moves the PORTS table to a different user account, all CODD must do is redefine the public synonym object, perhaps like this: CREATE OR REPLACE PUBLIC SYNONYM PORTS FOR NEWOWNER.PORTS; If you have a synonym for a database object, and the database object is dropped, the synonym is not dropped—it exists independently of the object it renames. CODD doesn’t even need to notify user LARRY about the changed location of the PORTS table. Most commercial database applications make heavy use of public synonyms for every table and view and other referenced object that goes into the database application. A combination of the appropriate GRANT and CREATE public synonym statements set up an application that can easily be relocated later to a different user 408 Chapter 10: Creating Other Schema Objects account without having to tell anyone or change any code. All that is required to move the application is a revised set of SQL statements to drop and recreate the appropriate public synonym objects. Name Priority We discussed namespaces in Chapter 2. As you might recall, objects created in the database are placed within different namespaces. You saw this in detail in Figure 2-2, where you saw which objects are assigned to which namespace. Objects within a given namespace cannot share the same name. A local user account contains a single namespace for the tables, views, sequences, and private synonyms it owns. This means that you cannot create a private synonym that has the same name as a table or view or sequence that already exists and already has that same name. You can, however, create a private synonym with a unique name to represent an existing object of a different name. But Figure 2-2 also showed us that public synonyms are kept in their own namespace, separate from the user account namespace. This means that you can create a public synonym with the same name as an existing user account synonym. This raises an interesting issue. Assume you have two valid tables in your user account, one called LAB_RESULTS and another called CABINETS. Consider the following code: CREATE SYNONYM ACCT_01 FOR LAB_RESULTS; CREATE PUBLIC SYNONYM ACCT_01 FOR CABINETS; SELECT * FROM ACCT_01; Question: are we selecting from LAB_RESULTS or CABINETS? We’ve already seen that it is perfectly valid to create private and public synonyms of the same name. But what happens when you try to use them? The answer is indicated in Figure 10-3. The priority of referencing objects goes first to local objects. When you are logged in to a given user account and attempt to access a particular object, SQL will first look to the local namespace for that object. If it does not find it, it will then look to the PUBLIC objects. Now we can answer the earlier question. The SELECT statement was looking for the local object—which was the private synonym ACCT_01, as opposed to the public synonym of the same name. That private synonym is pointing to LAB_ RESULTS. So we were querying LAB_RESULTS. Create Private and Public Synonyms FIGure 10-3 409 namespace Users Roles Public Synonyms Named objects conflicts and namespace priority 2 First, SQL looks for “an_object” in the local namespace for Schema_1, then the database namespace. 1 namespace Tables Views Sequences Private Synonyms User-Defined Types SQL> SELECT * 2 FROM an_object; Schema_1 Database Replacing There is no statement that combines ALTER with SYNONYM; not for private synonyms, nor for public synonyms. Instead you can use the OR REPLACE option with CREATE SYNONYM, like this: CREATE OR REPLACE SYNONYM CO FOR CODD.CRUISE_ORDERS; Or, for public synonyms: CREATE OR REPLACE PUBLIC SYNONYM CO FOR CODD.CRUISE_ORDERS; That’s the approach to “altering” a synonym. Note the preceding two CREATE statements. One does a “CREATE OR REPLACE” to build a private synonym; the other executes a “CREATE OR REPLACE” to build a public synonym. Question: at the end of these two statements, do you have two synonyms, or one? The answer is two—a synonym is different from a public synonym. A synonym is “private” unless specified otherwise. 410 Chapter 10: Creating Other Schema Objects Dropping To remove the synonym CO from the database, you can use this statement: DROP SYNONYM CO; Or for a public synonym CO, you can use this: DROP PUBLIC SYNONYM CO; That’s it. CertIFIcAtIon SummArY Views are objects that name a query and store the query in the database. Views do not store data. They look and act like tables. Views may be built with simple or complex SELECT statements. GROUP BY, HAVING, join queries, and more are all possible in a VIEW object’s SELECT statement. A SELECT statement can be used to query a view just as it would be used to query a table. But INSERT, UPDATE, and DELETE statements will only work with certain views, not all of them—it depends on whether the view’s structure allows appropriate access to the table or tables upon which the view is based. Any DML statement will work with a view based on a single table, provided that the required columns are all included in the select list of the SELECT statement used to create the view, and that the rows of the view are not aggregate rows, and that all of the table’s constraints are honored. A view is not necessarily required to include columns that are required by the view’s underlying table, but if the view omits such columns, then an INSERT statement cannot add—to the view—a value that is required by the underlying table, and the constraints on the underlying table will reject the INSERT and it won’t work for that view. Any SELECT statement used to create a view must have clearly defined column names. Complex expressions must be assigned a column alias; this will become the name of the column in the resulting view object. An inline view is a variation on a subquery, in which the SELECT statement replaces a table reference in a FROM clause of any DML statement. An inline view must be enclosed in its own set of parentheses. Once incorporated in a DML statement, the inline view behaves just like a view object would behave. If the underlying table is modified, the view may require recompilation using the ALTER VIEW . . . COMPILE statement. Certification Summary 411 Sequence objects are counters. They dispense numbers according to the parameters established when the sequence is first created. SQL automatically defines pseudocolumns for each sequence. The NEXTVAL pseudocolumn increments the sequence to the next available number as defined in the sequence’s parameters defined at the time the sequence is created. The CURRVAL pseudocolumn refers back to whatever the last NEXTVAL reference produced in a given session. In any session with a sequence, the NEXTVAL pseudocolumn must be referenced before the CURRVAL pseudocolumn may be referenced. A reference to a sequence pseudocolumn is a valid expression and can be invoked in many places where expressions are allowed, with certain restrictions. Indexes are objects that copy a subset of presorted information from a table, and may be referenced automatically by SQL to speed up the processing of a given SQL statement, depending on how that SQL statement is structured and what the Oracle Database optimizer chooses to do. An index can be built on one or more columns in a table. Once created, if a WHERE or ORDER BY clause references the indexed column, SQL may use the index to speed up the process of obtaining a result. An index that is built on multiple columns is known as a “composite” index. A UNIQUE INDEX can be used to enforce a unique rule on a column. There are two types of synonyms: private and public. Private synonyms exist within a user account. Public synonyms are owned by the system account PUBLIC and are automatically available for everyone’s use. Since private and public synonyms exist in different namespaces, it’s possible for one user account to create one of each with the same name. In such an event, SQL will look for any reference to the name by first searching in the local namespace (i.e., the user account) and then looking in the public namespace (the PUBLIC account). 412 Chapter 10: 3 Creating Other Schema Objects Two-MInute DrIll Create and use Simple and Complex Views q A VIEW is a SELECT statement that is stored in the database and assigned a name. q The columns and expressions of the SELECT statement used to create a view become the columns of the VIEW. q You can use SELECT statements on views just as you would a table. q You can use INSERT, UPDATE, and/or DELETE statements on some views, depending on the constraints of the view’s underlying table or tables, as well as other issues such as whether the view’s SELECT statement includes aggregate functions or not. q An “inline view” is a subquery that replaces a table reference in a FROM clause of a DML statement. q The VIEW can be treated like a table, with some limitations. q A VIEW based on a table that is subsequently altered may require recompila- tion with the ALTER VIEW . . . COMPILE statement. Create, Maintain, and use Sequences q A SEQUENCE is an object that dispenses numbers according to the rules established by the sequence. q A SEQUENCE specifies the starting number, the increment (which can be positive or negative), and an optional range of values within which the sequence can generate values. q The starting point can be within the range or at one end of the range. q SEQUENCES are ideal for populating primary key values. q The NEXTVAL pseudocolumn of a sequence returns the next available umber in the sequence and must be the first reference to the sequence in n any given login session. q The CURRVAL pseudocolumn can return the existing value as already d efined by NEXTVAL; it can only be referenced in a session after the NEXTVAL reference has occurred. Two-Minute Drill 413 q A pseudocolumn reference to a sequence is a valid expression and can be referenced anywhere that a valid expression is allowed. q If a valid sequence reference to NEXTVAL occurs within a DML statement that fails, the sequence still advances. Create and Maintain Indexes q An INDEX object is based on one or more columns in a table. q The INDEX copies data from its table’s columns on which it is built, and presorts that data in order to speed future queries. q When the DML statements INSERT, UPDATE, or DELETE are executed on an indexed table so that the indexed data is changed, the index is automatically updated by SQL, thus adding to the workload of the DML statements. q INDEX objects can be built on one or more columns. Multiple-column in- dexes are “composite” indexes. Create Private and Public Synonyms q SYNONYM objects are aliases for other objects in the database. q A SYNONYM can be created for objects that do not yet exist in the database. q A private SYNONYM is created with the CREATE SYNONYM statement and is owned by a user account. q A PUBLIC SYNONYM is created with the CREATE PUBLIC SYNONYM statement and is owned by the PUBLIC user account. q PUBLIC SYNONYMs are automatically accessible to all users; however, before user accounts can access the aliased object, the user must have the appropriate privileges for the object for which the PUBLIC SYNONYM is an alias. 414 Chapter 10: Creating Other Schema Objects SelF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Create and use Simple and Complex Views 1. Which of the following SQL statements can be executed on any VIEW object? (Choose all that apply.) A. SELECT B. INSERT C. DELETE D. UPDATE 2. Review the following illustration: Now review the following SQL code (line numbers added): 01 02 03 04 CREATE OR REPLACE VIEW SHIP_CAP_PROJ AS SELECT SHIP_ID, TO_CHAR(CAPACITY,'999,999'), PROJECT_COST Self Test 05 06 07 FROM USING WHERE 415 SHIPS JOIN PROJECTS (SHIP_ID) (PROJECT_COST * 2) < 100000; What will result from an attempt to execute this SQL code? A. The statement will fail because of an error in line 3. B. The statement will fail because of an error in line 6. C. The statement will fail because of an error in line 7. D. The statement will execute and the view will be successfully created. 3. Review the illustration from question 2, and the following SQL code: CREATE OR REPLACE VIEW PROJECTS_ROLLUP AS SELECT SHIP_NAME, CAPACITY, COUNT(PROJECT_ID) NUM_PROJECTS, ROUND(SUM(DAYS)) TOTAL_DAYS FROM SHIPS A JOIN PROJECTS B ON A.SHIP_ID = B.SHIP_ID GROUP BY SHIP_NAME, CAPACITY; What can be said of this code? A. After the view is created, a valid SELECT statement will work on the PROJECTS_ ROLLUP view, but an INSERT will not. B. After the view is created, a valid SELECT and valid INSERT statement will work on the PROJECTS_ROLLUP view. C. The attempt to create the view will fail because you cannot create a VIEW with a SELECT statement that uses a GROUP BY clause. D. The attempt to create the view will fail because you cannot create a VIEW with a SELECT statement that is a join. 4. Review the illustration from question 2, and the following SQL code (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 CREATE OR REPLACE VIEW MAJOR_PROJECTS AS SELECT PROJECT_ID, SHIP_ID, PROJECT_NAME, PROJECT_COST FROM PROJECTS WHERE PROJECT_COST > 10000; INSERT INTO MAJOR_PROJECTS (PROJECT_ID, SHIP_ID, PROJECT_NAME, PROJECT_COST) VALUES ((SELECT MAX(PROJECT_ID)+1 FROM PROJECTS), (SELECT MAX(SHIP_ID) FROM SHIPS), 'Small Project', 500); 416 Chapter 10: Creating Other Schema Objects What will result from an attempt to execute these two SQL statements? A. The CREATE statement will fail because it omits the PURPOSE column from the PROJECTS table. B. The INSERT statement will fail because of an error on lines 9 and 10. C. The INSERT statement will fail because the PROJECT_COST value being inserted is not consistent with the WHERE clause on line 4. D. The CREATE and INSERT statements will successfully execute. 5. You have created a view MED_BENEFITS on a table BENEFITS. After you created the view, the BENEFITS table was altered. Which of the following SQL statements will ensure the view is still valid—or determine if the view requires more substantial modification? A. COMPILE VIEW MED_BENEFITS; B. RECOMPILE VIEW MED_BENEFITS; C. ALTER VIEW MED_BENEFITS COMPILE; D. ALTER VIEW MED_BENEFITS RECOMPILE; Create, Maintain, and use Sequences 6. Which of the following keywords cannot be used with the CREATE SEQUENCE statement? A. CYCLE B. MAXVALUE C. INCREMENT D. JOIN 7. Review this code: DROP TABLE SHIPS CASCADE CONSTRAINTS; DROP SEQUENCE PROJ_ID_SEQ#; CREATE TABLE SHIPS (SHIP_ID NUMBER PRIMARY KEY, LENGTH NUMBER); CREATE SEQUENCE PROJ_ID_SEQ# START WITH 1 INCREMENT BY 4; INSERT INTO SHIPS (SHIP_ID, LENGTH) VALUES (PROJ_ID_SEQ#.NEXTVAL, 'NOT A NUMBER'); INSERT INTO SHIPS (SHIP_ID, LENGTH) VALUES (PROJ_ID_SEQ#.NEXTVAL, 750); COMMIT; Self Test 417 Note that the first INSERT statement is attempting to enter a string literal ‘NOT A NUMBER’ into a column declared with a numeric datatype. Given that, what will be the result of this SQL statements? A. One row added to the SHIPS table, with a SHIP_ID value of 1. B. One row added to the SHIPS table, with a SHIP_ID value of 5. C. Two rows added to the SHIPS table. The first SHIP_ID is 1; the second is 5. D. Two rows added to the SHIPS table. The first SHIP_ID is NULL; the second is 5. 8. Review this code: DROP SEQUENCE PROJ_ID_SEQ#; CREATE SEQUENCE PROJ_ID_SEQ# START WITH 1 INCREMENT BY 2; SELECT PROJ_ID_SEQ#.CURRVAL FROM DUAL; What will result from these SQL statements? A. The SELECT statement will fail because the sequence can only be referenced in an INSERT statement. B. The SELECT statement will fail because you cannot reference the CURRVAL pseudocolumn of a sequence until after you have referenced NEXTVAL for the sequence in a session. C. The SELECT statement will display a value of 1. D. The SELECT statement will display a value of 3. Create and Maintain Indexes 9. An index: A. Copies all of the data from all of the columns in any given table into a separate object and sorts the data for faster lookups. B. May improve the performance of an UPDATE statement that uses a WHERE clause, if the WHERE clause performs an equality comparison on an indexed column in a table. C. Requires a separate INSERT statement each time you add data to a table—one time to add a new row to the table, another time to add the corresponding and necessary data required by the index. D. Only works with a SELECT statement if you display data that is indexed. 418 Chapter 10: Creating Other Schema Objects 10. Review the following series of SQL statements: CREATE TABLE SUPPLIES_01 ( SUPPLY_ID NUMBER(7), SUPPLIER VARCHAR2(30), ACCT_NO VARCHAR2(50)); CREATE INDEX IX_SU_01 ON SUPPLIES_01(ACCT_NO); DROP TABLE SUPPLIES_01; CREATE TABLE SUPPLIES_02 ( SUPPLY_ID NUMBER(7), SUPPLIER VARCHAR2(30), ACCT_NO VARCHAR2(50)); CREATE INDEX IX_SU_02 ON SUPPLIES_02(ACCT_NO,SUPPLIER); Assuming there are no objects already in existence named SUPPLIES_01 or SUPPLIES_02 prior to the execution of the preceding statements, what database objects will result from these statements? A. A table called SUPPLIES_02, and nothing else B. A table called SUPPLIES_02, and an index called IX_SU_02 C. A table called SUPPLIES_02, and two indexes called IX_SU_01 and IX_SU_02 D. None of the above 11. An index that is based on more than one column is: A. Not possible B. A correlated index C. A combined index D. A composite index 12. Review this code: CREATE TABLE SPARES ( SPARE_ID NUMBER(8), PART_NO VARCHAR2(30), PART_NAME VARCHAR2(80)); Assume that no table called SPARES exists at the start of this series of statements. Which of the following will successfully create an index on the SPARES table? A. CREATE INDEX IX_01 ON SPARES PART_NO,PART_NAME; B. CREATE INDEX IX_01 ON SPARES COMPOSITE PART_NO,PART_NAME; C. CREATE INDEX IX_01 ON SPARES (PART_NO,PART_NAME); D. None of the above Self Test 419 Create Private and Public Synonyms 13. A private synonym: A. Can be seen by any user in the database who has privileges on it and has privileges on the synonym’s underlying object. B. Can only be seen by the user who creates it, and cannot ever be seen by any other user in the database under any circumstances. C. Is created with the CREATE PRIVATE SYNONYM statement. D. Is also called a “column alias” in a SELECT statement. 14. Review these SQL statements: CREATE CREATE INSERT CREATE CREATE SELECT TABLE BOXES (BOX_ID NUMBER(7)); TABLE TRUNKS (TRUNK_ID NUMBER(8)); INTO TRUNKS VALUES (1); OR REPLACE SYNONYM CONTAINERS FOR BOXES; OR REPLACE PUBLIC SYNONYM CONTAINERS FOR TRUNKS; COUNT(*) FROM CONTAINERS; What will be the result of this SQL code? A. At least one of the statements will fail with a error. B. The SELECT statement will return a value of 0. C. The SELECT statement will return a value of 1. D. None of the above. 15. Looking again at the code in the preceding question, how many synonyms—either public or private—will result from that code? A. 0 B. 1 C. 2 D. Not enough information is available to make a determination 420 Chapter 10: Creating Other Schema Objects SelF Test Answers Create and use Simple and Complex Views 1. ˛ A. The SELECT statement can be used against any view. ˝ B, C, and D are incorrect. There are many reasons why any given VIEW may reject attempts to execute the INSERT, UPDATE, or DELETE statements. For example, if the VIEW object does not contain sufficient access to its underlying tables, then it might not provide all the column access required to satisfy the underlying constraint restrictions that may exist for any INSERT, UPDATE, or DELETE statement. While many views allow all of these SQL statements to work, it’s entirely possible to create a VIEW that does not. 2. ˛ A. The error on line 3 is the failure to give the expression a column alias. The VIEW does not assign a name to the second column, so the attempt to create the view fails. ˝ B, C, and D are incorrect. These are not errors. Line 6 is fine; the use of USING works well here. Line 7 is fine; the expression that calculates the result of PROJECT_COST times 2 is fine; expressions in WHERE clauses have no restrictions in a CREATE VIEW statement. 3. ˛ A. The syntax for creating the view is correct, and any view can—at a minimum—work with a SELECT statement. But an INSERT will not work with this view since it consists of aggregate rows, as defined by the GROUP BY clause in the view’s SELECT statement. ˝ B, C, and D are incorrect. The view will not work with an INSERT because of the GROUP BY. In other words, there is no way to add single-row values through the view, since the view’s access to the tables is, by definition, at the aggregate level. Also, the GROUP BY and JOIN conditions for the SELECT are fine; you can most certainly create views with those clauses in the SELECT statement—they just have the effect of limiting the capabilities of the resulting view, as we’ve seen—it won’t accept INSERT statements. 4. ˛ D. The statements will successfully execute. ˝ A, B, and C are incorrect. The PURPOSE column is not required in order to create the view—the subquery in line 2 through line 4 is a valid SELECT statement. The code on lines 9 and 10 specifies scalar subqueries and is correct. The lower PROJECT_COST value will not prevent the INSERT from working; however, it will prevent the row from ever being seen through the MAJOR_PROJECTS view. A SELECT statement that attempts to display this row in the future could do so by querying the original table PROJECTS, but not the view MAJOR_ PROJECTS, which only sees rows with a PROJECT_COST greater than 10000 but certainly allows them to be inserted through the view into the underlying table. Self Test Answers 421 5. ˛ C. ALTER VIEW . . . COMPILE is the correct syntax. The statement will either succeed, in which case the view will be valid once again, or it will fail, indicating that the query upon which the view is based requires further assessment. ˝ A, B, and D are incorrect. There is no COMPILE VIEW statement. Nor is there a RECOMPILE keyword. Create, Maintain, and use Sequences 6. ˛ D. JOIN is used in a SELECT statement that connects two or more tables. But it is not used in a CREATE SEQUENCE statement, even thought its ultimate purpose may be to support the integrity of joins. ˝ A, B, and C are incorrect. CYCLE specifies if the sequence will repeat a range once it reaches the end of the range. MAXVALUE specifies one end of the range. INCREMENT specifies the number by which the sequence will increment. 7. ˛ B. There will be one row in the table. The reason: the first INSERT will fail because of the attempt to enter a character string into a numeric column. In the first failed INSERT statement, the PROJ_ID_SEQ# sequence generator will be invoked, and the NEXTVAL reference will use up the first number in the sequence, which will be 1. The second INSERT will succeed and grab the second number in the sequence, which will be 5. ˝ A, C, and D are incorrect. 8. ˛ B. Since the sequence was just created, NEXTVAL must be referenced before CURRVAL. This is also true if you were to log off and end the session, and then log back in to restart the session—the first reference for existing sequences must be NEXTVAL. ˝ A, C, and D are incorrect. You are allowed to reference sequence generators in any SQL statement where expressions are allowed. If CURRVAL were replaced with NEXTVAL, the correct answer to this question would have been answer C, meaning that the SELECT statement would have displayed a value of 1. Create and Maintain Indexes 9. ˛ B. An index can potentially speed up the WHERE clause of any DML statement, including the UPDATE statement. Comparisons of equality are ideal. ˝ A, C, and D are incorrect. An index does not copy all of the data from all of the rows of an indexed table but instead copies only that data that is contained within the indexed column or columns. It does not require a separate INSERT statement; instead, any future INSERTs will perform automatic index maintenance as required without any extra effort from you. The SELECT statement does not need to display indexed information for the index to be used. 422 Chapter 10: Creating Other Schema Objects 10. ˛ B. While all of the statements will execute successfully, the first DROP statement will drop the table SUPPLIES_01, which will cause the index IX_SU_01 to be dropped as well. In other words, the DROP TABLE SUPPLIES_01 statement has the effect of dropping the table SUPPLIES_01 as well as the index IX_SU_01. The table SUPPLIES_02 and IX_SU_02 will remain at the end. ˝ A, C, and D are incorrect. 11. ˛ D. A composite index is built on two or more columns. ˝ A, B, and C are incorrect. Combining columns is definitely possible. But it’s not a “correlated index” or “combined index”; those are not terms that are used. 12. ˛ C. The correct syntax includes a set of parentheses enclosing the list of columns on which the index is based. ˝ A, B, and D are incorrect. In answer A, the parentheses are missing. In answer B, the word COMPOSITE is used but not appropriate—there is no keyword COMPOSITE that has any relevance in this context. The correct answer C happens to create a composite index, but there’s no COMPOSITE keyword. Create Private and Public Synonyms 13. ˛ A. A private synonym is not automatically available to any user in the database, but the owner of the private synonym reserves the right to grant privileges on that synonym to anyone in the database. Contrast this with a public synonym, which is automatically available to every user in the database at the moment it is created. ˝ B, C, and D are incorrect. There is no PRIVATE keyword. The synonym object is not a column alias—the synonym is an object in the database, whereas a column alias is a feature within a SELECT statement that has no scope beyond the immediate execution of the SELECT statement. 14. ˛ B. The SELECT will identify the private synonym, which points to BOXES, because local objects are given preference over public objects. ˝ A, C, and D are incorrect. None of the statements has a problem with regard to syntax or execution. The SELECT won’t return one row, because the PUBLIC SYNONYM name CONTAINERS is subordinate to the private synonym CONTAINERS. Locally defined objects override other objects with regard to identity and reference. 15. ˛ C. The two statements will create two synonyms—one private, the other public. ˝ A, B, and D are incorrect. 11 Managing Schema Objects Certification Objectives 11.01 Add and Modify Columns 11.05 Create Function-Based Indexes 11.02 Drop Columns and Set Column UNUSED 11.06 Perform FLASHBACK Operations 11.07 Create and Use External Tables 11.03 Add Constraints 11.04 Create Indexes Using the CREATE TABLE Statement 3 Q&A Two-Minute Drill Self Test 424 Chapter 11: Managing Schema Objects T his chapter looks at a variety of tasks, features, and SQL statements, all designed to support the management of database objects and the data contained within them using constraints and indexes in new ways, in new statements and new clauses and in new combinations. This chapter also introduces new features like FLASHBACK and external tables. Certification Objective 11.01 Add and Modify Columns You can add columns to an existing table in the database. The SQL statement used to add or modify a column in a table is the ALTER TABLE statement. ALTER TABLE is a powerful statement with several clauses and options. The general syntax for the ALTER TABLE statement is as follows: ALTER TABLE table_name clause; Here, the table_name is the name of an existing table in the database that you wish to change in some fashion—and by “change”, I’m not talking about changing the data it contains, but changing the table’s structure—for example, its columns, the column datatypes, or the table’s constraints. In addition, “clause” can be many different things. ALTER TABLE has many different optional uses. For this section, we’ll be looking at two ALTER TABLE clauses: ADD and MODIFY. Adding Columns Let’s create a simple table and then, after it’s created, add a column to it. First, let’s create a table, CRUISE_ORDERS, using the following CREATE TABLE statement: CREATE TABLE CRUISE_ORDERS (CRUISE_ORDER_ID NUMBER, SALES_REP_ID NUMBER); The following ALTER TABLE statement adds a new column called ORDER_ DATE with a datatype of VARCHAR2(20): ALTER TABLE CRUISE_ORDERS ADD (ORDER_DATE VARCHAR2(20)); Add and Modify Columns 425 Notice the structure of this statement: n The required keywords ALTER TABLE n The name of the table we wish to alter n The required keyword ADD n The name of a new column, and its column specification, enclosed in parentheses The newly added column will be appended to the end of the current table’s list of columns. For each column, the clause specifies one or more of the following three elements: n Datatype and datatype specification—required n DEFAULT and default value—optional n CONSTRAINT definition—optional The datatype is required for each column specification. None of the other elements is required. However, if more than one is included, they must be included in the order listed here. In other words, if we want to add a column WEATHER_ CODE to the table CRUISE_ORDERS, and give it a default value of zero and a datatype of NUMBER(2), then this is syntactically wrong: ALTER TABLE CRUISE_ORDERS ADD (WEATHER_CODE DEFAULT 0 NUMBER(2)); But this is syntactically correct: ALTER TABLE CRUISE_ORDERS ADD (WEATHER_CODE NUMBER(2) DEFAULT 0); In other words—the syntax for the column definition is the same as it is for the CREATE TABLE statement. The syntax for adding multiple columns in a single statement is to use the keyword ADD one time, followed by a required pair of parentheses, inside of which is the series of column specifications, each of which is separated from the other by a comma. For example: ALTER TABLE CRUISE_ORDERS ADD (WEATHER_CODE NUMBER(2) DEFAULT 0, TRAVEL_AGENCY VARCHAR2(27) NOT NULL); In this example, we’re adding two columns to the CRUISE_ORDERS table: WEATHER_CODE and TRAVEL_AGENCY. Each has its datatype specification 426 Chapter 11: Managing Schema Objects included, and the first has a default value of zero, while the second is a NOT NULL column. Adding NOT NULL Columns If you are adding a column to a table, and the table already contains data, there are some restrictions you need to keep in mind. For example, if there are already rows in a given table, then you cannot alter that table by adding a new column with the NOT NULL constraint. For example: 01 02 03 ALTER TABLE CRUISE_ORDERS ADD FIRST_TIME_CUSTOMER VARCHAR2(5) NOT NULL; This statement might fail: if the CRUISE_ORDERS table already has rows, adding the FIRST_TIME_CUSTOMER column would have the effect of creating one column per row. But those columns would be empty. However, we’re trying to add the column with the NOT NULL constraint. The result: the preceding statement will fail if the CRUISE_ORDERS table already contains data. However, if we add a column with a DEFAULT value, the statement will succeed: 01 02 03 04 ALTER TABLE CRUISE_ORDERS ADD FIRST_TIME_CUSTOMER VARCHAR2(5) DEFAULT 'YES' NOT NULL; This statement is syntactically valid and will execute successfully. Each row already in the CRUISE_ORDERS table will be given a column value of ‘YES’ for the FIRST_TIME_CUSTOMER column. (Note: We’re assuming, of course, that there is not already a FIRST_TIME_ CUSTOMER column in the CRUISE_ORDERS table. If there were, then either of these SQL statements would fail.) If the statement were executed without the portion on line 3, and no FIRST_ TIME_CUSTOMER column were already present, then the statement would parse successfully yet fail in execution if any rows already existed in the CRUISE_ ORDERS table. That makes sense if you think about it—when you add a NOT NULL column to existing rows, you are attempting to create an instantly impossible situation—empty columns that are not allowed to be empty. SQL won’t let you do it. By providing the DEFAULT value in line 3, you are instructing the table how to handle NULL columns. If there are no rows in the table at the time you create a NOT NULL column, the DEFAULT clause isn’t necessary. But if rows exist, and Add and Modify Columns 427 you create a column that must have values in it, then you must also assign those values as you create the column—via the DEFAULT clause. Either that, or you’ll experience an execution error and the ALTER TABLE statement will fail. Modifying Columns Once we’ve created a table and its columns, we can modify any of those columns using the ALTER TABLE statement. This is true for any columns—including those created with the CREATE TABLE statement, or added later with the ALTER TABLE . . . ADD statement. Let’s look at the current structure of our CRUISE_ORDERS table: Name ---------------CRUISE_ORDER_ID SALES_REP_ID ORDER_DATE Null? ------ Type ------NUMBER NUMBER VARCHAR2(20) We could try to change the datatype of the ORDER_DATE column with this statement: ALTER TABLE CRUISE_ORDERS MODIFY (ORDER_DATE DATE); If the CRUISE_ORDERS table’s ORDER_DATE column is empty, this statement will execute successfully. (We’ll soon discuss what happens if it isn’t empty.) The statement follows the standard syntax of the ALTER TABLE statement’s MODIFY clause: n The required keywords ALTER TABLE, followed by the name of the table we wish to alter n The keyword MODIFY n An opening parenthesis, to begin the enclosure of the column specification n The name of an existing column in the table n The datatype of the column n A closing parenthesis, to end the enclosure of the column specification Note that parentheses, while part of the formal syntax for column specification in ALTER TABLE statements, are not required unless you are specifying more than one column in a single ALTER TABLE statement. 428 Chapter 11: Managing Schema Objects The syntax rules for the MODIFY clause are similar to—but not identical to—the ADD clause. Specifically: n You can modify the datatype, DEFAULT status, or constraint. n Only one such element is required in any MODIFY clause. n You can include multiple elements in any one MODIFY clause provided you define them in the proper order: datatype, then DEFAULT, then constraint— recognizing that you don’t have to specify them all. Note: The ADD clause differs in that each column specification of the ADD clause requires a datatype. You cannot use MODIFY to change the column’s name. There’s a separate RENAME COLUMN clause for that, which we’ll look at in a bit. The column definition syntax that can be included in the MODIFY clause of the ALTER TABLE statement is the same syntax you would use in the ADD clause of ALTER TABLE, which is also the same column definition syntax you use with CREATE TABLE. Modifying NOT NULL To add a NOT NULL constraint to a column, we could use this statement: ALTER TABLE CRUISE_ORDERS MODIFY (ORDER_DATE DATE NOT NULL); If you wish to reverse the effects of the NOT NULL constraint, you can’t drop the constraint. Instead, you modify the column by changing its NOT NULL constraint to NULL: ALTER TABLE CRUISE_ORDERS MODIFY (ORDER_DATE DATE NULL); The preceding two statements have the effect of adding and removing an unnamed NOT NULL constraint on a column. Modifying Populated Columns When we discussed the ADD clause, we had to consider what might happen if we tried to add a column to a table that already had rows in it. With MODIFY, you need to consider if a table has rows, and if it does, if those rows have any data in the column you wish to modify. Depending on the situation, you may or may not be able to modify a particular column in a table. The rules for what you can modify under what circumstances are spelled out in Table 11-1. Add and Modify Columns TABLE 11-1 429 Permissible Changes with the ALTER TABLE . . . MODIFY Clause Type of Change When the Table Has No Rows When the Table Has Rows and . . . . . . When the Column is NULL . . . When the Column Contains Data and Some NULL Values . . . When the Column Contains Data in All Rows Datatypes Yes No. Automatic datatype conversion not supported here. Precision and Scale Yes Yes, if no existing values lose significant digits or value; otherwise no. NOT NULL Yes No, unless DEFAULT is specified simultaneously. Yes PRIMARY KEY Yes No Yes, if existing values are unique; otherwise no. UNIQUE Yes Only if existing values are unique. FOREIGN KEY Yes Yes, provided that values match with referenced table’s values; otherwise no. CHECK Yes Yes, if existing values don’t violate the CHECK constraint, then no. DEFAULT Yes The bottom line: you cannot modify a column to take on properties that conflict with any existing data that is already present in the column. For example: n You cannot modify a column to make it a NUMBER column if it already contains character strings as data. n You cannot modify a column to make it a PRIMARY KEY if it already contains duplicate values. So just use common sense here; understand the functionality of all of the datatypes and constraints, and you’ll understand what you can and cannot do. Let’s look at some examples. In our earlier section, the CRUISE_ORDERS table had an ORDER_DATE column with a datatype of VARCHAR2(20). We changed the datatype to DATE. That would be accepted if—and only if—the CRUISE_ORDERS table’s ORDER_DATE column was empty at the time of the 430 Chapter 11: Managing Schema Objects ALTER TABLE statement. Otherwise, that ALTER TABLE statement would have been rejected. However, had the CRUISE_ORDERS table contained no data, this statement would have been accepted: ALTER TABLE CRUISE_ORDERS MODIFY ORDER_DATE VARCHAR2(35); In this particular ALTER TABLE statement, we’re only changing the precision of the VARCHAR2 datatype from 20 to 35. That is accepted in a table that contains data. In addition, you could have changed the column’s datatype if the column itself had been NULL, despite how many rows might exist in the table. Let’s modify an existing column by adding a new constraint to it. We’ll append an in-line constraint specification to the end of the clause, like this: ALTER TABLE CRUISE_ORDERS MODIFY ORDER_DATE NOT NULL; As an alternative, we could’ve done this: ALTER TABLE CRUISE_ORDERS MODIFY ORDER_DATE CONSTRAINT NN_ORDER_DATE NOT NULL; Here are several modifications to one column in one statement: ALTER TABLE CRUISE_ORDERS MODIFY ORDER_DATE DATE DEFAULT SYSDATE CONSTRAINT NN_ORDER_DATE NOT NULL; This statement is valid syntactically and will execute successfully if there are no rows in the table at the time it is executed. Remember that an ALTER TABLE statement is a DDL statement, and that when any DDL statement executes, it causes an implied commit event to occur. Renaming Columns You can rename columns using the ALTER TABLE statement with the RENAME COLUMN clause. Here is an example: ALTER TABLE CRUISE_ORDERS RENAME COLUMN SALES_REP_ID TO SALES_AGENT_ID; Drop Columns and Set Column UNUSED 431 The syntax is as follows: n The required keywords ALTER TABLE, followed by the name of the table we wish to alter n The keywords RENAME COLUMN n The name of the column we wish to change n The keyword TO, followed by the new name of the column All of these elements are required. Note that RENAME uses the keyword COLUMN. The ADD and MODIFY clauses do not include this keyword, but RENAME does. Certification Objective 11.02 Drop Columns and Set Column UNUSED This section looks at what you can do when you find that you have columns you no longer wish to keep in a table. You can choose to drop a column from the database, or as an alternative, you may render it UNUSED. This section looks at how to do either of these tasks. Dropping Columns Altering a table to drop columns that are no longer used can free up storage space and potentially improve performance of the table. Any constraints or indices on the column will also be dropped when you drop the column. Here are two examples—one without parentheses around the column name, another with the parentheses: ALTER TABLE ORDER_RETURNS DROP COLUMN CRUISE_ORDER_DATE; ALTER TABLE ORDER_RETURNS DROP (CRUISE_ORDER_DATE); Both are valid statements to drop the CRUISE_ORDER_DATE column. Note that the keyword COLUMN is required in the first variation, where the DROP clause syntax omits the parentheses. In the second variation, the keyword COLUMN is omitted, and the parentheses are used. The first variation is limited to dropping one column per SQL statement. Using the second variation, however, you can drop multiple columns by using the keyword 432 Chapter 11: Managing Schema Objects DROP one time, omitting the keyword COLUMN, and then including a pair of parentheses, followed by a list of the column names you wish to drop. For example: ALTER TABLE ORDER_RETURNS DROP (CRUISE_ORDER_DATE, FORM_TYPE, NAME_SUFFIX); You cannot drop all of the columns in a table. A table must have at least one column. Restrictions If a column is referenced by a foreign key constraint in another table, then the preceding syntax will trigger a warning message and the attempt to drop the column will fail. For example, consider this code: CREATE TABLE CRUISE_ORDERS (CRUISE_ORDER_ID NUMBER, ORDER_DATE DATE, CONSTRAINT PK_CO PRIMARY KEY (CRUISE_ORDER_ID, ORDER_DATE)); CREATE TABLE ORDER_RETURNS (ORDER_RETURN_ID NUMBER, CRUISE_ORDER_ID NUMBER, CRUISE_ORDER_DATE DATE, CONSTRAINT PK_OR PRIMARY KEY (ORDER_RETURN_ID), CONSTRAINT FK_OR_CO FOREIGN KEY (CRUISE_ORDER_ID, CRUISE_ORDER_DATE) REFERENCES CRUISE_ORDERS (CRUISE_ORDER_ID, ORDER_DATE)); These SQL statements will create two tables with a FOREIGN KEY relationship connecting them together—see Figure 11-1 for the data model representing the relationship. (Incidentally, this example is a great demonstration of a composite PRIMARY KEY and FOREIGN KEY constraint.) In the CRUISE_ORDERS table that we just created, we cannot drop the CRUISE_ ORDER_ID column, or the ORDER_DATE column, for two different reasons: n They form part of the PRIMARY KEY constraint, and constrained columns cannot be dropped unless the constraint is first dropped; n They form part of the referred key in the FOREIGN KEY of another table. They cannot be dropped as long as a FOREIGN KEY constraint refers to them. Similarly, we cannot drop the column in the ORDER_RETURNS table that is subject to the PRIMARY KEY constraint (ORDER_RETURN_ID), nor the Drop Columns and Set Column UNUSED 433 Figure 11-1 Data model for CRUISE_ ORDERS and ORDER_ RETURNS columns that are subject to the FOREIGN KEY constraint (CRUISE_ORDER_ID and ORDER_DATE). The reasons are similar: n ORDER_RETURN_ID is the PRIMARY KEY of this table. n CRUISE_ORDER_ID and ORDER_DATE are the FOREIGN KEY for this table. See Figure 11-2 for an example of the error messages that you’ll encounter when trying to drop these constrained columns. There is a solution here. We need to add the keywords CASCADE CONSTRAINTS to our SQL statements. For example: ALTER TABLE ORDER_RETURNS DROP COLUMN CRUISE_ORDER_DATE CASCADE CONSTRAINTS; This statement will successfully drop the CRUISE_ORDER_DATE column in ORDER_RETURNS. It will also drop the associated FOREIGN KEY constraint. Figure 11-2 Attempting to drop a column referenced in a FOREIGN KEY constraint 434 Chapter 11: Managing Schema Objects See Figure 11-3 for an example of the results. We could use this same approach to drop all of the columns we just reviewed, but as we stated, the effect of the CASCADE CONSTRAINT keywords with the DROP COLUMN clause is not only to drop the column but also to drop the associated constraints on the column that might prevent the column from being dropped. UNUSED Instead of dropping a table column you are no longer using, you may elect to declare it unused and leave it in place. Once you set a column as UNUSED, it is never again available; it is as though it has been dropped. As with dropped columns, any constraints or indices on the column will also be dropped. You will never be able to recover a column that is set to UNUSED. A ROLLBACK statement will have no effect—an UNUSED column will not be recovered in a ROLLBACK operation. Once a column is set to UNUSED, you can add new columns that have the same name as any unused columns for the table. So why wouldn’t you just DROP a column instead of setting it to UNUSED? One reason is the performance for the DROP statement versus the SET UNUSED approach. If you’re working with a very large table or set of tables, and you need to drop some columns, Once a column has been you may find that the system performance set to UNUSED, it can never be recovered. for executing the DROP is temporarily unacceptable, particularly for a system that is in heavy production. If this is an issue, and you need to achieve the look-and-feel of a dropped column immediately, then the SET UNUSED alternative is a welcome option. The performance is speedy, the results are—for all practical purposes—the same, and you can always schedule a Figure 11-3 DROP COLUMN with CASCADE CONSTRAINTS Drop Columns and Set Column UNUSED 435 time later to come back and drop the column during a period of low activity in the database. One thing to keep in mind: there’s a limit to the total number of columns any given table can have. That limit is 1,000—you cannot create more than a thousand columns in any one table. If you set a column to be UNUSED, that column will still count as part of the thousand columns toward your limit, until you eventually DROP the column—which you can do; we’ll discuss how to drop an unused column in a bit. The syntax for SET UNUSED is virtually identical to the ALTER TABLE . . . DROP syntax. Simply replace DROP with the keywords SET UNUSED, and the rest is the same. For example: ALTER TABLE ORDER_RETURNS SET UNUSED COLUMN CRUISE_ORDER_DATE; As with DROP, the syntax for changing multiple columns to the UNUSED state requires parentheses and eliminates the COLUMN reserved word, like so: ALTER TABLE ORDER_RETURNS SET UNUSED (CRUISE_ORDER_DATE, FORM_TYPE, NAME_SUFFIX); You can set as many columns to UNUSED as you wish. The only requirement is that you must, as you might guess, satisfy all constraints and other requirements of a table and its structure—for example, the table still must have at least one valid column at any time—so you cannot set all of its columns to UNUSED. Tables that have any columns that are set to UNUSED can be found in the data dictionary view USER_UNUSED_COL_TABS. However, this view doesn’t reveal any column names that are unused; it simply gives you the names of any and all tables that contain unused columns, and a numeric count of how many unused columns each one contains. You cannot recover the unused columns, nor can you even identify them. But you can drop them. To drop those unused columns, use this statement: ALTER TABLE table_name DROP UNUSED COLUMNS; For example: ALTER TABLE ORDER_RETURNS DROP UNUSED COLUMNS; This statement will drop all unused columns that are associated with the table ORDER_RETURNS. 436 Chapter 11: Managing Schema Objects Certification Objective 11.03 Add Constraints In Chapter 2, you created integrity constraints as part of the CREATE TABLE statement. This section discusses how you can use the ALTER TABLE statement to add a constraint to an existing table, how to modify an existing constraint, how to disable a constraint, and how to remove a constraint. If you’re looking for a section on using the CREATE CONSTRAINT statement—there isn’t one. You don’t create integrity constraints directly, but instead create them as part of the CREATE TABLE statement—which you’ve seen in Chapter 2—or with the ALTER TABLE statement, which is the subject of this section. Note that the term “integrity constraint” and “constraint” are used interchangeably. Using ALTER TABLE to Add Constraints When you looked at the CREATE TABLE statement, you saw that there were two major categories of syntax for creating constraints as part of the table: n In-line, where the syntax for the constraint is included as part of the column definition n Out-of-line, where the syntax for the constraint is defined on its own, separate from any particular column definition The same is true when using the ALTER TABLE statement. You can create a constraint in-line or out-of-line. For example, let’s start with the following CREATE TABLE statement: CREATE TABLE CRUISE_ORDERS (CRUISE_ORDER_ID NUMBER, SALES_AGENT_ID NUMBER, ORDER_DATE DATE, CONFIRMATION_DATE DATE); Now let’s look at three different ways to use the ALTER TABLE to add a PRIMARY KEY constraint to this table. First we’ll use the in-line syntax: ALTER TABLE CRUISE_ORDERS MODIFY CRUISE_ORDER_ID PRIMARY KEY; Add Constraints 437 That’s perfectly acceptable. This is in-line because this form of the ALTER TABLE statement is modifying the column, and specifying the constraint as part of the column definition. In this example, the only modification of the column is the addition of the constraint. Similarly, we could use this second form of in-line, where we do basically the same thing, although we name the constraint with a name of our choosing, as follows: ALTER TABLE CRUISE_ORDERS MODIFY CRUISE_ORDER_ID CONSTRAINT PK_NEW_CONSTRAINT PRIMARY KEY; Again, in this example, we’ve used the in-line approach, where the focus of the ALTER TABLE statement is the column, and as part of the column definition, we’ve named the constraint PK_NEW_CONSTRAINT. Here is an example of the out-of-line syntax for adding a constraint to an existing table: ALTER TABLE CRUISE_ORDERS ADD CONSTRAINT PK_NEW_CONSTRAINT PRIMARY KEY (CRUISE_ORDER_ID); Notice that in this example, we are not modifying a column. We are using a new clause here, the ALTER TABLE clause ADD CONSTRAINT. The focus of this form of ALTER TABLE is not a column, but the constraint itself. See Figure 11-4 for an example of what happens when we create this table and then execute the out-of-line form to add a constraint, along with the Oracle SQL messages that result. The out-of-line syntax is required for constraints that are applied to two or more columns, such as a composite primary key constraint. Such a constraint cannot be created in-line, since it is based on more than one column. For example, let’s go back to our primary key on the CRUISE_ORDERS table and create a composite primary key instead: ALTER TABLE CRUISE_ORDERS ADD CONSTRAINT PK_NEW_CONSTRAINT PRIMARY KEY (CRUISE_ORDER_ID, SALES_AGENT_ID); Figure 11-4 CREATE TABLE and ALTER TABLE ADD CONSTRAINT results 438 Chapter 11: Managing Schema Objects This statement creates a primary key based on two columns of the CRUISE_ ORDERS table. We could not accomplish this with the in-line syntax. The out-ofline syntax is the only way for creating composite constraints. Adding a NOT NULL Constraint The syntax for working with the NOT NULL constraint has the same limitation with the ALTER TABLE statement that we already observed it has with the CREATE TABLE statement. That is to say: you cannot declare a NOT NULL constraint with the out-ofline syntax; it can only be created with the in-line syntax. In other words, this works: ALTER TABLE CRUISE_ORDERS MODIFY CRUISE_ORDER_ID NOT NULL; So does this: ALTER TABLE CRUISE_ORDERS MODIFY CRUISE_ORDER_ID CONSTRAINT NN_CRUISE_ORDER_ID NOT NULL; But this does not: ALTER TABLE CRUISE_ORDERS ADD CONSTRAINT NN_THIS_IS_WRONG NOT NULL (CRUISE_ORDER_ID); This last sample code will fail. You cannot use the out-of-line syntax to create a NOT NULL constraint—you must use the in-line form. Know it and act accordingly. Syntax Notes The syntax rules for constraints and the ALTER TABLE out-of-line syntax are the same as those with the CREATE TABLE statement’s out-of-line syntax. In other words, they are as follows: n The keywords ALTER TABLE, followed by the name of the table n The keyword ADD n The optional keyword CONSTRAINT, and, if included, the name of the constraint you make up, according to the rules for naming database objects (Note: Our example chose to place a PK_ prefix at the start of the PRIMARY KEY constraint to indicate the constraint type, but this style is not required.) n The type of constraint: either UNIQUE, PRIMARY KEY, FOREIGN KEY, or CHECK (not the NOT NULL constraint, however) n Finally, the constraint’s specification appropriate to the type of constraint you chose, enclosed in a pair of parentheses Add Constraints 439 If you’re creating a UNIQUE or PRIMARY KEY constraint, the specification will include a list of one or more column names from the table, each separated from the other by a comma. If only one column is specified, no comma is required. If you’re creating a NOT NULL constraint, no additional specification is required. If you’re creating a CHECK constraint, then the specification includes an expression to filter incoming column data for each row added to the table. For example: ALTER TABLE CRUISE_ORDERS ADD CONSTRAINT CK_ORDER_DATE CHECK (ORDER_DATE <= CONFIRMATION_DATE); The preceding example shows: n The required keywords ALTER TABLE, followed by the table name n The required keyword ADD n The optional keyword CONSTRAINT, which—if used—is followed by the constraint name n The required keyword indicating the type of constraint, which in this example is CHECK (other types are PRIMARY KEY, UNIQUE, FOREIGN KEY—but not the NOT NULL option, since this is the out-of-line syntax) n The constraint’s expression, which in this case is an expression that compares the value of the incoming ORDER_DATE value and ensures that it is less than or equal to the incoming CONFIRMATION_DATE value In this example, once the constraint is created on the table, rows won’t be accepted by the CRUISE_ORDERS table if the ORDER_DATE is later than the CONFIRMATION_DATE. In the case of a FOREIGN KEY constraint, the syntax is more involved than the other constraint types, which you’ve seen before. Here is an example of the FOREIGN KEY constraint added with the ALTER TABLE statement using the out-of-line syntax: ALTER TABLE CRUISE_ORDERS ADD CONSTRAINT FK_CRUISE_ORDERS_SALES_AGENTS FOREIGN KEY (SALES_AGENT_ID) REFERENCES SALES_AGENTS(SALES_AGENT_ID); The preceding FOREIGN KEY constraint has the following syntax: n The reserved words ALTER TABLE, followed by the table name n The reserved words ADD CONSTRAINT, followed by the constraint name you make up n The reserved words FOREIGN KEY, followed by the name of the column in this table to which you are applying the constraint, enclosed in parentheses 440 Chapter 11: Managing Schema Objects n The reserved word REFERENCES, followed by the name of a different table in the database to which you wish to link this table as a foreign key, followed by the column list in that table to which you wish to relate this table, enclosed in parentheses The referenced table (in this example, it’s SALES_AGENTS) must already exist. The columns in that table are not required to have the same names, but the datatypes must match. In other words, you cannot create a FOREIGN KEY constraint on, for example, a DATE column in one table and then REFERENCE it to, say, a NUMBER column in another table. As you can see, all of these ALTER TABLE . . . ADD CONSTRAINT statements follow the out-of-line syntax style that you saw with CREATE TABLE earlier. Modifying Constraints You can use the ALTER TABLE statement to make a limited number of modifications to a constraint. If your goal is to change the definition of a particular constraint, you’ll probably need to drop and recreate it. Examples of situations in which you need to drop and recreate a constraint include n Adding or removing columns to the column list of a PRIMARY KEY, FOREIGN KEY, or UNIQUE constraint n Changing the logic of a CHECK constraint n Changing the table that a FOREIGN KEY constraint references In such situations as these, you can’t modify the constraint, but instead you must drop it and then create it with whatever changes you wish for it to have. The ALTER TABLE . . . MODIFY statement is limited to changing the state of a constraint. We’ll examine how this works when we discuss how to enable and disable constraints in an upcoming section. Removing Constraints To remove a constraint, you use the ALTER TABLE statement with the DROP clause option. There are three forms. DROP PRIMARy KEy To drop a PRIMARY KEY constraint, you don’t need the name of the constraint, since a given table can have one—and only one—PRIMARY KEY. The syntax is as follows: Add Constraints 441 ALTER TABLE table_name DROP PRIMARY KEY options; The options include the following: This drops any dependent constraints as well. In other words, a FOREIGN KEY may refer to this PRIMARY KEY constraint. Using CASCADE here will drop any and all FOREIGN KEY constraints that reference this PRIMARY KEY constraint. CASCADE is optional; the default is to not cascade. n CASCADE The PRIMARY KEY must have an associated index—this option indicates whether you wish to drop the index as well, or not. The clause is optional. The default is DROP INDEX. n KEEP INDEX or DROP INDEX If used, CASCADE must precede KEEP INDEX or DROP INDEX. DROP UNIQUE To drop a UNIQUE constraint, you don’t need the name of the constraint, just the list of columns that are included in the constraint: ALTER TABLE table_name DROP UNIQUE (column1, column2, . . . ) options; The options for UNIQUE are the same as they are for PRIMARY KEY. If you drop a PRIMARY KEY constraint with the ALTER TABLE . . . DROP statement, then by default you are also dropping the associated INDEX. The same is true for the UNIQUE constraint. DROP CONSTRAINT To drop other constraints, you need the constraint name: ALTER TABLE table_name DROP CONSTRAINT constraint_name options; The only option is CASCADE, which directs whether you wish for dependent constraints to be dropped as well. 442 Chapter 11: Managing Schema Objects Dropping NOT NULL Constraints You can’t really drop a NOT NULL constraint, but you can get the job done using this statement: ALTER TABLE table_name MODIFY column_name NULL; Remember: NOT NULL doesn’t work with out-of-line syntax, which is what this section is reviewing for modifying constraints. So you can’t use the out-of-line form to get rid of a NOT NULL restriction on a table. Instead, we “add” the keyword NULL, as the above syntax indicates. Disabling and Enabling Constraints Sometimes you find yourself in a situation where you wish to make changes to the database that an existing constraint is preventing you from changing. You won’t necessarily want to drop the constraint altogether, just render it ineffective for a limited time and purpose. There are many situations in which you would benefit from disabling a constraint. For example, perhaps you need to temporarily import data from a branch office or other source, data that perhaps isn’t consistent with your constraint rules, but data that you could easily clean up with some simple UPDATE statements once the data is in your database system. Even if the incoming data is compliant with the constraints, you may still prefer to temporarily disable the constraints for performance reasons if the data you are importing is large. Performance can be significantly slower when loading data into a table with constraints—one row is validated at a time. Such a process can be significantly slower than simply loading the data without the constraints and then enabling the constraints once the data is in the table, which is a significantly faster alternative. Another typical scenario in which the ability to disable a constraint is helpful involves the requirement to edit rows that are subject to PRIMARY KEY and FOREIGN KEY constraints. When a parent table has one or more PRIMARY KEY columns that are referenced by the child table’s FOREIGN KEY constraint, the parent table is not allowed to remove a PRIMARY KEY value upon which a child row depends. The mechanism that disallows this is the FOREIGN KEY constraint in the child table. However, you can disable that FOREIGN KEY and perform the task. You’ll look at a specific example involving FOREIGN KEY constraints in the next section. DISABLE For an example of disabling constraints, let’s look at a simplified version of the tables PORTS and SHIPS. See Figure 11-5. Add Constraints 443 Figure 11-5 Diagram of the PORTS and SHIPS tables In our example, PORTS is the parent table, with a column PORT_ID, on which is a PRIMARY KEY constraint. SHIPS is the child table to PORTS. SHIPS has a HOME_PORT_ID column and a FOREIGN KEY constraint upon that column that references the PORTS table’s PORT_ID column. As you know, the FOREIGN KEY in the SHIPS table means that if any row added to the SHIPS table includes a value for HOME_PORT_ID, that value must already be present in the PORTS table’s PORT_ID column. Here’s the SQL code that creates our tables and adds a few rows of data (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 CREATE TABLE PORTS (PORT_ID NUMBER(7), PORT_NAME VARCHAR2(20), CONSTRAINT PK_PORTS PRIMARY KEY (PORT_ID)); CREATE TABLE SHIPS (SHIP_ID NUMBER(7), SHIP_NAME VARCHAR2(20), HOME_PORT_ID NUMBER(7), CONSTRAINT PK_SHIPS PRIMARY KEY (SHIP_ID), CONSTRAINT FK_SH_PO FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID)); INSERT INTO PORTS VALUES (50, 'Jacksonville'); INSERT INTO PORTS VALUES (51, 'New Orleans'); INSERT INTO SHIPS VALUES (10, 'Codd Royale', 50); 444 Chapter 11: Managing Schema Objects After these statements successfully execute, we cannot delete a row in the PORTS table that is referenced by a SHIPS row: DELETE FROM PORTS WHERE PORT_ID = 50; Error starting at line 1 in command: DELETE FROM PORTS WHERE PORT_ID = 50 Error report: SQL Error: ORA-02292: integrity constraint (EFCODD.FK_SH_PO) violated - child record found 02292. 00000 - "integrity constraint (%s.%s) violated - child record found” *Cause: attempted to delete a parent key value that had a foreign dependency. *Action: delete dependencies first then parent or disable constraint. The conflict is with a row in the SHIPS table. It contains a HOME_PORT_ID value of 50, and since there’s a foreign key constraint that ties HOME_PORT_ID values with the PORTS table’s PORT_ID column, then the row with a value of 50 cannot be deleted as long as the child row exists. This restriction was created with the foreign key constraint named FK_SH_PO, as the error message indicates. We created that constraint in line 10 of our SQL code earlier. With the foreign key constraint in place, any row in the SHIPS table is dependent on the row in the PORTS table that shares the same PORT_ID value. In other words, the SHIPS table contains child rows that are dependent on the parent rows in PORTS. Note: In this example, the SHIPS table does not require all rows to have a value for HOME_PORT_ID. The HOME_PORT_ID column does not have the NOT NULL constraint. Therefore, it’s possible to add rows in SHIPS without a HOME_ PORT_ID, and therefore without creating a dependency. Furthermore, the PORTS table is capable of containing rows for which no children exist in SHIPS—not all PORT rows necessarily have a SHIP row sharing the same PORT_ID value in its HOME_PORT_ID column. This all means that, in this example, there may be independent rows in either table. Rows in PORTS that have no child rows in SHIPS can be deleted successfully: DELETE FROM PORTS WHERE PORT_ID = 51; 1 rows deleted (Note how Oracle points out that “1 rows” have been deleted.) Add Constraints 445 Also, any child row can be deleted in SHIPS, regardless of the foreign key constraint. Child rows can always be deleted without regard for the existence of parent rows. Foreign key constraints never restrict the deletion of child rows. But in any situation involving a foreign key constraint, parent rows cannot be deleted if corresponding child rows exist. This is why you may wish to disable the foreign key constraint in SHIPS in order to delete the parent rows in PORTS. The statement to disable the constraint in this example is ALTER TABLE SHIPS DISABLE CONSTRAINT FK_SH_PO; In this example, we disable the foreign key constraint by specifying its name. The result: the definition of the constraint remains in the database, but it is rendered ineffective for the time being. The preceding example of disabling a constraint adheres to the following syntax: ALTER TABLE table_name DISABLE validate_expression constraint_expression; n The required keywords ALTER TABLE n The name of the table n The keyword DISABLE n One of two optional keywords: VALIDATE or NOVALIDATE. Default is VALIDATE n One of three types of constraint expressions: n PRIMARY KEY n UNIQUE (column1, column2, . . . ) n CONSTRAINT constraint_name In our earlier example, we used the third form of the constraint expression. To disable any constraint, the syntax you use depends on which type of constraint you wish to disable: n PRIMARY KEY constraints require that you merely identify the constraint as the PRIMARY KEY for the table. n UNIQUE constraints require you to identify the columns that are constrained. n All other constraints require that you name them specifically. 446 Chapter 11: Managing Schema Objects These options are detailed in Table 11-2. If you aren’t sure what the names are of the constraints for a given table, you can query the data dictionary. Oracle’s data dictionary is a subject we discuss in detail in Chapter 14. For now, this query on the data dictionary will get you a list of the names of all the constraints for a given table, and the type of constraint each one represents: SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'SHIPS'; CONSTRAINT_NAME -----------------------------PK_SHIPS FK_SH_PO CONSTRAINT_TYPE --------------P R The values for CONSTRAINT_TYPE are explained in Chapter 14. For now, note that ‘R’ is a referential constraint, which is to say it’s a foreign key constraint, which refers to another table, which in this case is PORTS. Returning to our earlier example, once we’ve disabled the foreign key constraint FK_SH_PO, we can delete any parent rows in the PORTS table as we wish. But doing so will leave child rows in the SHIPS table that are assigned to the PORT row we delete in the PORTS table. Table 11-2 Disabling Constraints— Syntax Alternatives To DISABLE a Constraint of Type: Use One of These Syntax Forms: PRIMARY KEY ALTER TABLE table DISABLE PRIMARY KEY; ALTER TABLE table MODIFY PRIMARY KEY DISABLE; UNIQUE ALTER TABLE table DISABLE UNIQUE (column_list); ALTER TABLE table MODIFY UNIQUE (column_list) DISABLE; CHECK FOREIGN KEY ALTER TABLE table DISABLE CONSTRAINT constraint_name; ALTER TABLE table MODIFY CONSTRAINT constraint_name DISABLE; Add Constraints 447 ENABLE Once a constraint has been disabled, it can be enabled once again by executing a variation on the statement we examined earlier to disable it—replacing the word DISABLE with the word ENABLE. For example: ALTER TABLE SHIPS ENABLE CONSTRAINT FK_SH_PO; However, if the data contained in the table no longer supports the constraint, the statement will not execute successfully, and the constraint will not be enabled. Following our example, with the foreign key constraint FK_SH_PO disabled, if a parent row in the PORTS table were deleted, then an attempt to restore the FK_SH_PO constraint on the SHIPS table would result in child rows in SHIPS that have no parents in PORTS. These rows are known as orphans. SQL won’t allow the constraint to be enabled when orphan rows are present; there must be valid parent rows in the referenced table of the foreign key constraint, which is the PORTS table in this example. However, if you wish to enable a constraint, and the existing data subject to the constraint honors the requirements of the constraint, then you can enable it successfully. CASCADE If you wish to disable a constraint that has referential integrity constraints applied to it, you need the CASCADE keyword. For example, the foreign key constraint on the SHIPS table references the PORT_ID column of the PORTS table, which is the primary key in the PORTS table. You cannot disable the primary key constraint on the PORTS table with this statement: ALTER TABLE PORTS DISABLE PRIMARY KEY; Error report: SQL Error: ORA-02297: cannot disable constraint (EFCODD.PK_PORTS) - dependencies exist 02297. 00000 - "cannot disable constraint (%s.%s) - dependencies exist" *Cause: an alter table disable constraint failed becuase the table has foriegn keys that are dpendent on this constraint. *Action: Either disable the foreign key constraints or use disable cascade (Note: the misspellings of “becuase”, “foriegn”, and “dpendent” in the preceding error statement are from Oracle’s own system, and not this book.) The problem here is that the PORTS PRIMARY KEY is an integral part of the SHIPS table’s FOREIGN KEY. To disable both at the same time, you could use this statement: ALTER TABLE PORTS DISABLE PRIMARY KEY CASCADE; 448 Chapter 11: Managing Schema Objects The result: both constraints will be disabled. However, you cannot “cascade” the ENABLE statement. You must enable each constraint individually. For example: ALTER TABLE PORTS ENABLE PRIMARY KEY; This statement will enable the primary key. You’ll have to issue additional statements to enable any foreign key constraints that were disabled as a result of the CASCADE clause. VALIDATE / INVALIDATE Earlier we saw the optional keywords VALIDATE and INVALIDATE that can be used when enabling a constraint. These keywords may also be used when disabling a constraint. For example, we could have issued this statement earlier: ALTER TABLE SHIPS ENABLE VALIDATE CONSTRAINT FK_SH_PO; n The keyword VALIDATE is the default. n The keyword ENABLE may be replaced with DISABLE. n The keyword VALIDATE may be replaced with NOVALIDATE. The combinations are described in Table 11-3. Table 11-3 Keyword Combination Description Description of Constraint Keywords ENABLE VALIDATE Enables the constraint and applies it to existing rows in the table. VALIDATE is the default—therefore, ENABLE VALIDATE has the same effect as ENABLE. ENABLE NOVALIDATE Enables the constraint but does not apply it to existing rows. In other words, it allows existing rows in the table to violate the constraint. Ensures that incoming rows honor the constraint. DISABLE VALIDATE Disables the constraint. If the constraint has an associated index, the index is dropped. Can be used to temporarily speed up massive data imports using EXCHANGE PARTITION, which is beyond the scope of the exam and this book. DISABLE NOVALIDATE The same as DISABLE. Add Constraints 449 The benefit to NOVALIDATE is that it can support your efforts during development, or during a time in which you are moving and integrating large amounts of data. The use of ENABLE NOVALIDATE will allow you to create a constraint on a table but not yet apply it to the table’s data. The VALIDATE or NOVALIDATE keyword is optional and may be omitted from the ALTER TABLE ENABLE and ALTER TABLE DISABLE statements. Oracle formally recommends the following series of steps in performing a large data load into a table (or tables) in which constraints apply: • DISABLE the constraints.Take the default value of NOVALIDATE. • Move the data into the table. • ENABLE NOVALIDATE the constraints on the table. • ENABLE VALIDATE the constraints on the table. The preceding series of steps is intended to achieve optimal performance in working with large amounts of data. DROP TABLE and CASCADE CONSTRAINTS The DROP TABLE statement drops tables. For example: DROP TABLE SHIP_HISTORY; The previous statement will drop the SHIP_HISTORY table and any constraints and index objects on the table. However, if the table has any referential integrity constraints—that is, any FOREIGN KEY constraints in other tables that are dependent on a PRIMARY KEY or UNIQUE constraint in the SHIP_HISTORY table, then the DROP TABLE statement shown above will fail. But this will work: DROP TABLE SHIP_HISTORY CASCADE CONSTRAINTS; The previous statement drops the SHIP_HISTORY table, its integrity constraints and indices, and any referential integrity constraints—that is, any FOREIGN KEY constraints of other tables—that depend on a PRIMARY KEY or UNIQUE constraint of SHIP_HISTORY. If any FOREIGN KEY constraint is disabled, DROP TABLE on the PRIMARY KEY table will still fail if the constraints exist, unless CASCADE CONSTRAINTS is included in the DROP TABLE statement. 450 Chapter 11: Managing Schema Objects DELETE and ON DELETE Remember that you cannot DELETE a row in a table if dependent child rows exist. The reason is the FOREIGN KEY constraint on the child table, which is dependent on the PRIMARY KEY in the parent table. As we saw earlier, one alternative approach is to DISABLE the FOREIGN KEY constraint in SHIPS. Once disabled, you may delete the parent rows in PORTS. Another alternative is create the FOREIGN KEY with the ON DELETE CASCADE clause. To do that, we’ll first need to drop the old constraint, and for that, we’ll need the name of the constraint. You can obtain that information from the data dictionary with the following query: SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM USER_CONSTRAINTS WHERE R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'PORTS' AND CONSTRAINT_TYPE = 'P') The previous query finds the name of the PRIMARY KEY constraint for PORTS, then returns the names of any tables and their referential integrity constraints that refer to the PORTS table’s PRIMARY KEY constraint. For example: TABLE_NAME CONSTRAINT_NAME C ------------------------------ ------------------------------ SHIPS FK_SHIPS_PORTS R Once you have the name of the referential integrity constraint, you can drop it, then recreate it with the ON DELETE CASCADE clause: ALTER TABLE SHIPS DROP CONSTRAINT FK_SHIPS_PORTS; ALTER TABLE SHIPS ADD CONSTRAINT FK_SHIPS_PORTS FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID) ON DELETE CASCADE; Now, any attempt to delete a row in PORTS should be successful. It will also try to delete any and all rows in the SHIPS table with a value in the HOME_PORT_ID column that matches the PORT table’s PORT_ID value (or values) that are being deleted. Note, however, that it still might not work—if other tables have FOREIGN KEY constraints that are dependent on the PORTS or SHIPS table, the DELETE statement will fail for the same reasons. If it fails for any of these reasons, none of the rows are deleted—not in SHIPS, nor in PORTS. As an alternative, you can create the FOREIGN KEY with the ON DELETE SET NULL clause instead. The syntax is similar to ON DELETE CASCADE: ALTER TABLE SHIPS DROP CONSTRAINT FK_SHIPS_PORTS; ALTER TABLE SHIPS ADD CONSTRAINT FK_SHIPS_PORTS FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID) ON DELETE SET NULL; Add Constraints 451 Now any attempts to delete rows in the PORTS table will cause any rows in SHIPS that match (SHIPS.HOME_PORT_ID = PORTS.PORT_ID) to set their HOME_PORT_ID values to NULL. The SHIPS rows will otherwise remain in the SHIPS table, but they will now be “orphan” rows. Any referential integrity constraints that might refer to the SHIPS table will be unaffected, since no rows in the SHIPS table are deleted when a PORTS table row is deleted. DEFERRABLE and DEFERRED You can temporarily set a constraint to DEFERRED so that a large set of data might be processed without any constraint checking until after the transaction is completed. To do this, create the constraint with the DEFERRABLE clause, as follows: ALTER TABLE SHIPS DROP CONSTRAINT FK_SHIPS_PORTS; ALTER TABLE SHIPS ADD CONSTRAINT FK_SHIPS_PORTS FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID) DEFERRABLE; The default setting for constraints is NOT DEFERRABLE. Once the constraint has been created as DEFERRABLE, you may issue this statement during a session: SET CONSTRAINT FK_SHIPS_PORTS DEFERRED; Alternatively, you can set all constraints to DEFERRED: SET CONSTRAINT ALL DEFERRED; Once the SET CONSTRAINT command establishes a given constraint—or all constraints—as DEFERRED, the current transaction will temporarily ignore the deferred constraints, and accept rows of data that might violate those constraints. However, once a commit event occurs, the constraint automatically changes state from DEFERRED to IMMEDIATE, and the constraints will be applied. If any are violated, the commit will fail and all data is rolled back. At any time, you can restore the default behavior of constraints with this command: SET CONSTRAINT FK_SHIPS_PORTS IMMEDIATE; Alternatively, you can set all constraints to IMMEDIATE: SET CONSTRAINT ALL IMMEDIATE; Once set to IMMEDIATE, constraints go back to their default behavior, and are checked after each DML statement is executed. This approach is somewhat similar to disabling commands, only it’s a more temporary state. 452 Chapter 11: Managing Schema Objects Renaming Constraints You can rename an existing constraint on a table using the RENAME CONSTRAINT clause of the ALTER TABLE statement. Here’s an example: ALTER TABLE CRUISE_ORDERS RENAME CONSTRAINT SYS_C0015489 TO PK_CRUISE_ORDER_ID; The syntax is as follows: n The reserved words ALTER TABLE, followed by the table name n The reserved words RENAME CONSTRAINT n The existing name of the constraint you are renaming n The reserved word TO n The new name of the constraint you are renaming Any constraint may be renamed. This can be particularly useful in situations where you may have created a constraint using the in-line syntax of the CREATE TABLE statement, which creates a constraint but allows the system to automatically assign a name. See Table 11-4 for a summary of SQL statement syntax for creating and modifying constraints. TABLE 11-4 Constraint Syntax Summary CREATE TABLE ALTER TABLE In-line unnamed CREATE TABLE table_name ( column_name datatype inline_constraint, ... ); ALTER TABLE table_name ADD|MODIFY (column_name ... inline_constraint, ... ); In-line named CREATE TABLE table_name ( column_name datatype CONSTRAINT constraint_name inline_constraint, ... ); ALTER TABLE table_name ADD|MODIFY (column_name ... CONSTRAINT constraint_name inline_constraint, ... ); Add Constraints TABLE 11-4 Constraint Syntax Summary (Continued) CREATE TABLE ALTER TABLE CREATE TABLE table_name ( column_name datatype, ..., CONSTRAINT constraint_name outOfLine_constraint, ... ); ALTER TABLE table_name Type inline_constraint outOfLine_constraint PRIMARY KEY PRIMARY KEY PRIMARY KEY (column_list) REFERENCES table_name (column_list) FOREIGN KEY (column_list) REFERENCES table_name (column_list) UNIQUE UNIQUE UNIQUE (column_list) CHECK CHECK (expression) CHECK (expression) NOT NULL NOT NULL (*** Not Applicable *** ) Out-of-line FOREIGN KEY 453 ADD|MODIFY ( CONSTRAINT constraint_name outOfLine_constraint, ... ); Examples—assuming a table PORTS with a PRIMARY KEY of PORT_ID: FOREIGN KEY, in-line, unnamed (anonymous) CREATE TABLE SHIPS (SHIP_ID NUMBER, HOME_PORT_ID NUMBER REFERENCES PORTS (PORT_ID)); FOREIGN KEY, in-line, named: CREATE TABLE SHIPS (SHIP_ID NUMBER, HOME_PORT_ID NUMBER CONSTRAINT FK_SHIPS_PORTS REFERENCES PORTS (PORT_ID)); FOREIGN KEY, out-of-line: CREATE TABLE SHIPS (SHIP_ID NUMBER, HOME_PORT_ID NUMBER, CONSTRAINT FK_SHIPS_PORTS FOREIGN KEY (HOME_PORT_ID) REFERENCES PORTS (PORT_ID)); 454 Chapter 11: Managing Schema Objects Certification Objective 11.04 Create Indexes Using the CREATE TABLE Statement At the time a table is initially created, one or more indexes may be created along with the table. This section looks at this issue and what the options are for index creation as part of the CREATE TABLE statement. Automatic Index Creation Whenever you create a table with a constraint of type PRIMARY KEY or UNIQUE, an index is automatically created for you by default. You can choose to override this behavior and tell SQL to not create an index if you wish. For example, this statement will create an index: CREATE TABLE INVOICES (INVOICE_ID NUMBER(11) PRIMARY KEY, INVOICE_DATE DATE); The preceding CREATE TABLE statement includes two columns, and a single constraint of type PRIMARY KEY. The result will be the creation of n One table n One constraint n One index The index will be assigned a system-generated name, which can be found with the following query: SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'INVOICES'; INDEX_NAME -----------------------------SYS_C0013186 In our example, we’ve queried the data dictionary view USER_INDEXES and discovered that we now have an index associated with our new table INVOICES, and the index is called SYS_C0013186. Create Indexes Using the CREATE TABLE Statement 455 (Note: The data dictionary will be discussed in Chapter 14.) USING INDEX You can specify an index’s creation as part of the CREATE TABLE statement. The USING INDEX clause only works for PRIMARY KEY and UNIQUE constraints. It can be appended to any PRIMARY KEY or UNIQUE constraint specification, including the in-line anonymous, in-line named, and out-of-line syntax. Let’s revisit our INVOICES table example. We could have used this syntax (line numbers added): 01 02 03 04 05 06 CREATE TABLE INVOICES (INVOICE_ID NUMBER(11) PRIMARY KEY USING INDEX (CREATE INDEX IX_INVOICES ON INVOICES(INVOICE_ID)), INVOICE_DATE DATE ); Note the syntax here: n The PRIMARY KEY column is created at the end of line 2 as before. n The USING INDEX keywords are next. n Within parentheses, we include a complete CREATE INDEX statement. The preceding example will successfully create the table, along with the index, giving the index a name we specify. There will be no system-assigned names given to automatically generated indexes with this CREATE TABLE statement; we have control over the index’s naming and form. In this next example, we modify the CREATE TABLE slightly so as to name the constraint as well as the index: 01 02 03 04 05 06 CREATE TABLE INVOICES (INVOICE_ID NUMBER(11) CONSTRAINT PK_INVOICE_ID PRIMARY KEY USING INDEX (CREATE INDEX IX_INVOICES ON INVOICES(INVOICE_ID)), INVOICE_DATE DATE ); Notice line 2, where we include the keyword CONSTRAINT followed by the constraint name. Everything else in the statement is identical to the previous example. 456 Chapter 11: Managing Schema Objects In the two examples we’ve just examined, the USING INDEX clause was appended to an in-line constraint. We could have done the same thing with an outof-line constraint, like this: 01 02 03 04 05 06 07 CREATE TABLE INVOICES (INVOICE_ID NUMBER(11), INVOICE_DATE DATE, CONSTRAINT CK_INVOICES_INVOICE_ID PRIMARY KEY (INVOICE_ID) USING INDEX (CREATE INDEX IX_INVOICES ON INVOICES(INVOICE_ID)) ); This example creates the same table and the same index, but with the out-of-line constraint syntax. Remember that the out-of-line syntax allows us the option of creating constraints on two or more columns. In the rare instance when you create a composite index along with multiple constraints that call on the same index, a special syntax is required. For example, if we decide to create a composite index on both of our columns in the INVOICES table, we can use this syntax: 01 02 03 04 05 06 07 08 09 CREATE TABLE INVOICES (INVOICE_ID NUMBER(11), INVOICE_DATE DATE, CONSTRAINT UN_INVOICES_INVOICE_ID UNIQUE (INVOICE_ID, INVOICE_DATE) USING INDEX (CREATE INDEX IX_INVOICES ON INVOICES(INVOICE_ID, INVOICE_DATE)), CONSTRAINT UN_INVOICES_INVOICE_DATE UNIQUE (INVOICE_DATE, INVOICE_ID) USING INDEX IX_INVOICES ); In this example, we create two constraints and one index, referencing the newly created index IX_INVOICES in line 8 by specifying the same name of the index we create in line 5. The USING INDEX clause for creating indices can be used to specify an existing index by appending a constraint specification with “USING INDEX index_name” and nothing else. Create Function-Based Indexes 457 Certification Objective 11.05 Create Function-Based Indexes A function-based index is an index that is created on one or more columns that are used as one or more input parameters to a function. The advantage is that if you find yourself frequently querying a table using that function, then you can incorporate the function into the index and increase the likelihood that the Oracle Database optimizer will use the index in queries. For example, consider the following table: CREATE TABLE CUSTOMERS (CUSTOMER_ID NUMBER(11) PRIMARY KEY, LAST_NAME VARCHAR2(30)); CREATE INDEX IX_CUSTOMERS_LAST_NAME ON CUSTOMERS (UPPER(LAST_NAME)); This example shows how we can create the index so that data in the LAST_NAME column is indexed as though the column were already converted to uppercase letters with the function UPPER. Now we can run the following query: SELECT * FROM CUSTOMERS WHERE UPPER(LAST_NAME) = 'SMITH'; Had we created a typical (non-function-based) index on the LAST_NAME column, this query would not benefit from the index. But now, with the functionbased index implemented, we improve the odds that the optimizer will invoke the index for queries that use the same function as we coded into the functionbased index. Function-based indexes do not necessarily need to be based on a SQL function per se. Any expression will be accepted. For example: CREATE TABLE GAS_TANKS (GAS_TANK_ID NUMBER(7), TANK_GALLONS NUMBER(9), MILEAGE NUMBER(9)); CREATE INDEX IX_GAS_TANKS_001 ON GAS_TANKS (TANK_GALLONS * MILEAGE); In the preceding example, there is no particular SQL function. Instead there is an equation, and this is valid for creating a function-based index. Any future queries on the GAS_TANKS table that use this expression will leverage the power of the index. Note that SQL is smart enough to recognize whether you’ve changed the 458 Chapter 11: Managing Schema Objects position of the values within an expression without modifying the end results of the expression. In other words, the query SELECT * FROM GAS_TANKS WHERE MILEAGE*TANK_GALLONS > 750; Function-based indexes can be built on any valid expression— they are not limited to functions. may use the index, even though the expression reverses the position of MILEAGE and TANK_GALLONS. The computed values are the same, and the SQL index recognizes that fact. Certification Objective 11.06 Perform FLASHBACK Operations The topic of Oracle’s FLASHBACK operations is quite involved. To develop a complete understanding of all of what Oracle offers with FLASHBACK operations requires more study than what is necessarily required to pass the exam. I’ll provide some background information to give you an idea of what we are talking about, and then I’ll discuss the specific FLASHBACK operations that are relevant to the exam and to this chapter’s focus, which is the overall subject of managing schema objects. This won’t be the last word on the subject of FLASHBACK operations that you need to understand for the exam; we’ll revisit the topic of FLASHBACK again in Chapter 15, when we look at how to manipulate large amounts of data over time. This book will present what you need to know for the exam, but you may wish to continue your study of FLASHBACK operations beyond what is required for the exam. Overview Oracle’s FLASHBACK operations include a variety of statements you can use to recover objects and/or the data contained with them, as well as dependent objects and data. The sort of tasks you can accomplish with FLASHBACK operations include Perform FLASHBACK Operations 459 n Recovering complete tables you may have inadvertently dropped n Recovering data changes within one or more tables resulting from a series of DML statements n Performing data analysis on data that’s been changed over periods of time n Comparing data that existed at one point in time with data that existed at another point in time n Performing queries as of a prior time period FLASHBACK operations can support multiple user sessions gaining access to historical data dynamically, on any table—including the same tables—at the same time, with each user session potentially accessing different points in the history of the table simultaneously, all while the database is up and running in full operational mode. Some FLASHBACK operations require various configuration steps; some of those configurations can be involved and might require intervention by the database administrator. The configuration steps involved can affect system parameters, table clauses, and a feature of the database known as the undo segments, which have a purpose that goes beyond FLASHBACK. Recover Dropped Tables In this chapter, we’re only focusing on managing schema objects. Within the set of available FLASHBACK operations, the feature that affects schema objects as a whole is the FLASHBACK TABLE statement. This statement can recover a previously dropped table you specify from an historical point-in-time that you specify. However, there are limitations—for example, you cannot flash back to a point prior to when the table’s structure may have been altered. You can identify a point in time in a variety of ways: n Immediately prior to when a table was dropped n A specific time identified by a value of datatype TIMESTAMP n A specific transaction identified by the system change number (SCN) n A predetermined event identified by a database object known as the RESTORE POINT When used to restore a table, FLASHBACK TABLE restores the dropped table with either its original name or a new name you provide with the statement. It also recovers any indexes on the table, other than bitmap join indexes. All 460 Chapter 11: Managing Schema Objects constraints are recovered, except for referential integrity constraints that reference other tables—in other words, foreign key constraints. Granted privileges are also recovered. The beginning syntax of a FLASHBACK TABLE statement is as follows: n The required keywords FLASHBACK TABLE n One or more table names, separated by commas n The required keyword TO In other words: FLASHBACK TABLE table_name TO ... More than one table can be included in the list. Additional table names must be separated by commas: FLASHBACK TABLE table1, table2, table3 TO ... That’s the beginning. There are several ways to complete this statement. Here is how you complete it if you wish to recover a dropped table: n The required keywords BEFORE DROP n The optional keywords RENAME TO, followed by a new name for the table, if you wish to recover the dropped table into an object with a different name Here is an example of a SQL session where we create a table, drop it, and then use FLASHBACK TABLE to restore the dropped table (line numbers added): 01 02 03 04 05 06 CREATE TABLE HOUDINI (VOILA VARCHAR2(30)); INSERT INTO HOUDINI (VOILA) VALUES ('Now you see it.'); COMMIT; DROP TABLE HOUDINI; FLASHBACK TABLE HOUDINI TO BEFORE DROP; SELECT * FROM HOUDINI; Note the FLASHBACK TABLE statement on line 5. It combines the beginning: FLASHBACK TABLE HOUDINI TO with BEFORE DROP It omits the optional RENAME TO and the new name. Perform FLASHBACK Operations 461 You cannot roll back a FLASHBACK TABLE statement. The Recycle Bin The Flashback Drop feature recovers complete tables that are still retained in the “recycle bin”, and it can do so in spite of the fact that such a change results from the DROP TABLE statement, which, by definition, is DDL and therefore involves an implied COMMIT. In spite of this, we can recover the table if it is still in the recycle bin. Tables are put into the recycle bin automatically by SQL whenever a DROP TABLE statement is issued. A table’s dependent objects, such as indexes, are also placed into the recycle bin, along with the table’s constraints. The recycle bin is not counted as space that is used by a given user account. A user account’s dropped objects are retained in a separate recycle bin for each user. You may inspect the contents of your own recycle bin with the following query: SELECT * FROM USER_RECYCLEBIN; That query is identical to this one: SELECT * FROM RECYCLEBIN; RECYCLEBIN is a synonym for USER_RECYCLEBIN. In other words, the preceding two queries are identical. There is a DBA_RECYCLEBIN, which allows user accounts with database administrator (DBA) privileges to see all dropped objects in the database. If your user account has privileges on an object, then your user account will be able to see the object in the recycle bin in the event it is dropped. You don’t need to inspect the recycle bin before issuing a FLASHBACK statement. But you might find it helpful. The recycle bin is affected by the “recyclebin” initialization parameter and can be turned on or off accordingly with the following ALTER SESSION statements: ALTER SESSION SET recyclebin = ON; ALTER SESSION SET recyclebin = OFF; 462 Chapter 11: Managing Schema Objects Either of these statements takes effect immediately. The initial state of the recycle bin is dependent on the setting for recyclebin in the initialization parameter file, which is controlled by the DBA. Dependent Objects When a table is recovered, any associated dependent objects are also recovered, including the following: n Indexes, except for bitmap join indexes n Constraints, but with limitations—for example, restoring dropped tables does not recover referential constraints, meaning FOREIGN KEY constraints n Other objects that I don’t discuss in this book and are not a subject of the exam, such as triggers Objects that have the same name that are dropped can all be retrieved with FLASHBACK operations. For example, if a table VENDORS was dropped, then recreated and dropped, then there will be two VENDORS tables in the recycle bin. The last one dropped will be the first one retrieved. Objects such as indexes will be recovered with system-assigned names—not the names they were originally given. You can rename each retrieved object with the RENAME TO clause of the FLASHBACK TABLE statement as it is retreived. As of this writing, renaming retrieved objects is beyond the scope of the exam. Statement Execution The FLASHBACK TABLE statement operates as a single statement. If it fails, nothing in the statement succeeds. In other words, if there’s an attempt to restore three tables in a single statement and the third attempt is erroneous for whatever reason, none of the tables will be restored. PURGE The PURGE statement permanently removes a given item from the recycle bin—for example, to permanently remove the HOUDINI table from the recycle bin so that it cannot be recovered: PURGE TABLE HOUDINI; After executing this statement, the table HOUDINI cannot be recovered with the FLASHBACK TABLE statement we used earlier. Perform FLASHBACK Operations 463 Note that the table must have first been dropped in order for PURGE to execute successfully. Purging may be performed automatically by the Oracle database’s own automatic space reclamation operations. If that happens, the table is not in the recycle bin and cannot be recovered with FLASHBACK operations. Recovering Tables in Time This section discusses some additional ways to complete the FLASHBACK TABLE statement. In addition to performing a flashback operation to restore a dropped table, you can flash back an existing table to a specific point in time, showing its state prior to any committed changes that may have been transacted since the point in time of interest. The syntax can take any of these three forms. FLASHBACK TABLE HOUDINI TO SCN scn_expression; FLASHBACK TABLE HOUDINI TO TIMESTAMP timestamp_expression; FLASHBACK TABLE HOUDINI TO RESTORE POINT restore_point_expression; The recommended form of these three is the first: the SCN, which is the system change number. This is the mechanism that is recommended by Oracle for identifying points in time in the database. For example, let’s revisit our table HOUDINI: 01 02 03 04 05 06 07 08 09 CREATE TABLE HOUDINI (VOILA VARCHAR2(30)); INSERT INTO HOUDINI (VOILA) VALUES ('Now you see it.'); COMMIT; EXECUTE DBMS_LOCK.SLEEP(15); DELETE FROM HOUDINI; COMMIT; EXECUTE DBMS_LOCK.SLEEP(15); FLASHBACK TABLE HOUDINI TO TIMESTAMP SYSTIMESTAMP - INTERVAL '0 00:00:20' DAY TO SECOND; Let’s review the preceding code: n Line 3: We commit our change to the table. n Line 4: This is a statement that suspends processing for 15 seconds. The choice of 15 seconds is arbitrary; the intent here is to allow some time to pass. n Line 6: We commit the deletion of the one row. 464 Chapter 11: Managing Schema Objects n Line 8 and line 9: This statement attempts to restore the table back to where it was 20 seconds earlier. Note that line 9 contains nothing more than an expression of the TIMESTAMP datatype, which in this case is a call to the SYSTIMESTAMP function minus a 20-second interval. The SYSTIMESTAMP function returns the current time as defined by the Oracle database server’s operating system. Following the call to the function is the symbol for subtraction—the “minus” sign—followed by a literal value representing a time interval of 20 seconds. So—what is the result of this series of statements? Here it is: Error report: SQL Error: ORA-08189: cannot flashback the table because row movement is not enabled 08189. 00000 - "cannot flashback the table because row movement is not enabled" *Cause: An attempt was made to perform Flashback Table operation on a table for which row movement has not been enabled. Because the Flashback Table does not preserve the rowids, it is necessary that row movement be enabled on the table. *Action: Enable row movement on the table What is wrong here? The problem is that the capability to perform FLASHBACK operations to restore an existing table to an older state—is not a capability that exists by default. It only works on tables where the ROW MOVEMENT feature has been enabled. Here’s how to create the table with ROW MOVEMENT enabled: CREATE TABLE HOUDINI (VOILA VARCHAR2(30)) ENABLE ROW MOVEMENT; To enable ROW MOVEMENT on a table that’s already been created: ALTER TABLE HOUDINI ENABLE ROW MOVEMENT; If we were to go back and redo our earlier series of statements with ROW MOVEMENT enabled on the table, our FLASHBACK TABLE statement would work perfectly, and we’d restore our table to its original state. Once restored, we could query the table and see all the data in that table as it existed at the time we specified in our FLASHBACK TABLE statement. Data restoration is “permanent”. It invokes an implicit COMMIT so that the restored data is committed. Limitations You cannot use the FLASHBACK TABLE statement to restore older data to an existing table if the table has been structurally altered with the ALTER TABLE Perform FLASHBACK Operations 465 statement in such a way that it can’t accept the full definition of older data. For example, if a column has been dropped or a column’s datatype changed, the FLASHBACK TABLE statement won’t successfully restore the older data. Marking Time There are several ways to identify the point at which you wish to restore data in the database. You saw three in the previous section, and I’ll discuss them a bit more here. SCN The system change number, or SCN, is a numeric stamp that the database automatically increments for every committed transaction that occurs in the database. This includes both explicit and implicit commits, for all external or internal transactions. The SCN is automatically managed by the database in real time. Every committed transaction is assigned an SCN. If you wish to determine the current SCN at any given moment in the database, use the function DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER. For example (line numbers added): 01 02 03 04 05 SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM DUAL; GET_SYSTEM_CHANGE_NUMBER -----------------------5896167 This example shows the request and the answer. In this case, the SCN is 5896167. If you were to hesitate a few seconds and run the same statement in line 1 again, you might get a different value returned for SCN. The SCN can also be found with the query SELECT CURRENT_SCN FROM V$DATABASE, which is a query of the data dictionary. We’ll discuss the data dictionary later in Chapter 14, but for now, note that Oracle officially recommends that if your goal is to obtain an SCN from within an application or any comparable code, then you should use the DBMS_FLASHBACK .GET_SYSTEM_CHANGE_NUMBER function that we demonstrated earlier. This recommendation implies that you should steer away from tapping the V$DATABASE view for the SCN number.The DBMS_FLASHBACK.GET_ SYSTEM_CHANGE_NUMBER function is a function written in the PL/SQL language, and it is part of the DBMS_FLASHBACK package. See Oracle’s reference manual on PL/SQL packages if you wish to learn more—but you don’t need to do that for the exam. 466 Chapter 11: Managing Schema Objects Each time a transaction is committed in the database, the SCN is incremented and stored with each row in each table. The SCN for a given row can be found in the pseudocolumn ORA_ROWSCN. As is the case with any pseudocolumn, it can be included as an expression in any SELECT statement. For example, SELECT ORA_ROWSCN, VOILA FROM HOUDINI; returns each row in the table HOUDINI, along with the values in the VOILA column as well as the assigned SCN number for each row. Timestamp A TIMESTAMP value specifies a point in time. You’ll recall that the TIMESTAMP datatype stores the year, month, day, hour, minute, second, and fractional seconds, and that a literal value may be converted to the TIMESTAMP datatype with the TO_TIMESTAMP function, like this: SELECT TO_TIMESTAMP('2009-08-25 13:15:08.232349', 'RRRR-MM-DD HH24:MI:SS:FF') FROM DUAL; This example shows the TO_TIMESTAMP function, a literal value, and a format mask that defines the location within the literal value of each component that forms a valid TIMESTAMP value. Note the use of fractional seconds, where more than two digits are accepted. Also recall that MI is the format mask for minutes—not MM, which is the format mask for months. The FLASHBACK_TABLE function can use a TIMESTAMP value to specify a point in time in the database to within three seconds of accuracy. If a specific point in the database is needed, don’t use TIMESTAMP—use SCN instead. If you attempt to flash back to a point in time at which the database did not exist, you’ll get an error indicating “invalid timestamp specified”. If the time you’re referencing closely aligns with a time at which the object or data didn’t exist, and the SCN/Timestamp correlation misses your target and overshoots into a time frame in which the object or data didn’t exist, you may get an Oracle error. You can use a combination of one or more conversion functions to address this discrepancy, as we discuss in the next section. Perform FLASHBACK Operations 467 Conversion Functions SCN numbers can be converted into their equivalent TIMESTAMP values, and vice versa. The conversions are not exact, however, because the SCN and TIMESTAMP do not represent moments in time that are precisely identical. The conversion functions are Takes an SCN expression as input, returns a TIMESTAMP value roughly corresponding to when the SCN was set. n SCN_TO_TIMESTAMP(s1) Takes a TIMESTAMP expression representing a valid past or present timestamp as input, returns an SCN value roughly corresponding to when the TIMESTAMP occurred. n TIMESTAMP_TO_SCN(t) For example, let’s perform two separate conversions of timestamp values to SCN values (line numbers added): 01 02 03 04 05 06 07 08 SELECT TIMESTAMP_TO_SCN(SYSTIMESTAMP) NOW, TIMESTAMP_TO_SCN(TO_TIMESTAMP('01-AUG-09 09:12:23', 'DD-MON-RR HH:MI:SS')) NOT_NOW FROM DUAL; NOW NOT_NOW ---------------------- ---------------------5911139 5639192 In this example, we convert the current timestamp value, as defined by SYSTIMESTAMP, to its SCN equivalent. We also convert a date in the past to its SCN equivalent. The first column’s alias is NOW; the second column’s alias is NOT_NOW. Note: Any time referenced must be within a range that is relevant to the database—i.e., the function recognizes times that apply to whenever the database installation has been in existence. There is not a direct one-to-one relationship between timestamps and SCN values. For example, suppose you take a valid SCN value and convert: SELECT TIMESTAMP_TO_SCN(SCN_TO_TIMESTAMP(5895585)) FROM DUAL; TIMESTAMP_TO_SCN(SCN_TO_TIMESTAMP(5895585)) ------------------------------------------5895573 Note what happens here: one SCN goes in, and a slightly different SCN is ultimately returned. 468 Chapter 11: Managing Schema Objects For any work effort in which you require precision in specifying timing, Oracle recommends using SCN numbers, and obtaining them with the DBMS_ FLASHBACK packaged function GET_SYSTEM_CHANGE_NUMBER, which we reviewed earlier. Also note: It is important that if you wish to use FLASHBACK to restore to a specific point, you obtain that point precisely. One way to do that is the RESTORE POINT, which we discuss next. RESTORE POINT A RESTORE POINT is an object in the database you create to represent a given moment in the database. That moment can be identified by a TIMESTAMP value or an SCN. Here’s an example of the CREATE RESTORE POINT statement: CREATE RESTORE POINT balance_acct_01; Once executed, you can use this as a restore point representing the moment at which the CREATE RESTORE POINT statement was executed. You can refer to the restore point later in the current session, or in a later session: FLASHBACK TABLE HOUDINI TO RESTORE POINT balance_acct_01; This statement restores the HOUDINI table to the point in time that correlates to the “balance_acct_01” restore point. When you no longer need the RESTORE POINT, you can drop it: DROP RESTORE POINT balance_acct_01; You can find existing restore points with the data dictionary view V$RESTORE_ POINT. Note that users do not “own” RESTORE POINT objects; their scope is the entire database. They exist until they are dropped, or age out of the control file. Certification Objective 11.07 Create and Use External Tables An external table is a read-only table that is defined within the database but exists outside of the database. In more technical terms, the external table’s metadata is stored inside the database, and the data it contains is outside of the database. Create and Use External Tables 469 External tables have a number of restrictions on them. You can query them with the SELECT statement, but you cannot use any other DML statements on them. You can’t create an INDEX on them, and they won’t accept constraints. Benefits So why would you create an external table? Their primary benefit is to create an easy-to-use bridge between SQL tables and non-database data sources. If you’ve ever used the Oracle tool SQL*Loader, or Data Pump, then you’ll be pleased to discover that the external table feature was designed to incorporate the functionality found in those tools into a SQL context. A great example is when you have some non-SQL data source that regularly produces information needed in the database, such as a flat file transfer, a web site reference, a spreadsheet application, a legacy 3GL application, or something comparable. If that data source is capable of providing some sort of formatted flat file, then it can be structured in such a way that it can be copied directly into a file that the SQL external table will instantly recognize and be able to query. In other words, it will create the sort of one-way data transfer into the SQL database, but using SQL SELECT statements instead of utilities such as SQL*Loader. Creating External Tables To create an external table, you can declare its columns and their datatypes. You can also populate the external table with a subquery at the time you create it. But that’s about all you can do with external tables. They are restricted in a number of ways: n You cannot create a column with a LOB datatype—no CLOB, BLOB, NCLOB, etc. n You cannot add a constraint to an external table. n You cannot change the column of an external table to UNUSED. If you try, SQL will process the statement but will actually drop the column. Essentially, all you do with an external table is declare its structure and define the parameters by which the SQL database communicates with the external table. In order to establish that communication, you must first understand two subjects: n DIRECTORY objects n The Oracle utilities SQL*Loader and Oracle Data Pump 470 Chapter 11: Managing Schema Objects We’ll look at those next, and then we’ll create an external table. DIRECTORy Objects To create an external table, we’ll need to identify the location in the operating system where the external file containing the table will reside. For this, we need to look at the CREATE DIRECTORY statement. The CREATE DIRECTORY statement creates an object in the database that represents the name of a directory on the server’s file system. Here’s an example: CREATE OR REPLACE DIRECTORY directory_name AS directory_reference; where directory_name is a name you specify, just as you would any other database object, and directory_reference is a string literal, surrounded by single quotation marks, that identifies a location within your Oracle server’s file system, into which you wish for external tables to be stored. For example: CREATE OR REPLACE DIRECTORY BANK_FILES AS 'F:\bnk_files\trnsfr'; The result of this statement is that we’ve just created an object in the database named BANK_FILES that looks to the operating system where the Oracle server resides and assumes that the directory reference in the string literal is consistent with the syntax required for that particular operating system. In this case, we’re pointing to a Windows drive ‘F:’ and its root level directory “bnk_files”, within which is the subdirectory “trnsfr”—that subdirectory is our target. The DIRECTORY object will not parse this reference but instead will just store it as is. If it’s incorrect, you won’t find out until later when you try to use the DIRECTORY object. Also, the DIRECTORY object will not create the subdirectory; the assumption here is that the subdirectory already exists. If it does not, you won’t get an error message until you use the DIRECTORY object later. The keywords OR REPLACE are optional. In our example, the name BANK_FILES is a name we specify. This name is the name assigned to the object, and this name is how we will reference the DIRECTORY object in the future. Once a directory has been created, the owner must grant READ and/or WRITE access to any user who may use it: GRANT READ ON DIRECTORY directory_name TO username; That includes users who may wish to use external tables that are built with the directory objects. Create and Use External Tables 471 Oracle Utilities The Oracle database provides a number of utilities that accompany their database product. Those utilities that are important to external tables include n SQL*Loader n Oracle Data Pump Export n Oracle Data Pump Import Each is documented in the Oracle Corporation reference manual titled “Oracle Utilities”. Together, the utilities provide capabilities that allow external data sources to communicate with SQL objects within the database. A complete review of their capabilities is beyond the scope of the exam and therefore this book. But it’s important for the exam to recognize that a large component of the definitions associated with the declaration of an external table come from these utilities. Creating an External Table Let’s walk through an example. Let’s say we have an external text file containing the following data about invoices: ID --701 702 703 INV_DATE -----------03/15/09 03/17/09 03/18/09 ACCT_NO -------------CODDA009 CODDA010 CODDA011 We want to create an external table for this data; let’s call it INVOICE_ DATA.TXT. First, we go to the file system on which the Oracle database resides, locate the same drive, and we create a subdirectory off of the root level. We’ll call it “LOAD_ INVOICES”. Then we create the associated DIRECTORY object: CREATE DIRECTORY INVOICE_FILES AS '\LOAD_INVOICES'; By this point, we won’t necessarily have to have created the LOAD_INVOICES directory, nor to have put the INVOICE_DATA.TXT file in that directory. But for the sake of our example, now we do so, before continuing. 472 Chapter 11: Managing Schema Objects Next, we execute a CREATE TABLE statement that references the directory, along with the necessary clauses to tell Oracle SQL to load the external file, and how to load it (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 CREATE TABLE INVOICES_EXTERNAL ( INVOICE_ID CHAR(3), INVOICE_DATE CHAR(9), ACCOUNT_NUMBER CHAR(13) ) ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY INVOICE_FILES ACCESS PARAMETERS (RECORDS DELIMITED BY NEWLINE SKIP 2 FIELDS (INVOICE_ID CHAR(3), INVOICE_DATE CHAR(9), ACCOUNT_NUMBER CHAR(13)) ) LOCATION ('INVOICE_DATA.TXT') ); Once this statement executes, we end up with an external table in the database called INVOICES_EXTERNAL. n Note lines 2 through 4 where we declared our table using the datatypes CHAR. You’ll recall these are fixed-length datatypes. We did this to accommodate the transfer of rows in from the text file in lines 12 through 14. Each column’s datatype is set to CHAR, the fixed-length alphanumeric datatype, and the counts for each datatype correspond to the counts of the columns in the text file ‘INVOICE_DATA.TXT’, which is identified in line 16 and is in the directory stored in the directory object INVOICE_FILES, named in line 8. n Lines 1 through 5 form a complete CREATE TABLE statement by themselves, without the external table clause. But starting on line 6 are the keywords and clauses used to declare the external table, and together, lines 1 through 17 form the complete CREATE TABLE statement for our example. n Line 6 includes the keywords ORGANIZATION EXTERNAL, which are required. Create and Use External Tables 473 n Line 7 is where we specify that we are using ORACLE_LOADER, aka the SQL*Loader features. An alternative TYPE value here would be ORACLE_ DATAPUMP. n Line 9 begins the set of values for ACCESS PARAMETERS, which are enclosed within the parentheses that open on line 10 and close on line 15. n Three ACCESS PARAMETERS are used here: RECORDS, SKIP, and FIELDS. n Line 10—RECORDS DELIMITED BY NEWLINE—means that each new line starts a new row of data for the INVOICES_EXTERNAL table. n Line 11—SKIP 2—tells ORACLE_LOADER that the first two lines of the INVOICE_DATA.TXT file are to be skipped—they just contain header information. n Line 12—FIELDS—starts the specifications for each column, where each column’s length is carefully specified to match the length in the INVOICES_ DATA.TXT file. Many more ACCESS PARAMETERS exist that are not invoked here. I could probably write a separate book just on all the options and features that exist with the various clauses for the types ORACLE_LOADER and ORACLE_DATAPUMP. But I won’t, and you shouldn’t need that for the exam. Using an External Table Once we’ve created an external table, we can SELECT from it just like any other table—for example: SELECT * FROM INVOICES_EXTERNAL; INVOICE_ID INVOICE_DATE ACCOUNT_NUMBER ---------- ------------ -------------701 03/15/09 CODDA009 702 03/17/09 CODDA010 703 03/18/09 CODDA011 Many external tables will start with source data that is rough and unformatted. However, the first step is just to get it in the database. Once that is accomplished, you can use the various conversion functions and other features of SQL to clean up and reformat the data: 474 Chapter 11: Managing Schema Objects SELECT TO_NUMBER(INVOICE_ID), TO_DATE(INVOICE_DATE,'MM/DD/RR') INVOICE_DATE, LTRIM(ACCOUNT_NUMBER,' ') ACCOUNT_NUMBER FROM INVOICES_EXTERNAL; INVOICE_ID ---------------------701 702 703 External tables can be queried like any table or view in the database. INVOICE_DATE ------------------------15-MAR-09 17-MAR-09 18-MAR-09 ACCOUNT_NUMBER -------------CODDA009 CODDA010 CODDA011 Note the output—the numbers are reformatted, the date values are converted, and the account numbers have been trimmed up and everything looks terrific. Remember that you cannot use INSERT, UPDATE, or DELETE statements on external tables. Certification Summary The ALTER TABLE statement can be used with the ADD clause to add columns to a table that’s already been created, and with the MODIFY clause to modify the existing columns of the table. Changes to a column can include changes to datatype, and to scale and precision, but you cannot change a table in such a way that existing data would be in conflict with the change, or that would cause loss of detail in data. The RENAME clause of the ALTER TABLE statement can be used to rename columns in a table. Columns can be dropped from a table. Columns that are part of a referential constraint—in other words, a FOREIGN KEY constraint—may be dropped with the CASCADE CONSTRAINTS keywords added so that the constraints are dropped as well. Columns may be set to UNUSED to render them virtually dropped, but sparing the processing overhead required to drop a column. An UNUSED column is no longer available, and it can be dropped later. The ALTER TABLE statement can be used to add or modify constraints. The NOT NULL constraint has limited syntax requirements, but other constraints can be added using in-line or out-of-line syntax. A constraint can be disabled and enabled with the ALTER TABLE statement. You can also change a constraint’s name. Index objects support application performance tuning. Indexes can be built on one or more columns of a table; multicolumn index objects are known as composite Certification Summary 475 indexes. When a query references indexed columns in its WHERE clause, SQL will consider using the index as part of its processing strategy and the results may be returned more quickly. An index can be created explicitly with the CREATE INDEX statement, or created as part of the CREATE TABLE statement, either implicitly, such as when you create a PRIMARY KEY constraint, or explicitly, such as with the USING INDEX keywords. Function-based indexes are built on an expression. The result is an index that may be automatically invoked by any query that uses the same expression. Flashback operations can restore data to a previous point in time, with some limitations. The point to which you restore data can be identified using values of datatype TIMESTAMP, or SCN, or RESTORE POINT. Tables that have been dropped but that are still in the recycle bin can be recovered. Any table that’s been purged from the recycle bin is gone for good. Data that’s been changed in existing tables can be restored to some previous point in time, provided that the table’s structure hasn’t been changed in such a way that the table is no longer able to receive the restored data—such as perhaps having had a column dropped. External tables exist outside of the database. The process that supports them has its roots and syntax in the SQL*Loader tool, but the result is a table that can be described just like any other. External tables can be queried but cannot receive data input via INSERT, UPDATE, or DELETE. 476 Chapter 11: 3 Managing Schema Objects Two-Minute Drill Add and Modify Columns q The ALTER TABLE statement can be used to add or modify columns. q The ADD clause of ALTER TABLE can be used to add a column to a table. q A column is added by specifying the column name and datatype; optionally, you can add a constraint and a default value. q The MODIFY clause can be used to modify existing columns in a table. q A column’s datatype and other characteristics can be modified, but only insofar as the change does not conflict with any existing data in the table. q You cannot change a column’s datatype if the column contains data already. Drop Columns and Set Column UNUSED q The DROP clause of ALTER TABLE can be used to remove a column from a table. q Once a column is removed with DROP, the data is lost. q Dropping a column can consume significant processing time if the table involved contains a lot of data. q If you drop a column with a constraint, the constraint is also dropped. The same is true for any index objects on the column; they are also dropped. q SET UNUSED renders a column permanently unavailable; it cannot be recovered. q The SET UNUSED clause can benefit a large table in heavy production that cannot afford the overhead processing power of a DROP. q After a table has columns that are set to UNUSED, they can be dropped with the DROP UNUSED COLUMNS clause of ALTER TABLE. Add Constraints q The ALTER TABLE statement can be used to add constraints to a table with the ADD clause. q The DROP clause can be used to drop constraints. q A disabled constraint can be enabled again later, provided that the data contained with the column satisfies the constraint. Two-Minute Drill 477 Create Indexes Using the CREATE TABLE Statement q When a PRIMARY KEY or UNIQUE constraint is created as part of a CREATE TABLE statement, and if no existing index supports the constraint, then an index is automatically created as part of the constraint. q The USING INDEX clause can be invoked to explicitly define the index. Create Function-Based Indexes q A function-based index can be based on an expression; it does not necessarily need to include a SQL function, and can simply be based on an expression of any kind. q Queries that use the same function or expression may benefit from the index. Perform FLASHBACK Operations q FLASHBACK TABLE can be used to restore a table that has been dropped. q If a table has been dropped, it goes into the recycle bin. q You can investigate the contents of the recycle bin to determine what objects are available for use by FLASHBACK operations. q Once an object has been dropped, if it is also purged with the PURGE state- ment, it is no longer able to be recovered with FLASHBACK TABLE. q In addition to restoring a dropped table, the FLASHBACK TABLE state- ment can also be used to restore data within the table as of a particular time in the database. q Time in the database is marked by either a system change number (SCN), a RESTORE POINT, or a timestamp. Create and Use External Tables q An external table is a read-only table within the database that stores data outside of the database. q The communication between the external table’s data storage file and data- base objects is based on the logic of SQL*Loader or Oracle Data Pump. q You use a database object known as the DIRECTORY object as part of the definition of an external table. 478 Chapter 11: Managing Schema Objects Self Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Add and Modify Columns 1. Assume a table INVOICES exists in the database, it contains no rows, and it has a column called DISCOUNT. Which of the following statements will not execute? (Choose two.) A. ALTER TABLE INVOICES ADD COLUMN DEPOT_ID NUMBER; B. ALTER TABLE INVOICES ADD DEPOT_ID DEFAULT 0 NUMBER; C. ALTER TABLE INVOICES DROP COLUMN DISCOUNT; D. ALTER TABLE INVOICES RENAME COLUMN DISCOUNT TO DISC; 2. Review the following SQL statements: CREATE TABLE INVOICES (INVOICE_ID NUMBER, DISCOUNT NUMBER(3)); INSERT INTO INVOICES VALUES (7,5); INSERT INTO INVOICES VALUES (3,12); After executing these SQL statements, which of the following SQL statements will fail to execute? (Choose two.) A. ALTER TABLE INVOICES MODIFY DISCOUNT PRIMARY KEY; B. ALTER TABLE INVOICES MODIFY DISCOUNT VARCHAR2(3); C. ALTER TABLE INVOICES MODIFY DISCOUNT DEFAULT ‘Zero’; D. ALTER TABLE INVOICES MODIFY INVOICE_ID PRIMARY KEY; 3. You have a table called CUSTOMERS, and you want to change the name of a column in the CUSTOMERS table from NAME to LAST_NAME. Which of the following statements could you use? A. RENAME NAME TO LASTNAME; B. ALTER TABLE CUSTOMERS RENAME COLUMN NAME TO LASTNAME; C. ALTER TABLE CUSTOMERS RENAME NAME LASTNAME; D. It can’t be done. Self Test 479 Drop Columns and Set Column UNUSED 4. The difference between dropping a column from a table with DROP and setting a column to be UNUSED is: A. An UNUSED column can be recovered. B. The UNUSED column and its data are retained within the table’s storage allocation and counts against the total limit on the number of columns the table is allowed to have. C. A column that is dropped with DROP no longer appears within the table’s description as shown with the DESC or DESCRIBE statement, whereas a column that is set to UNUSED still appears in the table’s structure as shown in the output of the DESC statement. D. Nothing. 5. Review the following SQL statement: CREATE TABLE LETTERS (LETTER_ID NUMBER(7), POSTAGE NUMBER(7)); Which of the following will change POSTAGE to be an UNUSED column? A. ALTER TABLE LETTERS MODIFY POSTAGE SET UNUSED; B. ALTER TABLE LETTERS MODIFY COLUMN POSTAGE SET UNUSED; C. ALTER TABLE LETTERS SET UNUSED COLUMN POSTAGE; D. ALTER TABLE LETTERS SET COLUMN POSTAGE UNUSED; Add Constraints 6. Review the following illustration: 480 Chapter 11: Managing Schema Objects You are tasked with adding a constraint so that the PROJECTS table will not accept any rows with a value for the DAYS column of more than 90. You are aware that there are already rows in the PROJECTS table with a value for DAYS of 120. What will happen when you attempt to apply a constraint on the table? Assume the constraint is applied with the defaults of ENABLE VALIDATE. A. It will succeed, and the existing values for DAYS will remain unchanged, but no new rows will be accepted unless the DAYS value is less than 90. B. It will succeed, and the existing values for DAYS will be changed automatically by the system to NULL. C. It will succeed, but the rows in which DAYS is greater than 90 will be assigned a status of INVALID. D. It will fail and the constraint will not be created. 7. Review the illustration from question 6. You are tasked with adding a constraint so that the PROJECTS table will not accept any rows with a value for the DAYS column of more than 90. Which of the following statements will accomplish the task? A. ALTER TABLE PROJECTS ADD CK_DAYS CHECK (DAYS <= 90); B. ALTER TABLE PROJECTS ADD (DAYS) CHECK (DAYS <= 90); C. ALTER TABLE PROJECTS MODIFY DAYS CONSTRAINT CK_DAYS CHECK (DAYS <= 90); D. ALTER TABLE PROJECTS MODIFY DAYS ADD CONSTRAINT CK_DAYS CHECK (DAYS <= 90); Create Indexes Using the CREATE TABLE Statement 8. Review the following illustration: Now review this SQL statement: CREATE INDEX RN_SC FOR TABLE SHIP_CABINS (ROOM_NUMBER); Self Test 481 Which of the following statements is true for this SQL statement? A. It will fail due to a syntax error because of an error with the index name. B. It will fail due to a syntax error because of the FOR TABLE keywords. C. It will successfully execute but create an index that is INVALID. D. It will successfully execute and create an index as intended. 9. Review the illustration from question 8, and these SQL statements: CREATE INDEX RT_INDEX ON SHIP_CABINS (ROOM_TYPE, ROOM_STYLE); SELECT * FROM SHIP_CABINS WHERE ROOM_STYLE = 'SUITE'; Which of the following assertions about these SQL statements is true? A. The SQL optimizer will not consider the RT_INDEX index because the WHERE clause does not reference the ROOM_TYPE column. B. The SQL optimizer will consider the RT_INDEX index in exactly the same fashion that it would if the WHERE clause referenced ROOM_TYPE instead of ROOM_STYLE. C. The SQL optimizer will consider the RT_INDEX index once for each unique value in the ROOM_TYPE column, until it finds all the values that satisfy the WHERE clause. D. The SQL optimizer will consider the RT_INDEX index once for each unique value in the ROOM_STYLE column, until it finds all the values that satisfy the WHERE clause. 10. Review these SQL statements (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 CREATE TABLE ITEMS (ITEM_NUM NUMBER(7) PRIMARY KEY, ITEM_NAME VARCHAR2(30)); CREATE TABLE REPAIR_HISTORY ( REPAIR_HISTORY_ID NUMBER(11) PRIMARY KEY, REPAIR_DATE DATE, ITEM_NUM NUMBER(11) REFERENCES ITEMS(ITEM_NUM), REPAIR_TRACKING VARCHAR2(11) UNIQUE, REPAIR_AGENT VARCHAR2(30) USING INDEX (CREATE INDEX IX_RA ON REPAIR_HISTORY (REPAIR_AGENT) ), NOTES VARCHAR2(200)); How many indexes on the REPAIR_HISTORY table will be created as a result of these statements? A. None, because the CREATE TABLE statement in line 4 will fail due to a syntax error in line 9 through line 11 B. One C. Two D. Three 482 Chapter 11: Managing Schema Objects 11. Review this code and note the placeholder for option in italics: 01 02 03 CREATE TABLE REPAIR_HISTORY ( REPAIR_HISTORY_ID NUMBER(11) PRIMARY KEY option, REPAIR_DATE DATE); To create an INDEX within this CREATE TABLE statement, what can be substituted for option? A. USING INDEX (CREATE INDEX IND_PK) B. USING INDEX (CREATE INDEX IND_PK ON REPAIR_HISTORY) C. USING INDEX (CREATE INDEX IND_PK ON REPAIR_HISTORY(REPAIR_HISTORY_ID)) D. USING INDEX IND_PK (REPAIR_HISTORY_ID) Create Function-Based Indexes 12. Review the following SQL statement: CREATE INDEX IND_004 ON SHIP_CABINS ((SQ_FT + BALCONY_SQ_FT)/GUESTS); Which of the following statements will cause the optimizer to consider this index? A. SELECT * FROM SHIP_CABINS WHERE SQ_FT + BALCONY_SQ_FT < 500; B. SELECT * FROM SHIP_CABINS WHERE ((BALCONY_SQ_FT + SQ_FT)/GUESTS) < 500; C. SELECT * FROM SHIP_CABINS WHERE (SQ_FT/GUESTS) < 500; D. SELECT * FROM SHIP_CABINS WHERE (GUESTS/(SQ_FT + BALCONY_SQ_FT)) < 500; Perform FLASHBACK Operations 13. Review the following SQL code (line numbers added): 01 02 03 04 05 06 07 08 09 10 DROP TABLE PO_BOXES; CREATE TABLE PO_BOXES (PO_BOX_ID NUMBER(3), PO_BOX_NUMBER VARCHAR2(10)) ENABLE ROW MOVEMENT; INSERT INTO PO_BOXES VALUES (1, 'A100'); INSERT INTO PO_BOXES VALUES (2, 'B100'); COMMIT; EXECUTE DBMS_LOCK.SLEEP(30); DELETE FROM PO_BOXES; COMMIT; EXECUTE DBMS_LOCK.SLEEP(30); Self Test 483 Which of the following statements could be added as line 11, and recover the deleted rows from the PO_BOXES table? A. FLASHBACK TABLE PO_BOXES TO TIMESTAMP SYSTIMESTAMP—INTERVAL ‘0 00:00:45’ DAY TO SECOND; B. FLASHBACK TABLE PO_BOXES TO SYSTIMESTAMP—INTERVAL ‘0 00:00:45’ DAY TO SECOND; C. FLASHBACK TABLE PO_BOXES INTERVAL ‘0 00:00:45’ DAY TO SECOND; D. FLASHBACK TABLE PO_BOXES TO TIMESTAMP INTERVAL ‘0 00:00:45’ DAY TO SECOND; 14. Review the following SQL code (line numbers added): 01 02 03 04 05 06 07 08 09 CREATE TABLE PO_BOXES (PO_BOX_ID NUMBER(3), PO_BOX_NUMBER VARCHAR2(10)) ENABLE ROW MOVEMENT; INSERT INTO PO_BOXES VALUES (1, 'A100'); INSERT INTO PO_BOXES VALUES (2, 'B100'); COMMIT; DROP TABLE PO_BOXES; COMMIT; PURGE TABLE PO_BOXES; COMMIT; What statement will recover the PO_BOXES table after these statements are executed? A. FLASHBACK TABLE PO_BOXES TO BEFORE DROP; B. FLASHBACK TABLE PO_BOXES TO TIMESTAMP SYSTIMESTAMP—INTERVAL ‘0 00:00:03’ DAY TO SECOND; C. FLASHBACK TABLE PO_BOXES TO BEFORE COMMIT; D. None of the above Create and Use External Tables 15. The purpose of the CREATE DIRECTORY statement is to create a named object in the database: A. That lists names of user accounts that have external privileges B. That contains lookup reference material for queries C. That identifies the root directory of the Oracle server installation D. That points to a directory you choose somewhere within the Oracle server’s file system 484 Chapter 11: Managing Schema Objects Self Test Answers Add and Modify Columns 1. ˛ A and B. These answers are correct, meaning that the SQL statements shown will not execute and will fail. The reasons: You cannot include the COLUMN keyword in the ADD or MODIFY clause of ALTER TABLE. If you include the DEFAULT keyword, then it must follow any datatype specification, not precede it. ˝ C and D are incorrect. These statements are syntactically correct. Even though you cannot include the COLUMN keyword in the ADD or MODIFY clauses of the ALTER TABLE statement, the COLUMN keyword is a part of the DROP clause and the RENAME clause. 2. ˛ B and C. These answers are correct, meaning that the SQL statements here will fail to execute. You cannot change a populated column from one datatype to another—in this case, you cannot change a populated NUMBER to VARCHAR2. Even though SQL could theoretically do an automatic datatype conversion in this particular scenario, it won’t. Also, you cannot set the DEFAULT value for a column to something that conflicts with its datatype. ˝ A and D are incorrect. These are fine. Either column could be made into the primary key. 3. ˛ B. This is the correct syntax. ˝ A, C, and D are incorrect. You can change the name of a column in a table. The RENAME COLUMN clause is part of the ALTER TABLE statement and requires use of the keyword TO, as shown in answer B. Drop Columns and Set Column UNUSED 4. ˛ B. The UNUSED column is still stored as part of the table. There’s no storage benefit to the table—no space is reclaimed from an unused column. ˝ A, C, and D are incorrect. Neither a column dropped with DROP nor an UNUSED column can be seen in the table’s structure. A column, once set to UNUSED, can never be recovered. It can only be dropped. 5. ˛ C. The SET UNUSED keywords follow the table name and precede the keyword COLUMN, followed by the name of the column to be set to UNUSED. ˝ A, B, and D are incorrect. The syntax doesn’t use the MODIFY option, but rather the SET UNUSED option, along with the keyword COLUMN and the column name. Self Test Answers 485 Add Constraints 6. ˛ D. The attempt to add the constraint to the table will fail. All existing rows in the table must satisfy the constraint at the time it is added. ˝ A, B, and C are incorrect. All wrong. The addition of the constraint will not change existing values in any way. No rows will be marked as invalid. 7. ˛ C. This is the correct syntax. When the MODIFY clause is used to modify a column, the in-line syntax for a constraint is what you must use. ˝ A, B, and D are incorrect. While it’s possible to add the constraint using the ADD clause of ALTER TABLE, these particular examples are not valid. For one thing, the CONSTRAINT keyword is required after ADD when adding a CHECK constraint. Were that included in Answer A, the syntax there would work fine. But Answer B is another story—note the reference to the DAYS column in parentheses. CHECK constraints do not require a column reference, not even in the out-of-line syntax; the column reference should be included within the expression, which in this instance—it is. As for the remaining incorrect answer, whenever the MODIFY clause is used to modify a column, the ADD keyword is not used. Create Indexes Using the CREATE TABLE Statement 8. ˛ B. The FOR TABLE keywords are not valid in this context. They should be replaced simply with the word ON and nothing more. ˝ A, C, and D are incorrect. 9. ˛ C. The INDEX is a composite, which means that it includes more than one column. Given that, and the fact that the query’s WHERE clause specifies a column other than the leading column in the index, the query optimizer considers performing a “skip scan” to search the index once for each unique value in the ROOM_TYPE column. ˝ A, B, and D are incorrect. The INDEX may be considered, but it will probably not be used in the same way it would were the first column referenced instead of the second column. 10. ˛ A. You cannot use the USING INDEX clause in a CREATE TABLE statement unless you are using it as part of a PRIMARY KEY or UNIQUE constraint, and neither is involved with line 9. ˝ B, C, and D are incorrect. Were it not for the improper use of USING INDEX in line 9, the table would create two indexes automatically—one as a result of the PRIMARY KEY constraint in line 5, and one as a result of the UNIQUE constraint. 11. ˛ C. The correct syntax restates the table name and column name, as well as the name of the index. ˝ A, B, and D are incorrect. 486 Chapter 11: Managing Schema Objects Create Function-Based Indexes 12. ˛ B. The fact that the columns SQ_FT and BALCONY_SQ_FT are reversed in the expression is not an issue—the index will still be used. ˝ A, C, and D are incorrect. None of the other options represents an expression that is recognizable to the function-based index. Answer D is the closest in the sense that it includes all of the components, but by reversing the positions of the values with regard to the division operator, the result is a fundamentally different equation. Perform FLASHBACK Operations 13. ˛ A. This is the correct syntax—the TO TIMESTAMP clause with the expression that starts with the current date and time and subtracts an interval of 45 seconds. ˝ B, C, and D are incorrect. Answer B is missing the keyword TIMESTAMP. Answer C is missing the keywords TO TIMESTAMP, and includes an incomplete expression that only represents a time interval of 45 seconds. Answer D has the keyword TIMESTAMP but also has the incomplete expression that only includes the interval value and nothing more. 14. ˛ D. None of the above. The PURGE statement on line 8 prevents any recovery from being possible. PURGE cleans out the recycle bin of the objects specified in the PURGE statement, from which FLASHBACK TABLE recovers objects. ˝ A, B, and C are incorrect. Were it not for the PURGE, answer A would be correct. Answer B is syntactically correct, but again, only were it not for the PURGE statement in the code sample. There is no BEFORE COMMIT option for FLASHBACK TABLE. Create and Use External Tables 15. ˛ D. CREATE DIRECTORY lets you create a database object name for a directory you choose. Later you can use this object for creating an external table. ˝ A, B, and C are incorrect. 12 Using the Set Operators CertIFIcAtIon ObJectIVes 12.01 Describe Set Operators 12.02 Use a Set Operator to Combine Multiple Queries into a Single Query 12.03 3 Q&A Control the Order of Rows Returned Two-Minute Drill Self Test 488 Chapter 12: Using the Set O perators T his chapter describes the set operators in SQL. Set operators work with sets of output data from two or more SELECT statements. They combine standalone SELECT statements in ways that cannot be done with joins or other conventional methods in SQL. Set operators are ideal for a variety of situations where a SELECT statement’s output can be combined with other data that isn’t necessarily related through a structured key relationship but can still be combined into one complete output data set. A series of SELECT statements combined with set operators may include a single ORDER BY clause at the end of the series of SELECT statements. Set operators should not be confused with the reserved word SET that is used with SQL statements like UPDATE. The set operators have nothing to do with the keyword SET and don’t use it. CertIFIcAtIon ObJectIVe 12.01 Describe Set Operators There are four set operators: UNION, UNION ALL, INTERSECT, and MINUS. Set operators combine two or more separate SELECT statements so that their output is merged in some manner. Each set operator merges the data in a different way. The set operators are described in Table 12-1 and summarized in Figure 12-1. The UNION operator merges the resulting row sets of one SELECT statement with the resulting row sets of another, so that all of the records from both SELECT statements are included in the final output. UNION also eliminates any duplicate records that might result in the combined output. TAbLe 12-1 Set Operator Description The Set Operators UNION Combines row sets. Eliminates duplicate row sets. UNION ALL Combines row sets. Does not eliminate duplicate row sets. INTERSECT Includes all row sets that are present in both queries. MINUS Subtracts the rows in the second row set from the rows in the first row set. Describe Set Operators FIGure 12-1 The set operators in action SELECT ID, NAME… ID -1 2 NAME ------Sneezy Grumpy SELECT NO, TITLE … NO -2 3 TITLE ------Grumpy Doc 489 UNION -1 2 3 ------Sneezy Grumpy Doc UNION ALL INTERSECT -2 -1 2 2 3 ------Sneezy Grumpy Grumpy Doc ------Grumpy MINUS -1 ------Sneezy UNION ALL does the same thing as UNION, except that it does not eliminate duplicate rows. INTERSECT combines both sets of rows so that only those rows that were present in both SELECT statements appear in the final result. MINUS starts with the first set of rows and then uses the second SELECT statement’s row set to see if any duplicates occur. If they do, those duplicates are completely removed altogether, leaving only those rows that uniquely exist in the first SELECT statement’s row set. The only rules for ensuring that the SELECT statements will combine successfully with any of the set operators are as follows: n The number of expressions selected in the select lists must be identical in each SELECT statement. n The datatypes of each expression must match, so that each SELECT statement’s first expression shares the same datatype group with the other first expressions, and each second expression shares the same datatype group with 490 Chapter 12: Using the Set O perators the other second expressions, etc. By datatype group, we mean datatypes that are either identical or can be made to be identical by SQL through automatic datatype conversion. n Large datatypes such as BLOB and CLOB cannot be used. n The ORDER BY clause cannot be included in the SELECT statements— except for the final SELECT statement. The SELECT statements are not required to have any sort of PRIMARY KEY / FOREIGN KEY relationships. Their tables and columns don’t have to be identical in any other way—they don’t have to be named with the same names—none of that applies. You can combine Each individual SELECT statement can be a complex SELECT statements with the complete, standalone statement (but without an set operators. Examples include SELECT ORDER BY clause), with all the complexities statements that involve multi-table joins, of any SELECT statement, including GROUP subqueries, aggregate functions, and/or BY clauses, subqueries, and everything that GROUP BY clauses. forms a complete SELECT statement. As long as the numbers of columns are identical, and the respective datatype groups match up, the set operators will perform as intended—subject to the restrictions we just identified. CertIFIcAtIon ObJectIVe 12.02 Use a Set Operator to Combine Multiple Queries into a Single Query Let’s look at the syntax for the set operators. Each is very simple—they each connect two SELECT statements, causing them to behave as one. UNION To demonstrate the use of UNION, we’ll look at an exercise in which we are trying to combine e-mail addresses from different tables. First, we’ll look at one of the two tables shown in Figure 12-2, the CONTACT_EMAILS table. Use a Set Operator to Combine Multiple Queries into a Single Query 491 FIGure 12-2 Diagram of the CRUISE_ CUSTOMERS and CONTACT_ EMAILS tables Notice the column EMAIL_ADDRESS in the CONTACT_EMAILS table. Let’s get a data listing: SELECT CONTACT_EMAIL_ID, STATUS, EMAIL_ADDRESS FROM CONTACT_EMAILS; CONTACT_EMAIL_ID ---------------------1 2 3 STATUS ------Opt Out Valid Valid EMAIL_ADDRESS --------------------bubblegum@tlivecar.com nora@astann.com watcher@foursigma.org Next, let’s look at another table called ONLINE_SUBSCRIBERS, shown in Figure 12-3. You can see that it has a column called simply EMAIL. Let’s get a data listing for that table as well: SELECT ONLINE_SUBSCRIBER_ID, EMAIL FROM ONLINE_SUBSCRIBERS; ONLINE_SUBSCRIBER_ID ---------------------1 2 3 EMAIL ----------------------------pendicott77@kasteelinc.com watcher@foursigma.org hardingpal@ckofca.com 492 Chapter 12: Using the Set O perators FIGure 12-3 Diagram of the ONLINE_ SUBSCRIBERS table In order to demonstrate the set operator UNION, we’ll create two SELECT statements with similar select lists—but by similar, we mean only that the select lists are identical in the number of expressions in the list, and their respective datatype groups. The first SELECT will include a WHERE clause to limit our rows to ‘Valid’ data. Let’s give it a try (line numbers added): 01 02 03 04 05 06 SELECT FROM WHERE UNION SELECT FROM CONTACT_EMAIL_ID, EMAIL_ADDRESS CONTACT_EMAILS STATUS = 'Valid' ONLINE_SUBSCRIBER_ID, EMAIL ONLINE_SUBSCRIBERS; Notice how we’ve structured this UNION query: n Both SELECT statements have two expressions in their select lists (line 1 and line 5). n The datatypes of each list’s first expression are the same—in this case, they are both numeric—CONTACT_EMAIL_ID (line 1) and ONLINE_ SUBSCRIBER_ID (line 5). n The datatypes of each list’s second expression are the same—in this case, they are both character: EMAIL_ADDRESS (line 1) and EMAIL (line 5). Here’s the output from our UNION: CONTACT_EMAIL_ID ---------------------1 2 2 3 3 EMAIL_ADDRESS -----------------------------pendicott77@kasteelinc.com nora@astann.com watcher@foursigma.org hardingpal@ckofca.com watcher@foursigma.org Use a Set Operator to Combine Multiple Queries into a Single Query 493 Notice the first column of output under the heading CONTACT_EMAIL_ID. The output shown includes data from both SELECT statements, which means you’re seeing values from the column CONTACT_EMAIL_ID of the first SELECT, and the column ONLINE_SUBSCRIBER_ID of the second SELECT statement. Logically, though, there’s a problem: the values for CONTACT_EMAIL_ID and ONLINE_SUBSCRIBER_ID don’t really represent the same information. Both are primary key values, but for different tables, and they don’t really belong in the same column—they represent totally different values. The evidence of this problem is present in the list of email addresses—we only wanted a single list of unique values, but instead we have a duplication of at least one email address. The reason is that UNION looks at the entire row of output from each SELECT, and shows unique occurrences of the combined set of columns in the row. The first occurrence of the email address “watcher@foursigma.org” has a first column value of 2, and the second has a first column value of 3, so as far as the UNION is concerned, these are unique rows of data. Let’s remove the illogical references to the first column in this example, and produce something that makes more sense (line numbers added): 01 02 03 04 05 06 SELECT FROM WHERE UNION SELECT FROM EMAIL_ADDRESS CONTACT_EMAILS STATUS = 'Valid' EMAIL ONLINE_SUBSCRIBERS; The result: EMAIL_ADDRESS ---------------------------hardingpal@ckofca.com nora@astann.com pendicott77@kasteelinc.com watcher@foursigma.org The result of UNION (line 4) is a combination of the original rows, with any duplicate values removed. In this case, there were two rows for the email address “watcher@foursigma.org”, but only one is shown in our final result. Notice that the output columns have headings from the first SELECT statement’s expressions (line 1). We’ll have more to say about that when we discuss ORDER BY and column references. For now, let’s move on to the UNION ALL set operator. 494 Chapter 12: Using the Set O perators UNION ALL The only difference between UNION and UNION ALL is that duplicate values aren’t removed from UNION ALL. If we were to execute the same SQL statement from the last example with the UNION ALL set operator, it would look like this: 01 02 03 04 05 06 SELECT EMAIL_ADDRESS FROM CONTACT_EMAILS WHERE STATUS = 'Valid' UNION ALL SELECT EMAIL FROM ONLINE_SUBSCRIBERS; The results: EMAIL_ADDRESS ---------------------------nora@astann.com watcher@foursigma.org pendicott77@kasteelinc.com watcher@foursigma.org hardingpal@ckofca.com Notice that the duplicate entry is included. The value for ‘watcher@foursigma.org’ appears in both tables, so it appears twice in the output of our UNION ALL use of the SELECT statement. Notice also that the ordering of the rows is totally different—remember that without an explicit ORDER BY clause, you can never guarantee the ordering of rows in any SELECT statement. We’ll look at how to use ORDER BY later in this chapter. First—let’s look at another set operator. INTERSECT The set operator INTERSECT looks for common values among the rows of the SELECT statement. Let’s change our example to use INTERSECT: 01 02 03 04 05 06 SELECT EMAIL_ADDRESS FROM CONTACT_EMAILS WHERE STATUS = 'Valid' INTERSECT SELECT EMAIL FROM ONLINE_SUBSCRIBERS; Use a Set Operator to Combine Multiple Queries into a Single Query 495 And the results: EMAIL_ADDRESS -----------------------------watcher@foursigma.org Just one row was common between the two SELECT statements. INTERSECT will eliminate duplicate rows. If one or both SELECT statement row sets contains duplicates within its own set of rows, the resulting output from INTERSECT will eliminate those duplicates. MINUS The final set operator is MINUS. Up to now, the results of the set operators would be the same regardless of which SELECT statement was placed first before the set operator. That’s not the case with MINUS, however. MINUS will start with the first SELECT statement and remove any rows from that SELECT’s output that might happen to appear in the second SELECT’s output. The results may differ, depending on which SELECT is placed first, and which is placed second. Using our same example, here is the SELECT from CONTACT_EMAILS first: 01 02 03 04 05 06 SELECT FROM WHERE MINUS SELECT FROM EMAIL_ADDRESS CONTACT_EMAILS STATUS = 'Valid' EMAIL ONLINE_SUBSCRIBERS; The results: EMAIL_ADDRESS -------------------nora@astann.com But now let’s reverse the placement of the SELECT statements: 01 02 03 04 05 06 SELECT FROM MINUS SELECT FROM WHERE EMAIL ONLINE_SUBSCRIBERS EMAIL_ADDRESS CONTACT_EMAILS STATUS = 'Valid'; 496 Chapter 12: Using the Set O perators The results: EMAIL -------------------hardingpal@ckofca.com pendicott77@kasteelinc.com Notice that the results are completely different. Notice also that the column heading is different—the column has taken the heading of the first SELECT statement, as it always does, but now the first SELECT statement is different, and along with it (in this example), so is the heading. Combinations The set operators may be used in multiple combinations, such as SELECT... UNION SELECT... INTERSECT SELECT... Such combinations can be continued indefinitely. Set operators have equal precedence among themselves, meaning that they will all execute from start to finish, in the order that they appear in the SELECT statement. To change the order of execution, use parentheses, like this: SELECT... UNION (SELECT... INTERSECT SELECT...) INTERSECT SELECT... Just be sure to use the parentheses so that: n The code enclosed is a standalone query and does not include an ORDER BY clause. n The enclosed code is placed into the outer query as though it were a single, standalone SELECT statement, without the ORDER BY clause. n If an ORDER BY is desired, it must be the final clause in the entire series of statements. Control the Order of Rows Returned 497 Follow those rules, and you can connect as many SELECT statements together as required. The set operators are useful for requirements to combine the data of two tables into one output listing when the two tables have no primary key— foreign key relationship with each other. CertIFIcAtIon ObJectIVe 12.03 Control the Order of Rows Returned As with any SELECT statement, the ORDER BY clause is the only way to determine the ordering of rows that appear in output. As we already know, the ORDER BY clause determines how to sort rows by identifying a series of one or more expressions that have something to do with the table—or tables—that are involved with the SELECT statement. Often the expression is simply a column within each row, but ORDER BY also accepts complex expressions. These expressions may involve one or more columns and perform some sort of transformation on the data. However, when set operators are involved, there’s a bit of an issue—how do you identify data in the rows when there are multiple rows from multiple tables that aren’t necessarily consistent with each other in terms of names or structures? The answer is that the ORDER BY clause is a bit restricted in this situation. The clause is restricted to identifying common expression items in the select list, and nothing more. There are two ways to identify them, and we’ve seen these earlier—by reference and by position. The following sections show examples of these approaches with the set operators. ORDER BY—By Position One way to sort rows of output that result from a series of SELECT statements combined with set operators is to use the “by position” approach. For example: 01 02 03 04 SELECT 'Individual', LAST_NAME || ', ' || FIRST_NAME FROM CRUISE_CUSTOMERS UNION 498 Chapter 12: 05 06 07 Using the Set O perators SELECT CATEGORY, VENDOR_NAME FROM VENDORS; The preceding example combines rows from two tables. The first query has two expressions: n A string literal, ‘Individual’ n A concatenation of two columns, LAST_NAME and FIRST_NAME, separated by a comma and a space The second SELECT statement has two expressions: n The column CATEGORY n The column VENDOR_NAME Here are the results: 'INDIVIDUAL' -----------Individual Individual Individual Partner Supplier LAST_NAME||','||FIRST_NAME --------------------------------------------------Bryant, William Gilbert, Nada MacCaulay, Nora Acme Steaks Acme Poker Chips We can sort the rows with an ORDER BY that identifies the position within the select list of the expression we wish to sort by, like this: 01 02 03 04 05 06 07 08 SELECT 'Individual', LAST_NAME || ', ' || FIRST_NAME FROM CRUISE_CUSTOMERS UNION SELECT CATEGORY, VENDOR_NAME FROM VENDORS ORDER BY 2; The result: 'INDIVIDUAL' -----------Supplier Partner Individual Individual Individual LAST_NAME||','||FIRST_NAME --------------------------------------------------Acme Poker Chips Acme Steaks Bryant, William Gilbert, Nada MacCaulay, Nora Control the Order of Rows Returned 499 Remember: When using ORDER BY with a series of SELECT statements connected with set operators, you can only use ORDER BY once, at the end. ORDER BY—By Reference There is another way to use ORDER BY with set operators. ORDER BY reference is when you name one of the columns in the SELECT statement’s expression list. When using set operators, the column names used in the first SELECT statement are in force. Using our earlier example, let’s add column aliases to our first SELECT statement, and we’ll be able to use ORDER BY: 01 02 03 04 05 06 07 08 SELECT FROM UNION SELECT 'Individual' CONTACT_CATEGORY, LAST_NAME || ', ' || FIRST_NAME POINT_OF_CONTACT CRUISE_CUSTOMERS CATEGORY, VENDOR_NAME FROM VENDORS ORDER BY POINT_OF_CONTACT; Note the column alias POINT_OF_CONTACT that is specified at the end of line 2, and used in the ORDER BY in line 8. The results: CONTACT_CATEGORY -------------------Supplier Partner Individual Individual Individual POINT_OF_CONTACT ----------------------------------------------Acme Poker Chips Acme Steaks Bryant, William Gilbert, Nada MacCaulay, Nora So—either the “by position” or “by reference” approach works with ORDER BY—just be sure that you make it the last clause of the entire series of SELECT statements. If you combine a series of three or more SELECT statements with set operators, your ORDER BY clause must be the final clause, and can only specify columns by name if it uses the column names from the very first SELECT statement, regardless of how many SELECT statements might be connected with set operators. 500 Chapter 12: Using the Set O perators CertIFIcAtIon SummAry The set operators combine the rows from several independent SELECT statements in various combinations. Set operators allow you to combine rows without a join, by merging entire sets of rows based solely on ensuring that the number of expressions and datatypes involved match up. The set operators include UNION, UNION ALL, INTERSECT, and MINUS. UNION combines rows and eliminates duplicates that might appear as a result of the combination. UNION ALL combines rows but does not eliminate any duplicates. INTERSECT looks only for duplicates, and only the duplicates become the output from the SELECT statement. MINUS takes the set of rows from the first SELECT and removes any for which duplicates exist in the second set. You can combine several SELECT statements with as many set operators as you wish. They will execute one after the other, unless you choose to override that behavior using parentheses. Each SELECT statement can be a complex query, with multiple joins, subqueries, and GROUP BY clauses. However, only one ORDER BY clause is allowed, and it must be at the end of the series of SELECT statements and set operators. ORDER BY with set operators can sort rows by position or reference. If by reference, the first SELECT statement’s expression names are in effect for the entire series of SELECT statements. You can use column aliases in the first (or any) SELECT statement if you wish, but it is not required. Two-Minute Drill 3 501 Two-MInute DrILL Describe Set Operators q UNION combines the output of two SELECT statements, eliminating any duplicate rows that might exist. q INTERSECT combines the output of two SELECT statements, showing only the unique occurrences of data present in both rowsets, and ignoring anything that doesn’t appear in both sets. q MINUS takes the first SELECT statement’s output and subtracts any occur- rences of identical rows that might exist within the second SELECT statement’s output. q UNION ALL does the same thing as UNION but does not eliminate dupli- cate rows. Use a Set Operator to Combine Multiple Queries into a Single Query q The set operators are placed between two SELECT statements. q The two SELECT statements can be simple or complex and can include their own GROUP BY clauses, WHERE clauses, subqueries, and more. q The ORDER BY clause, if used, must be the final clause of the combined SELECT statements. q You can connect multiple SELECT statements with multiple set operators. q The set operators have equal precedence. q You can use parentheses to override set operator precedence. Control the Order of Rows Returned q If an ORDER BY clause is used, it must be placed at the very end of the SQL statements. q Multiple SELECTs that are connected with set operators may be sorted by position or reference. q When using ORDER BY reference, the column name in force is whatever column name exists in the first SELECT statement. 502 Chapter 12: Using the Set O perators SeLF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Describe Set Operators 1. The set operators do not include which one of the following keywords: A. ALL B. SET C. MINUS D. UNION 2. You are tasked with cleaning up a database application. There are two tables in the database: ORDERS contains completed ORDERS, and ORDER_RETURNS contains duplicate information for all ORDERS that were later returned. Your goal is to find out if any rows in ORDER_RETURNS exist that were never in the ORDERS table to begin with. Which of the following set operators should you use? A. ALL B. SET C. MINUS D. UNION 3. Review the following illustrations: SELECT * FROM FURNISHING: CAT# ITEM_NAME ADDED SECTION 1 2 3 Side table Desk Towel 23-DEC-09 12-SEP-09 10-OCT-09 LR BR BA SELECT * FROM STORE_INVENTORY: NUM AISLE PRODUCT LAST_ORDER 77 78 79 F02 B11 SP01 Jacket Towel Lava lamp 2009-09-09 2009-11-11 2009-12-21 Self Test 503 Next, review the following SQL code (line numbers added): 01 02 03 04 05 06 SELECT TO_CHAR(A.LAST_ORDER,'RRRR-MM-DD') FROM STORE_INVENTORY A ORDER BY 1 UNION SELECT ADDED FROM FURNISHINGS; What will result from an attempt to execute this SQL statement? A. It will fail with a syntax error because of the TO_CHAR conversion function on line 1. B. It will fail because of the table alias in lines 1 and 2, which cannot be used in this context. C. It will fail with a syntax error on line 3, because you cannot use an ORDER BY in this context. D. It will execute successfully. 4. When combining two SELECT statements, which of the following set operators will produce a different result, depending on which SELECT statement precedes or follows the operator? A. MINUS B. UNION ALL C. INTERSECT D. UNION 504 Chapter 12: Using the Set O perators 5. Which of the following statements about set operators is true? A. If you add the reserved word ALL to the end of any set operator, it will change the behavior of the set operator by removing duplicate rows. B. Set operators can be used to combine INSERT statements. C. You can connect two SELECT statements together with one set operator. D. The UNION set operator has precedence over the others. Use a Set Operator to Combine Multiple Queries into a Single Query 6. Review the first two illustrations from question 3, then review this SQL code: SELECT NUM, PRODUCT FROM STORE_INVENTORY INTERSECT SELECT CAT#, ITEM_NAME FROM FURNISHINGS; How many rows will result from this query? A. 0 B. 1 C. 3 D. 6 7. Review the first two illustrations from question 3, and then review this SQL code: 01 02 03 04 05 06 SELECT '--', SECTION FROM FURNISHINGS WHERE CAT# NOT IN (1,2) UNION ALL SELECT TO_CHAR(LAST_ORDER,'Month'), AISLE FROM STORE_INVENTORY; How many rows will result from this query? A. 0 B. 4 C. 6 D. It will not execute because it will fail with a syntax error. 8. Review the first two illustrations from question 3, and then review this SQL code: ( SELECT PRODUCT UNION ALL FROM STORE_INVENTORY Self Test 505 SELECT ITEM_NAME FROM FURNISHINGS ) INTERSECT ( SELECT ITEM_NAME FROM FURNISHINGS WHERE ITEM_NAME = 'Towel' UNION ALL SELECT ITEM_NAME FROM FURNISHINGS WHERE ITEM_NAME = 'Towel' ); How many rows will result from this code? A. 1 B. 2 C. 4 D. 6 9. Review the first two illustrations from question 3, as well as the ONLINE_SUBSCRIBERS table in Figure 12-3, and then review this SQL code: 01 02 03 04 05 06 SELECT COUNT(*) FROM ONLINE_SUBSCRIBERS WHERE SUB_DATE IN (SELECT LAST_ORDER FROM STORE_INVENTORY UNION SELECT ADDED FROM FURNISHINGS); What will happen when this SQL statement is executed? A. It will fail with a syntax error because you cannot use an aggregate function like COUNT(*) in line 1 in this context. B. It will fail with a syntax error starting at line 4. C. It will execute, but it will not perform as intended, because the second SELECT statement within the subquery on line 6 will not execute; only the first SELECT in the subquery on line 4 will execute. D. It will execute successfully. 10. Review the first two illustrations from question 3, as well as the ONLINE_SUBSCRIBERS table in Figure 12-3, and then review this SQL code: 01 02 03 04 05 SELECT (SELECT LAST_ORDER FROM STORE_INVENTORY UNION SELECT ADDED "Date Added" FROM FURNISHINGS) FROM ONLINE_SUBSCRIBERS ORDER BY 1; 506 Chapter 12: Using the Set O perators What will happen when this SQL statement is executed? A. It will fail with an execution error on line 1. B. It will execute, but the UNION will not work as expected. C. It will execute and display one column under the heading “Date Added”. D. It will execute and display one column under the heading LAST_ORDER. 11. Review the first two illustrations from question 3, as well as the ONLINE_SUBSCRIBERS table in Figure 12-3, and then review this SQL code: 01 02 03 04 SELECT FROM (SELECT PRODUCT FROM STORE_INVENTORY INTERSECT SELECT ITEM_NAME FROM FURNISHINGS) ONLINE_SUBSCRIBERS; What will happen when this SQL statement is executed? A. It will fail with a general syntax error. B. It will fail with an execution error. C. It will execute, but the INTERSECT will not work correctly. D. It will execute and repeat the value ‘Towel’ for each row of the ONLINE_SUBSCRIBERS table. 12. Review the first two illustrations from question 3, as well as the ONLINE_SUBSCRIBERS table in Figure 12-3, and then review this SQL code: 01 02 03 04 05 06 07 SELECT FROM A.SUB_DATE, COUNT(*) ONLINE_SUBSCRIBERS A JOIN (SELECT LAST_ORDER, PRODUCT FROM STORE_INVENTORY UNION SELECT ADDED, ITEM_NAME FROM FURNISHINGS) B ON A.SUB_DATE = B.LAST_ORDER GROUP BY A.SUB_DATE; Which of the following are true about this SQL statement? (Choose two.) A. The GROUP BY clause on line 7 is not allowed here. B. The B.LAST_ORDER reference at the end of line 6 refers to data included in the ADDED column referred to in line 5. C. The JOIN at the end of line 2 is not allowed in this context. D. The statement is syntactically correct and will execute successfully. Self Test 507 Control the Order of Rows Returned 13. Review the first two illustrations from question 3, as well as the ONLINE_SUBSCRIBERS table in Figure 12-3, and then review this SQL code: 01 02 03 04 05 06 07 SELECT FROM A.SUB_DATE, COUNT(*) ONLINE_SUBSCRIBERS A JOIN (SELECT LAST_ORDER, PRODUCT FROM STORE_INVENTORY UNION SELECT ADDED, ITEM_NAME FROM FURNISHINGS) B ON A.SUB_DATE = B.LAST_ORDER GROUP BY A.SUB_DATE; Where can you add an ORDER BY to this code? (Choose two.) A. At the end of line 5 before the parentheses B. Between lines 5 and 6 C. After line 7 D. Nowhere 14. The ORDER BY clause can be included in a SELECT with set operators if: A. It follows the first SELECT statement. B. It follows the final SELECT statement. C. It is used in each SELECT statement and its ORDER BY expressions match in datatype. D. The ORDER BY clause cannot be used in a SELECT with set operators. 15. Review the first two illustrations from question 3, and then review this SQL code: 01 02 03 04 05 06 SELECT '--' "Order Date", SECTION FROM FURNISHINGS WHERE CAT# NOT IN (1,2) UNION ALL SELECT TO_CHAR(LAST_ORDER,'Month') "Last Order", AISLE FROM STORE_INVENTORY; Which of the following are valid ORDER BY clauses for this query? (Choose two.) A. ORDER BY AISLE B. ORDER BY “Last Order” C. ORDER BY SECTION D. ORDER BY 1 508 Chapter 12: Using the Set O perators SeLF Test Answers Describe Set Operators 1. ˛ B. The keyword SET is not used with the set operators. ˝ A, C, and D are incorrect. ALL is part of the UNION ALL clause. MINUS and UNION are both set operators. 2. ˛ C. MINUS is what you would use. That is the set operator with which you can remove rows from one table that are also present in the second table, resulting in output that shows rows from the first table that are not present in the second. ˝ A, B, and D are incorrect. ALL is not a full set operator; it works with UNION ALL but is not a set operator on its own. SET is not a set operator. UNION would combine records from both tables, which is not what is desired here. 3. ˛ C. The ORDER BY of the first SELECT statement in line 3 is incorrect and causes the statement to fail. ˝ A, B, and D are incorrect. The TO_CHAR conversion function in line 1 is correct syntax. It ensures that the datatypes for LAST_ORDER and ADDED correspond to each other. The table alias on lines 1 and 2 is fine. But the entire statement will not execute for the reason explained above for answer C. 4. ˛ A. The only set operator that changes its end result based on which SELECT statement precedes or follows the set operator is MINUS. ˝ B, C, and D are incorrect. 5. ˛ C. You can connect two SELECT statements together with one set operator. ˝ A, B, and D are incorrect. The reserved word ALL only works with UNION. Set operators can only combine SELECT statements, not other SQL statements. All set operators have equal precedence; only parentheses can be used to override set operator precedence. Use a Set Operator to Combine Multiple Queries into a Single Query 6. ˛ A. No rows will result. The reason: we’re trying to intersect rows, which means to show only those rows that are common between the two rowsets. While both tables share a value of ‘Towel’, the SELECT statements are including the NUM and CAT# columns from the two tables. The result: neither row that includes ‘Towel’ is a complete match. ˝ B, C, and D are incorrect. Self Test Answers 509 7. ˛ B. The first select will produce one row. The second will produce three rows. The UNION ALL set operator will combined the results and return four rows. ˝ A, C, and D are incorrect. The syntax is fine and the statement will execute. 8. ˛ A. Only one row will result, as explained below. ˝ B, C, and D are incorrect. It might be tempting to have chosen answer B, since the first and second SELECT statement combinations with the UNION ALL will produce two rows containing the value for ‘Towels’, and so will the second UNION ALL. But the INTERSECT will eliminate duplicate rows and return one row for ‘Towel’. 9. ˛ D. It will execute successfully. Set operators are perfectly acceptable in a subquery. ˝ A, B, and C are incorrect. 10. ˛ A. Since we know from the data listings that the results of the SELECT statements with the set operator UNION will produce multiple rows, the statement will fail, since a scalar subquery is what is expected here by the outer query. ˝ B, C, and D are incorrect. UNION is fine, but the end result caused a problem for reasons unrelated to the UNION. The column heading issues don’t apply, but if the subquery had not produced the execution error, answers C and D would still be incorrect—the heading would be a concatenated version of the entire string of characters forming the subquery. 11. ˛ D. We can tell from the data listing that the subquery will return one value representing the INTERSECT of both queries. That, and the fact that the subquery will return just one column in that one row, makes this a scalar subquery, albeit a risky one, since there’s no guarantee that it will always execute as a scalar subquery. But it will work given the data listings, and the subquery will perform as though it were a literal value within the outer SELECT, returning the same result for each row of the ONLINE_SUBSCRIBERS table. ˝ A, B, and C are incorrect. There is nothing wrong syntactically with the SQL statement, and as we discuss in describing the correct choice, because of the data listings we are provided with, we can tell that there will be no execution errors either. The INTERSECT will perform just fine. 12. ˛ B and D. This is a valid SQL statement that will execute successfully. The subquery on lines 3 through 5 is the complete UNION and is treated as an inline view in this context. As such, it behaves like any other inline view and is perfectly fine in this context. At the end of line 5 is a table alias B that is given to the inline view, and that table alias is used in line 6 to identify the column of the inline view called LAST_ORDER, which represents the first column of the combined SELECT statements, including the ADDED column. ˝ A and C are incorrect. GROUP BY is allowed, as is the JOIN, for reasons explained under the correct choice. 510 Chapter 12: Using the Set O perators Control the Order of Rows Returned 13. ˛ A and C. The ORDER BY can go at the end of the inline view, or at the end of the entire SQL statement. ˝ B and D are incorrect. 14. ˛ B. The ORDER BY is optional, but if used, it must be the last clause in the entire series of SELECT statements. ˝ A, C, and D are incorrect. ORDER BY cannot be used in any SELECT statements within a series of SELECT statements connected by set operators. It can only be placed at the end, following the final SELECT statement. 15. ˛ C and D. Any ORDER BY that uses the “by reference” technique must reference column names of the first SELECT statement. So ORDER BY SECTION is valid. Also, the “by position” is accepted, so ORDER BY 1 is good. ˝ A and B are incorrect. The AISLE column name isn’t recognized, since it isn’t a column in the first SELECT statement. The same is true for the “Last Order” column alias. 13 enerating Reports G by Grouping Related Data CertIFIcAtIon ObJectIVes 13.01 Use the ROLLUP Operation to Produce Subtotal Values 13.02 Use the CUBE Operation to Produce Crosstabulation Values 13.03 Use the GROUPING Function to Identify the Row Values Created by ROLLUP or CUBE 13.04 3 Q&A Use GROUPING SETS to Produce a Single Result Set Two-Minute Drill Self Test 512 Chapter 13: Generating Reports by Grouping Related Dat T his chapter is about a number of extensions to the capabilities of the GROUP BY clause of the SELECT statement, CUBE, ROLLUP, and GROUPING SETS. We’ll also examine a function named GROUPING that supports the GROUP BY operations discussed in this chapter. Each is addressed separately in the pages that follow, starting with ROLLUP. CertIFIcAtIon ObJectIVe 13.01 use the ROLLuP Operation to Produce Subtotal Values The ROLLUP operation is a subclause of GROUP BY that aggregates the aggregate data in the SELECT statement’s output. The aggregated aggregate rows are known as superaggregate rows. ROLLUP is of primary benefit with the aggregate function SUM, but it works with other aggregates as well. ROLLUP returns a single summary row for each grouped set of records within a SELECT statement that uses the GROUP BY clause. ROLLUP is part of GROUP BY and as such is parsed as part of the GROUP BY clause within the overall execution of the SELECT statement. For example, consider the following data listing from the table SHIP_CABINS: SHIP_CABIN_ID ---------------------1 2 3 4 5 6 7 8 9 10 11 12 ROOM_STYLE ---------Suite Stateroom Suite Stateroom Suite Suite Stateroom Stateroom Stateroom Suite Suite Suite ROOM_TYPE -------------------Standard Standard Standard Standard Standard Royal Large Standard Large Presidential Royal Skyloft SQ_FT ---------------------533 160 533 205 586 1524 211 180 225 1142 1745 722 Use the ROLLUP Operation to Produce Subtotal Values 513 We can write a SELECT statement that will group these rows according to the values in the ROOM_STYLE and ROOM_TYPE columns and add up the total amount of square feet in each group. Here’s the SQL statement: SELECT FROM WHERE GROUP BY ORDER BY ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),0) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 ROOM_STYLE, ROOM_TYPE ROOM_STYLE, ROOM_TYPE; The output of this GROUP BY follows: ROOM_STYLE ---------Stateroom Stateroom Suite Suite Suite Suite ROOM_TYPE -------------------Large Standard Presidential Royal Skyloft Standard SUM_SQ_FT ---------------------436 545 1142 3269 722 1652 Here is where the ROLLUP operation comes in. We can use ROLLUP to add up subtotals and totals within the SQL statement’s output for each grouped category. Let’s use ROLLUP on the combination of ROOM_STYLE and ROOM_TYPE: SELECT FROM WHERE GROUP BY ORDER BY ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 ROLLUP (ROOM_STYLE, ROOM_TYPE) ROOM_STYLE, ROOM_TYPE; Here’s the output (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 ROOM_STYLE ---------Stateroom Stateroom Stateroom Suite Suite Suite Suite Suite ROOM_TYPE -------------------Large Standard Presidential Royal Skyloft Standard SUM_SQ_FT ---------------------436 545 981 1142 3269 722 1652 6785 7766 514 Chapter 13: GGnneraiig RReoors by GGruupig RRllatd DDat This listing shows these effects of ROLLUP: n Lines 5 and 10 show the subtotals for each ROOM_STYLE group—notice the NULL value displayed in the ROOM_TYPE column to indicate the presence of a subtotal line. n Line 11 shows a grand total for the entire set of output. The syntax rules for ROLLUP include the following: n The keyword ROLLUP is used after the keywords GROUP BY, and is part of the GROUP BY clause. n The keyword ROLLUP is followed by a grouping expression list enclosed in parentheses. n ROLLUP can be repeated for each grouping in the GROUP BY clause you wish to roll up. You can include as many GROUP BY groups as you would in a typical GROUP BY clause. ROLLUP can be used to compute a subtotal for each group. You can use any aggregate function with ROLLUP. For example, AVG will compute averages for each group. The ROLLUP operation can be used as part of a series of GROUP BY expressions. For example, we can take our example SQL statement and add the column WINDOW as a grouped value, retaining our ROLLUP operation we were already performing. The result looks like this (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 SELECT FROM WHERE GROUP BY ORDER BY WINDOW, ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 WINDOW, ROLLUP (ROOM_STYLE, ROOM_TYPE) WINDOW, ROOM_STYLE, ROOM_TYPE; WINDOW ---------Balcony Balcony Balcony Balcony Balcony Balcony None None ROOM_STYLE ---------Suite Suite Suite Suite Suite ROOM_TYPE -------------------Presidential Royal Skyloft Standard Stateroom Stateroom Large SUM_SQ_FT ---------------------1142 3269 722 1652 6785 6785 211 211 Use the CUBE Operation to Produce Crosstabulation Values 17 18 19 20 21 None Ocean Ocean Ocean Ocean Stateroom Stateroom Stateroom Large Standard 515 211 225 545 770 770 By incorporating a standard GROUP BY expression as well as the ROLLUP operation, we prevent a grand total value from being displayed but obtain subtotal values for each WINDOW value. ROLLUP computes and displays subtotals and totals for the expressions contained with the set of parentheses that follow the ROLLUP keyword. The GROUP BY clause is For every n groups, ROLLUP produces n+1 processed by SQL before the select list. groupings. Therefore it doesn’t recognize column The rows that are displayed as a result of the aliases created in the select list—this GROUP BY clause are known as regular rows. applies to ROLLUP and CUBE as well. The other rows—the aggregated aggregate rows—are known as superaggregate rows. CertIFIcAtIon ObJectIVe 13.02 use the CuBE Operation to Produce Crosstabulation Values CUBE can potentially produce the greatest amount of output of all the GROUP BY features examined in this chapter. The CUBE operation is something of a threedimensional version of ROLLUP. CUBE goes beyond the functionality of ROLLUP by calculating subtotals for every possible grouping within the columns selected and grouped. The CUBE is part of the GROUP BY and as such is parsed as part of the GROUP BY clause within the overall execution of the SELECT statement. 516 Chapter 13: Generating Reports by Grouping Related Dat Let’s take our ROLLUP example from before and make one simple change: we’ll replace the keyword ROLLUP with the keyword CUBE: SELECT FROM WHERE GROUP BY ORDER BY ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 CUBE (ROOM_STYLE, ROOM_TYPE) ROOM_STYLE, ROOM_TYPE; Here’s the output (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 ROOM_STYLE ---------Stateroom Stateroom Stateroom Suite Suite Suite Suite Suite ROOM_TYPE -------------------Large Standard Presidential Royal Skyloft Standard Large Presidential Royal Skyloft Standard SUM_SQ_FT ---------------------436 545 981 1142 3269 722 1652 6785 436 1142 3269 722 2197 7766 Notice that these results include three lines that we had with ROLLUP: n Lines 5 and 10 show the subtotals for each ROOM_STYLE group—notice the NULL value displayed in the ROOM_TYPE column to indicate the presence of a subtotal line. n Line 16 shows a grand total for the entire set of output. n Lines 11 through 15 show subtotals for each ROOM_TYPE value. For n expressions, CUBE returns 2 to the nth power groupings. The syntax rules for CUBE are the same as for ROLLUP. The grouping expression list can include multiple GROUP BY groups specified within the GROUP BY clause, each separated within the required parentheses by a comma. Both ROLLUP and CUBE are an efficient ways to execute a single SQL statement to calculate totals and subtotals for different levels of aggregated data. Use the GROUPING Function to Identify the Row Values Created by ROLLUP or CUBE 517 CertIFIcAtIon ObJectIVe 13.03 use the GROuPING Function to Identify the Row Values Created by ROLLuP or CuBE The GROUPING function identifies superaggregate or aggregate rows produced by a ROLLUP or CUBE operation in a SELECT . . . GROUP BY statement. It returns a value of the NUMBER datatype, and its value is either a one (1) or a zero (0). The GROUPING function is only valid in a SELECT statement that uses a GROUP BY clause. While GROUPING may be used in a GROUP BY that doesn’t include the ROLLUP or CUBE operation, it doesn’t produce anything meaningful without those operators—it will always return a zero if ROLLUP and CUBE are absent from the statement. For example, let’s add the GROUPING function to the same ROLLUP operation we looked at a few pages ago (line numbers added): 01 02 03 04 05 06 SELECT GROUPING(ROOM_TYPE), ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROLLUP (ROOM_STYLE, ROOM_TYPE) ORDER BY ROOM_STYLE, ROOM_TYPE; The function is on line 1. Notice that we’ve passed one parameter to the GROUPING function—the name of a grouped item specified in the GROUP BY clause from line 5. Here’s the output: GROUPING(ROOM_TYPE) ---------------------0 0 1 0 0 0 0 1 1 ROOM_STYLE ---------Stateroom Stateroom Stateroom Suite Suite Suite Suite Suite ROOM_TYPE -------------------Large Standard Presidential Royal Skyloft Standard SUM_SQ_FT --------436 545 981 1142 3269 722 1652 6785 7766 Notice that the GROUPING function assigned a “1” to each superaggregate row—meaning a row that shows a subtotal or total of the expression specified 518 Chapter 13: Generating Reports by Grouping Related Dat in GROUPING—in this case, ROOM_TYPE—as a result of the ROLLUP function. This is what the GROUPING function does—it differentiates between superaggregate rows and regular rows in the output of a ROLLUP or CUBE operation. Once you programmatically differentiate between regular and superaggregate rows, you can bring other functions into play to customize output or perform some other conditional action. For example, the following SQL statement uses NVL and DECODE to display different information for superaggregate rows (line numbers added): 01 02 03 04 05 06 07 08 09 10 SELECT NVL( DECODE(GROUPING(ROOM_TYPE),1,UPPER(ROOM_STYLE), INITCAP(ROOM_STYLE)), 'GRAND TOTAL') ROOM_STYLE_FORMATTED, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT FROM SHIP_CABINS WHERE SHIP_ID = 1 GROUP BY ROLLUP (ROOM_STYLE, ROOM_TYPE) ORDER BY ROOM_STYLE, ROOM_TYPE; Here’s the output—notice that the superaggregate rows show the ROOM_STYLE in all caps for subtotals, and the words ‘GRAND TOTAL’ for the final row. 01 02 03 04 05 06 07 08 09 10 11 ROOM_STYLE_FORMATTED ROOM_TYPE ------------------- -------------------Stateroom Large Stateroom Standard STATEROOM Suite Presidential Suite Royal Suite Skyloft Suite Standard SUITE GRAND TOTAL SUM_SQ_FT -----------436 545 981 1142 3269 722 1652 6785 7766 The GROUPING function is the key to providing customized behavior to the results of a ROLLUP or CUBE statement that highlights or in some other fashion changes its behavior for superaggregate rows of data. GROUPING is ideal when used in combination with DECODE or string concatenation, or some other SQL function, to process and/or format output that differentiates between aggregate and superaggregate data. Use GROUPING SETS to Produce a Single Result Set 519 CertIFIcAtIon ObJectIVe 13.04 use GROuPING SETS to Produce a Single Result Set The GROUPING SETS operation is another subclause of GROUP BY. It provides a finer level of detail in specifying which groups you wish to display, with optional subtotals and an optional grand total. With GROUPING SETS, you can be more selective with the results of a GROUP BY clause, and specify particular groups you wish to include in your output, omitting the rest—potentially reducing processing time accordingly. To demonstrate GROUPING SETS, let’s first revisit the CUBE operation and expand our SELECT statement to look at more data than what we saw earlier in this chapter (line numbers added): 01 02 03 04 05 SELECT FROM WHERE GROUP BY ORDER BY WINDOW, ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 CUBE(WINDOW, ROOM_STYLE, ROOM_TYPE) WINDOW, ROOM_STYLE, ROOM_TYPE; Here is the output (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 WINDOW -----None None None None None None None None None None Ocean Ocean Ocean Ocean Ocean Ocean Ocean ROOM_STYLE ---------Stateroom Stateroom Stateroom Suite Suite Suite ROOM_TYPE -------------------Large Standard Presidential Standard Large Presidential Standard Stateroom Stateroom Suite Suite Suite Suite Standard Royal Skyloft Standard Royal SUM_SQ_FT ---------------------436 180 616 1142 1119 2261 436 1142 1299 2877 365 365 3269 722 533 4524 3269 520 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 Chapter 13: Generating Reports by Grouping Related Dat Ocean Ocean Ocean Skyloft Standard Stateroom Stateroom Stateroom Suite Suite Suite Suite Suite Large Standard Presidential Royal Skyloft Standard Large Presidential Royal Skyloft Standard 722 898 4889 436 545 981 1142 3269 722 1652 6785 436 1142 3269 722 2197 7766 This output listing is obviously rather lengthy. We can use GROUPING SETS to selectively choose particular groups of data, ignoring any unwanted groups in the output. The GROUPING SETS syntax is somewhat similar to ROLLUP and CUBE: n The reserved words GROUPING SETS must follow GROUP BY. n A pair of parentheses follows GROUPING SETS. n Enclosed in the parentheses are a series of lists, each of which specifies one or more groups. These lists are each separated by commas, and all enclosed in parentheses. n Each set specifies separate GROUP BY clause groups. In other words, each list constitutes a separate set of one or more valid GROUP BY expressions. It’s as if you were running several GROUP BY statements at once, combining the results together. Let’s revise line 4 of our sample query to replace the CUBE clause with an example of GROUPING SETS: 01 02 03 04 05 SELECT FROM WHERE GROUP BY ORDER BY WINDOW, ROOM_STYLE, ROOM_TYPE, ROUND(SUM(SQ_FT),2) SUM_SQ_FT SHIP_CABINS SHIP_ID = 1 GROUPING SETS((WINDOW, ROOM_STYLE),(ROOM_TYPE),NULL) WINDOW, ROOM_STYLE, ROOM_TYPE; This example uses GROUPING SETS to specify three groups: n The first group, WINDOW and ROOM_STYLE, is equivalent to executing a SELECT statement with a GROUP BY WINDOW, ROOM_STYLE. Use GROUPING SETS to Produce a Single Result Set 521 n The second group is ROOM_TYPE by itself, which is the equivalent to executing a SEELCT statement with a GROUP BY ROOM_TYPE. n The third group is NULL, which is the equivalent (in GROUPING SETS syntax) of asking for a single grand total. Here’s the output (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 WINDOW -----None None Ocean Ocean ROOM_STYLE ROOM_TYPE ---------- -------------------Stateroom Suite Stateroom Suite Large Presidential Royal Skyloft Standard SUM_SQ_FT ---------616 2261 365 4524 436 1142 3269 722 2197 7766 Note that we target the specific groups we wish to see and exclude the rest. Instead of 36 rows of output, we get only 12. n The output of the first grouping set—WINDOW and ROOM_STYLE—is included in lines 3 through 6. n The output of the second grouping set—ROOM_TYPE—is included in lines 7 through 11. n The output of the final grouping set—the grand total—is included in line 12. The GROUPING SETS clause identifies one or more GROUP BY lists and processes each individually. In other words, if you were To understand to execute two or three different GROUP GROUPING SETS, you must first have a BY clauses on the same table or set of tables, solid understanding of the GROUP BY you could alternatively use a single SELECT clause. Remember that NULL is used in statement with the GROUPING SETS operation GROUPING SETS to cause a grand total and combine the various groups from each to be calculated and displayed. GROUP BY clause into one. The GROUPING SETS operation combines the resulting row sets with a UNION ALL operation. The GROUPING SETS keywords are a useful and efficient midpoint between a GROUP BY clause, and a GROUP BY clause with ROLLUP or CUBE. 522 Chapter 13: Generating Reports by Grouping Related Dat CertIFIcAtIon SuMMArY There are a number of operations you can perform with GROUP BY to generate subtotals and totals at various group levels, and selectively process individual groups of rows in unique combinations that a single SQL statement could not otherwise do. The ROLLUP operation identifies expressions specified in the GROUP BY clause. ROLLUP defines levels for superaggregation, so that subtotals and totals will be computed and displayed in the context of the GROUP BY statement’s output. The CUBE operation calculates and displays subtotals and totals for all combinations of GROUP BY clause expressions. The GROUPING function returns a number one or zero to each row of output, to identify each row as either a regular row or a superaggregate row. The result empowers other functions within your SELECT statement to be able to customize output and customize processing at the grouped level. The GROUPING SETS operation specifies sets of GROUP BY clause expressions in various combinations, providing a finer level of access to directing GROUP BY to perform aggregation selectively. The use of GROUPING SETS can potentially reduce unnecessary processing and speed up results. Two-Minute Drill 3 523 Two-MInute DrIll use the ROLLuP Operation to Produce Subtotal Values q The ROLLUP operation is only allowed with the GROUP BY clause. q ROLLUP calculates subtotals and total values for the grouped sets of records. q The keyword ROLLUP follows GROUP BY. q Following the keyword ROLLUP is a set of parentheses that identifies the GROUP BY items that are to be aggregated with ROLLUP. q ROLLUP may be included with other GROUP BY expressions; each must be separated by commas. use the CuBE Operation to Produce Crosstabulation Values q The CUBE operation is only allowed with the GROUP BY clause. q CUBE tallies subtotals and totals for all combinations of the grouped expressions. q The keyword CUBE appears after GROUP BY and is followed by the CUBE list, enclosed in parentheses, citing the GROUP BY expressions to be CUBEd. use the GROuPING Function to Identify the Row Values Created by ROLLuP or CuBE q The GROUPING function identifies a grouped row set as either a regular row or a superaggregate row. q A regular row is a non-ROLLUP or non-CUBE row of typical GROUP BY output. q A superaggregate row is a GROUP BY row that represents a subtotal or total as directed by ROLLUP or CUBE. q The GROUPING function returns a value of 1 for superaggregate rows or 0 for regular rows. q You can combine GROUPING with other functions to customize output format and behavior for superaggregate rows versus regular rows. 524 Chapter 13: Generating Reports by Grouping Related Dat use GROuPING SETS to Produce a Single Result Set q The GROUPING SETS operator is ideal for GROUP BY queries that work with multiple groups and relatively large amounts of data. q The GROUPING SETS operator allows you to specify one or more GROUP BY combinations in a single query. q The use of GROUPING SETS offers advantages over ROLLUP or CUBE when only some of the subtotaled rows are desired. Self Test 525 SelF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. use the ROLLuP Operation to Produce Subtotal Values 1. The ROLLUP operation can be used with: A. Only SUM B. Only SUM and AVG C. All aggregate functions other than COUNT D. Any aggregate function 2. Review the following illustration: Now review this SQL code (line numbers added): 01 02 03 04 SELECT FROM ON GROUP BY D.DECK_NAME, P.CATEGORY, P.PRODUCT, SUM(P.QTY) QTY DECKS D JOIN PROVISIONS P D.DECK_ID = P.DECK_ID ROLLUP(D.DECK_NAME, P.CATEGORY, P.PRODUCT); 526 Chapter 13: Generating Reports by Grouping Related Dat What can be said of this SELECT statement? A. It will fail due to an error on line 1. B. It will fail due to an error on line 4. C. It will execute and produce a subtotal for each grouped expression but no grand total value. D. It will execute and produce a subtotal for each grouped expression as well as a grand total. 3. Review the illustration in question 2, and then review this SQL code (line numbers added): 01 02 03 SELECT CAPACITY, AVG(LENGTH) FROM SHIPS GROUP BY ROLLUP CAPACITY; What can be said of this SELECT statement? A. It will fail due to an error on line 1. B. It will fail due to an error on line 3. C. It will execute, but the output will be meaningless because the AVG function doesn’t work correctly with ROLLUP. D. It will execute and produce output as desired. 4. Review the illustration in question 2, and then review this SQL code (line numbers added): SELECT PRODUCT, MIN(QTY) FROM PROVISIONS GROUP BY ROLLUP (PRODUCT); How many superaggregate rows will be displayed by this statement? A. One B. Two C. One for each distinct value for PRODUCT D. One for each distinct value for PRODUCT, plus one more use the CuBE Operation to Produce Crosstabulation Values 5. The CUBE operation can only be performed with: A. INSERT statements B. ROLLUP C. GROUP BY D. None of the above Self Test 527 6. The CUBE operation used with the SUM function often results in: (Choose two.) A. More rows than ROLLUP B. Fewer rows than ROLLUP C. A grand total D. No grand total 7. The CUBE operator: A. Requires the ORDER BY clause. B. Requires at least three grouped items. C. Displays regular rows and superaggregate rows. D. Will not work with joins. 8. Review the illustration in question 2, and then review this SQL code (line numbers added): 01 02 03 04 SELECT FROM GROUP BY ORDER BY SHIP_ID, ROUND(LENGTH,-2) LGTH, SUM(CAPACITY) SHIPS CUBE (LGTH, SHIP_ID) SHIP_ID; What can be said of this SELECT statement? A. It will fail due to a syntax error because you cannot use the ROUND function in line 1. B. It will fail due to a syntax error because the column alias LGTH in line 1 won’t be recognized by the GROUP BY in line 3. C. It will successfully execute but the use of ROUND will produce meaningless output. D. It will successfully execute and produce output as desired. use the GROuPING Function to Identify the Row Values Created by ROLLuP or CuBE 9. The purpose of the GROUPING function is to: (Choose the best answer.) A. Group rows dynamically according to common information. B. Compute the aggregate value as it applies to each group of rows. C. Differentiate between regular rows and superaggregate rows. D. Automatically identify commonly named columns for possible GROUP BY aggregation. 10. The GROUPING function can only work: A. With an aggregate function such as SUM or AVG B. With the GROUP BY clause C. With the ROLLUP or CUBE operations D. With data that contains NULL values 528 Chapter 13: Generating Reports by Grouping Related Dat 11. Review the illustration in question 2, and then review this SQL code (line numbers added): 01 02 03 SELECT GROUPING(HOME_PORT_ID) A FROM SHIPS GROUP BY HOME_PORT_ID; What can be said of this SQL statement? A. The value for the column represented by a column alias of “A” will always be zero. B. The value for the column represented by a column alias of “A” will always be one. C. The statement will fail due to a syntax error. D. None of the above. use GROuPING SETS to Produce a Single Result Set 12. The GROUPING SETS operation combines the equivalent of several GROUP BY clauses with the functionality of which of the following? (Choose the best answer.) A. UNION B. UNION ALL C. INTERSECT D. MINUS 13. Review the illustration in question 2, and then review this SQL code (line numbers added): 01 02 03 04 SELECT FROM ON GROUP BY D.SHIP_ID, D.DECK_NAME, P.CATEGORY, SUM(P.QTY) DECKS D JOIN PROVISIONS P D.DECK_ID = P.DECK_ID GROUPING SETS ((D.SHIP_ID), (D.DECK_NAME, P.CATEGORY)); You are tasked with editing the preceding SQL statement to include a superaggregate row in the output that shows the grand total summing up all of P.QTY for all rows. How should line 4 be changed in order to accomplish this task? A. GROUP BY GROUPING SETS (NULL, (D.SHIP_ID), (D.DECK_NAME, P.CATEGORY)); B. GROUP BY GROUPING SETS (SUM(P.QTY), (D.SHIP_ID), (D.DECK_NAME, P.CATEGORY)); C. No change to line is required; it will already perform as required D. No change to line 4 can accomplish the task Self Test 529 14. Review the illustration in question 2, and then review this SQL code (line numbers added): 01 02 03 04 05 06 07 08 SELECT P.CATEGORY, P.PRODUCT, P.DECK_ID, SUM(P.QTY) SUM_QTY FROM PROVISIONS P JOIN DECKS D ON P.DECK_ID = D.DECK_ID GROUP BY GROUPING SETS ((P.CATEGORY, P.PRODUCT),(P.DECK_ID)) ORDER BY P.CATEGORY, P.PRODUCT, P.DECK_ID; In the preceding SQL statement, the output column SUM_QTY will include calculated values for each row. What will some of those rows—but not all—include as values in the SUM_QTY column? (Choose the single best answer.) A. One sum for each group of rows that have the same value for P.CATEGORY B. One sum for each group of rows that have the same value for P.PRODUCT C. One sum for each group of rows that have the same value for P.DECK_ID D. A single grand total for all rows in the PROVISIONS and DECKS tables that satisfy the join condition 15. Which of the following GROUP BY operations is most likely to produce the greatest number of rows of output, all other things being equal? (Choose the single best answer.) A. CUBE B. ROLLUP C. GROUPING SETS D. Impossible to say 530 Chapter 13: Generating Reports by Grouping Related Dat SelF Test Answers use the ROLLuP Operation to Produce Subtotal Values 1. ˛ D. You can use ROLLUP with any aggregate function. ˝ A, B, and C are incorrect. ROLLUP tends to be most useful with SUM, but you can use it with any aggregate function. 2. ˛ D. The statement is syntactically correct and will produce subtotals for all grouped items as well as a grand total. ˝ A, B, and C are incorrect. No errors exist in the code. 3. ˛ B. The ROLLUP operator must be followed by the grouped items enclosed in parentheses. The lack of parentheses around CAPACITY will trigger a syntax error, and the statement will not successfully execute. ˝ A, C, and D are incorrect. There is no error on line 1. If there were parentheses around CAPACITY on line 3 this statement would execute and produce valid output. The use of AVG is fine here, as long as you recognize what is being computed, which is the average value for each grouped item, which in this case is rows with the same value for CAPACITY. 4. ˛ A. There will be one superaggregate row. The output will include one aggregate row for each product value, plus one superaggregate row showing the grand total summing up the aggregate rows. ˝ B, C, and D are incorrect. use the CuBE Operation to Produce Crosstabulation Values 5. ˛ C. GROUP BY. You cannot use CUBE without it. ˝ A, B, and D are incorrect. 6. ˛ A and C. The ROLLUP operator performs a limited number of subtotal calculations. CUBE performs every possible combination, including the grand total. ˝ B and D are incorrect. 7. ˛ C. CUBE displays regular rows and superaggregate rows. ˝ A, B, and D are incorrect. ORDER BY is fine and helpful but not required. Joins are allowed. The number of grouped items is not required to be a minimum of three; any amount will do. Self Test Answers 531 8. ˛ B. The CUBE operation is parsed like a typical GROUP BY, which means that line 3 is parsed before the SELECT statement’s select list (line 1), so the column alias won’t be recognized. The solution is to reference the full expression in the GROUP BY. ˝ A, C, and D are incorrect. The rest of the statement is syntactically correct, and it will execute fine once the column alias issue is addressed. use the GROuPING Function to Identify the Row Values Created by ROLLuP or CuBE 9. ˛ C. The GROUPING function identifies the rows that would normally be returned by GROUP BY—i.e., regular rows—from those that are the result of aggregate calculations determined as a result of the ROLLUP or CUBE group operations. ˝ A, B, and D are incorrect. 10. ˛ B. The GROUP BY clause is required for GROUPING to be invoked; otherwise, a syntax error will result. ˝ A, C, and D are incorrect. GROUPING does not require other aggregate functions, although it will work well with them. It does not technically require the ROLLUP or CUBE operation to be present, although it doesn’t produce anything meaningful without them. NULL values have no bearing on the performance of GROUPING. 11. ˛ A. Since neither ROLLUP or CUBE is included, the GROUPING result will always be zero—there cannot be any superaggregate rows without ROLLUP or CUBE, so there cannot be any returned values of 1. ˝ B, C, and D are incorrect. There is no syntax error in the statement; it will function, albeit without much in the way of meaningful output, since there is no ROLLUP or CUBE operator included in the GROUP BY clause. use GROuPING SETS to Produce a Single Result Set 12. ˛ B. UNION ALL is the correct answer. ˝ A, C, and D are incorrect. 13. ˛ A. If a value of NULL is included as one of the GROUPING SET lists, its presence will cause GROUPING SETS to include the grand total in the output as a superaggregate row. ˝ B, C, and D are incorrect. 532 Chapter 13: Generating Reports by Grouping Related Dat 14. ˛ C. The answer lies in line 7. There is one sum for each group of rows that have the same value for P.DECK_ID as defined by the GROUPING SET operation. That’s because there is one ‘column list’ in the GROUPING SET that consists solely of P.DECK_ID. The other grouping set value is a two-column set, not one. ˝ A, B, and D are incorrect. The answer cannot be P.CATEGORY because there is not one GROUPING SET list that consists solely of P.CATEGORY, but rather there is one that consists of both P.CATEGORY and P.PRODUCT combined, so the grouped rows will be aggregated according to unique values found in the combination of those two columns, not in the columns individually. Also, there is no provision for a grand total in this implementation of GROUPING SET; for that to have been included, a NULL set would need to be included somewhere in the GROUPING SET list of values. 15. ˛ A. CUBE tends to produce the largest number of rows, as it produces every possible combination of aggregations from among the rows. ˝ B, C, and D are incorrect. 14 Managing O bjects with Data Dictionary Views CertIFIcAtIon ObJectIVes 14.01 Use the Data Dictionary Views to Research Data on Your Objects 14.02 Query Various Data Dictionary Views 3 Q&A Two-Minute Drill Self Test 534 Chapter 14: Managing O bjects with Data Dictionary Views T his chapter describes a valuable tool that all Oracle professionals should understand. The data dictionary is Oracle’s built-in real-time reference source for all information about the applications that you build in your database. Armed with the full capabilities of the data dictionary, you can obtain information on the database objects that have been created within your database, who created them, when, and much more. CertIFIcAtIon ObJectIVe 14.01 use the Data Dictionary Views to Research Data on Your Objects The data dictionary is a collection of database tables and views. It is automatically built and populated by the Oracle database. The information stored in the data dictionary includes the full description of all the database objects you create as part of your application: tables, views, indexes, constraints, synonyms, sequences, and more. In other words, the result of each DDL statement you’ve studied in this book is recorded in the dictionary, and the information is automatically maintained by the Oracle system in real time as you change database objects and their structures. The information stored in the data dictionary includes (but is not limited to) n The names of database objects, their owners, and when they were created n The names of each table’s columns, along with datatypes, precision, and scale n Any constraints n Views, indexes, synonyms, sequences n Much more This chapter will explore how the data dictionary is structured, and what sort of information is contained within it. We’ll go through some examples of how to extract valuable information and use the data dictionary to assist you as you build your applications. The data dictionary is often referred to as “metadata”. The term metadata means “data about data”, and that is what the data dictionary is—it’s a comprehensive detailed database that tracks everything there is to know about the database Use the Data Dictionary Views to Research Data on Your Objects 535 applications you create within the Oracle system. Every time you create a database object, the Oracle system works in the background to record that object’s name and structure, and make that information available to you by way of the data dictionary. Every object created by every user is documented within the data dictionary. Structure The data dictionary consists of tables and views that are owned by the user account SYS. As owner, SYS has full privileges over these tables and views. No user should ever alter data owned by SYS, or else the integrity of the database may be compromised. The SYS account is one of a few powerful accounts that comes with every implementation of the Oracle database.The SYS account is something of a “super user” account, with master privileges to virtually everything in the database. Generally, no developer uses the SYS account for anything other than database system maintenance, and often it’s the database administrator (DBA) who possesses exclusive access to the SYS account. All data dictionary information is stored in tables, but much of that data is presented to users through views. In other words, users don’t get direct access to the tables of the data dictionary; they instead get access to the views, which provide somewhat limited access in order to protect the integrity of the data dictionary. In addition, many data dictionary objects are renamed via public synonyms, and those are the names by which you know the data. In other words, there are multiple levels of abstraction that separate users from the underlying data. No matter—the ability to read the information in the data dictionary is a great asset to all SQL professionals. Every DDL statement that is issued throughout the database causes an automatic update to the data dictionary. That update is handled by the Oracle system and applied to the base tables that form the foundation of the data dictionary. Users do not explicitly update any information in the dictionary. (Note: there is one exception to this. Users may optionally choose to add comments, which you’ll explore later in this chapter.) As of this writing, there are over 2,000 views in the data dictionary. One in particular is a good starting point: DICTIONARY. This view contains information about the views that compose the data dictionary. It includes the name of each view, along with a brief explanation of each view. You’ll look at it a bit later. 536 Chapter 14: Managing O bjects with Data Dictionary Views The USER_TABLES view contains information about the tables owned by the current user account. In other words, no matter which account you log in to, you can query the USER_TABLES view and get detailed information about the tables owned by whatever account you are logged in with. A full description of the USER_TABLES view would show that it consists of 50 columns. Some of the columns include n TABLE_NAME The name of the table. Indicates whether or not the table is currently valid and therefore available for use. n STATUS Indicates whether ROW MOVEMENT has been enabled for the table. (See our discussion in Chapter 11 about the FLASHBACK TABLE statement for more information about enabling and disabling ROW_MOVEMENT.) n ROW_MOVEMENT n AVG_ROW_LEN The average length of the rows currently stored in the table. These are just some of the several dozen columns that are in the USER_ TABLES view. But what if you wish to see information about tables other than your own? Well it just so happens there are two other views in the data dictionary that have almost the identical set of columns as USER_TABLES: Shows all the same table information, but for tables to which the current user has privileges, regardless of owner. n ALL_TABLES Shows all the same table information, but for all the tables in the entire database, regardless of owner or table privileges. These other two views also have an additional column: n DBA_TABLES n OWNER The owner of the table in question. And that makes sense—there is no need for OWNER in the USER_TABLES view, since that view only shows information about one owner—the current owner. This naming pattern of using one of these three prefixes—USER_, ALL_, DBA_—is a pattern that is used throughout the data dictionary. Many of the data dictionary views that store information about objects in the database have names that start with one of these three prefixes. Some examples are listed in Table 14-1. Use the Data Dictionary Views to Research Data on Your Objects TAbLe 14-1 Prefixes of some of the Data Dictionary Views 1 537 Prefix # of Views1 Description USER_ 359 Objects owned by the current user accessing the view. ALL_ 334 Objects owned by any user in the database to which the current user has privileges. DBA_ 670 All objects in the database. V_$ (for views) V$ (for public synonyms) 488 Dynamic performance views, each of which has a public synonym counterpart. Stores information about the local database instance. GV_$ (for views) GV$ (for public synonyms) 450 Global dynamic performance views. Other SM$, AUDIT_, CHANGE_, TABLE_ CLIENT_, COLUMN_, DICT_, DATABASE_, DBMS_, GLOBAL_, INDEX_, LOGSTDBY_, NLS_, RESOURCE_, ROLE_, SESSION_, CLIENT_RESULT_CACHE_STATS$, or no prefix, etc. 40 The remaining views of the data dictionary have a variety of prefixes and unique individual names. View counts were determined using Oracle 11.1.0.7.0. Other versions may vary. As you can see from Table 14-1, the vast majority of data dictionary views have a prefix of USER_, ALL_, or DBA_. A set of three views that have the USER_, ALL_, and DBA_ prefix and share the same suffix, such as TABLES, draw their data from a single data dictionary table. For example, USER_CONSTRAINTS, ALL_ CONSTRAINTS, and DBA_CONSTRAINTS share the same data dictionary table. Note that public synonyms are not listed in the USER_SYNONYMS view, which only shows private synonyms. Even if you’re logged in to a user account that created a particular public synonym object, you’ll still not find it listed in the USER_SYNONYMS view. Instead you’ll find it in ALL_SYNONYMS and DBA_ SYNONYMS. 538 Chapter 14: Managing O bjects with Data Dictionary Views TAbLe 14-2 Suffix Description Selected Data Dictionary Views Showing Objects Owned by the Current User USER_CATALOG All tables, views, synonyms, and sequences owned by USER USER _COL_PRIVS Grants on columns of tables owned by USER USER _CONSTRAINTS Constraints on tables owned by USER USER _CONS_COLUMNS Accessible columns in constraint definitions for tables owned by USER USER _DEPENDENCIES Dependencies to and from a user’s objects USER _ERRORS Current errors on stored objects owned by USER USER _INDEXES Indexes owned by USER USER _IND_COLUMNS Columns in user tables used in indexes owned by USER USER _OBJECTS Objects owned by USER USER _SEQUENCES Sequences owned by USER USER _SYNONYMS Private synonyms owned by USER (Public synonyms are displayed in ALL_SYNONYMS and DBA_ SYNONYMS.) USER _TABLES Tables owned by USER USER _TAB_COLUMNS Columns in USER’s own tables and views USER _TAB_PRIVS Grants on objects owned by USER USER _VIEWS Views owned by USER Dynamic Performance Views Table 14-1 includes references to a set of views that begin with the prefixes V_$ and GV_$. These are defined as the dynamic performance views and the global dynamic performance views. Dynamic performance views display information about current database activity in real time. They receive data dynamically from the database through mechanisms that go beyond the scope of this book. For our purposes, it’s important to know that they are maintained automatically by the system and are available for querying— with some limitations. The dynamic performance views start with the prefix V_$. There are public synonyms created for each of the views, and they have similar names but begin with the prefix V$. Use the Data Dictionary Views to Research Data on Your Objects 539 Simple queries on dynamic performance views are accepted, but complex queries, with or without joins, require some special attention. Oracle formally recommends that the dynamic nature of these views does not guarantee read consistency for anything other than the simplest of single-view queries, so it’s advised that you perform complex joins and/or queries by n Creating a set of temporary tables to mirror the views n Copying the data out of the views and into a set of temporary tables n Performing the join on the temporary tables This way, you’ll avoid getting bad results caused by a lack of read consistency. Some of the dynamic performance synonyms (that point to views that point to tables) include the following: Includes information about the database itself, including the database name, the date created, the current operating system platform, and much more. n V$DATABASE Includes the instance name, the host name, the startup time, and much more. n V$INSTANCE The current settings for system parameters, such as NLS_LANGUAGE, NLS_DATE_LANGUAGE, NLS_CURRENCY, NLS_TIME_FORMAT, NLS_TIME_TZ_FORMAT, NLS_TIMESTAMP_ TZ_FORMAT, SQL_VERSION, and much more. n V$PARAMETER Many current settings for each individual user session, showing active connections, login times, machine names that users are logged in to, the current state of transactions, and much more. n V$SESSION n V$RESERVED_WORDS Remember, only simple queries are recommended when querying the V$ (v-dollar) views directly. Current list of reserved words, including information indicating if the keyword is always reserved or not, and if not, under what circumstances it is reserved. n V$OBJECT_USAGE Useful for monitoring the usage of INDEX objects. Includes two columns: TZNAME, which is time zone region, and TZABBREV, which is the time zone abbreviation. n V$TIMEZONE_NAMES 540 Chapter 14: Managing O bjects with Data Dictionary Views Reading Comments The data dictionary is rich with comments that help describe the intent of the various views of the data dictionary, and the columns within them. In addition to the comments that are provided in the DICTIONARY view for each of the individual data dictionary views, you can also view comments about the columns within those views, or for any object stored anywhere in the database: n ALL_TAB_COMMENTS Displays comments for all objects in the database. n ALL_COL_COMMENTS Displays comments for all columns of all tables and views in the database. Say you’re looking at a data dictionary view like USER_SEQUENCES, and you wish to learn more about its columns. Here’s a query that will help you: SELECT FROM WHERE AND UNION SELECT FROM WHERE AND '*TABLE: ' || TABLE_NAME, COMMENTS ALL_TAB_COMMENTS OWNER = 'SYS' TABLE_NAME = 'USER_SYNONYMS' 'COL: ' || COLUMN_NAME, COMMENTS ALL_COL_COMMENTS OWNER = 'SYS' TABLE_NAME = 'USER_SYNONYMS' ; That’s the query; here are the results: '*TABLE:'||TABLE_NAME ----------------------*TABLE: USER_SYNONYMS COL: DB_LINK COL: SYNONYM_NAME COL: TABLE_NAME COL: TABLE_OWNER COMMENTS ---------------------------------------------The user's private synonyms Database link referenced in a remote synonym Name of the synonym Name of the object referenced by the synonym Owner of the object referenced by the synonym As you can see, we’re using the data dictionary to study the data dictionary. The right-side listing under COMMENTS is helpful in describing the contents of the view in the data dictionary. You can use this technique to inspect all of the contents of the data dictionary. Use the Data Dictionary Views to Research Data on Your Objects 541 Adding Comments You can add your own comments to the data dictionary to add notes and descriptions about the tables and columns you create. The COMMENT statement is what we use to add comments to the data dictionary for a particular database object. Its syntax is as follows: COMMENT ON objectType fullObjectName IS c1; where: n objectType is one of the keywords TABLE, COLUMN, or some other objects that are not subjects of the certification exam, such as INDEXTYPE, OPERATOR, MATERIALIZED VIEW, and others. n fullObjectName is the name of the object for which you wish to add a comment. If it’s a TABLE, name the table. But if it’s a column, use the TABLE.COLUMN syntax. n c1 is the full text of the comment you wish to add. When you add a comment to the table, the comment will be displayed in the data dictionary views USER_TAB_COMMENTS, ALL_TAB_COMMENTS, and DBA_TAB_COMMENTS. When you add a comment to a column in a table, the comment will be displayed in the data dictionary views USER_COL_COMMENTS, ALL_COL_ COMMENTS, and DBA_COL_COMMENTS. For example, let’s say we wish to add a comment to the data dictionary about the PORTS table. Here’s an example: COMMENT ON TABLE PORTS IS 'Listing of all ports of departure and arrival.'; To see the results, you could use this query: SELECT COMMENTS FROM USER_TAB_COMMENTS WHERE TABLE_NAME = 'PORTS'; COMMENTS --------------------------Listing of all ports of departure and arrival. 542 Chapter 14: Managing O bjects with Data Dictionary Views Here’s an example of adding a comment to a table’s column: COMMENT ON COLUMN PORTS.CAPACITY IS 'Maximum number of passengers (exclusive of crew).'; You can’t really drop a comment from the data dictionary. Instead, you change it to a blank, like this: COMMENT ON TABLE PORTS IS ''; CertIFIcAtIon ObJectIVe 14.02 Query Various Data Dictionary Views Let’s take a look at some useful examples of the data dictionary in action. DICTIONARY The DICTIONARY view is a great starting point for any investigation of the data dictionary. If we DESCRIBE the view, we get the following: DESC DICTIONARY; Name Null ------------------------------ -------TABLE_NAME COMMENTS Type -----------------------VARCHAR2(30) VARCHAR2(4000) There are just two columns in the DICTIONARY view, but note that the second column can potentially hold a great deal of information. In my current installation of the Oracle database, I’m showing 2,340 entries in this view. You can run a simple query to list all of its contents in your own user account: SELECT TABLE_NAME, COMMENTS FROM DICTIONARY ORDER BY TABLE_NAME; Query Various Data Dictionary Views 543 The output is too much to list here, and it’s generally the same here as it will be on your own Oracle database implementation, depending on which version you’re using. You might want to run this query in your own user account and review its output. If you’re looking for something specific, such as anything that addresses index objects, you might try a query like this: SELECT FROM WHERE ORDER BY TABLE_NAME, COMMENTS DICTIONARY UPPER(COMMENTS) LIKE '%INDEX%' TABLE_NAME; That query will locate anything in the DICTIONARY table that mentions “index” in the comments. The result will include the name of the data dictionary view that lists all of the indexes, the one that lists all of the columns upon which an index is based, etc. Then, if you locate a particular entry in the dictionary you want to know more about—for example, USER_DEPENDENCIES—you can run the following query to get comments on that particular view and its columns: SELECT FROM WHERE AND COLUMN_NAME, COMMENTS ALL_COL_COMMENTS OWNER = 'SYS' TABLE_NAME = 'USER_DEPENDENCIES'; Those queries should help to zero in on helpful information in the data dictionary. Identifying a user’s owned objects There are a variety of data dictionary views from which you might gather data about your own user account’s objects. Two views in particular are a good starting point: USER_CATALOG and USER_OBJECTS. user_CAtALoG The USER_CATALOG view displays a summary listing of tables, views, synonyms, and sequences owned by the user. See Figure 14-1 for a diagram of the view. Figure 14-1 Diagram of the USER_ CATALOG data dictionary view 544 Chapter 14: Managing O bjects with Data Dictionary Views Here’s a sample query to get a quick overview of what a particular user account may own: SELECT TABLE_TYPE, COUNT(*) FROM USER_CATALOG GROUP BY TABLE_TYPE; TABLE_TYPE ----------SEQUENCE TABLE VIEW SYNONYM COUNT(*) ---------------------21 35 2 1 Be sure you have at least a basic working knowledge of each of the data dictionary views that track the basic objects in the database—tables, views, sequences, synonyms, sequences, constraints—and the difference for each with regard to the USER_, DBA_, and ALL_ prefixes. Figure 14-2 Diagram of the USER_ OBJECTS data dictionary view There are only two columns in USER_ CATALOG: TABLE_TYPE and TABLE_ NAME, where TABLE_NAME is actually the name of the table, view, sequence, or synonym object. A synonym for USER_CATALOG is CAT. user_obJeCts The USER_OBJECTS view contains information about all objects owned by the user. A synonym for USER_OBJECTS is OBJ. See Figure 14-2 for a diagram. Query Various Data Dictionary Views 545 Inspecting Tables and Columns The USER_TABLES table (synonym TABS) is helpful for inspecting table metadata, as is its companion USER_TAB_COLUMNS (synonym COLS). This section will look at USER_TAB_COLUMNS in particular. Here’s a query that will display some of the most basic information about a table and its columns. Let’s get column information for the table shown in Figure 14-3. Here is a SELECT statement that will pull information from the data dictionary about the columns of this table: SELECT COLUMN_NAME, DECODE( DATA_TYPE, 'DATE' , DATA_TYPE , 'NUMBER' , DATA_TYPE || DECODE(DATA_SCALE, NULL, NULL, '(' || DATA_PRECISION || ',' || DATA_SCALE || ')'), 'VARCHAR2', DATA_TYPE || '(' || DATA_LENGTH || ')', NULL) DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'INVOICES'; Here’s the output: COLUMN_NAME -----------------------------INVOICE_ID INVOICE_DATE ACCOUNT_NUMBER TERMS_OF_DISCOUNT VENDOR_ID TOTAL_PRICE SHIPPING_DATE FIgure 14-3 Diagram of the INVOICES table DATA_TYPE --------------------NUMBER DATE VARCHAR2(80) VARCHAR2(20) NUMBER NUMBER(8,2) DATE 546 Chapter 14: Managing O bjects with Data Dictionary Views Note: For the record—the preceding SELECT statement isn’t totally perfect. It only addresses datatypes of DATE, NUMBER, and VARCHAR2, and in the event a NUMBER datatype has a precision but no scale, the formatting won’t come out looking quite right. That being said, the point here is to illustrate the sort of query you might want to do in order to extract data dictionary information out of the database. Compiling Views One of the many useful tasks you can accomplish with the data dictionary is to check for the status of a view that you’ve created. Remember from Chapter 10 that a view is a named query based on a table, and that after the view has been created, if the table is altered for any reason, you may have to recompile the view. For example, if a table’s structure is altered, such as by a change to a column’s datatype, or perhaps if a column is dropped from the table altogether—a column that is used by the view—then it may change the status of the view to ‘INVALID’. You can check the data dictionary’s USER_OBJECTS view to determine the status of any of your views, like this: SELECT FROM WHERE ORDER BY STATUS, OBJECT_TYPE, OBJECT_NAME USER_OBJECTS STATUS = 'INVALID' OBJECT_NAME; In our case, the output is: STATUS ------INVALID INVALID OBJECT_TYPE ------------------VIEW VIEW OBJECT_NAME ---------------EMP_PHONE_BOOK VW_EMPLOYEES So now we know we need to recompile these views. See Chapter 10 for details about how to recompile a view. The data dictionary contains a lot of information about views, including the query upon which the view is based, which can be found in the USER_VIEWS view and its TEXT column. Here’s a query on the data dictionary that asks for the query that was used to create the view VW_EMPLOYEES: SELECT TEXT FROM USER_VIEWS WHERE VIEW_NAME = 'VW_EMPLOYEES'; Query Various Data Dictionary Views 547 Here is the output: TEXT --------------------------------------------------------SELECT EMPLOYEE_ID, LAST_NAME || ', ' || FIRST_NAME EMP_NAME, PRIMARY_PHONE FROM EMPLOYEES In summary, all of the metadata for your database is stored in the data dictionary, and available for display and inspection. Checking Privileges Privileges are discussed at length in Chapter 18, when we discuss user access. For now, note that privileges can be inspected using the following views: System privileges granted to the current user n USER_SYS_PRIVS Granted privileges on objects for which the user is the owner, grantor, or grantee n USER_TAB_PRIVS n USER_ROLE_PRIVS Roles granted to the current user System privileges granted to users and roles n DBA_SYS_PRIVS All grants on objects in the database n DBA_TAB_PRIVS n DBA_ROLE_PRIVS Roles granted to users and roles n ROLE_SYS_PRIVS System privileges granted to roles n ROLE_TAB_PRIVS Table privileges granted to roles n SESSION_PRIVS Session privileges which the user currently has set Each can be inspected by the user to determine the current state of privileges and roles. See Chapter 18 for a full discussion of user access, privileges, and roles, including sample queries of these data dictionary views. Inspecting Constraints The USER_CONSTRAINTS view is one of the more useful views. Here’s a query you might run to check the current state of constraints on a table CRUISES: SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, R_CONSTRAINT_NAME, STATUS FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'CRUISES'; 548 Chapter 14: Managing O bjects with Data Dictionary Views Here is an example of the output: CONSTRAINT_NAME -----------------------PK_CRUISE FK_CRUISES_CRUISE_TYPES FK_CRUISES_SHIPS FK_CRUISES_EMPLOYEES CONSTRAINT_TYPE --------------P R R R R_CONSTRAINT_NAME STATUS ------------------ -------ENABLED PK_CRUISE_TYPE_ID ENABLED PK_SHIP ENABLED PK_EMPLOYEES ENABLED The output lists all of the constraints on the CRUISES table. We’re seeing four: one primary key and three foreign keys. How do you know which constraint is a PRIMARY KEY, and which is a FOREIGN KEY? The answer is by the CONSTRAINT_TYPE column. The possible entries in the CONSTRAINT_TYPE column are n P = PRIMARY KEY n R = FOREIGN KEY. The R is for “referential integrity”. n U = UNIQUE n C = CHECK or NOT NULL constraint The DELETE_RULE column shows if a foreign key constraint was created with ON DELETE CASCADE or ON DELETE SET NULL. The SEARCH_CONDITION column is particularly useful for inspecting CHECK constraint criteria. For example: SELECT FROM WHERE AND SEARCH_CONDITION USER_CONSTRAINTS CONSTRAINT_NAME = 'CK_PROJECT_COST' CONSTRAINT_TYPE = 'C'; SEARCH_CONDITION -----------------------PROJECT_COST < 1000000 Take note of the constraints with unexpected values for CONSTRAINT_ TYPE: R for FOREIGN KEY, and C for NOT NULL, as well as for CHECK. The data dictionary provides additional information about constraints in the USER_ CONS_COLUMN data dictionary view. That view contains all the information about which columns in CRUISES are constrained, and what the names are of the referenced tables and columns that make up the FOREIGN KEY constraints. Certification Summary 549 Finding Columns One query I find useful is this: SELECT TABLE_NAME FROM USER_TAB_COLUMNS WHERE COLUMN_NAME = 'EMPLOYEE_ID'; That’s a query that looks for all tables in the current user account that happen to have a column named EMPLOYEE_ID. Seems simple enough, but I find that a rather helpful query from time to time. There are many helpful software tools available that will extract data dictionary information—such as comments—and provide a nice pointand-click interface to make it easy to navigate.That’s all very helpful. But sometimes you’ll find yourself in a situation where you simply don’t have access to those tools. And you might even realize that a particular application you’re developing could benefit by programmatically accessing data dictionary information by way of SQL statements to draw data into your application for some project requirement.The point is that the data dictionary is a certification exam objective for a good reason—a comfortable understanding of its information and an ability to navigate it easily is important for any serious SQL professional. CertIFIcAtIon SuMMAry The data dictionary is a powerful tool. It consists of a series of tables and views that are automatically maintained by the Oracle system to document the state of every object in the database. Whenever a DDL statement is executed, the data dictionary is updated in some fashion. The data dictionary is often referred to as “metadata”, a term which means “data about data”. The data dictionary contains information about the database objects you create—their structures, names, status, and more. The SYS account owns the data dictionary’s underlying base tables, which cannot be changed directly by users. Instead, all of the tables have views and—in some cases—public synonyms that have been created, and it is these the user accesses in a read-only mode. 550 Chapter 14: Managing O bjects with Data Dictionary Views Many of the data dictionary views follow a prefix pattern that indicates the contents of the view. Views with a prefix of USER_ show data about objects owned by the user accessing the view. ALL_ is the prefix for objects that exist anywhere in the database to which the current user has access. DBA_ is the prefix for views that show data about all objects in the database, regardless of who owns them, or what privileges may be granted to them. Information in the data dictionary includes the names of tables and their columns, including each column’s datatype, along with its precision, scale, and/or length where applicable. All of the database objects are listed in the data dictionary: all tables, views, indexes, sequences, constraints, synonyms, and more. Views that have a prefix of V$ or some variation are dynamic performance views and show real-time database performance information. Oracle cannot guarantee the read consistency of these views, so it’s recommended that for dynamic performance views you limit your access to single table queries. If more complex queries and/or joins are required, you are advised to first copy data out of the views into your own temporary tables and then query those tables, for better results and data integrity. You can add comments to the entries in the data dictionary for your own tables and columns using the COMMENT statement. You cannot delete comments, but instead update comments with a blank string. The data dictionary can be used to perform a variety of useful tasks, such as obtaining information about time zones, determining if a view requires recompilation, identifying any privileges that are currently granted, and much more. Two-Minute Drill 3 551 Two-MInute DrILL use the Data Dictionary Views to Research Data on Your Objects q The data dictionary is made of tables that store data about the database. q The data dictionary contains the metadata for your database. q It contains information about tables, views, constraints, indexes, sequences, synonyms, roles, privileges, and any and all other objects you might create in the database. q It keeps track of all the users in the database, and which user account owns which objects, who has privileges on which object, the status of each object, and more. q Oracle automatically updates and maintains the data dictionary views with each DDL statement executed throughout the database. q The data dictionary views that begin with the prefix USER_ contain infor- mation about objects owned by the user accessing the view. q The ALL_ prefix indicates a data dictionary view that contains information about objects that might be owned by any user in the database, but to which the accessing user has privileges. q The DBA_ prefix is affixed to all views that contain data about all objects in the database. q The V$ or GV$ prefix identifies views that are part of the set of dynamic performance tables and views, which show real-time performance data about the database. q Most (but not all) of the data dictionary views are stored with comments that provide brief descriptions about each view and what it contains; many of the columns of the views also have comments. q You can add comments of your own alongside the data dictionary record for your own objects that you’ve created. q The COMMENT statement is how you store a comment in the data diction- ary for any table you own, and also for its associated columns. 552 Chapter 14: Managing O bjects with Data Dictionary Views Query Various Data Dictionary Views q The DICTIONARY view is a great starting point for finding what you might be looking for in the data dictionary. q The USER_CATALOG view contains a summary of information about some of the major objects owned by your user account. q The USER_OBJECTS view is similar but with much more information. q You can get a full listing from the data dictionary for your tables; their columns; and associated datatypes, lengths, precision, and scale. q The status of objects is also stored—for example, the data dictionary flags views that are invalid and might need recompilation. q All roles and privileges of all users on all objects are stored somewhere in the data dictionary. q If you have the name of a column and aren’t sure which table it might be part of, the data dictionary can assist. Self Test 553 SeLF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. use the Data Dictionary Views to Research Data on Your Objects 1. One place to get a master list of all the views that form the data dictionary: A. DICTIONARY B. DATA_DICTIONARY C. CATALOG D. USER_CATALOG 2. You are tasked with querying the data dictionary view that lists only those sequences to which you currently have privileges, but don’t necessarily own. To do this, you log in to your own user account and query the data dictionary view called: A. ALL_SEQUENCES B. DBA_SEQUENCES C. USER_SEQUENCES D. USER_PRIV_SEQUENCES 3. Which of the following actions will not cause the contents of the data dictionary to be changed in some way? A. Create a new table. B. Modify the datatype of an existing column. C. Execute a valid COMMENT statement. D. None of the above. 4. The data dictionary is owned by: A. PUBLIC B. SYS C. SYSTEM D. Each individual user 5. You can add your own comments to the data dictionary with the COMMENT statement using which of the following? (Choose two.) A. INDEX B. COLUMN C. SYNONYM D. TABLE 554 Chapter 14: Managing O bjects with Data Dictionary Views 6. You need to get information about columns in a table you do not own, nor do you have privileges to it. Which view can you query to get this information? A. DBA_TAB_COLUMNS B. ALL_TAB_COLUMNS C. ALL_COLUMNS D. It can’t be done 7. Which among the following is considered an acceptable query with V$DATAFILE? A. A join with two other objects in the data dictionary B. A complex GROUP BY with multiple levels of aggregation C. A query that displays rows from the table with no joins D. All of the above 8. You are tasked with the job of adding a comment to the data dictionary to accompany the column PIER in the table MARINA. Which of the following will execute successfully? A. COMMENT ON COLUMN (MARINA.PIER) IS ‘Number of piers’; B. COMMENT ON COLUMN MARINA.PIER IS ‘Number of piers’; C. COMMENT ON COLUMN MARINA(PIER) IS ‘Number of piers’; D. COMMENT ON TABLE COLUMN MARINA.PIER IS ‘Number of piers’; 9. Now you have changed the purpose of the PIER column in the MARINA table and wish to remove the comment you just created in the last question. Which of the following statements will remove the comment? A. COMMENT ON COLUMN MARINA.PIER DROP; B. COMMENT ON COLUMN MARINA.PIER IS NULL; C. COMMENT ON COLUMN MARINA.PIER SET UNUSED; D. COMMENT ON COLUMN MARINA.PIER IS ‘’; Query Various Data Dictionary Views 10. When you’re looking for a particular bit of data and you’re not sure where in the data dictionary it might be, a good starting point is: (Choose the best answer.) A. SELECT * FROM V$DATABASE; B. SELECT * FROM GV_$START_HERE; C. SELECT * FROM DICTIONARY; D. SELECT * FROM V$RESERVED_WORDS; Self Test 555 11. The USER_CONSTRAINTS view in the data dictionary lists FOREIGN KEY constraints in the CONSTRAINT_TYPE column with which of the following single-letter abbreviations? A. K B. R C. F D. G 12. You are tasked to work with a view. The view’s underlying table has been altered. What information can the data dictionary provide at this point? (Choose all answers that are correct.) A. The status of the view so that you can determine if the view requires recompilation. B. The current state of the table. C. The query that was used to create the view. D. The names of columns in the underlying table. 13. The term “metadata” means: A. Data about data B. Global data that is accessible throughout the database C. Data that is automatically updated and maintained by the database system D. Distributed data 14. Which of the following data dictionary views does not have an OWNER column? A. USER_TABLES B. ALL_INDEXES C. DBA_CONS_COLUMNS D. All of the above 15. If an ALTER TABLE . . . DROP COLUMN statement is executed against an underlying table upon which a view is based, the status of that view in the data dictionary changes to A. COMPILE B. INVALID C. ALTERED D. FLAG 556 Chapter 14: Managing O bjects with Data Dictionary Views SeLF Test Answers use the Data Dictionary Views to Research Data on Your Objects 1. ˛ A. DICTIONARY. You can run a DESC DICTIONARY statement to see the two columns that form DICTIONARY, and then query it for additional information. ˝ B, C, and D are incorrect. There is no system view called DATA_DICTIONARY. CATALOG is also incorrect. There is a view in the data dictionary called USER_CATALOG; it’s a useful resource for finding information about tables, views, and other database objects the current user owns. 2. ˛ A. ALL_SEQUENCES will list any sequences in the database, regardless of owner, to which your account has been granted access. ˝ B, C, and D are incorrect. DBA_SEQUENCES will list all sequences in the database, regardless of who owns them, and regardless of who has privileges on them. USER_SEQUENCES will list only those sequences that your user account currently owns. There is no view called USER_PRIV_SEQUENCES. 3. ˛ D. None of the above. ˝ A, B, and C are incorrect. All of these will enact some sort of change to the information in the data dictionary. Any DDL that creates or modifies objects will update the object listings in the data dictionary. The COMMENT statement adds to the data dictionary a comment about a particular object. 4. ˛ B. SYS is the owner of the data dictionary. ˝ A, C, and D are incorrect. Neither PUBLIC nor SYSTEM owns the data dictionary, although both are valid users in the system. 5. ˛ B and D. TABLE and COLUMN objects are supported by the COMMENT statement. ˝ A and C are incorrect. You cannot add comments of your own to the data dictionary for an INDEX or SYNONYM object. 6. ˛ A. DBA_TAB_COLUMNS is the view that contains information about columns in tables, and because of the DBA_ prefix, you know it contains information about tables and columns that exist anywhere in the database, regardless of owner or privileges granted. ˝ A, C, and D are incorrect. ALL_TAB_COLUMNS would be correct if you were limiting your search to tables and columns to which you’ve been granted privileges, for that is what the ALL_ prefix indicates. There is no ALL_COLUMNS view in the data dictionary. 7. ˛ C. The V$ prefix indicates that V$DATAFILE is a public synonym for a dynamic performance view, for which Oracle Corporation does not guarantee read consistency. Therefore you are recommended to limit your direct access of V$ objects to simple queries. Self Test Answers 557 ˝ A, B, and D are incorrect. Oracle Corporation officially advises against using any of the V$ objects in complex queries and/or joins. 8. ˛ B. The correct syntax is to use the keywords COMMENT ON COLUMN, followed by the table name and column name, separated by a period, and the keyword IS, followed by the string. ˝ A, C, and D are incorrect. Parentheses are not a part of the COMMENT statement. The keyword TABLE is only used when adding a comment to a table. 9. ˛ D. There really isn’t a statement to explicitly drop a comment or delete it. The practice is to overwrite the old comment with a blank space. ˝ A, B, and C are incorrect. None of these options are valid statements. They contain bits and pieces of valid reserved words from other statements but do not apply to COMMENT. Query Various Data Dictionary Views 10. ˛ C. The DICTIONARY view summarizes the names of tables and views in the data dictionary, along with detailed comments about each one. ˝ A, B, and D are incorrect. The V$DATABASE and V$RESERVED_WORDS objects are valid public synonyms for data dictionary views, but these are part of the set of dynamic performance tables and not good for getting an overview of the dictionary as a starting point. There is no such object in the Oracle data dictionary called GV_$START_HERE. 11. ˛ B. R is the answer. R stands for “referential integrity”, and indicates the presence of a FOREIGN KEY constraint in the CONSTRAINT_TYPE column of the USER_ CONSTRAINTS data dictionary view. ˝ A, C, and D are incorrect. It’s not K or G. And you’d think it would be F, but it’s not. Alas. R makes sense, though, when you think about it. 12. ˛ A, B, C, and D. The data dictionary can assist with all of the answers listed. ˝ None are incorrect. 13. ˛ A. Metadata is “data about data”. ˝ B, C and D are incorrect. 14. ˛ A. USER_TABLES does not have nor need an OWNER column, since the view only presents a set of tables owned by the user accessing them. ˝ B, C, and D are incorrect. Even if you haven’t looked in detail at these views, you can rely on the fact that views that start with ALL_ and DBA_ have a column showing OWNER information, since they contain, by definition, objects owned by—potentially—more than one user. 15. ˛ B. It changes to INVALID. Recompiling the view could restore the status of the view to VALID. ˝ A, C, and D are incorrect. This page intentionally left blank 15 Manipulating Large Data Sets CertIFIcAtIon ObJectIVes 15.01 Manipulate Data Using Subqueries 15.04 Merge Rows in a Table 15.02 Describe the Features of Multitable INSERTs 15.05 Track the Changes to Data over a Period of Time 15.03 Use the Following Types of Multitable INSERTs: Unconditional, Conditional, and Pivot 3 Q&A Two-Minute Drill Self Test 560 Chapter 15: Manipulating Large Data Sets T his chapter looks at a variety of features and operations that are useful for working with large groups of data. Many of these features combine SQL statements we’ve already reviewed, but in this chapter we look at new combinations of these features, and new keywords and clauses to broaden capabilities and combine tasks into a single SQL statement. The result is more flexibility and power, as well as more efficient performance in your production code. The operations we’ll review here include additional features to the INSERT statement, so that you can use one INSERT statement to add multiple rows of data to a given table, or to several tables, with and without conditional logic. We’ll look at the SQL statement MERGE. We’ll see how to create a table without specifying column names or datatypes, and how to create a table that will be instantly populated upon successful completion of the CREATE TABLE statement. All this and more await you in this chapter. We’ll start by looking at a familiar topic in a new and more expansive way: subqueries. CertIFIcAtIon ObJectIVe 15.01 Manipulate Data using Subqueries We’ve already seen how subqueries can be incorporated into SELECT statements to make the combined SQL statement more powerful and more flexible. We’re going to continue that discussion here by looking at new ways to use the subquery. The SQL statements we’ll look at here include CREATE TABLE, INSERT, and UPDATE. CREATE TABLE and Subqueries The CREATE TABLE statement can include a subquery to speed up the process of creating and populating a table. The prerequisite with this form of SQL statement is that there be some sort of data already available in the database that we wish to use to build new database objects. If that’s not the case, this syntax is not helpful. But if there is already any sort of data that can be displayed using a SELECT statement—including SELECTing from external tables, for example—then this syntax is a powerful way to quickly create tables in the database that are immediately populated with data. The syntax for this form of CREATE TABLE requires the AS SELECT clause. For this reason, this particular form of CREATE TABLE is often referred to as CTAS: “Create Table As Select”. Let’s look at the syntax. First, consider the table shown in Figure 15-1. Manipulate Data Using Subqueries 561 FIGure 15-1 Diagram of the INVOICES table The INVOICES table includes a column for SHIPPING_DATE. Let’s say that we decide to archive rows out of the INVOICES table a year after shipping. Let’s write a new CREATE TABLE statement in the CTAS form based on the table in Figure 15-1 (line numbers added): 01 02 03 04 CREATE TABLE INVOICES_ARCHIVED AS SELECT * FROM INVOICES WHERE SHIPPING_DATE < (ADD_MONTHS(SYSDATE,-12)); In this example, we select rows from the INVOICES table and use them as the basis for the new table called INVOICES_ARCHIVED. As soon as we’ve done this, we can issue the following DESCRIBE command: DESC INVOICES_ARCHIVED Name Null ------------------------------ -------INVOICE_ID INVOICE_DATE ACCOUNT_NUMBER TERMS_OF_DISCOUNT VENDOR_ID TOTAL_PRICE SHIPPING_DATE Type ----------------------NUMBER DATE VARCHAR2(80) VARCHAR2(20) NUMBER NUMBER(8,2) DATE The new table INVOICES_ARCHIVED was created without any columns explicitly defined in the CREATE TABLE statement. The CTAS statement interpreted the subquery and used the entire set of column definitions from the query on INVOICES to build the new table INVOICES_ARCHIVED. In this example, we used the asterisk format as the SELECT statement’s select list. We’ve seen before that this is an alternative to listing each column in the table by name. The result is that each column name and datatype from INVOICES was used to create the new table INVOICES_ARCHIVED. Furthermore, any rows returned by the subquery in the preceding example (lines 2 through 4) are automatically inserted into the newly created table. 562 Chapter 15: Manipulating Large Data Sets However—any CONSTRAINT or INDEX objects, or any other supporting objects that might exist for the source table or tables, are not replicated but need to be created individually if desired for the new table, with one exception: any explicitly created NOT NULL constraints on the queried table are copied into the new table, are assigned a system-generated name, and form part of the new table’s definition. NOT NULL constraints that were created implicitly—for example, as part of a PRIMARY KEY constraint—are not included. The CTAS syntax will accept any valid subquery, including those that use joins, set operators, the GROUP BY clause, and complex expressions in the select list. For example, here’s a CTAS statement that joins two tables (line numbers added): 01 02 03 04 05 06 07 CREATE TABLE ROOM_SUMMARY AS SELECT A.SHIP_ID, A.SHIP_NAME, B.ROOM_NUMBER, B.SQ_FT + NVL(B.BALCONY_SQ_FT,0) TOT_SQ_FT FROM SHIPS A JOIN SHIP_CABINS B ON A.SHIP_ID = B.SHIP_ID; This example is a valid CREATE TABLE statement. Note the column alias at the end of line 5. You cannot create a table unless you provide a name for each column. If you use CTAS to create a table based on a subquery that is lacking column names, you can include a column alias within the subquery to ensure that each column is created with a name. There’s an alternative syntax in which you can provide column names as part of the CREATE TABLE clause of the CREATE TABLE statement, like this: 01 02 03 04 05 06 07 08 CREATE TABLE ROOM_SUMMARY (SHIP_ID, SHIP_NAME, ROOM_NUMBER, TOT_SQ_FT) AS SELECT A.SHIP_ID, A.SHIP_NAME, B.ROOM_NUMBER, B.SQ_FT + NVL(B.BALCONY_SQ_FT,0) FROM SHIPS A JOIN SHIP_CABINS B ON A.SHIP_ID = B.SHIP_ID; The statement above defines each column’s name in line 1. Any valid database name may be provided—they are not required to match the subquery’s column names. Note the fourth column of the subquery, which is specified in line 6, and is given the name TOT_SQ_FT in line 1 of the CREATE TABLE statement. If you omit a column name, then the CREATE TABLE using the CTAS syntax statement will fail. The table that results from our preceding example looks like this: Manipulate Data Using Subqueries DESC ROOM_SUMMARY Name Null ------------------------------ -------SHIP_ID SHIP_NAME ROOM_NUMBER TOT_SQ_FT 563 Type --------------------------| NUMBER(7) VARCHAR2(20) VARCHAR2(5) NUMBER Note: Tables created with the CTAS syntax in this way do not maintain any connection with the source tables. Any changes made to the data or structure of the source tables do not have any impact in our newly created tables. The subqueries exist to create the initial data structure and data population and nothing more. Once the CTAS statement has been executed and the subquery has created the initial data population, there is no connection between the newly created table and whatever source table or tables were used. INSERT and Subqueries We’ve already seen how to use a scalar subquery within an INSERT statement to include a value within an overall INSERT. This section describes something that goes far beyond that—how to use the INSERT statement and leverage the subquery syntax to populate multiple rows of data in a single statement. To illustrate this concept, let’s work with two existing tables—CRUISE_ CUSTOMERS and EMPLOYEES, as shown in Figure 15-2. FIGure 15-2 Diagrams of the CRUISE_ CUSTOMERS and EMPLOYEES tables 564 Chapter 15: Manipulating Large Data Sets We’ll pull data out of EMPLOYEES to add new rows to the CRUISE_ CUSTOMERS table, using the INSERT statement with a subquery. Here’s the example (line numbers added): 01 02 03 04 05 06 INSERT INTO CRUISE_CUSTOMERS (CRUISE_CUSTOMER_ID, FIRST_NAME, LAST_NAME) SELECT SEQ_CRUISE_CUSTOMER_ID.NEXTVAL, EMP.FIRST_NAME, EMP.LAST_NAME FROM EMPLOYEES EMP; In this SQL statement, we use a subquery that selects rows from the EMPLOYEES table. Notice that SEQ_CRUISE_CUSTOMER_ID.NEXTVAL is the first expression in the SELECT statement’s list; note that it is not a column in the EMPLOYEES table at all but is a reference to the sequence generator for the CRUISE_CUSTOMERS table. The remaining two columns are from EMPLOYEES, and all three values are inserted into the CRUISE_CUSTOMERS table in the three columns identified in line 2. In this form of INSERT, the output of the subquery becomes the set of input values for the INSERT. Note that the datatypes for the expressions in the SELECT statement subquery must match the datatypes in the target table of the INSERT statement. All of the rows returned by the subquery (lines 3 through 6) are inserted into the CRUISE_CUSTOMERS table as specified in line 1. If any one row fails the INSERT due to a constraint violation or datatype conflict, the entire INSERT fails and no rows are inserted. Any valid subquery may be used within the INSERT statement. CTAS and INSERT statements with subqueries are very useful in testing environments for creating test tables filled with test data. uPDATE and Correlated Subqueries The UPDATE statement is capable of updating many rows within a single execution. This is true for virtually any of the various forms of UPDATE. Also, in Chapter 9 we saw how we can optionally use single-row and multiple-row subqueries in a WHERE clause, which, when incorporated in an UPDATE statement, can empower that UPDATE to modify potentially many rows in the target table based on what might be many rows within the subquery. We’ve also looked at how to use a scalar subquery within the SET clause of an UPDATE statement. Manipulate Data Using Subqueries 565 This section looks at something that goes a bit beyond those capabilities. This section describes how to use UPDATE and a correlated subquery to update multiple rows in something of an integrated fashion. The important word here is “correlated”— this technique ties the UPDATE statement’s target rows with the subquery’s rows in a correlated fashion. Correlated subqueries in an UPDATE can potentially modify each row in a given table with different values for each row—something that the previous forms of UPDATE we’ve reviewed up to now are not capable of doing. For an example, we’ll work with a variation of the PORTS table—see Figure 15-3. Notice that we have two numeric columns at the end of the table’s structure—one called TOT_SHIPS_ASSIGNED, and one called TOT_SHIPS_ASGN_CAP. These represent aggregate values that we’re going to calculate by way of a GROUP BY query on the SHIPS table. The GROUP BY will aggregate rows for all ships assigned to a given home port, defined by HOME_PORT_ID. We can create a SELECT statement to get the data we’re looking for like this (line numbers added): 01 02 03 04 05 06 SELECT HOME_PORT_ID, COUNT(SHIP_ID) TOTAL_SHIPS, SUM(CAPACITY) TOTAL_SHIP_CAPACITY FROM SHIPS GROUP BY HOME_PORT_ID ORDER BY HOME_PORT_ID; The output of our SELECT is as follows: HOME_PORT_ID ---------------------1 2 3 FIGure 15-3 Diagram of the PORTS table TOTAL_SHIPS -------------------1 4 2 1 TOTAL_SHIP_CAPACITY ------------------2052 6895 5948 2974 566 Chapter 15: Manipulating Large Data Sets Note that the values of HOME_PORT_ID correspond back to the PORTS table. Also, we apparently have a ship that isn’t assigned a home port. To use this information and update the PORTS table in a single UPDATE statement, we use the preceding SELECT statement and transform it into a correlated subquery within the UPDATE statement. That means we need to n Create table aliases and reference all appropriate columns with their corresponding table alias. n Connect the subquery with the outer UPDATE statement using a WHERE clause. Here’s the UPDATE statement (line numbers added): 01 02 03 04 05 06 07 UPDATE PORTS PT SET (TOT_SHIPS_ASSIGNED, TOT_SHIPS_ASGN_CAP) = (SELECT COUNT(S.SHIP_ID) TOTAL_SHIPS, SUM(S.CAPACITY) TOTAL_SHIP_CAPACITY FROM SHIPS S WHERE S.HOME_PORT_ID = PT.PORT_ID GROUP BY S.HOME_PORT_ID); Notice that we’ve done the following: n Line 2: listed all of the columns we are updating in the UPDATE table, enclosed in parentheses. n Line 2: added the assignment operator of the “equal” sign at the end of the line. n Lines 3 through 7: enclosed the subquery in parentheses. n Line 3: removed the reference to HOME_PORT_ID in the subquery’s select list, since we have no need to assign that value to the PORTS table. n Lines 3 and 4: specified a column alias for each expression in the subquery’s select list—which is not required here, but looks good nonetheless. n Line 6: added a WHERE clause to connect the UPDATE statement with the subquery—this is where the correlation is specified. So the correlation occurs on line 6. We also added a table alias for each table, and referenced each column name with the appropriate table alias prefix. That really isn’t required in this particular example, since there are no columns of the same Describe the Features of Multitable INSERTs Be familiar with all syntax variations of CTAS and INSERT statements that use subqueries. 567 name in both tables, so there are no reference conflicts in this example. But it’s still good design to alias every column so the source of each column is clear. This UPDATE statement will update multiple columns and multiple rows—all from a single UPDATE statement. CertIFIcAtIon ObJectIVe 15.02 Describe the Features of Multitable INSERTs The multitable INSERT statement is a variation on the INSERT statement syntax we’ve already seen. A multitable INSERT statement repeats the INTO clause of the INSERT statement to insert data into more than one table. Each INTO clause applies to just one table, but by repeating the INTO clause, you can add data to multiple tables. The multitable INSERT must have a subquery to select rows for inserting. Multitable INSERT statements can accomplish a variety of tasks, including the following: n Query data from one table, and insert the data into multiple tables with conditional logic, such as transforming data into a series of archive tables. n Exchange data between two similar systems of different requirements— perhaps between a transaction-based application and a data warehouse optimized for analysis. n Support logical archiving at any level of detail with logical decision points embedded in the INSERT statements. n Integrate complex queries with GROUP BY, HAVING, set operators, and more, all while moving any number of rows dynamically, distributing output into multiple data targets, and programming logical decision points to control data distribution. n Transform data that is stored in rows and levels into a cross-tabulation output, the type you would typically see in a spreadsheet application. 568 Chapter 15: Manipulating Large Data Sets There are two general types of multitable INSERT statements: unconditional and conditional. n Unconditional multitable INSERT statements process each of the INSERT statement’s one or more INTO clauses without condition, for all rows returned by the subquery. n Conditional multitable INSERT statements use WHEN conditions before INTO clauses to determine if the given INTO clause (or clauses) will execute for a given row returned by the subquery. In other words, for each row returned by the INSERT statement’s subquery, each WHEN condition’s expression is considered and evaluates to either a true or false condition. If true, the associated INTO clause(s) will execute. If false, it will not. Finally, an optional ELSE clause can include an alternative INTO clause that can be executed if none of the WHEN conditions are found to be true. Let’s look at the overall syntax for the multitable INSERT statement. First, we’ll examine an unconditional multitable INSERT statement. The syntax repeats the INTO statement from one to many times as required: INSERT ALL INTO tab1 VALUES (col_list1) INTO tab2 VALUES (col_list2) INTO tab3 VALUES (col_list3) ... subquery; The unconditional multitable INSERT statement syntax just shown assumes the following: n The keyword ALL is required in an unconditional multitable INSERT. Note, however, that while the presence of the keyword ALL is indicative of a multitable INSERT, it doesn’t necessarily indicate the unconditional multitable INSERT, as you’ll see in the next section. n Following the keyword ALL, there must be at least one INTO clause. n You can include multiple INTO clauses. n Each INTO may have its own VALUES clause. n Each VALUES list is optional; if omitted, the select list from the subquery will be used. n The subquery is a subquery. Describe the Features of Multitable INSERTs 569 The conditional multitable INSERT statement syntax is similar but adds the WHEN condition, like this: INSERT option WHEN expression THEN INTO tab1 VALUES (col_list1) WHEN expression THEN INTO tab2 VALUES (col_list2) . . . ELSE INTO tab3 VALUES (col_list3) subquery; For each row returned by the subquery, each WHEN condition is evaluated and determined to either be true or false. If true, then the WHEN condition’s associated set of one or more INTO clauses is executed; otherwise, processing skips over the INTO clauses to the next WHEN condition. If none of the WHEN conditions evaluate to true, the ELSE clause is processed and its associated set of one or more INTO clauses is executed. The conditional multitable INSERT statement syntax just shown is used as follows: n The option is one of two keywords: ALL or FIRST. n ALL is the default and may be omitted. n FIRST is the alternative keyword; it indicates that the only set of INTO clauses that will execute are those that follow the first WHEN clause that evaluates to true. n You can include multiple WHEN conditions. n Each WHEN condition is followed by one or more INTO clauses. n Each INTO may have its own VALUES clause; if omitted, the subquery’s select list must match the number and datatypes of the INTO table’s columns. n Each expression evaluates to true or false and should involve one or more columns from the subquery. n The tab and col_list are the components of the INSERT statement that will execute if the WHEN expression evaluates to true. n The optional ELSE . . . INTO clause, if included, must be last. n The subquery is required, and must be a valid subquery. 570 Chapter 15: Manipulating Large Data Sets A conditional multitable INSERT statement will process each row returned by the subquery. The multitable INSERT statement always uses a subquery. As we know, a subquery may return anywhere from zero to many rows. For each individual row returned by a subquery, processing does a pass through the set of WHILE ... INTO clauses. But the way it processes the WHILE ... INTO clauses differs based on whether the keyword ALL or FIRST is used. If the keyword ALL is specified, then all of the WHEN conditions will be evaluated for each row returned by the subquery. For each WHEN condition that evaluates to true, the corresponding INTO clause—or clauses—that follow the WHEN will be executed. For each WHEN condition that evaluates to false, the corresponding INTO clause—or clauses—will not be executed. All of the WHEN conditions are evaluated if the keyword ALL is specified at the beginning of the multitable INSERT statement. On the other hand, if the keyword FIRST is used, then for each row returned by the subquery, WHEN conditions are evaluated until the first true condition is encountered. As soon as a WHEN condition is determined to be true, the corresponding set of one or more INTO clauses that follows the WHEN will be executed. Processing will then skip over the remaining WHEN conditions for that row of the subquery. In either situation—INSERT FIRST or INSERT ALL—if no WHEN condition was found to be true, and if the optional ELSE clause is present, then the ELSE clauses’ INTO clause will be executed for the row. Then processing moves on to the next row returned by the subquery. Note that for the conditional multitable INSERT statement—which is to say any multitable INSERT with a WHEN condition—ALL is the default keyword. If no WHEN condition is used, then the multitable INSERT is unconditional, and the ALL keyword must be present. In other words, you may not omit the keyword in an unconditional multitable INSERT like this: INSERT INTO ... VALUES ... INTO ... VALUES ... subquery; The preceding statement shows incorrect syntax, since it omits the ALL option and yet has no WHEN condition—therefore it is syntactically incorrect. However, you may do something like this: Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 571 INSERT ALL INTO ... VALUES ... INTO ... VALUES ... subquery; The preceding unconditional multitable INSERT correctly shows the ALL keyword. The conditional multitable INSERT allows you to omit the keyword, like this: INSERT WHEN ... THEN INTO ... VALUES ... WHEN ... THEN INTO ... VALUES ... subquery; The default keyword is ALL. In all forms of the multitable INSERT, the subquery is required; it is not optional. And as is always the case with any INSERT that uses a subquery, the INSERT statement will execute once for each row returned by the subquery. Note: If any one INTO clause fails with an execution error for any one row returned by the Multitable INSERT subquery, then the entire statement fails for all statements require a subquery. rows of the subquery, and no data change results. CertIFIcAtIon ObJectIVe 15.03 use the Following Types of Multitable INSERTS: unconditional, Conditional, and Pivot In this section, we’ll continue our discussion of multitable INSERT statements. We’ll look at some examples of its various forms, and how they can be used to process large amounts of data, using conditional logic and affecting multiple tables, all from within a single SQL statement. unconditional Let’s look at an example of an unconditional multitable INSERT statement. For our example, we’ll work with the CRUISE_ORDERS table—see Figure 15-4. 572 Chapter 15: Manipulating Large Data Sets FIGure 15-4 Diagram for the CRUISE_ ORDERS table We also have three identically structured tables named CO_2008, CO_ELCARO, and CO_ARCHIVED, each with the same columns as the table CRUISE_ORDERS. The three identically structured tables are used for archiving and analyzing the CRUISE_ORDERS table data. Here is an example of a valid SQL statement that queries the CRUISE_ORDERS table and inserts the output into each of our three archive tables (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 INSERT ALL INTO CO_2008 (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) INTO CO_ELCARO (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) INTO CO_ARCHIVED (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) SELECT CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID FROM CRUISE_ORDERS; Note that we have three INTO clauses here. If the subquery returns, for example, three rows, then the end result of this INSERT statement will be to insert nine rows: three into the CO_2008 table (line 2), three into the CO_ELCARO table (line 6), and three into the CO_ARCHIVED table (line 10). As we see in the preceding example, the unconditional INSERT statement uses the keyword ALL (line 1), followed by one or more INTO clauses (lines 2, 6, and 10), each of which specifies a table and the columns into which we are inserting data, followed by the VALUES list. The VALUES list can specify expressions found in the subquery’s select list. In our example, in line 4 we specify CRUISE_ORDER_ID as the first expression in the VALUES list to be inserted into the CO_2008 table. This corresponds to the Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 573 CRUISE_ORDER_ID column in the subquery select list in line 14. The other VALUES lists that refer to CRUISE_ORDER_ID (line 8 and line 12) are specifying that same column. Each VALUES list in a multitable INSERT can specify any column names or expressions that are in the subquery select list. On the other hand, the column references within each INTO list (each starting at lines 2, 6, and 10) specify the columns of the tables named for the INTO clause. In our example, line 2 names the CO_2008 table, and the INTO list that follows on line 2 and line 3 specifies columns in the CO_2008 table. You’ll recall that in a standard INSERT statement, the list of values in the VALUES expression list must match in number and in datatype (or be able to be automatically converted to a matching datatype) with the columns specified in the INTO clause. The same is true here for each pair of INTO and VALUES lists. Each VALUES expression list may use any complex expression in specifying the value to be inserted into its corresponding table and column. For example: 01 02 03 04 05 06 07 08 09 10 11 12 13 INSERT ALL INTO CO_2008 (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, SYSDATE, 14, 1) INTO CO_ELCARO (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, ORDER_DATE+30, 15, 1) INTO CO_ARCHIVED (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) VALUES (CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID) SELECT CRUISE_ORDER_ID, ORDER_DATE, CRUISE_CUSTOMER_ID, SHIP_ID FROM CRUISE_ORDERS; In this example, we are choosing to insert some values that are different than the subquery is returning. For the CO_2008 table, in lines 2 through 4, we are defining the ORDER_DATE for all rows to be SYSDATE, and the CRUISE_ CUSTOMER_ID to be the literal value of 14, and the SHIP_ID to be a literal value of 1. For the CO_ELCARO table, in lines 5 through 7, we are giving each row an ORDER_DATE that is 30 days beyond the incoming value in the subquery, and we’re assigning the number 15 to each CRUISE_CUSTOMER_ID, and 1 to each SHIP_ID. For the CO_ARCHIVED table, in lines 8 through 11, we are choosing to pass through values from the subquery unchanged. As the example shows, the VALUES list can specify column names and expressions from the subquery’s select list but may also define any valid SQL expression. The INTO column list must specify columns in the table into which the INTO statement is inserting data. 574 Chapter 15: Manipulating Large Data Sets If the VALUES list is omitted, the columns of the subquery become the de facto VALUES list and therefore must match the columns of the corresponding INTO clause. By “match”, we mean that they must match in number, and in datatype, or be of such datatypes that an automatic datatype conversion may be performed. If there is no column list in the INTO clause, the subquery’s select list must match the columns in the table of the INTO clause. Conditional Conditional multitable INSERT statements use conditional logic to determine which INTO clause or clauses to process. Each row that is returned by the subquery is processed through a series of one or more WHEN conditions. Each WHEN condition is followed by a set of one or more INTO clauses. For each row returned by the subquery, each WHEN condition is evaluated to be either true or false. If true, the following set of one or more INTO clauses are executed. If false, the set of one or more INTO clauses are skipped over, and the next WHEN condition is evaluated. An ELSE clause may optionally be included in the conditional multitable INSERT statement. If present, it must define its own set of one or more INTO clauses, and the ELSE/INTO clauses must follow all WHEN conditions/INTO clause combinations. If all WHEN conditions are skipped for any given row, then the ELSE clause’s INTO will be processed. Otherwise, it will be skipped for that row. Each row returned by the subquery is processed according to these rules we have just reviewed. Let’s look again at our table INVOICES, and the archive table INVOICES_ ARCHIVED, in which we stored invoice records that are over a year old. See Figure 15-1 for the INVOICES table, and Figure 15-5 for the INVOICES_ARCHIVED table. Let’s say our organization is engaged in a merger and we are tasked with the job of integrating data from another application. The newly acquired company has provided us with the table WO_INV, as shown in Figure 15-6. FIGure 15-5 Diagram for the INVOICES_ ARCHIVED table Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 575 FIGure 15-6 Diagram for the WO_INV table We need to create an INSERT statement that will n Pull data from the WO_INV table. n Insert WO_INV’s invoice information from within the past year into our INVOICES table. n Insert WO_INV’s invoice information that is over a year old into our INVOICES_ARCHIVED table. It’s a perfect task for a conditional multitable INSERT statement, as follows (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 INSERT FIRST WHEN (DATE_SHIPPED < (ADD_MONTHS(SYSDATE,-12))) THEN INTO INVOICES_ARCHIVED (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) ELSE INTO INVOICES (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) SELECT INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT FROM WO_INV; In this statement, we see the following: n A subquery on lines 10 through 11. Note the subquery includes a column DATE_SHIPPED. n Line 2 compares the DATE_SHIPPED value in a WHEN condition. n If line 2 evaluates to true for a given row from the subquery, the INSERT statement will take that row’s data and insert it into the INVOICES_ ARCHIVED table, as specified on line 3. The columns in the INVOICES_ ARCHIVED table are specified in lines 3 and 4. 576 Chapter 15: Manipulating Large Data Sets n Line 5 defines the values from the subquery that will be inserted if the WHEN clause on line 2 is true. For example, the subquery’s column INV_NO (line 5) will be inserted into the target table’s column INVOICE_ID (line 3). n Line 6 is an ELSE clause that will execute for each row that does not satisfy the WHEN condition in line 2. In the example we just reviewed, there was one WHEN condition and one ELSE condition. Let’s look at an example with multiple WHEN conditions. Let’s say you had three archive tables, named INVOICES_THRU_2009, INVOICES_ THRU_2008, and INVOICES_THRU_2007, and wished to insert rows from the incoming table into each archived table based on the year of the DATE_SHIPPED value. Note that each table is not mutually exclusive; for example, the INVOICES_ THRU_2009 table will contain invoices from 2009, 2008, and 2007, as well as earlier. One row returned by the subquery might be inserted into all three tables. To accomplish this task, you could use the following INSERT statement (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 INSERT WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2009') THEN INTO INVOICES_THRU_2009 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2008') THEN INTO INVOICES_THRU_2008 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2007') THEN INTO INVOICES_THRU_2007 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) SELECT INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT FROM WO_INV; Notice that there is no keyword FIRST or ALL in this example. Therefore the statement will default to ALL. Since there are three WHEN conditions, each with an associated INTO clause, then each and every WHEN condition that evaluates to true will execute. Also, this example omits the ELSE clause, so if any row from the subquery does not satisfy a WHEN condition, then no action will be taken for that particular row returned by the subquery. After any WHEN condition, you may include more than one INTO clause. For example, let’s say we have a table INVOICES_CLOSED that takes any invoice rows that shipped prior to 2008. We might modify our example like this (line numbers added): Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 577 INSERT WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2009') THEN INTO INVOICES_THRU_2009 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2008') THEN INTO INVOICES_THRU_2008 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) INTO INVOICES_CLOSED (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) WHEN (TO_CHAR(DATE_SHIPPED,'RRRR') <= '2007') THEN INTO INVOICES_THRU_2007 (INVOICE_ID, INVOICE_DATE, SHIPPING_DATE, ACCOUNT_NUMBER) VALUES (INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT) SELECT INV_NO, DATE_ENTERED, DATE_SHIPPED, CUST_ACCT FROM WO_INV; Note the new INTO clause, lines 10 through 12. This INTO is subject to the WHEN condition in line 6. In other words, if DATE_SHIPPED is in the year 2008 or before, the INSERT statement will add the candidate row to both the INVOICES_THRU_2008 table and the INVOICES_CLOSED table. One WHEN condition is the gateway to both INTO clauses. What this example shows us is that any WHEN condition can have multiple INTO clauses that follow it. If the WHEN condition evaluates to true, all of its INTO clauses will execute. If the WHEN condition evaluates to false, execution will skip over the INTO clauses and move on directly to either the next WHEN condition, an ELSE if it is present, or the next row in the subquery. The INSERT ALL will evaluate each and every WHEN condition, and process all INTO clauses for all WHEN conditions that evaluate to true. Therefore the INSERT ALL may result in a single row being added to more than one table. The INSERT FIRST will evaluate every WHEN condition until one of them evaluates to true. It will then process that WHEN condition’s INTO, and skip the remaining WHEN conditions. The INSERT FIRST will only process zero or one WHEN condition; however, it may also result in a single row being added to more than one table, but only if the first true WHEN condition has more than one INTO clause. Table aliases in the subquery of a multitable INSERT are not recognized outside in the rest of the INSERT—for example, you can’t reference them from within a WHEN condition or INTO statement. If a subquery’s column reference depends on a table alias, be sure to use a column alias for the column, and then reference the column alias. For example, see Figure 15-7. 578 Chapter 15: Manipulating Large Data Sets FIGure 15-7 Diagram of the POSITIONS and SALARY_CHART tables In a query that queries rows from the POSITIONS table and conditionally inserts them into the SALARY_CHART table, we cannot use this query (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 INSERT WHEN (B.MAX_SALARY-A.MAX_SALARY < 10000) THEN INTO SALARY_CHART (EMP_TITLE, SUPERIOR, EMP_INCOME, SUP_INCOME) VALUES (A.POSITION, B.POSITION, A.MAX_SALARY, B.MAX_SALARY) SELECT A.POSITION, B.POSITION, A.MAX_SALARY, B.MAX_SALARY FROM POSITIONS A JOIN POSITIONS B ON A.REPORTS_TO = B.POSITION_ID WHERE A.MAX_SALARY > 100000; This statement will not work. Here is the result: Error at Command Line:6 Column:35 Error report: SQL Error: ORA-00904: "B"."MAX_SALARY": invalid identifier 00904. 00000 - "%s: invalid identifier" Notice how the subquery is a self-join and uses table aliases to identify each table and column reference. These table aliases are perfectly fine in the subquery but are Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 579 not recognized beyond the subquery. In other words, the attempts to reference each table alias from within the WHEN condition or VALUES clause are invalid. So what do we do? The solution is to specify a column alias to any column names within the subquery that use a table alias, then reference the column alias from the rest of the conditional INSERT statement, like we do below in lines 5 and 6 (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 INSERT WHEN (BOSS_SALARY-EMPLOYEE_SALARY < 10000) THEN INTO SALARY_CHART (EMP_TITLE, SUPERIOR, EMP_INCOME, SUP_INCOME) VALUES (EMPLOYEE, BOSS, EMPLOYEE_SALARY, BOSS_SALARY) SELECT A.POSITION EMPLOYEE, B.POSITION BOSS, A.MAX_SALARY EMPLOYEE_SALARY, B.MAX_SALARY BOSS_SALARY FROM POSITIONS A JOIN POSITIONS B ON A.REPORTS_TO = B.POSITION_ID WHERE A.MAX_SALARY > 100000; Note that this version has done more than is required, and applies column aliases to each column in the subquery, then references those column aliases from the WHEN and VALUES clauses. We only needed column aliases on A.POSITION and B.POSITION in lines 5 and 6, so we can reference the column aliases in line 4. Either way, this version of the conditional INSERT is syntactically correct. You cannot execute a multitable INSERT on a view; it can only be used with a table. Sequence generators do not behave consistently in a multitable INSERT statement. If you try to use a sequence generator within the subquery, you’ll get a syntax error. If you try to include one within the expression list of the INTO statement, you may or may not get the functionality you wish—the NEXTVAL function will not advance as you might expect it to. The reason: a multitable insert is treated as a single SQL statement. Therefore, if you reference NEXTVAL with a sequence generator, Oracle’s documentation warns that NEXTVAL will be incremented once in accordance with the sequence generator’s parameters and stay that way for the duration of a pass through the multitable insert. In other words, a conditional INSERT with a single INTO, one that invokes a single sequence generator once with a NEXTVAL, will increment the sequence once for each row returned by the subquery—regardless of whether or not the WHEN condition is true. For example, consider this example: 01 02 03 04 05 INSERT WHEN (TO_CHAR(DATE_ENTERED,'RRRR') <= '2009') THEN INTO INVOICES_ARCHIVED (INVOICE_ID, INVOICE_DATE) VALUES (SEQ_INV_NUM.NEXTVAL, DATE_ENTERED) SELECT INV_NO, DATE_ENTERED FROM WO_INV; 580 Chapter 15: Manipulating Large Data Sets The sequence generator in line 4 will increment for each row returned by the subquery, regardless of whether the WHEN condition is true or not. For this example, assume the sequence generator has just been created and has never been used, and that it has the default settings of an initial value of 1 and an increment of 1. Given that, then if the subquery returns ten rows, and if, for instance, the final row alone causes the WHEN condition in line 2 to be true, then the one row inserted into the INVOICES_ARCHIVED table will be assigned a value of 10 for the INVOICE_ID column. If this statement contained additional calls to the same sequence generator, in additional INTO clauses, they would not cause the sequence generator to increment. The sequence Remember: a table alias generator increments with each row of the defined in a subquery of a multitable subquery returned, no more, no less, regardless INSERT is not recognized throughout the of additional calls to NEXTVAL. rest of the INSERT statement. Also, if a Oracle’s documentation warns that “you multitable INSERT statement fails for cannot specify a sequence in any part of a any reason, the entire statement is rolled multitable insert statement”. The only place back and no rows are inserted in any of you’ll get the syntax error is in the subquery, the tables. but know that attempts to invoke a sequence generator from the WHEN or INTO clauses of the INSERT may produce undesirable results. Pivot You can use a conditional multitable INSERT statement to transform data from a spreadsheet structure to a rows-and-columns structure. This section describes the technique. First, let’s start with the following data listing: ROOM_TYPE -------------------ROYAL SKYLOFT PRESIDENTIAL LARGE STANDARD OCEAN ---------------1745 722 1142 225 217 BALCONY NO_WINDOW ---------------- --------1635 722 1142 1142 211 554 586 This is the sort of data that you might find in a typical spreadsheet display. Let’s say that this spreadsheet has been stored in an external table. The table’s structure is shown in Figure 15-8. Use the Following Types of Multitable INSERTS: Unconditional, Conditional, and Pivot 581 FIGure 15-8 Diagram of the SHIP_CABIN_ GRID table Next, you’re given the task of moving this data into the table shown in Figure 15-9. This isn’t a straightforward row-for-row insert with a subquery. This data must be transformed so that each column from the spreadsheet is transformed into an individual row in the new table. The following query will accomplish the task (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 INSERT ALL WHEN OCEAN IS NOT NULL THEN INTO SHIP_CABIN_STATISTICS (ROOM_TYPE, WINDOW_TYPE, SQ_FT) VALUES (ROOM_TYPE, 'OCEAN', OCEAN) WHEN BALCONY IS NOT NULL THEN INTO SHIP_CABIN_STATISTICS (ROOM_TYPE, WINDOW_TYPE, SQ_FT) VALUES (ROOM_TYPE, 'BALCONY', BALCONY) WHEN NO_WINDOW IS NOT NULL THEN INTO SHIP_CABIN_STATISTICS (ROOM_TYPE, WINDOW_TYPE, SQ_FT) VALUES (ROOM_TYPE, 'NO WINDOW', NO_WINDOW) SELECT ROWNUM RN, ROOM_TYPE, OCEAN, BALCONY, NO_WINDOW FROM SHIP_CABIN_GRID; Note how each row of the subquery is considered three times. For a given row returned by the subquery, each of three columns of the row is individually considered. If any one of the three columns OCEAN, BALCONY, or NO_ WINDOW is not NULL, then a row is inserted into the target table. It’s possible that some individual rows returned by the subquery will result in three new rows being added to the target table SHIP_CABIN_STATISTICS. FIGure 15-9 Diagram of the SHIP_CABIN_ STATISTICS table 582 Chapter 15: Manipulating Large Data Sets Let’s take a look at the results: SELECT ROOM_TYPE, WINDOW_TYPE, SQ_FT FROM SHIP_CABIN_STATISTICS ORDER BY ROOM_TYPE, WINDOW_TYPE; ROOM_TYPE -------------------LARGE LARGE PRESIDENTIAL PRESIDENTIAL PRESIDENTIAL ROYAL ROYAL SKYLOFT SKYLOFT STANDARD STANDARD STANDARD WINDOW_TYPE ----------NO WINDOW OCEAN BALCONY NO WINDOW OCEAN BALCONY OCEAN BALCONY OCEAN BALCONY NO WINDOW OCEAN SQ_FT ---------------------211 225 1142 1142 1142 1635 1745 722 722 554 586 217 In this example, the conditional multitable INSERT transformed incoming data from a spreadsheet summary style into a row-by-row structure, all within a single SQL statement. In this way, the conditional multitable INSERT statement “pivots” the data by changing columns into rows. Note that this “pivot” technique is different from SQL operations that use the keyword PIVOT or UNPIVOT. What we’ve described here is a technique that uses the conditional multitable INSERT to pivot data.The keyword PIVOT, while somewhat similar in function, is a separate feature and not discussed here, nor is it listed in the exam certification objectives. CertIFIcAtIon ObJectIVe 15.04 Merge Rows in a Table The MERGE statement is a SQL DML statement that combines the functionality of INSERT, UPDATE, and DELETE, all into a single SQL statement. There isn’t anything you can do with MERGE that you cannot already do with some combination Merge Rows in a Table 583 of those three DML statements. However, if it’s possible to use MERGE as an alternative to executing two or more DML statements, then MERGE is preferable, since it combines multiple DML actions into a single SQL statement, resulting in a single pass through the database. In other words, it will perform more efficiently. The syntax of MERGE follows (line numbers added): 01 02 03 04 05 06 07 08 09 10 MERGE INTO table USING table | subquery ON condition WHEN MATCHED THEN UPDATE SET col = expression | DEFAULT where_clause DELETE where_clause WHEN NOT MATCHED THEN INSERT (col, col2) VALUES (expr1, expr2 | DEFAULT) where_clause WHERE condition; Note the following: n Line 1: INTO specifies the target into which you are either inserting or updating rows; it can be a table or an updatable view. n Line 2: USING identifies the source of the data, which can be a table, view, or subquery. n Line 3: The ON condition for MERGE behaves essentially like a WHERE clause. It determines how to compare each row in the USING data source with each row in the MERGE INTO data target. The ON condition can use Boolean operators and expressions to form complex comparisons. In practice it is often limited to comparing primary key values, but this is not required. n Lines 4 through 6 are considered the update clause and identify the logic by which the MERGE will update target rows; it cannot update a column in the ON condition. n Lines 7 through 9 are considered the insert clause and identify the logic by which the MERGE will insert rows into the target table. n Lines 1 through 3 are required; all other lines are optional. As you can see, it’s an involved statement. Let’s look at an example in action— let’s say you are responsible for an application that uses the WWA_INVOICES table (see Figure 15-10), and you have been tasked to bring in data from an outside table, ONTARIO_ORDERS (see Figure 15-11). 584 Chapter 15: Manipulating Large Data Sets FIGure 15-10 Diagram of the WWA_ INVOICES table FIGure 15-11 Diagram of the ONTARIO_ ORDERS table The data listing for the WWA_INVOICES table follows: INV_ID ---------------------10 20 CUST_PO ---------WWA-200 WWA-001 INV_DATE NOTES ------------------- ----17-DEC-09 23-DEC-09 For the ONTARIO_ORDERS table: ORDER_NUM ---------------------882 883 884 PO_NUM -------------------WWA-001 WWA-017 NBC-201 SALES_REP -------------------C. Nelson J. Metelsky D. Knight Let’s use MERGE to bring the data from ONTARIO_ORDERS into the WWA_INVOICES table (line numbers added): 01 02 03 04 05 06 07 08 MERGE INTO WWA_INVOICES WWA USING ONTARIO_ORDERS ONT ON (WWA.CUST_PO = ONT.PO_NUM) WHEN MATCHED THEN UPDATE SET WWA.NOTES = ONT.SALES_REP WHEN NOT MATCHED THEN INSERT (WWA.INV_ID, WWA.CUST_PO, WWA.INV_DATE, WWA.NOTES) VALUES Merge Rows in a Table 09 10 11 585 (SEQ_INV_ID.NEXTVAL, ONT.PO_NUM, SYSDATE, ONT.SALES_REP) WHERE SUBSTR(ONT.PO_NUM,1,3) <> 'NBC'; The preceding MERGE statement includes the following features: n Line 1: we specify that we are going to merge rows into the table WWA_INVOICES. n Line 1: we assign a table alias WWA to the table WWA_INVOICES. n Line 2: we specify the ONTARIO_ORDERS table as the data source and give that table an alias of ONT. n Line 3: we define the ON condition, indicating that the columns CUST_PO and PO_NUM are where the common information exists that will “join” the rows logically in order to associate them with each other for the merge. n Lines 4 through 5 are the “update clause”. n Lines 6 through 10 are the “insert clause”. n Line 11 is the WHERE clause for the MERGE, filtering out rows from the USING data source—in this case, ONTARIO_ORDERS. The result of our MERGE is to merge rows from ONTARIO_ORDERS into WWA_INVOICES. If we query the WWA_INVOICES table, here are the results, after the MERGE: SELECT * FROM WWA_INVOICES; INV_ID ---------------------10 20 40 CUST_PO ---------WWA-200 WWA-001 WWA-017 INV_DATE ----------------17-DEC-09 23-DEC-09 30-JUL-09 NOTES --------C. Nelson J. Metelsky Notice the following: n We merged the row where CUST_PO equals “WWA-001”. n We added the row where CUST_PO equals “WWA_017”. n Our MERGE statement’s WHERE clause correctly omitted the row where the PO_NUM was NBC-201. MERGE is a useful and efficient process. In this example, we saw how we performed an INSERT and UPDATE statement in a single MERGE statement. 586 Chapter 15: Manipulating Large Data Sets Our example did not make use of the DELETE feature of the “update clause” within MERGE. But we could have included one, like this: 01 02 03 04 05 06 07 08 09 10 11 12 MERGE INTO WWA_INVOICES WWA USING ONTARIO_ORDERS ONT ON (WWA.CUST_PO = ONT.PO_NUM) WHEN MATCHED THEN UPDATE SET WWA.NOTES = ONT.SALES_REP DELETE WHERE WWA.INV_DATE < TO_DATE('01-SEP-09') WHEN NOT MATCHED THEN INSERT (WWA.INV_ID, WWA.CUST_PO, WWA.INV_DATE, WWA.NOTES) VALUES (SEQ_INV_ID.NEXTVAL, ONT.PO_NUM, SYSDATE, ONT.SALES_REP) WHERE SUBSTR(ONT.PO_NUM,1,3) <> 'NBC'; In this example, we’ve added line 6, which contains the “delete clause” for the MERGE. But take note: n The “delete clause” only affects rows that are a result of the completed “update clause” and remain in the target table—which in this instance is WWA_INVOICES. The USING clause can base a MERGE on a subquery as well as a table or view. n Rows added as a result of the “insert clause” are unaffected by the “delete clause”. So MERGE represents a combination of the UPDATE and INSERT DML statements, and to a lesser and somewhat limited extent, the DELETE statement. CertIFIcAtIon ObJectIVe 15.05 Track the Changes to Data over a Period of Time This section reviews a number of features that support the ability to investigate older versions of rows in the database that have been changed and committed. In other words—if you have already issued any number of INSERT, UPDATE, or DELETE statements and subsequently committed those changes any number of times, you have the ability to go back prior to those committed changes and query Track the Changes to Data over a Period of Time 587 the older versions of the data, prior to when the changes were committed. You can display different versions of the rows that have existed at prior times. You can query historic data and combine such a query with queries from other times, or of current data. There are a few restrictions—for example, you won’t be able to query data changes prior to any DDL statements that altered the structure of the table or tables you are querying. The oldest data you can query is limited to data within a particular time period that is dependent on the configuration of the database. Database configuration is under the control of the database administrator (DBA) and is determined by factors outside the control of your application code. As a result, flashback operations, while technically capable of being integrated within production code of your application, may not be ideal for such a situation. However, these operations are potentially useful when performing ad hoc analysis, system development, system testing, and other comparable scenarios. Flashback operations include just some of the many options for managing historic data and managing data changes. Table 15-1 shows flashback operations and compares them with other major options for performing data recovery. Note that the certification exam addresses TCL and flashback operations. It does not address the underlying architecture of either, nor does it deal with the import and export utilities mentioned in Table 15-1. TAble 15-1 Data Recovery Options and Comparisons Option Examples Data Recovery Timeframe Recommended use Transaction Control Language (TCL) COMMIT, ROLLBACK, SAVEPOINT statements Current session Application design; production code Flashback Operations FLASHBACK TABLE, SELECT . . . AS OF, SELECT . . . VERSIONS BETWEEN, etc. Recent sessions (minutes/hours, depending on configuration) Application development support; recovering recent data changes; performing analysis comparing current data with recently changed data; analysis of recent transactions Backup Recovery Import/Export Utilities Long term (days/ weeks/months/ longer, depending on configuration) Recovering older data 588 Chapter 15: Manipulating Large Data Sets We’ve already looked at transaction control language (TCL), including the SQL statements COMMIT, ROLLBACK, and SAVEPOINT. Those statements are used to control transactions in production systems. TCL supports transactions within a given login session. Flashback operations serves as an alternative to backup and recovery operations. Flashback can recover data programmatically—in other words, using SQL statements. Oracle Corporation’s documentation stresses that the various flashback operations support programmatic access to historic data. However, the underlying support structures upon which flashback operations depend are outside the boundaries of a typical application and may require a unique configuration to accommodate the specifics of any given application. Furthermore, depending on hardware limitations, the time frame within which flashback operations can apply may vary from one database implementation to another. Any application that incorporates flashback operations must take the potential for these environmental variations into account. In Chapter 11 we examined the FLASHBACK TABLE statement. This section looks at Flashback Query operations and related features. Specifically, we’ll look at the following: n Flashback Query (FQ) For querying a table as it existed in the past For querying multiple past points at once and comparing rows as they existed at various points in history n Flashback Version Query (FVQ) For querying the data dictionary and obtaining a variety of metadata about historical rows in the database— including information about the transaction that caused the most recent changes n Flashback Transaction Query (FTQ) Note that flashback operations are limited; you cannot recover any data from any time in the past but are limited to recovering data changed within the amount of time defined by the undo retention period. We’ll discuss that after we’ve looked at Flashback Query. Flashback Query Oracle’s Flashback Query (FQ) feature enables you to query data as it existed in the database at a previous moment in time. The query will produce results as it would have done during that moment in time, regardless of changes to the data that may have already been committed. Track the Changes to Data over a Period of Time 589 The FQ feature is a clause of the SELECT statement involving the keywords AS OF. To demonstrate the AS OF feature in Oracle SQL, let’s look at a simple example with a table we’ll call CHAT: CREATE TABLE CHAT (CHAT_ID NUMBER(11) PRIMARY KEY, CHAT_USER VARCHAR2(9), YACKING VARCHAR2(40)); CREATE SEQUENCE SEQ_CHAT_ID; There’s our table and a sequence generator; let’s put some data into the CHAT table: INSERT INTO INSERT INTO INSERT INTO INSERT INTO COMMIT; CHAT CHAT CHAT CHAT VALUES VALUES VALUES VALUES (SEQ_CHAT_ID.NEXTVAL, (SEQ_CHAT_ID.NEXTVAL, (SEQ_CHAT_ID.NEXTVAL, (SEQ_CHAT_ID.NEXTVAL, USER, USER, USER, USER, 'Hi there.'); 'Welcome to our chat room.'); 'Online order form is up.'); 'Over and out.'); Next, let’s see what we did—we’ll examine data from the primary key column CHAT_ID, and also a pseudocolumn we haven’t yet examined called ORA_ ROWSCN: SELECT CHAT_ID, ORA_ROWSCN, SCN_TO_TIMESTAMP(ORA_ROWSCN) FROM CHAT; CHAT_ID ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN) ---------------------- ---------------------- ------------------------1 2 3 4 5576336 5576336 5576336 5576336 30-JUL-09 30-JUL-09 30-JUL-09 30-JUL-09 10.43.37.000000000 10.43.37.000000000 10.43.37.000000000 10.43.37.000000000 PM PM PM PM The ORA_ROWSCN pseudocolumn displays the SCN value for the row. We examined the SCN in Chapter 11—remember that the SCN is the system change number, which is assigned by the database and is incremented and assigned automatically by the database for every committed transaction that occurs in the database, for all internal and external transactions, and all explicit and implicit commits.What we see in this example is the primary key and SCN information associated with our inserted rows. Our four INSERT statements specified the use of the sequence generator SEQ_CHAT_ID to assign values to the primary key 590 Chapter 15: Manipulating Large Data Sets CHAT_ID of 1, 2, 3, and 4. The INSERT statements were committed, and the SQL database stored the associated SCN for the commit transaction with each row. This is the value we see in the pseudocolumn ORA_ROWSCN. In the preceding query, we used the conversion function SCN_TO_TIMESTAMP to see the timestamp that corresponds to the SCN values in ORA_ROWSCN. Now we’ll wait a minute or two. If you ever need to build a timed delay into a script, you can use the command EXECUTE DBMS_LOCK.SLEEP(s), executed on a line by itself, complete with semicolon termination character at the end. The parameter s is the number of seconds you wish to delay a process. You can learn more about that command and a great deal more in Oracle’s documentation about PL/SQL packages. PL/SQL is not part of the exam. After a couple of minutes, we’ll delete all of the rows we just added to the database: EXECUTE DBMS_LOCK.SLEEP(120); DELETE FROM CHAT; COMMIT; We’ve just deleted our four rows. Furthermore, we’ve committed the changes. Let’s confirm that the data is gone: SELECT * FROM CHAT; CHAT_ID CHAT_USER YACKING ---------------------- --------- ------------------------------0 rows selected Seems like it’s all gone, doesn’t it? BUT WAIT . . . here comes FQ to the rescue— let’s look at what the CHAT table looked like 90 seconds ago: SELECT * FROM CHAT AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '0 0:01:30' DAY TO SECOND; CHAT_ID ---------------------1 2 3 4 CHAT_USER --------TESTIT TESTIT TESTIT TESTIT YACKING ------------------------------Hi there. Welcome to our chat room. Online order form is up. Over and out. Track the Changes to Data over a Period of Time 591 Note what we are doing here—in the SELECT statement we are using the AS OF clause, in which we query for data in the table as of a moment in time equal to the current time minus a time interval of 0 days, 0 hours, 1 minute, and 30 seconds, specified by the literal value as follows: INTERVAL '0 0:01:30' DAY TO SECOND And suddenly—there’s our data. Yet this data is not currently present in the table—we already eliminated it with a DELETE, and we even used COMMIT to make the changes “permanent”. So where did it come from? The FQ feature retrieves older versions of rows from within Oracle’s rollback segments, the same feature of the database that supports TCL execution. Rollback segments—also known as undo segments—contain older versions of data for as long as the undo retention period allows. The result: We can investigate changes performed to a table over time, within limitations. Those limitations are defined by the undo retention period. undo Retention Period Flashback Query operations can obtain historic data that existed during the time frame specified by the database system’s undo retention period. The duration of the undo retention period depends upon the configuration of your database and its undo management, which is under the control of the database administrator (DBA). In practice, the time frame within which you can recover data using Flashback Query is generally in the range of several minutes to several hours, possibly a day or longer, but generally not much more. You can get some insight into the undo retention period within your database with this query: SELECT NAME, VALUE FROM V$SYSTEM_PARAMETER WHERE NAME LIKE ('undo%'); NAME -----------------------undo_management undo_tablespace undo_retention VALUE -------------AUTO UNDOTBS1 900 592 Chapter 15: Manipulating Large Data Sets This query on the data dictionary view V$SYSTEM_PARAMETER reveals the values of three important initialization parameters. These initialization parameter values are set as follows: n UNDO_MANAGEMENT set to AUTO indicates that the Automatic Undo Management feature is turned on; this is correct to support Flashback Query operations. n The UNDO_TABLESPACE identifies an undo tablespace, which is beyond the scope of the exam and this book—but anyone working with Flashback Operations would benefit from a study of this feature—see one of the Oracle Press books about Oracle database architecture. n The UNDO_RETENTION is specified in seconds—the preceding example shows an undo retention of 900 seconds, which equates to 15 minutes. Note, however, this does not necessarily represent the undo retention period, which depends on this value, but also on available space and other factors beyond the scope of the exam—and this book. The best answer here is: check with your database administrator. As for the undo retention period: there is no absolute time frame that is easily established for flashback support; it is dependent on a series of issues, all of which are under the control of the DBA. FQ Syntax There are two formats for performing an FQ: SELECT * FROM tablename AS OF TIMESTAMP timestamp_expression; and SELECT * FROM tablename AS OF SCN scn_expression; The timestamp_expression or scn_expression cannot be a subquery. One tremendous advantage to accessing historical data in this fashion is that it can be done without changing the table by restoring exported data, and thus overwriting existing data. This means we can query data from multiple timeframes simultaneously, including the present time. For example (line numbers added): Track the Changes to Data over a Period of Time 01 02 03 04 05 06 593 SELECT CHAT_ID, CHAT_USER, YACKING FROM CHAT AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '0 0:01:30' DAY TO SECOND MINUS SELECT CHAT_ID, CHAT_USER, YACKING FROM CHAT; Note our use of the set operator MINUS in line 4. The first SELECT on lines 1 through 3 will return any rows that were in the table at the time specified in line 3, which is 90 seconds prior to the current time. The second SELECT returns all rows in the CHAT table at the current time. By using the set operator MINUS with these two SELECT statements, we are asking to display the difference between their results—in other words, only those rows that have been removed since the timestamp specified in line 3. Let’s look a little more closely at the syntax in line 3 specifically. First are the reserved words AS OF TIMESTAMP. The portion that follows is an expression that evaluates to a datatype of TIMESTAMP: SYSTIMESTAMP - INTERVAL '0 0:01:30' DAY TO SECOND First, the function SYSTIMESTAMP specifies the current date and time according to the Oracle database server’s operating system. From that value, we subtract a time interval, which we specify with this literal value: INTERVAL '0 0:01:30' DAY TO SECOND This literal value specifies a time interval of one minute, thirty seconds. In other words, 90 seconds. The result is that the entire expression evaluates to a timestamp value representing a moment in time that was 90 seconds prior to the current time. If you use Oracle’s FQ using AS OF TIMESTAMP, Oracle will internally translate the timestamp value to the nearest corresponding SCN value and then perform the query using the SCN. Remember that SCN values are assigned systematically within a three-second degree of granularity, and that there is not an exact one-to-one correspondence between timestamp values and SCN values. SELECT statements that use the AS OF clause can be joined to other queries. They can be used to create VIEW objects. They can be used in any way that any other SELECT statement can be utilized. You can create a view with a SELECT ... AS OF statement to more easily investigate older data in a given table. For example, a query to create a view that will display the previous day’s version of the CHAT table is: CREATE VIEW YESTERDAYS_CHAT AS SELECT * FROM CHAT AS OF TIMESTAMP (SYSTIMESTAMP-1); 594 Chapter 15: Manipulating Large Data Sets Flashback Version Query Oracle’s Flashback Version Query (FVQ) takes the FQ feature a step further. With FVQ, you can display rows from multiple committed versions of the database over a range of time. You can perform analysis, do comparisons, and execute virtually any DML statement against any time range of the database. Each row displayed as the result of an FVQ is a committed version of the row that was in the database at some point in the past. FVQ will not show rows that were not committed. If a row was added with the INSERT command and then later removed with a DELETE statement, but never committed during that time with an implicit or explicit commit event, then FVQ will not display the row at all in any form. Only historically committed changes are returned by the FVQ operation, within the range of time specified, and within the range allowed and supported by flashback operations. VERSIONS BETwEEN TIMESTAMP The syntax for FVQ using TIMESTAMP is as follows (line numbers added): 01 02 03 SELECT * FROM tablename VERSIONS BETWEEN TIMESTAMP timestamp_expression1 AND timestamp_expression2; A query using this syntax will show any given row once for each of its versions, however many there were, as they each existed in the table within the range identified by the VERSIONS clause. The preceding syntax has the following rules and guidelines: n The required keywords VERSIONS BETWEEN follow the FROM clause. n If the WHERE clause is included, it follows the VERSIONS BETWEEN clause. n The keyword TIMESTAMP in line 2 is required for the TIMESTAMP variant of VERSIONS BETWEEN. n The values for timestamp_expression1 can be a valid expression with the datatype of TIMESTAMP, or it can be the reserved word MINVALUE, where MINVALUE represents the earliest TIMESTAMP available for the data retained for the table. n The keyword AND in line 3 is required. n The value for timestamp_expression2 can be a valid expression with the datatype of TIMESTAMP, or it can be the reserved word MAXVALUE, where MAXVALUE represents the latest TIMESTAMP available for the data retained for the table. Track the Changes to Data over a Period of Time 595 These rules apply to FVQ with VERSIONS BETWEEN TIMESTAMP. You can also use FVQ with SCN, which we discuss next. VERSIONS BETwEEN SCN You can use FVQ with SCN instead of TIMESTAMP: 01 02 03 SELECT * FROM tablename VERSIONS BETWEEN SCN scn_expression1 AND scn_expression2; Other than the use of SCN, the same syntax rules of VERSIONS BETWEEN TIMESTAMP apply to this variation, including MINVALUE and MAXVALUE. Whenever you use a value of datatype TIMESTAMP to identify a past time in the database, SQL will internally translate that value to the closest SCN that was established at the given time, and use the SCN value to process the statement. Rules of FVQ Note that you cannot use the VERSIONS clause when querying a view. But you can use SELECT with a VERSIONS clause to create a view, meaning that VERSIONS can be included in the subquery of a CREATE VIEW statement. The FVQ feature includes a set of pseudocolumns that provide information about each version of the row, to help identify how each row came to exist, and when. The pseudocolumns are identified in Table 15-2. These pseudocolumns help to clarify the rows that are returned from the FVQ query by differentiating each row from the other. For example: SELECT CHAT_ID, VERSIONS_STARTSCN, VERSIONS_ENDSCN, VERSIONS_OPERATION FROM CHAT VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE ORDER BY CHAT_ID, VERSIONS_OPERATION DESC; CHAT_ID ---------------1 1 2 2 3 3 4 4 VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_OPERATION ---------------------- --------------------- -----------------6311693 6311693 D 6311693 6311693 D 6311693 6311693 D 6311693 6311693 D 596 Chapter 15: Manipulating Large Data Sets TAble 15-2 Pseudocolumn Explanation Flashback Version Query (FVQ) Pseudocolumns VERSIONS_STARTTIME VERSIONS_STARTSCN Starting time or SCN for when the version of the row was created. If NULL, then the row version was created before the lower time boundary returned by the BETWEEN clause. VERSIONS_ENDTIME VERSIONS_ENDSCN Expiration time or SCN for the version of the row. If NULL, then the row version is still current, or the row version resulted from a DELETE (see VERSIONS_OPERATION). VERSIONS_XID Identifies the transaction that created the row. (Useful for Flashback Transaction Query.) VERSIONS_OPERATION Identifies the operation that performed whatever change created the row version: either I for INSERT, U for UPDATE, or D for DELETE. Note that the output shows two versions of rows for each CHAT_ID value. The second row for each CHAT_ID value shows a value of D in the pseudocolumn VERSIONS_OPERATION, indicating that the version represented was deleted with a DELETE statement. A row version is valid on and past its VERSIONS_STARTTIME, and up to but not including its VERSIONS_ENDTIME. In other words, the row version is considered to have been valid at and after the time of its VERSIONS_ STARTTIME, but only valid before the time of its VERSIONS_ENDTIME, not at the same time as the VERSIONS_ENDTIME. The same truths apply to the VERSIONS_STARTSCN and VERSIONS_ ENDSCN. You can combine the AS OF clause and the VERSIONS BETWEEN clause in a single SELECT statement. For example: SELECT CHAT_ID, VERSIONS_STARTSCN, VERSIONS_ENDSCN, VERSIONS_OPERATION FROM CHAT VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '0 00:15:00' DAY TO SECOND ORDER BY CHAT_ID, VERSIONS_OPERATION DESC; Note that the VERSIONS BETWEEN clause precedes the AS OF clause; this is required. When combined, the VERSIONS BETWEEN values are determined AS OF the time specified by the AS OF clause. In other words, the VERSIONS Track the Changes to Data over a Period of Time 597 BETWEEN parameters are defined from the perspective of the AS OF query. Rows that existed later than the AS OF data will return a NULL value. The same is true for rows that precede the first value of the BETWEEN clause. Note that the AS OF and VERSIONS clauses of the SELECT statement are considered ashback operations, even though they do not use the FLASHBACK reserved word in their syntax. Flashback Transaction Query Oracle’s Flashback Transaction Query (FTQ) feature is a query on the data dictionary view FLASHBACK_TRANSACTION_QUERY. The view looks like this: DESC FLASHBACK_TRANSACTION_QUERY; Name Null ------------------------------ -------XID START_SCN START_TIMESTAMP COMMIT_SCN COMMIT_TIMESTAMP LOGON_USER UNDO_CHANGE# OPERATION TABLE_NAME TABLE_OWNER ROW_ID UNDO_SQL Type ----------------------RAW(8) NUMBER DATE NUMBER DATE VARCHAR2(30) NUMBER VARCHAR2(32) VARCHAR2(256) VARCHAR2(32) VARCHAR2(19) VARCHAR2(4000) Note the first column in the view: XID. This is the global transaction identifier. Each transaction that is executed within the database is tracked and assigned a global transaction identifier, which is essentially a transaction identification number. The XID value is of the RAW datatype, which is a binary value, and is not interpreted by the Oracle database. But it can be converted into readable form using the RAWTOHEX function, which converts RAW data into character data that represents the hexadecimal equivalent of the RAW data, which is binary. The function HEXTORAW converts character data containing hexadecimal notation back into the RAW datatype. 598 Chapter 15: Manipulating Large Data Sets Hexadecimal refers to a base-16 numeric scale. Decimal, of course, is base-10, and binary is base-2. Because there is a direct exponential relation between base-2 and base-16, hexadecimal notation, or hex, is a great way to present base-2 data in a relatively succinct fashion. If any of this is confusing to you, don’t worry—you don’t need to understand it all for the exam—but do be aware of the RAW datatype and the ability to convert to character output in hexadecimal notation. The XID column in the data dictionary view FLASHBACK_TRANSACTION_ QUERY corresponds to the FVQ VERSIONS_XID pseudocolumn we saw in Table 15-2. We can use that pseudocolumn in an FVQ to locate a specific transaction that caused a change to a table, and then use the FLASHBACK_TRANSACTION_ QUERY data dictionary view to identify the specific SQL statement and its associated UNDO_SQL value—which is the SQL that can undo the transaction. For example, let’s look at our CHAT table again, but this time let’s use the RAWTOHEX conversion function to display the contents of the VERSIONS_XID pseudocolumn, which would be otherwise unreadable: SELECT FROM VERSIONS WHERE ORDER BY CHAT_ID, VERSIONS_OPERATION, RAWTOHEX(VERSIONS_XID) CHAT BETWEEN TIMESTAMP MINVALUE AND MAXVALUE CHAT_ID = 1 VERSIONS_OPERATION DESC; This query shows all versions of the row in the CHAT table for which the primary key of CHAT_ID is equal to 1. Note the WHERE clause follows the VERSIONS BETWEEN clause. Here is the output from our table: CHAT_ID VERSIONS_OPERATION RAWTOHEX(VERSIONS_XID) ---------------------- ------------------ ---------------------1 1 D 04002000C10E0000 That’s our output. We don’t need to display this output in order to get the UNDO_ SQL value for this transaction though; we can use a subquery, like this: SELECT UNDO_SQL FROM FLASHBACK_TRANSACTION_QUERY WHERE XID = (SELECT VERSIONS_XID FROM CHAT VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE WHERE CHAT_ID = 1 AND VERSIONS_OPERATION = 'D'); Track the Changes to Data over a Period of Time 599 The preceding query is asking the data dictionary view FLASHBACK_ TRANSACTION_QUERY for the value in the UNDO_SQL column that corresponds to our CHAT table row in which the CHAT_ID is equal to 1, in the version that was deleted. Here is the answer—and please note—the output is too wide to be displayed in the book, so we’ve allowed it to line-wrap, and displayed the line numbers to let you know where each row begins: 01 02 03 04 05 06 UNDO_SQL ---------------------------------------------------------------------insert into "EFCODD"."CHAT"("CHAT_ID","CHAT_USER","YACKING") values ('4','EFCODD','Over and out.'); insert into "EFCODD"."CHAT"("CHAT_ID","CHAT_USER","YACKING") values ('3','EFCODD','Online order form is up.'); insert into "EFCODD"."CHAT"("CHAT_ID","CHAT_USER","YACKING") values ('2','EFCODD','Welcome to our chat room.'); insert into "EFCODD"."CHAT"("CHAT_ID","CHAT_USER","YACKING") values ('1','EFCODD','Hi there.'); Note that our UNDO_SQL value for just the one row where CHAT_ID = 1 shows four INSERT statements. Why? Because the transaction that caused the CHAT_ID = 1 row to be deleted was a single DELETE statement that didn’t just delete the one row, but all the rows that existed in the table at that time—in other words, all four of these rows. Therefore, the UNDO_SQL statement that is required to undo that DELETE statement will quite correctly restore all four rows. That is what this Note that a “transaction” UNDO_SQL column shows—the necessary in SQL is not necessarily just one SQL SQL code that will undo the transaction. statement.Technically speaking, a single If you were to execute these SQL statements, “transaction” consists of all the SQL you would effectively “undo” the DELETE that statements that are executed from removed the CHAT_ID row of 1—and all the one commit event to another commit other rows as well. event. Keep in mind that a ROLLBACK In this example, we only reviewed the statement can interrupt a transaction contents of the UNDO_SQL column, but and resets the starting point of the next as you can see from the description of the transaction. SCN values are assigned FLASHBACK_TRANSACTION_QUERY to transactions. UNDO_SQL shows the view that we displayed earlier, there is much code to undo the effects of a single SQL more information available—such as the SCN statement, which may be less than a single at the time of the COMMIT that saved the transaction as defined in this paragraph. changes, and more. 600 Chapter 15: Manipulating Large Data Sets Note that the UNDO_SQL code cannot necessarily perform a complete restoration of all the data throughout the database as it existed before—depending on the situation. For example, the ROWID values won’t be the same. And depending on the sequence of changes that have occurred, you may need to step through a series of undo statements, and you won’t be able to just jump quickly to a previous state of the table using this technique. CertIFIcAtIon SummArY Subqueries can be used in SQL statements to process large numbers of database rows from within a single SQL statement. The CREATE TABLE statement can use a subquery to populate a table and assign its column names and datatypes all at the same time. The UPDATE statement can use a correlated subquery to update multiple columns and multiple rows using varying values and varying comparison conditions. The INSERT statement can be augmented with a number of clauses to introduce conditional logic into its execution, and to add data to more than one table from within a single INSERT statement. Conditional logic can be added with a WHEN condition and optionally the ELSE keyword. The INSERT ALL form will test incoming data against each WHEN condition, and the INSERT FIRST form will stop at the first WHEN condition that evaluates to true. In either situation, the optional ELSE clause can define an insert that will execute if all previous WHEN conditions failed. Conditional INSERT statements may be used to “pivot” data from columns into rows and back again. The MERGE statement does not do anything you cannot otherwise do with a series of other DML statements, but its advantage is its powerful ability to perform multiple operations from within a single SQL statement, and therefore a single execution and single pass through the database. Oracle’s flashback operations analyze data over time. The AS OF clause of the SELECT statement can query a table at a particular moment in time, as far back as the undo retention period supports. The VERSIONS BETWEEN clause compares rows of data in all its different versions over time. The data dictionary view FLASHBACK_TRANSACTION_QUERY supports many forms of analysis, including the ability to identify the UNDO_SQL code that can logically reverse the effects of a given DML statement. Two-Minute Drill 3 601 Two-MInute DrIll Manipulate Data using Subqueries q The CREATE TABLE AS SELECT statement, also known as CTAS, uses a subquery to populate the new table’s rows. q CTAS can also be used to name each column in the new table. q CTAS can also define the datatype of each new column. q Subqueries in CTAS must provide a name for each column; complex expres- sions should be named with a column alias. q The UPDATE statement can use a correlated subquery to set values to one or more columns from one or more rows within a data source at one time. q In the UPDATE statement with correlated subquery, the table alias for the UPDATE table can be referenced within the subquery. q The INSERT statement can be used with a subquery to insert more than one row at a time. Describe the Features of Multitable INSERTs q Multitable inserts are useful for applying conditional logic to the data being considered for insertion. q Conditional logic can evaluate incoming rows of data in a series of steps, using several evaluation conditions, and offer alternative strategies for adding data to the database, all in a single SQL statement. q Multitable INSERT statements offer flexibility and performance efficiency over the alternative approaches of using multiple SQL statements. use the Following Types of Multitable INSERTs: unconditional, Conditional, and Pivot q Multitable INSERT statements may use conditional operations such as the WHEN condition and the ELSE clause. q A WHEN condition can be used to evaluate incoming data and determine if it should be inserted into the database, and if yes, which table and which columns are to be inserted. 602 Chapter 15: Manipulating Large Data Sets q The ELSE clause is a last alternative choice that will execute if no WHEN condition evaluated to true. q Both WHEN and ELSE are associated with their own unique INSERT statement directives; depending on which conditions apply, the appropriate INSERT statement directives will execute. q Each condition can INSERT data in different ways into different tables. q The INSERT FIRST statement tests each WHEN condition and executes the associated INSERT statement directives with the first WHEN condition that evaluates to true. q The INSERT ALL statement executes all of the WHEN conditions that evaluate to true. q The ELSE clause executes for either the INSERT FIRST or INSERT ALL statement when none of the WHEN conditions have executed. q The subquery of a multitable INSERT determines the data that will be con- sidered in the insert logic; it can be a complex query, and can include joins, GROUP BY clauses, set operators, and other complex logic. Merge Rows in a Table q The MERGE statement is one of the SQL DML statements, alongside SELECT, INSERT, UPDATE, and DELETE. q MERGE replicates some of the functionality found in INSERT, UPDATE, and DELETE and combines it all into a single statement that executes with a single pass through the database. q MERGE doesn’t do anything new that you cannot already do with existing DML statements, but it does them more efficiently in combination. q The MERGE statement includes an “update clause” and an “insert clause”. q The WHEN MATCHED THEN UPDATE keywords form the “update clause”. q The WHEN NOT MATCHED THEN INSERT keywords form the “insert clause”. q The DELETE clause of the MERGE statement only deletes rows that were first updated with the “update clause” and remain after a successful update; they must also meet the WHERE condition of the “delete clause”. Two-Minute Drill 603 Track the Changes to Data over a Period of Time q The AS OF clause of SELECT can query data in the table as it existed AS OF a particular time in the past, as defined by a TIMESTAMP value or SCN, and within the limitations of the undo retention period. q The AS OF clause comes after the FROM and before any WHERE clause that might be used within the SELECT statement. q The VERSIONS BETWEEN clause can display rows as they existed in their various states of changes within a range of time. q The VERSIONS BETWEEN clause marks time ranges in terms of SCN or timestamp values. q The VERSIONS BETWEEN clause activates a number of pseudocolumns to identify the time range and other data associated with the historic data returned by the VERSIONS BETWEEN clause. q The data dictionary view FLASHBACK_TRANSACTION_QUERY can be used with the VERSIONS BETWEEN clause to identify metadata associated with a particular transaction that caused the changes to a particular version of the row returned by the VERSIONS BETWEEN clause. 604 Chapter 15: Manipulating Large Data Sets SelF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Manipulate Data using Subqueries 1. A CREATE TABLE statement can include a subquery as long as the subquery satisfies which of the following requirements? A. It cannot use any joins. B. It must have column names for each column specified. C. It must return data. D. None of the above. 2. Review the diagrams of the tables PORT_INVENTORY, STORE_INVENTORY, and SHIP_INVENTORY, shown below: Now consider the following SQL statement: INSERT INTO STORE_INVENTORY (NUM, PRODUCT) {keyword} SELECT SEQ_SHIP_NUM.NEXTVAL, PRODUCT FROM PORT_INVENTORY; Self Test 605 Which of the following replaces the {keyword} reference in this INSERT statement in order to form a valid INSERT statement? A. VALUES B. AS C. IN D. Nothing Describe the Features of Multitable INSERTs 3. An INSERT statement can: (Choose two.) A. Add rows into more than one table. B. Add data into more than one column in a table. C. Delete rows by overwriting them. D. Join tables together. 4. A multitable INSERT statement: A. Can accomplish tasks that cannot otherwise be done in any combination of SQL statements. B. Will create any tables in which it attempts to INSERT but that do not yet exist. C. Can use conditional logic. D. Is capable of inserting rows into non-updatable views. use the Following Types of Multitable INSERTs: unconditional, Conditional, and Pivot 5. Review the diagrams of the SPARES table below: Also examine the diagrams in question 2, and consider the following SQL statement (line numbers added): 01 02 03 INSERT ALL WHEN (SUBSTR(PART_NAME,1,4) = 'MED-') THEN INTO STORE_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) 606 04 05 06 07 08 09 10 11 Chapter 15: Manipulating Large Data Sets VALUES (SPARE_ID, 'Back', PART_NAME, SYSDATE) INTO SHIP_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) VALUES (SPARE_ID, 'Back', PART_NAME, SYSDATE) WHEN (SUBSTR(PART_NAME,1,4) = 'ARR-') THEN INTO PORT_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) VALUES (SPARE_ID, 'Back', PART_NAME, SYSDATE) SELECT SPARE_ID, PART_NO, PART_NAME FROM SPARES; Regarding this SQL statement, which of the following statements is true? A. The statement will fail because there is no ELSE clause. B. The statement will fail because it is missing a WHEN condition. C. The statement will add a row returned from the SPARES table to the SHIP_INVENTORY table only if the WHEN condition on line 2 evaluates to true. D. The statement will add every row returned from the SPARES table to the SHIP_INVENTORY table. 6. Review the SQL statement in the preceding question. If one of the INTO clauses executed on a table and resulted in a constraint violation on that table, what would result? A. The row would not be inserted and the INSERT statement would skip to the next row returned by the subquery, and perform another pass through the WHEN conditions. B. The row would not be inserted and the INSERT statement would stop. No additional rows would be returned by the subquery or processed, but rows that have already been processed are unaffected. C. The row would not be inserted, the INSERT statement would stop, and all rows affected by the INSERT statement would be rolled back, as if the INSERT statement had never been executed. D. None of the above. 7. Review the diagrams in question 2 and question 5, and consider the following SQL statement (line numbers added): 01 02 03 04 05 06 07 08 09 INSERT FIRST WHEN (SUBSTR(PART_NAME,5,3) = 'OPS') THEN INTO STORE_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) VALUES (SEQ_NUM.NEXTVAL, 'Back', PART_NAME, SYSDATE) WHEN (SUBSTR(PART_NAME,1,4) = 'PAN-') THEN INTO SHIP_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) VALUES (SEQ_SHIP_NUM.NEXTVAL, 'Back', PART_NAME, SYSDATE) ELSE INTO PORT_INVENTORY (NUM, AISLE, PRODUCT, LAST_ORDER) Self Test 10 11 12 13 607 VALUES (SEQ_PORT_NUM.NEXTVAL, 'Back', PART_NAME, SYSDATE) SELECT SPARE_ID, PART_NO, PART_NAME FROM SPARES WHERE LENGTH(PART_NO) > 2; Which one of the following answers correctly identifies data that, if present in the SPARES table, will be inserted by this conditional INSERT statement into the table—or tables— identified by the answer? A. PART_NO = 123; PART_NAME = ‘BAH-OPS,’ in both STORE_INVENTORY and PORT_INVENTORY B. PART_NO = 401; PART_NAME = ‘PAN-OPS,’ in both SHIP_INVENTORY and PORT_INVENTORY C. PART_NO = 170; PART_NAME = ‘TRA-OPS,’ in STORE_INVENTORY D. PART_NO = 4; PART_NAME = ‘PAN-OPS,’ in both STORE_INVENTORY and SHIP_INVENTORY 8. Review the diagrams in question 2 and question 5, and examine the following statement (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 INSERT WHEN (PART_NO < 500) THEN INTO STORE_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) INTO PORT_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) WHEN (PART_NO >= 500) THEN INTO SHIP_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) SELECT SPARE_ID, PART_NO, PART_NAME FROM SPARES; Which of the following statements are true for this SQL statement? A. If the first WHEN condition in line 2 is true, the INTO clause in line 3 through line 4 will be executed, after which processing will skip to the next row returned by the subquery. B. If the first WHEN condition in line 2 is true, the WHEN condition in line 7 will not be evaluated. C. No matter which WHEN condition is true, the INTO clause in line 5 will be executed regardless. D. Regardless of whether the first WHEN condition is true or not, the second WHEN condition will be evaluated. 608 Chapter 15: Manipulating Large Data Sets 9. Let’s modify the SQL statement from the last exercise and add a sequence generator to the subquery (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 INSERT WHEN (PART_NO < 500) THEN INTO STORE_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) INTO PORT_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) WHEN (PART_NO >= 500) THEN INTO SHIP_INVENTORY (NUM, PRODUCT) VALUES (SPARE_ID, PART_NAME) SELECT SEQ_SPARES_ID.NEXTVAL SPARE_ID, PART_NO, PART_NAME FROM SPARES; Which one of the following statements is true? A. The statement will fail with a syntax error. B. The statement will execute but only NULL values will be inserted for numbers into the target tables identified in the INTO clauses. C. The statement will execute but the same number will be generated for all the rows inserted. D. The statement will execute and perform successfully. Merge Rows in a Table 10. The MERGE statement includes a USING clause. Which of the following statements is NOT true of the USING clause? A. It can be used to specify a subquery. B. The data it identifies remains unchanged after the MERGE statement executes. C. The USING clause is optional. D. It can be used to specify an inline view. 11. See the diagrams in question 2. You want to merge rows from the PORT_INVENTORY table into the SHIP_INVENTORY table. You start with the following SQL statement: 01 02 03 04 05 06 07 08 MERGE INTO SHIP_INVENTORY A USING PORT_INVENTORY B ON (A.NUM = B.NUM) WHEN NOT MATCHED THEN INSERT (A.NUM, A.AISLE, A.PRODUCT, A.LAST_ORDER) VALUES (B.NUM, B.AISLE, B.PRODUCT, B.LAST_ORDER) WHERE TO_CHAR(A.LAST_ORDER,'RRRR') = '2009'; Self Test 609 What will this SQL statement do? A. It will fail with a syntax error because you must have an ELSE clause. B. It will fail with a syntax error because you cannot reference the target table (SHIP_INVENTORY) in the WHERE clause in line 8. C. It will add rows from PORT_INVENTORY to SHIP_INVENTORY that do not already exist in SHIP_INVENTORY, limited to LAST_ORDER values from the year 2009. D. It will add rows from PORT_INVENTORY to SHIP_INVENTORY that do not already exist in SHIP_INVENTORY, regardless of the value for LAST_ORDER. 12. Examine the SQL syntax in the last statement. Which of the following two alternatives for line 3 are syntactically correct? OPTION 1: OPTION 2: A. B. C. D. ON (A.NUM = B.NUM AND A.AISLE = B.AISLE) ON (A.LAST_ORDER < B.LAST_ORDER) Only option 1 Only option 2 Both option 1 and option 2 Neither option 1 nor option 2 Track the Changes to Data over a Period of Time 13. Which one of the following is a valid SQL statement? A. SELECT * FROM SHIPS AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '0 00:30:00' DAY TO SECOND; B. SELECT * FROM SHIPS WHERE VERSIONS BETWEEN IN (MINVALUE AND MAXVALUE); C. SELECT * FROM SHIPS AS OF SCN (SELECT ORA_ROWSCN-50 FROM SHIPS WHERE ROWNUM < 2); D. SELECT * FROM SHIPS AS OF DATE SYSDATE - INTERVAL '0 00:30:00' DAY TO SECOND; 610 Chapter 15: Manipulating Large Data Sets 14. How does a table change as the result of the execution of a valid flashback operation using the AS OF clause? A. The table is restored to its state at the beginning of the undo retention period. B. The table is enhanced with additional historic data it did not contain before. C. It’s impossible to know what happens to the table. D. No change occurs to the table. 15. Examine this SQL code (line numbers added): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 CREATE TABLE PROMOTIONS (PROMOTION_ID NUMBER(7), PROMOTER VARCHAR2(30)); INSERT INTO PROMOTIONS VALUES (1,'Barnum'); COMMIT; EXECUTE DBMS_LOCK.SLEEP('120'); UPDATE PROMOTIONS SET PROMOTER = 'P.T. Barnum.' WHERE PROMOTION_ID = 1; INSERT INTO PROMOTIONS VALUES (2,'D. King'); EXECUTE DBMS_LOCK.SLEEP('240'); DELETE FROM PROMOTIONS; COMMIT; SELECT PROMOTION_ID, PROMOTER, VERSIONS_OPERATION, RAWTOHEX(VERSIONS_XID) VERSIONS_XID FROM PROMOTIONS VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE; The SELECT statement on line 13 will return data that includes values for VERSIONS_XID. Which SQL statements will be represented in the output of this SELECT statement? Choose all that apply. A. Line 4—INSERT B. Line 7—UPDATE C. Line 9—INSERT D. Line 11—DELETE Self Test Answers 611 SelF Test Answers Manipulate Data using Subqueries 1. ˛ D. None of the items listed is a restriction on the subquery of a CTAS. ˝ A, B, and C are incorrect. Joins are allowed. The subquery is not required to have column names for each column specified if the CTAS provides names in the CREATE TABLE clause. Returned data is not required. 2. ˛ D. There is no keyword for this form of INSERT statement. The subquery itself is sufficient and correct. ˝ A, B, and C are incorrect. Any attempt to use the keywords VALUES, AS, or IN in this context will result in a syntax error. Describe the Features of Multitable INSERTs 3. ˛ A and B. INSERT statements can add rows to more than one table using conditional and unconditional logic. INSERT statements can also add data to more than one column in any given table. ˝ C and D are incorrect. INSERT cannot overwrite data; it adds new rows to a table. INSERT does not perform joins. 4. ˛ C. Multitable INSERT statements can use conditional logic, with statements such as WHEN and ELSE. ˝ A, B, and D are incorrect. Multitable INSERTS do not do anything you couldn’t otherwise do with one or more SQL statements. Their advantage is that they can accomplish complex SQL tasks in a single pass that might otherwise require multiple passes through the database, thus yielding performance advantages. And nothing can add rows into a non-updatable view— if it’s not updatable, it’s not updatable. use the Following Types of Multitable INSERTs: unconditional, Conditional, and Pivot 5. ˛ C. The WHEN condition in line 2 determines whether the INTO clauses in lines 3, 4, 5, and 6 will execute. ˝ A, B, and D are incorrect. The ELSE clause is not required. No particular WHEN condition is required. The INTO clause for SHIP_INVENTORY is subject to the WHEN condition in line 2. 612 Chapter 15: Manipulating Large Data Sets 6. ˛ C. The entire statement fails, and all inserted rows are rolled back. It is as if the statement had never been executed. Had this statement included any calls to a sequence generator and its NEXTVAL pseudocolumn would have advanced the count in the generator, that effect would remain unchanged. However, this example does not include any sequence generators, so that particular exception does not apply. ˝ A, B, and D are incorrect. 7. ˛ C. The PART_NO of 170 has a length of 3, and that is longer than 2, so the WHERE clause in line 13 is found to be true, and the row will be evaluated by the rest of the INSERT FIRST statement. Next, the PART_NAME of PAN-OPS will cause the first WHEN condition to be true, and since this is an INSERT FIRST statement, no other WHEN condition will be considered. ˝ A, B, and D are incorrect. These answers result from various interpretations of the WHEN conditions and ELSE. In an INSERT FIRST statement, the first WHEN condition that evaluates to true is the only condition that is executed. All others are ignored. If no WHEN is found to be true, then the optional ELSE clause will be processed. 8. ˛ D. Both WHEN conditions will be evaluated because the conditional INSERT is an INSERT ALL statement. ˝ A, B, and C are incorrect. If the first WHEN condition is true, both INTO clauses that follow it will be executed—that includes the INTO on line 5 through line 6. Whether the first WHEN condition is true or false, the second will also be evaluated, since this is an INSERT ALL statement. The INTO in line 5 through line 6 will only be evaluated if the first WHEN condition is true. 9. ˛ A. The statement will yield a syntax error and not execute. No sequence generator is allowed in the subquery. ˝ B, C, and D are incorrect. Oracle Corporation formally advises against using a sequence generator in a multitable INSERT statement. While it will be rejected in the subquery, a sequence generator may be included in the VALUES clause of the INTO statement but with potentially unpredictable or undesirable results. Merge Rows in a Table 10. ˛ C. The USING clause is not optional; it is required in the MERGE statement. ˝ A, B, and D are incorrect. USING can identify a table, view, or subquery. An inline view is also acceptable. It identifies the source of data to be merged; the source data remains unchanged after the MERGE statement is executed. 11. ˛ B. It will fail because the WHERE clause references something that is not in the source table. The WHERE clause is an extension of USING, which specifies the target table. The A table alias reference is meaningless and will fail. Self Test Answers 613 ˝ A, C, and D are incorrect. There is no ELSE clause in MERGE, so it is not only not required, it is not accepted. 12. ˛ C. Both options are acceptable. The ON condition can be any comparison of expressions, and it can include Boolean operators. ˝ A, B, and D are incorrect individually. Track the Changes to Data over a Period of Time 13. ˛ A. The statement SELECT with AS OF TIMESTAMP is syntactically correct. ˝ B, C, and D are incorrect. You do not put VERSIONS BETWEEN after the WHERE clause, much less as a part of the WHERE clause. VERSIONS BETWEEN, if used, precedes the WHERE clause, if used. Also, VERSIONS BETWEEN does not use the IN keyword. The AS OF SCN clause cannot take a subquery as an argument. The AS OF clause only works with SCN and TIMESTAMP, not DATE values, so the SYSDATE option won’t be accepted, nor will the DATE keyword. 14. ˛ D. No change occurs to the table. Flashback operations leverage data that is already in the undo segments, but cause no changes to occur to the table. ˝ A, B, and C are incorrect. 15. ˛ A and D. The INSERT on line 4 was committed, and the row it created was removed with the DELETE statement in line 11, which was also committed. The other statements were not explicitly committed, so therefore are not included. ˝ B and C are incorrect. The UPDATE in line 7 was not committed, nor was the INSERT in line 9; both were removed with the DELETE before a COMMIT event occurred, therefore they were omitted. The curious thing about this DELETE statement is that it removed the committed row from line 4, and the uncommitted changes from lines 7 and 9. Only the committed events are identified in the VERSIONS BETWEEN feature, so some of the DELETE statement’s effects are tracked, but others are not. This page intentionally left blank 16 Hierarchical Retrieval CertIFIcAtIon ObJectIVes 16.01 Interpret the Concept of a Hierarchical Query 16.02 Create and Format Hierarchical Data 16.03 3 Q&A Exclude Branches from the Tree Structure Two-Minute Drill Self Test 616 Chapter 16: Hierarchical Retrieval T his chapter discusses the hierarchical query which is based on data structured in a self-join table or view. The hierarchical query uses clauses in the SELECT statement to create a dynamic, tree-structured report appropriate for corporate organization charts, a distribution chain, family genealogy research, or any situation that requires a multilevel data structure. CertIFIcAtIon ObJectIVe 16.01 Interpret the Concept of a hierarchical Query The hierarchical query extends the typical parent-child relationship into a multigenerational construct. In the typical parent-child relationship, one table will contain parent rows, and another table will contain child rows. In other words, only two generations are represented. For example, we’ve already seen our PORTS table, which contains data about ports, and where each port can be home to one or more ships in the SHIPS table. In this situation, each PORT row may be a parent to any SHIP row. In other words, we have the parent row’s generation, and the child row’s generation, and no more generations beyond these two. Hierarchical data is structured differently to allow for the possibility of multiple generations. Instead of two separate tables with one parent table and one child table, all data is contained within a single table or comparable structure (such as a view), and the multiple generations are defined based on the data within each row. The result is that we might have parent–child–grandchild–great-grandchild, and so on. The hierarchical structure allows for a theoretically endless number of generations. The classic example of a hierarchy is an organization chart, in which a CEO is the top level, or the root node, and everyone in the organization who reports directly to the CEO is a child record at the second level. Furthermore, each employee who reports to the second level is a grandchild of the root node and exists at the third level relative to the root node, and so on (see Figure 16-1). The first level shows the CEO, which serves as the root node of this hierarchy. The second level consists of nodes that report to the root node. Each of these represents a branch in the tree, where the CFO ends its particular branch, making it a leaf node. But the other two nodes continue to Level 3, and so on. Nodes that extend to two or more additional nodes at the next level are considered forks. Nodes that do not fork are just nodes. For example—see Interpret the Concept of a Hierarchical Query 617 FIGure 16-1 Architecture of a hierarchical join Level 1 Root Node CEO Leaf Node Level 2 Node SVP VP CFO Node Node Level 3 Director 1 Director 2 Director 4 Leaf Node Leaf Node Level 4 Director 3 Manager 1 Leaf Node Leaf Node “Director 2” in Level 3. The organization branches from that node to Level 4, but only to one node of “Manager 1”, so the “Director 2” node would not be considered a fork. But the nodes for the VP and SVP would be considered forks. In SQL, the structure that would hold all of the information for these nodes and their relationships may consist of just one table with a self-join. Let’s look at an example. First, let’s create a table that will support a hierarchical structure: CREATE TABLE EMPLOYEE_CHART ( EMPLOYEE_ID NUMBER(7) PRIMARY KEY, TITLE VARCHAR2(20), REPORTS_TO NUMBER(7)); The EMPLOYEE_CHART table will store data from our organizational chart in Figure 16-1. For the table, we created a PRIMARY KEY constraint. We also included a column for TITLE, showing the titles from Figure 16-1. We also added a column called REPORTS_TO that will contain the EMPLOYEE_ID of the superior in the organization. In order to apply a constraint to this column, let’s add a foreign key for it: ALTER TABLE EMPLOYEE_CHART ADD CONSTRAINT FK_EM_EM FOREIGN KEY (REPORTS_TO) REFERENCES EMPLOYEE_CHART (EMPLOYEE_ID); 618 Chapter 16: Hierarchical Retrieval This foreign key isn’t necessarily required to make the hierarchical query perform correctly. But it’s good design; it documents the intention of the REPORTS_TO column, showing that its values will come from the EMPLOYEE_ID column of the same table. Next we’ll add the following data so that the table’s contents appear as follows: EMPLOYEE_ID ---------------------1 2 3 4 5 6 7 8 9 TITLE -------------------CEO VP SVP CFO Director 1 Director 2 Director 3 Director 4 Manager 1 REPORTS_TO ---------------------1 1 1 2 2 3 3 6 Note the structure, where each row contains a primary key value for EMPLOYEE_ID, and also a foreign key in the REPORTS_TO column. The value for REPORTS_TO is the EMPLOYEE_ID value of another row. For example, “Manager 1” reports to “Director 2” as evidenced by the REPORTS_TO column’s value of 6, which matches the EMPLOYEE_ID for “Director 2”. This is the type of data structure that supports a hierarchical query. This relationship is a “self-join” and is fully extensible—the levels in the hierarchy can easily be extended beyond the four levels represented here. To create a hierarchical query on this data structure, we’ll need to look at some new features of the SELECT statement, which we address in the next section. CertIFIcAtIon ObJectIVe 16.02 Create and Format hierarchical Data In our last section, we built a data structure to support a hierarchical query. The diagram for that structure is represented in Figure 16-2. Create and Format Hierarchical Data 619 FIGure 16-2 Diagram for the EMPLOYEE_ CHART table To create a hierarchical query, we use the SELECT statement clauses START WITH and CONNECT BY, as follows (line numbers added): 01 02 03 04 SELECT FROM START WITH CONNECT BY LEVEL, EMPLOYEE_ID, TITLE EMPLOYEE_CHART EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID; In the preceding SQL statement, we do the following: n Line 3: The START WITH clause identifies the root node of our query. In this case, we’re choosing to start with the row containing information about the CEO, which we specify by identifying a START WITH EMPLOYEE_ID = 1, which is pointing to the primary key of the CEO. It is good design to use the primary key here, but it’s not syntactically necessary—any expression that uniquely identifies a row in the table will accomplish the task. n Line 4: We establish the self-join hierarchical relationship using CONNECT BY and PRIOR. By specifying that we wish to connect each row by relating the REPORTS_TO column to the EMPLOYEE_ID column, we’re identifying the values to use when comparing one row to another. But the placement of the keyword PRIOR is critical—it must be placed before one of the two column references. The choice determines if the hierarchy will traverse up the tree or down the tree from the START WITH row. In this example, PRIOR is placed before the EMPLOYEE_ID reference. This indicates that for each row in the EMPLOYEE_CHART table, SQL will go find the next row in the hierarchy by locating a row with a REPORTS_TO value that is equal to the PRIOR row’s EMPLOYEE_ID value. n Line 1: We’ve chosen to add a reference to the LEVEL pseudocolumn, which is available to any hierarchical query that uses the START WITH and CONNECT BY clause. Once the keywords START WITH and CONNECT 620 Chapter 16: Hierarchical Retrieval BY are included, LEVEL is automatically defined to show the hierarchical level of the row relative to the root node of the hierarchical query, as defined in the START WITH clause. Its use isn’t required. The output of this query looks like this: LEVEL ----------------1 2 3 3 4 2 3 3 2 EMPLOYEE_ID ---------------------1 2 5 6 9 3 7 8 4 A single SELECT statement may define a join and also a CONNECT BY.The join may be defined with the keyword JOIN or with a WHERE clause. If that is the case, the order of processing is: the join (as defined by JOIN or WHERE), then the CONNECT BY, and finally the remaining WHERE clause predicates. When combined with a join, CONNECT BY treats the joined rows as a view, and performs the hierarchical query as if the combined rows were a single table. Note that the pseudocolumn LEVEL should not be given a table alias in a joined query with CONNECT BY. TITLE -------------------CEO VP Director 1 Director 2 Manager 1 SVP Director 3 Director 4 CFO Notice that the LEVEL value corresponds to the diagram we looked at originally in Figure 16-1. That happens to be true in this situation because we chose to START WITH the CEO node and work our way down the tree. However, note that the value for LEVEL is calculated relative to the root node of the query, and we could have chosen a different root node within this same data. More on that in a bit. Oracle formally stipulates that the CONNECT BY clause must have one occurrence of the keyword PRIOR included within it. This is documented but as of this writing isn’t built into the system—you will not receive a syntax error if you omit the PRIOR clause. But note that you are required to include it in order to satisfy the documented requirements of the CONNECT BY clause. The START WITH and CONNECT BY clauses are both required to create a hierarchical query. The order of clauses is not Create and Format Hierarchical Data 621 important—either clause can precede the other. However, the SELECT statement’s WHERE clause, if used, must precede both START WITH and CONNECT BY. Furthermore, the ORDER BY clause, if used, follows both START WITH and CONNECT BY. And beware, the ORDER BY clause, when used with hierarchical queries, requires special consideration, which we’ll get in to a bit later. Create a Tree-Structured Report One common technique for using LEVEL is to incorporate it into some formatting functions to produce more readable output. For example, the LPAD function can be used to add spaces and indent the TITLE values based on the level each value represents. Here’s an example: SELECT FROM START WITH CONNECT BY LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE EMPLOYEE_CHART EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID; This query concatenates spaces in front of the TITLE data to indent the start of whatever value is included in each row. In this example, LPAD will add more spaces for greater levels; for each LEVEL, two spaces are indented. The results are as follows: LEVEL ----------------1 2 3 3 4 2 3 3 2 EMPLOYEE_ID TITLE ----------------- --------------------------1 CEO 2 VP 5 Director 1 6 Director 2 9 Manager 1 3 SVP 7 Director 3 8 Director 4 4 CFO The result is output that is easier to read—as you glance down the column of values for TITLE, you can see more easily where TITLE values of the same level are lined up. This sort of technique is one common way to display hierarchical data from a self-join. 622 Chapter 16: Hierarchical Retrieval Choosing Direction In a hierarchical query, the choice of where to place the keyword PRIOR is instrumental in determining the direction of the query. Our example started with the CEO row and moved down through the chain of command: CONNECT BY REPORTS_TO = PRIOR EMPLOYEE_ID To move in the opposite direction, move the PRIOR keyword to the opposite side of the equal sign, like this: CONNECT BY PRIOR REPORTS_TO = EMPLOYEE_ID However, if your query is starting at one end of the hierarchy already, then to move in the opposite direction won’t get you more than one row—you’re already at one end of the query. A reverse hierarchical query is more helpful when starting at another location in the hierarchy, such as one of the leaf nodes of the overall organization chart, like this: SELECT FROM START WITH CONNECT BY LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE EMPLOYEE_CHART EMPLOYEE_ID = 9 PRIOR REPORTS_TO = EMPLOYEE_ID; Here we are beginning our hierarchy with EMPLOYEE_ID = 9, which is the “Manager 1” title, and moving up the org chart toward the CEO, as is indicated by reversing the position of the keyword PRIOR. The results are as follows: LEVEL -------------1 2 3 4 EMPLOYEE_ID TITLE ----------------- ------------------------------9 Manager 1 6 Director 2 2 VP 1 CEO Notice that this results in a more limited number of rows. By starting from the position of the “Manager 1” row and working our way up, we are only connecting to those rows in the hierarchy that have a directly upward relationship to the starting point. Note that the LEVEL value shows the level relative to the root node of the query—not necessarily the root node of the overall hierarchy within the table. In other words, in our example, “Manager 1” is at LEVEL 1, and the CEO is at LEVEL 4. We are not limited to starting our hierarchical query from the root node or a leaf node; we could initiate from somewhere within the query at any node and work in either direction. Create and Format Hierarchical Data 623 Remember, to reverse direction in a hierarchical query, move PRIOR to the other side of the equal sign. Also, if you prefix a column name with PRIOR in the select list (SELECT PRIOR EMPLOYEE_ID, ...), you specify the “prior” row’s value. ORDER SIBLINGS BY You have to be careful when trying to order the rows of output in a hierarchical query. By default, if you omit the ORDER BY clause altogether, the query attempts to sort rows in an order that’s reflective of the hierarchy. Display will start first with a LEVEL 1 row. If that row is superior to any LEVEL 2 rows, those rows will display next before another LEVEL 1 row displays. The same approach is taken at LEVEL 2, so that rows will display down to leaf node levels before the next rows show at the higher levels. The result is a display that is meaningful to the hierarchy. But if you try to order these rows with the ORDER BY clause, you’ll create a syntactically correct statement that probably doesn’t help you much, such as this: SELECT LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE_FORMATTED FROM EMPLOYEE_CHART START WITH EMPLOYEE_ID = 1 CONNECT BY REPORTS_TO = PRIOR EMPLOYEE_ID ORDER BY TITLE; In this example, we’ve changed the alias for the reformatted TITLE column to TITLE_FORMATTED. This way, we can reference the original unformatted version of the TITLE column in our ORDER BY clause. Another way would have been to use ORDER BY 3, but in this case we’ve chosen to stick with the column name. Either way, the results come out somewhat meaningless, like this—here is the output of our sample query: LEVEL ----------------1 2 3 3 3 3 4 2 2 EMPLOYEE_ID TITLE_FORMATTED ------------------ ----------------------1 CEO 4 CFO 5 Director 1 6 Director 2 7 Director 3 8 Director 4 9 Manager 1 3 SVP 2 VP 624 Chapter 16: Hierarchical Retrieval Look carefully at this output. It is not what you might think it is. For example, the four “Director” titles all appear to report to the CFO. But as we’ve seen earlier— they really don’t. All we have here is an alphabetical listing of TITLE values, but their row ordering is not consistent with their position in the hierarchy. They are each indented correctly, but not necessarily underneath their direct report. This is where we might use the ORDER SIBLINGS BY clause instead. Let’s do the same query with this one change, and we’ll see very different results: SELECT LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE_FORMATTED FROM EMPLOYEE_CHART START WITH EMPLOYEE_ID = 1 CONNECT BY REPORTS_TO = PRIOR EMPLOYEE_ID ORDER SIBLINGS BY TITLE; LEVEL ---------------------1 2 2 3 3 2 3 3 4 EMPLOYEE_ID TITLE_FORMATTED ---------------------- ----------------------1 CEO 4 CFO 3 SVP 7 Director 3 8 Director 4 2 VP 5 Director 1 6 Director 2 9 Manager 1 Notice that our TITLE values are now alphabetized for a given level, but not across all levels. The rows are sorted within their hierarchical structure. That’s because ORDER SIBLINGS sorts rows within each given level, not across levels, thus retaining the hierarchical relationship across rows of output. Note that our earlier use of ORDER BY did not create an error message, just misleading output. So be careful here—ORDER SIBLINGS BY is what you want to use if you are trying to sort rows in a hierarchical query. SYS_CONNECT_BY_PATh The SYS_CONNECT_BY_PATH function is a useful feature for formatting hierarchical data output. It takes two arguments: a column you wish to include as data, and an expression used to separate each level represented within the output. It takes two parameters: n The first parameter is the value to be displayed within the path. n The second parameter is a separating character. Create and Format Hierarchical Data 625 Here’s an example: SELECT FROM START WITH CONNECT BY LEVEL, EMPLOYEE_ID, SYS_CONNECT_BY_PATH(TITLE,'/') TITLE EMPLOYEE_CHART EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID; LEVEL ---------------------1 2 3 3 4 2 3 3 2 EMPLOYEE_ID ---------------------1 2 5 6 9 3 7 8 4 TITLE -----------------------------/CEO /CEO/VP /CEO/VP/Director 1 /CEO/VP/Director 2 /CEO/VP/Director 2/Manager 1 /CEO/SVP /CEO/SVP/Director 3 /CEO/SVP/Director 4 /CEO/CFO This output shows the full path from the root node in each row. The character separating each level within the string comes from the second argument of the SYS_CONNECT_BY_PATH function. CONNECT_BY_ROOT The CONNECT_BY_ROOT operator will display any data from the root node row of a given row. Like the PRIOR operator, it is only valid in hierarchical queries. In other words, no matter which row of output prints in the hierarchical query’s output, that row is capable of accessing data from the same root node row with the CONNECT_BY_ROOT operator. It takes one parameter—an expression that will be processed against the root node’s row to determine the response. Generally, a column of the root node row is included in the parameter. For example: SELECT FROM START WITH CONNECT BY LEVEL, EMPLOYEE_ID, TITLE, CONNECT_BY_ROOT TITLE AS ANCESTOR EMPLOYEE_CHART EMPLOYEE_ID = 3 REPORTS_TO = PRIOR EMPLOYEE_ID; This example starts with a root node of EMPLOYEE_ID of 3, which is the SVP title. Therefore, any row’s attempt to use the CONNECT_BY_ROOT operator will reference that same root node row, no matter the requesting row. In this example, for each row, our reference to CONNECT_BY_ROOT is showing the TITLE column 626 Chapter 16: Hierarchical Retrieval from the root node row, which is the SVP row, and giving the output the column alias of ANCESTOR: LEVEL ---------------------1 2 2 EMPLOYEE_ID ---------------------3 7 8 TITLE -------------------SVP Director 3 Director 4 ANCESTOR --------SVP SVP SVP The CONNECT_BY_ROOT operator empowers any row in the hierarchical query’s output to directly reference any data from within the root node row. CertIFIcAtIon ObJectIVe 16.03 Exclude Branches from the Tree Structure You can use the WHERE clause in a hierarchical query to filter out specific rows from your output, just as you would with any other query. But with a hierarchical query, you can go further: you can selectively restrict entire branches of the tree of your output. This is done from within the CONNECT BY clause. For example, if we go back to our original query that starts with the CEO and shows all of our organization, we can choose to exclude, say, the branch starting with the SVP position and every subordinate row. Here’s the query: SELECT FROM START WITH CONNECT BY AND LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE EMPLOYEE_CHART EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID EMPLOYEE_ID <> 3; The query will exclude the EMPLOYEE_ID of 3, which is the TITLE value of ‘SVP’. Now—the hierarchical query is generated by traversing the tree and moving from the root node to the leaf nodes logically from row to row. By excluding the EMPLOYEE_ID value of 3 in the CONNECT BY clause, you essentially tell the query to ignore that entire branch. The result: LEVEL ---------------------1 2 3 EMPLOYEE_ID TITLE ---------------------- -----------------1 CEO 2 VP 5 Director 1 Exclude Branches from the Tree Structure 3 4 2 6 9 4 627 Director 2 Manager 1 CFO Notice that the SVP and all subordinate rows are gone. In this particular example, we could have achieved the same result with this query: SELECT FROM START WITH CONNECT BY AND LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE EMPLOYEE_CHART EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID TITLE <> 'SVP'; In other words, all you’re doing in the CONNECT BY is identifying rows by finding some sort of data that can identify the row. There’s no particular requirement to use the primary key column—although it can be good design, depending on the situation. As we have seen in this example, the CONNECT BY can use Boolean operators such as AND and OR in its syntax. Also, functions can be used to formulate expressions in much the same way that a WHERE clause would do. Note: if you wish to include a WHERE clause, it is placed before the START WITH clause. For example, assuming we have a table FORMER_EMPLOYEES with a primary key column called ID, we could do something like this: SELECT FROM WHERE START WITH CONNECT BY AND LEVEL, EMPLOYEE_ID, LPAD(' ', LEVEL*2) || TITLE TITLE EMPLOYEE_CHART EMPLOYEE_ID NOT IN (SELECT ID FROM FORMER_EMPLOYEES) EMPLOYEE_ID = 1 REPORTS_TO = PRIOR EMPLOYEE_ID TITLE <> 'SVP'; This query shows how a WHERE clause can be included, provided it precedes the START WITH clause. It’s theoretically possible to use the WHERE clause to omit rows that will collectively represent an entire branch. But that’s not the same thing as identifying a branch and excluding it as a branch. CONNECT BY is the clause that can identify a branch and exclude it in its entirety. 628 Chapter 16: Hierarchical Retrieval CertIFIcAtIon SuMMAry The hierarchical query is a feature in SQL that can create tree-structured output from row-based table data. It requires a particular structure that involves a table—or view—that is structured as a self-join, with hierarchical relationships defined within the primary key and foreign key relationship of the self-join. Typical examples are organization charts of employees or divisions, family trees, or any other data structure in which multiple generations of parent-child-grandchild-etc. relationships may exist. Any row of data within the hierarchy is considered a “node”. The starting point, or trunk, is the “root node”. A node that has two more children is considered a “fork”. A node that has no children is a “leaf node”. The syntax for the hierarchical query uses the START WITH clause to define the root node of the hierarchy. The CONNECT BY clause defines the self-join as well as the direction in which the query will traverse the tree, or hierarchy. The keyword PRIOR is used within the CONNECT BY clause to determine the direction of the query. CONNECT BY may also be used to exclude any node, in which case all associated child records will be excluded as well; the effect is to exclude the entire branch represented by the excluded node. The pseudocolumn LEVEL is automatically calculated to display the value corresponding to the level within the hierarchy, where LEVEL 1 is the root node, LEVEL 2 is the child level relative to the root, and so on. The LEVEL pseudocolumn is helpful in formatting output to create indentation of data and thus highlight the nature of the hierarchy in displayed output. START WITH and CONNECT BY may appear in any order within the SELECT statement. However, the WHERE clause, if used in the SELECT statement, must precede the CONNECT BY and START WITH clauses. The ORDER BY clause may be used, but it must follow the CONNECT BY and START WITH clauses. The ORDER BY clause is tricky, however, in that it sorts rows without respect to the hierarchical ordering of data. The better choice for sorting rows is probably ORDER SIBLINGS BY, depending on the desired result. The function SYS_CONNECT_BY_PATH can show the complete path from root node to current node for any given node. The CONNECT_BY_ROOT operator can be called from within any node’s row to reference data from the root node row. Two-Minute Drill 3 629 Two-MInute DrIll Interpret the Concept of a hierarchical Query q A hierarchical query extends the parent-child relationship into a structure that can be multigenerational, in which multiple levels of relationships may be added to a given table so that each row may form a relationship at a new generational level beyond the typical parent-child-grandchild-etc. relationship. q Hierarchical queries are based on a self-join table. q All rows in a hierarchical query represent a node. q The starting point of the hierarchical query is the root node. q Any node that branches into two or more children is a fork. q Any node that ends with no children is a leaf node. Create and Format hierarchical Data q The SELECT statement clauses START WITH and CONNECT BY are used to form a hierarchical query. q The START WITH clause identifies the root node. q The CONNECT BY clause defines the self-join relationships. q There must be at least one use of the PRIOR keyword in the CONNECT BY, according to Oracle’s documentation. q The PRIOR row determines the direction of the hierarchical query. q The pseudocolumn LEVEL identifies the generational level from the root node. q The ORDER SIBLINGS BY clause sorts rows within a generational level without compromising the default hierarchical ordering of output rows. q The SYS_CONNECT_BY_PATH function can show the complete path to any given node from the root node within a single data element. q The CONNECT_BY_ROOT operator can reference a root node row from any row of a hierarchical query. q The order of clauses, if used, in a SELECT statement is SELECT, FROM, WHERE, START WITH, CONNECT BY, and ORDER BY, where the START WITH and CONNECT BY can be interchanged. 630 Chapter 16: Hierarchical Retrieval Exclude Branches from the Tree Structure q The CONNECT BY clause can be used to exclude complete branches from the tree. q The WHERE clause can exclude individual rows but will not exclude complete branches automatically. Self Test 631 SelF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. Interpret the Concept of a hierarchical Query 1. The earliest ancestor in a hierarchy is known as the: (Choose the best answer.) A. Fork B. Leaf node C. Root node D. Grandchild 2. Which of the following join conditions is generally associated with a hierarchical query? (Choose the best answer.) A. Self-join B. Natural join C. Nonequijoin D. None in particular 3. Examine the data model and data listing for the DISTRIBUTORS table shown below. ID LOCATION LOC_TYPE UPLINE 1 2 3 4 5 6 7 8 New York Memphis Minneapolis Salt Lake Atlanta Wichita Sacramento El Paso HQ REGIONAL REGIONAL REGIONAL LOCAL LOCAL LOCAL LOCAL 1 1 1 2 2 4 4 632 Chapter 16: Hierarchical Retrieval Which of the rows of output is a potential root node for a hierarchical query? (Choose all that apply.) A. ID = 1 B. Any row with a LOC_TYPE of ‘REGIONAL’ C. Any row with a LOC_TYPE of ‘LOCAL’ D. ID = 7 Create and Format hierarchical Data 4. To identify a root node, you must: A. Use the START WITH clause to identify a row, but only if you use the primary key. B. Use the START WITH clause to identify a row. C. Use the CONNECT BY clause to identify a row, but only if you use the primary key. D. Use the CONNECT BY clause to identify a row. 5. Examine the diagram and the data listing shown in question 3, then consider the following SQL statement (line numbers added): 01 02 03 04 SELECT LEVEL, LOC_TYPE, LOCATION, CONNECT_BY_ROOT(LOC_TYPE) FROM DISTRIBUTORS START WITH ID = 7 CONNECT BY PRIOR UPLINE = ID; What will be the value for LEVEL for the row with a LOCATION value of ‘Sacramento’? A. 1 B. 2 C. 3 D. 4 6. Examine the diagram and the data listing shown in question 3, and consider the SQL statement shown in question 5. How many total rows will result from the query? A. 0 B. 1 C. 3 D. 8 7. Examine the diagram and the data listing shown in question 3, along with the SQL statement shown in question 5. For this example, which of the following could replace line 3 to establish the root node as New York? A. START WITH LOCATION = 'New York' B. START WITH PRIOR ID Self Test 633 C. START WITH ROOT NODE D. None of the above 8. Examine the diagram and the data listing shown in question 3, along with the SQL statement shown in question 5. Which of the following statements will be true of the values displayed in the fourth column of output, as indicated by the fourth expression in the SELECT list, specified at the end of line 1? (Choose two.) A. The value will be the same for each row of output. B. The value will be NULL for the first row of output. C. At least one row will display the value ‘LOCAL’ for the fourth column. D. At least one row will display the value ‘HQ’ for the fourth column. 9. Examine the diagram and the data listing shown in question 3, along with the SQL statement in question 5. How could you edit the SQL statement to reverse the direction of the hierarchical output? A. Change line 3 to START WITH to ID = 1. B. Change line 4 to CONNECT BY UPLINE = PRIOR ID. C. Add as line 5 ORDER BY LOCATION DESC. D. It can’t be done. 10. According to Oracle’s documentation, how many occurrences of the keyword PRIOR must exist in a CONNECT BY clause? A. 0 B. 1 C. 2 D. There is no rule 11. Which of the following options is a list of SELECT statement clauses in the proper order in which they can appear in a syntactically correct SELECT statement? A. SELECT, FROM, START WITH, CONNECT BY, WHERE B. SELECT, FROM, WHERE, CONNECT BY, START WITH C. SELECT, FROM, START WITH, WHERE, CONNECT BY D. None of the above 12. Examine the diagram and the data listing shown in question 3, and the following hierarchical query SQL statement (line numbers added): 01 02 03 04 05 SELECT LEVEL, LOC_TYPE, LOCATION FROM DISTRIBUTORS START WITH LOC_TYPE = 'HQ' CONNECT BY UPLINE = PRIOR ID ORDER BY LOCATION; 634 Chapter 16: Hierarchical Retrieval What will be true of the output from this SQL statement? A. There will only be one row of output. B. The statement will fail because of a syntax error in line 3. C. The statement will execute and produce output as intended. D. The rows will not be sorted hierarchically. 13. Which of the following functions can list, for a given node, the complete hierarchical path to that node from the root node? A. SYS_CONNECT_BY_PATH B. CONNECT_BY_ROOT C. START_WITH D. CONNECT_BY Exclude Branches from the Tree Structure 14. Which clause of the SELECT statement is used to exclude entire branches from the output of a hierarchical query? A. START WITH B. CONNECT BY C. WHERE D. HAVING 15. Examine the diagram and the data listing shown in question 3, along with the following hierarchical query SQL statement (line numbers added): 01 02 03 04 05 06 SELECT LEVEL, LOC_TYPE, LOCATION FROM DISTRIBUTORS WHERE LOCATION <> 'El Paso' START WITH LOC_TYPE = 'HQ' CONNECT BY PRIOR ID = UPLINE AND ID <> 4; What will be true of the output from this SQL statement? A. The row with a LOCATION of ‘New York’ will be omitted from output. B. The row with a LOCATION of ‘Sacramento’ will be omitted from output. C. All three rows with a LOC_TYPE of ‘REGIONAL’ will be displayed. D. None of the above. Self Test Answers 635 SelF Test Answers Interpret the Concept of a hierarchical Query 1. ˛ C. The “root node” is the best answer. ˝ A, B, and D are incorrect. A leaf node is the far end of any branch from the root node. A fork is any node that has two or more children. A grandchild is a third-level node below any given node. 2. ˛ A. Typically a self-join is associated with a hierarchical query. ˝ B, C, and D are incorrect. While these joins are theoretically possible as part of a structure that supports a hierarchical query, the self-join is more likely and the best answer. 3. ˛ A, B, C, and D. Any row is a potential candidate root node to be identified by the START WITH clause. ˝ None are incorrect. Create and Format hierarchical Data 4. ˛ B. The START WITH clause identifies the root node. And while the primary key is an ideal way to identify a row, it is not required by the START WITH clause. ˝ A, C, and D are incorrect. 5. ˛ A. The correct answer is 1, because ‘Sacramento’ has an ID of 7, and the START WITH clause defines that row as the root node for the query. The LEVEL pseudocolumn will assign a value of 1 to the root node of the hierarchical query. ˝ B, C, and D are incorrect. 6. ˛ C. The results will include three rows. The reason: the START WITH points to the row with an ID of 7, which is the LOCATION of ‘Sacramento’. By specifying CONNECT BY PRIOR UPLINE = ID, the query is stipulating that it wishes to find the next row by finding a value of ID that matches the ‘Sacramento’ row value of UPLINE, since ‘Sacramento’ will be the “prior” row to the next row. ˝ A, B, and D are incorrect. 7. ˛ A. By specifying LOCATION = ‘New York’, the START WITH identifies the row for ‘New York’ and will start with that row. You could also have used START WITH ID = 1, which is ideal, since that’s the primary key—but either works fine in this example. ˝ B, C, and D are incorrect. The keyword PRIOR doesn’t apply here. The keywords ROOT NODE don’t exist. 636 Chapter 16: Hierarchical Retrieval 8. ˛ A and C. The values will be ‘LOCAL’ for every row of output. The reason: the CONNECT_BY_ROOT operator shows data for the root node, accessible by each row of output from the hierarchical query. ˝ B and D are incorrect. No value in this example will be NULL, since the root node of ID = 7 contains the value ‘LOCAL’ for the LOC_TYPE column. 9. ˛ B. By moving PRIOR to the other side of the equal sign in the CONNECT BY clause, you reverse the direction in which SQL will traverse the hierarchical tree. ˝ A, C, and D are incorrect. Changing START WITH will specify a different root node, but it will not reverse direction. Adding an ORDER BY clause will sort the output rows but not affect the hierarchical processing, which will include the assignment of values to the pseudocolumn LEVEL. 10. ˛ B. While you can get away syntactically with omitting the PRIOR keyword as of the writing of this book, Oracle’s formally published position is that the CONNECT BY clause must have one proper usage of the PRIOR keyword in order to be correct. ˝ A, C, and D are incorrect. 11. ˛ B. The WHERE clause, if used, must precede the START WITH and CONNECT BY clauses. The START WITH and CONNECT BY clauses can appear in any order with respect to each other. ˝ A, C, and D are incorrect. Answer A is wrong because WHERE cannot follow CONNECT BY and/or START WITH. Answer C is wrong because START WITH cannot precede WHERE. 12. ˛ D. The ORDER BY clause will cause the rows to sort alphabetically by LOCATION, which will alter the hierarchical sorting of output. The better choice here would be ORDER SIBLINGS BY LOCATION. ˝ A, B, and C are incorrect. The output will display all of the eight rows of the table in this example. There is no syntax error in line 3; the reference to LOC_TYPE of ‘HQ’ will identify the row with an ID of 1 as the root node. But it’s incorrect to say that the output will be produced as intended, since the ORDER BY clause is not what is typically used with a hierarchical query, but rather the ORDER SIBLINGS BY is the better choice, as is explained for the correct answer. 13. ˛ A. The SYS_CONNECT_BY_PATH is the correct function. ˝ B, C, and D are incorrect. CONNECT_BY_ROOT does not show the full list; it merely shows information from the root node row. There is no START_WITH function, nor a CONNECT_BY function; those are clauses of the SELECT statement—but without the underscores, as in START WITH and CONNECT BY. Self Test Answers 637 Exclude Branches from the Tree Structure 14. ˛ B. CONNECT BY establishes the self-join and the direction of the hierarchy, and can also be used to exclude a hierarchical branch from the output listing. ˝ A, C, and D are incorrect. START WITH does not exclude branches, it establishes the root node. WHERE can exclude individual rows but not branches directly. HAVING can exclude groups identified in a GROUP BY clause, but it does not explicitly filter out branches from a hierarchical query. 15. ˛ B. The row with a LOCATION of ‘Sacramento’ will be omitted. The reason: because of the CONNECT BY including the expression ID <> 4, the hierarchical query will omit the row where ID = 4, which is ‘Salt Lake’. The rest of the CONNECT BY specifies that the hierarchical processing will be traversing from the root node of LOC_TYPE = ‘HQ’, which in this case is LOCATION ‘New York’, and move to the next row by finding an UPLINE value that matches the prior row’s ID value. So from ID = 1, we move to the next rows with an UPLINE of 1, but one of those is ‘Salt Lake’, which we are omitting via the ID <> 4 clause. Had we included ‘Salt Lake’, we would’ve traversed the hierarchy to the child rows of ‘Salt Lake’, which include ‘Sacramento’. But by omitting ‘Salt Lake’, we never get ‘Sacramento’. Hence, it is excluded from output. ˝ A, C, and D are incorrect. ‘New York’ is included—it’s the root node identified in the START WITH clause—and nothing in the rest of the SQL statement omits the row. We won’t get all rows with a LOC_TYPE of ‘REGIONAL’, since we are omitting ‘Salt Lake’. This page intentionally left blank 17 Regular Expression Support CertIFIcAtIon ObJectIVes 17.01 Using Metacharacters 17.02 Regular Expression Functions 17.03 Replacing Patterns 17.04 3 Q&A Regular Expressions and CHECK Constraints Two-Minute Drill Self Test 640 Chapter 17: Regular Expression Support T his chapter explores the use of regular expressions in Oracle SQL. The term “regular expressions” refers to a specific language for working with text. You can use regular expressions to specify some complex character patterns and perform complex searches in a succinct and efficient manner. Regular expressions have an identity that goes beyond SQL and Oracle. They are used in Unix, C, and elsewhere. This chapter will look at the functionality of regular expressions and Oracle SQL’s capabilities for working with them. CertIFIcAtIon ObJectIVe 17.01 using Metacharacters The heart of regular expressions is the set of metacharacter operators. (Note: “meta character” is how it’s spelled in the exam objectives list, but it’s spelled “metacharacters” elsewhere in Oracle’s documentation. We’ll use “metacharacters”, but don’t be thrown if you see it spelled as two words elsewhere.) Metacharacter operators are special symbols and codes you use when defining patterns for searches using regular expressions. See Table 17-1 for a listing of the metacharacter operators, also known as regular expression operators. If you’ve worked with regular expressions before, this section will be a great refresher. If you’ve never worked with regular expressions before, it might not make much sense until we get to some examples— which we’ll examine in the next section when we discuss how to use regular expressions with functions. TAbLe 17-1 # Operator Description Regular Expression Operators 1 () Treats the enclosed expression or set of literals as a subexpression. 2 [. . .] A bracket expression, consisting of a pair of brackets enclosing a list of one or more expressions: collating elements, collating symbols, equivalence classes, character classes, or range expressions. The closing bracket symbol may have other meanings—it may appear within the expression as a part of one of the enclosed expressions; if not then it closes the bracket expression. The bracket expression forms a matched list when it opens with something other than the sequence “[.”, “[:”, or “[=”, as detailed in entries 4, 5, and 6. Using Metacharacters 641 TAbLe 17-1 # Operator Description Regular Expression Operators (Continued) 3 [^. . .] A “not equals” bracket expression. The caret indicates that the enclosed expressions are not to be matched. 4 [. . . . .] Specifies a collation element in accordance with the current locale. Useful in situations where two or more characters are needed to specify a single collating element, such as in Czech, Welsh, and others, where ‘ch’ represents a single collating element. For example, to establish a range of letters from ‘a’ to ‘ch’, you would use [a..[.ch.]]. 5 [: . . . :] Specifies a character class—see Table 17-2 and Table 17-3. 6 [= . . . =] Specifies an equivalence class. For example [=e=] represents e, é, è, ë, etc. 7 . Match any character in the database character set. 8 ? Match zero or one occurrence of the preceding subexpression. 9 * Match zero or more occurrences of the preceding subexpression. 10 + Match one or more occurrences of the preceding subexpression. 11 {n1} Match precisely n1 occurrences of the preceding subexpression. 12 {n1,} Match n1 or more occurrences of the preceding subexpression. 13 {n1,n2} Match between n1 to n2 occurrences of the preceding subexpression, inclusive. 14 \ Depending on the context, the backslash could be just a backslash. If it’s followed by another regular expression operator, the backslash transforms that operator into a literal value. For example, \+ is a literal plus sign instead of the symbol to match one or more occurrences of the preceding subexpression, as is explained elsewhere in this table. 15 \n1 Backreference. Repeats the ‘n1th’ subexpression within the previous expression. 16 | Logical OR. Used to separate two expressions; one of the expressions is matched. 17 ^ Beginning of line anchor. 18 $ End of line anchor. Notice the fifth item listed in Table 17-1—it’s the entry for character classes, and its description refers to Table 17-2 and Table 17-3. The character classes described in Table 17-2 are references to POSIX character classes, which are independent of character sets. On the other hand, the examples of character ranges shown in Table 17-3 are specific to character sets. 642 Chapter 17: Regular Expression Support TAbLe 17-2 Character Class All Characters of Type POSIX Character Classes [:alnum:] Alphanumeric characters. Includes letters and numbers. Omits punctuation marks. [:alpha:] Alphabetic characters. Includes letters only. [:blank:] Blank space characters. [:cntrl:] Control (non-printing) characters. [:digit:] Numeric characters. [:graph:] All [:punct:], [:upper:], [:lower:], [:digit:] character classes combined. [:lower:] Lowercase alphabetic characters. [:print:] Printable characters. [:punct:] Punctuation characters. [:space:] Space (non-printing) characters. [:upper:] Uppercase alphabetic characters. [:xdigit:] Valid hexadecimal characters. TAbLe 17-3 Range All Characters of Type Examples of Character Ranges [A–Z] All uppercase alphabetic characters. [a–z] All lowercase alphabetic characters. [0–9] All numeric digits. [1–9] All numeric digits excluding zero. There’s a school of thought out there that advocates the use of POSIX character classes where possible, so that multilingual applications can automatically leverage benefit from configuration changes to the underlying POSIX character classes in globalized application deployment. This is a good idea. But—having said that—note that you need to understand both approaches for the certification exam—both the character classes described in Table 17-2 and the character-specific range examples demonstrated in Table 17-3. Note that the character classes shown in Table 17-2 are specified in lowercase letters. This is required—if you include them in a regular expression pattern using uppercase letters, such as [:ALPHA:], you’ll get a syntax error. Regular Expression Functions 643 You can use regular expressions in a specific set of Oracle SQL functions and conditions that we address in the next sections of this chapter. We’ll look at examples next. CertIFIcAtIon ObJectIVe 17.02 Regular Expression Functions Oracle SQL includes several functions that extend the capabilities of some of the existing string functions such as SUBSTR and INSTR. These extensions consist of functions that support regular expressions. See Table 17-4 for a list and an accompanying description of them. TAbLe 17-4 Regular Expression Functions Regular Expression Function Parameters Description REGEXP_SUBSTR (s1, pattern1, p1, n1, m1) s1—a character string. Required. pattern1—a regular expression. Required. p1—numeric. Optional. Defaults to 1. n1—numeric. Optional. Defaults to 1. m1—one or more of the match parameter text literals, see Table 17-5. Optional. Searches within s1 for any string that matches the pattern defined in pattern1 . Starts looking at position p1 in the string. Looks for the n1’th occurrence of the pattern. Performs the match in accordance with the instructions specified by m1 . Output: Character string representing the matched pattern found within s1 that matched pattern1 . REGEXP_INSTR (s1, pattern1, p1, n1, opt1, m1) s1—a character string. Required. pattern1—a regular expression. Required. p1—numeric. Optional. Defaults to 1. n1—numeric. Optional. Defaults to 1. opt1—numeric, limited to either 0 or 1. Optional. Defaults to 0. m1—one or more of the match parameter text literals, see Table 17-5. Optional. Searches within s1 for any substring that matches the pattern defined in pattern1 . Starts looking at position p1 in the string. Looks for the n1’th occurrence of the pattern. Performs the match in accordance with the instructions specified by m1 . Output: Numeric value representing the location of the pattern within the source string. If opt1 = 1, then it returns the location of the first position after the pattern. (Continued) 644 Chapter 17: TAbLe 17-4 Regular Expression Support Regular Expression Functions (Continued) Regular Expression Function Parameters Description REGEXP_REPLACE (s1, pattern1, rep1, p1, o1, m1) s1—a character string. Required. pattern1—a regular expression. Required. repl—string. Optional. Defaults to NULL. p1—a numeric value, optional. Defaults to 1. o1—numeric value, optional. Defaults to 0. m1—one or more of the match parameter text literals, see Table 17-5. Optional. Replaces o1 occurrences of pattern1 within s1 with rep1, starting at position p1 within s1 . Performs the match in accordance with the instructions specified by m1 . TAbLe 17-5 Match Parameter Text Literals Match Parameter Value Description ‘c’ Case-sensitive matching. ‘i’ Case-insensitive matching. ‘n’ Enables the ‘.’ (period) character (which is the “match-anycharacter” character) to match the newline character. Otherwise, ‘.’ matches any character but does not treat the newline character as a character. ‘m’ Treat the source character string as multiple lines. Any occurrences of the anchor characters (^ and $) are assumed to be the start and end of lines within the string. Without it, the source character string is assumed to be one line of text. ‘x’ Ignores whitespace characters. Regular Expression Functions TAbLe 17-6 Regular Expression Condition REGEXP_LIKE 645 Regular Expression Condition Parameters Description REGEXP_LIKE (s1, pattern1, m1) s1—a character string. Required. pattern1—a regular expression. Required. m1—one or more of the match parameter text literals, see Table 17-5. Optional. Compares the pattern represented in pattern1 with the string in s1 and determines if there is a match. Performs the match in accordance with the instructions specified by m1 . Output: Boolean. True if the pattern finds a match, false if it does not. (Note: Does not use the wildcard operators that LIKE uses.) In addition to the regular expression functions, there is also one regular expression condition, listed in Table 17-6. Note that if the match parameter text literals (Table 17-5) are used in a conflicting combination, such as ‘ic’, the last value will take precedence and any prior conflicting values will be ignored. In the parameter lists described in Table 17-4 and Table 17-6, the REGEXP functions and the REGEXP condition take regular expression patterns as input parameters. A regular expression pattern uses regular expression operators, which we can draw from Tables 17-1, 17-2, and 17-3. Let’s consider the following string: '123 Maple Avenue' Let’s take a look at the following SQL statement: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[a-z]') ADDRESS FROM DUAL; ADDRESS ------a Notice the output. The value returned is a letter “a”, taken from the second letter within “Maple”. The reason: our regular expression pattern, which we passed into the function as the second parameter, identifies a bracketed set of values. The bracketed set is explained in Table 17-1, item 2, and represents a list of characters that form our pattern. In essence, we are looking for any one occurrence of the 646 Chapter 17: Regular Expression Support characters specified in this list; the first character that matches is good, and in this case it was the letter “a”. Remember: text is case sensitive by default, so if we wanted to capture that capital letter “M”, we would need to do something to indicate our desire to include capital letters in our search. One way is this: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[A-Za-z]') ADDRESS FROM DUAL; ADDRESS ------M By expanding our list of possible character matches, we have included upperand lowercase letters. But we are only retrieving the first letter and no more. That’s because our bracketed list, by default, only retrieves the first character that represents one occurrence of any of the characters within the bracketed list. Let’s add the plus sign operator to the end of our pattern, indicating that we want to return one or more consecutive characters that match our pattern: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[A-Za-z]+') ADDRESS FROM DUAL; ADDRESS ------Maple The plus sign operator is explained in Table 17-1, item number ten. This SQL statement starts its search in the first position of the target string and looks for the first occurrence of the pattern, which is specified to be any number of consecutive occurrences of the letters “A” through “Z” in either upper- or lowercase. In our example, we did not include a blank space in our set of bracketed characters to match, so as soon as a blank space was encountered, the returned value ended—with the “e” in “Maple”. We’ve been using character ranges of “a” through “z”. As an alternative, we can use a reference to the full set of alphabetic characters, like this: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[[:alpha:]]+') ADDRESS FROM DUAL; ADDRESS ------Maple Regular Expression Functions 647 Note that the character class reference is enclosed in brackets, even though the reference itself already contains brackets. This is necessary. And beware! Don’t forget that the brackets around the character class are an integral part of that class. Omitting them will be accepted syntactically, but it’s logically erroneous: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[:alpha:]+') ADDRESS FROM DUAL; ADDRESS ------apl This example does not define the alphabetic character class. Instead, it defines a set of individual characters, including a colon character and the letters “a”, “l”, “p”, and “h”, followed by a repetition of the letter “a” and the “colon” character. The result is that the returned value represents the first complete continuous pattern that matches that particular set of characters we specified—“apl”. It’s syntactically accurate, but on a practical level it’s probably worthless. So beware—this is yet another example of how SQL will let you do something erroneous and never complain. Character classes such as [:alpha:] are preferable to letter ranges such as [a–z] in multilingual environments for consistency and flexibility in your applications. Remember that there are more than two parameters for this function. The third and fourth parameters default to 1. The third parameter defines where in the target string you will begin your search, and the fourth parameter defines which occurrence that matches your pattern you wish to return. In these examples, we’ve taken the default values for both the third and fourth parameters. But let’s change that—we’ll restore our correct character class reference, and we’ll look for the second occurrence of our pattern: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[[:alpha:]]+', 1, 2) ADDRESS FROM DUAL; ADDRESS ------Avenue 648 Chapter 17: Regular Expression Support Now let’s go back to the first occurrence of a pattern match and try a different character class reference: SELECT REGEXP_SUBSTR('123 Maple Avenue', '[[:alnum:]]+') ADDRESS FROM DUAL; ADDRESS ------123 In this example, we returned the first string that matched the alphanumeric character class. That class allows for numeric characters, and now we’ve retrieved the first numeric string from the target string. Let’s try a different character class. This time we’ll query the ORDER_ ADDRESSES table and show both the original column and the transformed column value in the same output: SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'[[:digit:]]+') ZIP_CODE FROM ORDER_ADDRESSES; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 Ronks, PA 17572 Weeki Wachee, FL 34607 Kalamazoo, MI 49001 Little Egg Harbor Township, NJ 08087 Pumpkin Center, OK 74451 Woonsocket, RI 02895 ZIP_CODE ----------74103 37183 98027 93109 21078 17572 34607 49001 08087 74451 02895 This example looks for the first occurrence of a continuous pattern of digits. If you wish to look for a fixed literal value, that’s simple—just leave out the brackets, like this: SELECT REGEXP_SUBSTR('123 Maple Avenue', 'Maple') ADDRESS FROM DUAL; ADDRESS ------Maple Regular Expression Functions 649 You can mix and match literals and operators: SELECT REGEXP_SUBSTR('she sells sea shells down by the seashore', 's[eashor]+e' ) THE_RESULT FROM DUAL; THE_RESULT ---------she The example above looks for a pattern that starts with the letter “s”, followed by any one or more consecutive occurrences of the letters “e”, “a”, “s”, “h”, “o”, or “r”, and finally ending in the letter “e”. While the final word “seashore” matches this pattern, the first word “she” is what is found first. If the first word “she” in the source string were capitalized, as in “She”, then that word would not be found by our pattern, since patterns are case sensitive and our pattern is specifically looking for a lowercase “s”. Instead, the first three letters of “shell” would be returned. To look for a particular string, you can use parentheses: SELECT REGEXP_SUBSTR('she sells sea shells down by the seashore', 's(eashor)e' ) THE_RESULT FROM DUAL; THE_RESULT ---------seashore By using parentheses, you are no longer looking for the first one or more consecutive occurrences of the letters included within but instead are now looking for the letter “s”, followed by the string “eashor”, followed by the letter “e”. It’s the same thing as this: SELECT REGEXP_SUBSTR('she sells sea shells down by the seashore', 'seashore' ) THE_RESULT FROM DUAL; However, parentheses give you the opportunity to mix strings with other metacharacter operators: SELECT REGEXP_SUBSTR('she sells sea shells down by the seashore', '[[:alpha:]]+(shore)' ) THE_RESULT FROM DUAL; THE_RESULT ---------seashore 650 Chapter 17: Regular Expression Support This example looks for any occurrences of a complete word that ends with the string “shore”. The character class [:alpha:] is enclosed in brackets to specify that the matched list being Be sure you understand sought consists of any one occurrence of an the function of each metacharacter alphabetic character, and the plus sign operator operator. after the bracketed list transforms the pattern to become one “or more consecutive” occurrences of an alphabetic character. To look for any one example of a set of multicharacter options, you can enclose the list in parentheses to declare it as a single grouped expression, and then separate each entry with the logical OR operator: SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'(TN|MD|OK)') STATE FROM ORDER_ADDRESSES; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 Ronks, PA 17572 Weeki Wachee, FL 34607 Kalamazoo, MI 49001 Little Egg Harbor Township, NJ 08087 Pumpkin Center, OK 74451 Woonsocket, RI 02895 STATE ----------------------OK TN MD OK Note that the parentheses are a key part of one of the regular expression operators. If you need to specify any of the operators as a literal value instead of an operator, you must precede it with a backslash. For example, this search will interpret the parentheses in the pattern as the grouping expression operator: SELECT REGEXP_SUBSTR('Help desk: (212) 555-1212', '([[:digit:]]+)') AREA_CODE FROM DUAL; AREA_CODE --------212 Regular Expression Functions 651 This variation will interpret the parentheses as literal values and include them in the targeted substring: SELECT REGEXP_SUBSTR('Help desk: (212) 555-1212', '\([[:digit:]]+\)') AREA_CODE FROM DUAL; AREA_CODE --------(212) In this particular set of two examples, we get output in both situations. But if you need to locate a literal character in a place where a pattern might be expecting an operator that requires the same character, you need to use the backslash in front of the character to specify that you intend for the character—in this case the opening and closing parentheses—to be a literal character instead of the regular expression operator. As we have seen, the bracketed expression can represent any number of characters within a larger pattern definition. For example: SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'[TBH][[:alpha:]]+') NAME FROM ORDER_ADDRESSES; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 Ronks, PA 17572 Weeki Wachee, FL 34607 Kalamazoo, MI 49001 Little Egg Harbor Township, NJ 08087 Pumpkin Center, OK 74451 Woonsocket, RI 02895 NAME -------------Tulsa Bugscuffle Barbara Havre Harbor This query looks for any strings that match a pattern in which the first letter is either a “T”, a “B”, or an “H”, followed by any number of alphabetic characters. Notice that we are only looking for the first such occurrence within any string—the string that produces “Harbor” also has a substring for “Township”, but our function only asks for the first occurrence. 652 Chapter 17: Regular Expression Support Here’s an example that uses the “not equal” sign—the caret—to indicate that we want the second occurrence of a string that doesn’t have a semicolon included: SELECT REGEXP_SUBSTR('BMW-Oracle;Trimaran;February 2010', '[^;]+', 1, 2) AMERICAS_CUP FROM DUAL; AMERICAS_CUP -----------Trimaran In this example, we have no spaces in the source string, only punctuation marks. We could try going with the [[:alpha:]] pattern instead, but had we done that in this example, we’d return a value of “Oracle” instead of “Trimaran”, since “Oracle” is the first string separated by non-alphabetic characters—the dash between “BMW” and “Oracle” separates those strings. But we included the bracketed expression “[^;]+”, which specifies multiple characters that are “not equal to the semicolon character”, which is to say that we are stipulating that we only want the semicolon to serve as the substring separation character. And also note—we are specifying the fourth parameter of the REGEXP_SUBSTR function to have a value of 2, so we’re looking for the second occurrence of our pattern of a string that does not include the semicolon. Here’s an example of the metacharacter operator “$” that specifies the end-of-line position: SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'[37]$') LAST_DIGIT FROM ORDER_ADDRESSES; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 Ronks, PA 17572 Weeki Wachee, FL 34607 Kalamazoo, MI 49001 Little Egg Harbor Township, NJ 08087 Pumpkin Center, OK 74451 Woonsocket, RI 02895 LAST_DIGIT ------------3 3 7 7 7 In this case, we’re looking for the first occurrences of either a ‘3’ or a ‘7’ that is followed immediately by the end-of-line anchor. In other words, we’re looking for strings that end in either a ‘3’ or a ‘7’. If we were looking for occurrences of strings that ended with ‘37’ together, we could omit the square brackets, like this: Replacing Patterns 653 SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'37$') LAST_DIGIT FROM ORDER_ADDRESSES; And if we wanted to search for strings that ended in ‘83’, ‘78’, or either a ‘1’ or a ‘2’, we could use this: SELECT ADDRESS2, REGEXP_SUBSTR(ADDRESS2,'(83|78|1|2)$') LAST_DIGIT FROM ORDER_ADDRESSES; ADDRESS2 ------------------------------------------ Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 Ronks, PA 17572 Weeki Wachee, FL 34607 Kalamazoo, MI 49001 Little Egg Harbor Township, NJ 08087 Pumpkin Center, OK 74451 Woonsocket, RI 02895 LAST_DIGIT ------------------------------------83 78 2 1 1 The next section will expand our discussion and look at methods for editing text through pattern matching and replacement. The regular expression functions are just like any other function— and may be used in any SQL statement and clause that accepts any valid SQL function. CertIFIcAtIon ObJectIVe 17.03 Replacing Patterns The function REGEXP_REPLACE uses regular expressions to identify patterns and replace them with something else. For example, consider this pattern: [.]+ 654 Chapter 17: Regular Expression Support This pattern encloses a period in a pair of square brackets, which is to say any single occurrence of a literal period character. But it’s followed by the plus sign operator, which repeats the previous reference one or more consecutive times. The result: we are specifying any number of one or more consecutive occurrences of the literal period character. This example uses the function REGEXP_REPLACE to replace the pattern with a single hyphen: SELECT REGEXP_REPLACE('Chapter 1 ......................... I Am Born', '[.]+','-') TOC FROM DUAL; TOC --------------------Chapter 1 - I Am Born In the next example, we look for any occurrence of the following list of characters: !@#$%^&*() To specify that we are looking for any single occurrence of these characters, we enclose them in square brackets. Once again, let’s replace any single occurrence of the characters in our list with a single dash: SELECT REGEXP_REPLACE('And then he said *&% so I replied with $@($*@', '[!@#$%^&*()]','-') PRIME_TIME FROM DUAL; PRIME_TIME --------------------------------------------And then he said --- so I replied with ------ In the preceding example, we could have replaced any consecutive string of those characters in our list with a single occurrence of a dash by adding the plus sign operator after our bracketed list, like this: SELECT REGEXP_REPLACE('And then he said *&% so I replied with $@($*@', '[!@#$%^&*()]+','-') PRIME_TIME FROM DUAL; PRIME_TIME -------------------------------------And then he said - so I replied with - By adding the single plus sign operator after the square brackets, we specify any number of repetitions of the characters within our list. Replacing Patterns 655 A classic use of the REGEXP_REPLACE function is to clean up unnecessary blank spaces from within a string. Here’s one approach: SELECT REGEXP_REPLACE('and in conclusion, '( ){2,}', ' ') TEXT_LINE FROM DUAL; 2/3rds of our revenue ', TEXT_LINE ----------------------------------------and in conclusion, 2/3rds of our revenue This example uses a regular expression that opens with a set of parentheses enclosing a single blank space. The number two that follows is enclosed in curly braces with a comma, which is to say that it defines the pattern to be the preceding character—a single blank space—in two or more successive occurrences. In other words, we’re looking for any occurrences of two or more continuous blank spaces. If we find one, the third argument to the function says to replace it with a single blank space. The cleaned-up text appears below the query. One advantage to an approach like this lies in the ability to easily identify the number of repetitions of a given character you wish to replace. While this example only shows two spaces, how many times have you found yourself dealing with text files that contained multiple blank spaces you wished to retain, combined with dozens and perhaps many hundreds of generated blank spaces fattening up a text file unnecessarily, blank spaces you wish to eliminate? Using this sort of technique, you could eliminate all repetitions of blank spaces that number, say, 20, which could help dramatically reduce your unused file space while simultaneously preserving any correctly formatted text with some more modest usage of blank space elsewhere in the file. Let’s build a more complex example. We’ll start with something simple—let’s replace a city name with the string constant ‘CITY’. To start, we’ll replace the first occurrence of a text string in the ADDRESS2 column and limit our output to the first five rows for our example: SELECT ADDRESS2, REGEXP_REPLACE(ADDRESS2, '(^[[:alpha:]]+)', 'CITY') THE_STRING FROM ORDER_ADDRESSES WHERE ROWNUM <= 5; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 THE_STRING -----------------------------CITY, OK 74103 CITY, TN 37183 CITY, WA 98027 CITY Barbara, CA 93109 CITY De Grace, MD 21078 656 Chapter 17: Regular Expression Support Notice that our last two rows of output didn’t quite work as we might have wished. Some of our city names contain spaces, so the word search didn’t replace the complete names of ‘Santa Barbara’ or ‘Havre De Grace’. We can resolve this by including a space as one of the acceptable characters for our target substring to be replaced. Within the set of square brackets is the bracketed character class for alphabetic characters, meaning that the operator [:alpha:] simply represents all alphabetic characters within the set of acceptable characters, which in turn is enclosed in square brackets, like this: [[:alpha:]] All we need to do is slip in a single blank space in the list of acceptable characters: [[:alpha:] ] Let’s keep our plus sign operator, which indicates that we’re looking for any continuous string of these characters, in any order: [[:alpha:] ]+ Now let’s put it all together, keeping the ^ operator at the front, which—in this context—is the anchor to the first position in the search string: SELECT ADDRESS2, REGEXP_REPLACE(ADDRESS2, '(^[[:alpha:] ]+)', 'CITY') THE_STRING FROM ORDER_ADDRESSES WHERE ROWNUM <= 5; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 THE_STRING --------------------CITY, OK 74103 CITY, TN 37183 CITY, WA 98027 CITY, CA 93109 CITY, MD 21078 The first character that did not match our pattern is the comma. Our pattern specified alphabetic characters and a space, but not a comma. The result is shown in the right column in the preceding example. Now let’s expand this a bit. Let’s define three consecutive patterns. We already have the first pattern, which is anchored to the start of the search string and looks Replacing Patterns 657 for a consecutive series of alphabetic characters and/or a space, until something else is encountered, all enclosed in a pair of parentheses: (^[[:alpha:] ]+) Next, let’s allow for a comma literal followed by a space literal: , (There’s a blank space following that comma that will become apparent in a bit.) Next, let’s create a second pattern, enclosed in parentheses to group it together as a single pattern. We’ll look for any two alphabetic characters: ([[:alpha:]]{2}) The square-bracketed set of characters—which is the character class [:alpha:] with its own set of square brackets—defines the list of possible characters, and the curly braces following it specify a fixed number of occurrences of these characters. The number 2 indicates that we’re only looking for two alphabetic characters. This is our state abbreviation that we’re looking for. Finally, let’s create a third pattern, which we’ll use to define a five-digit ZIP code: ([[:digit:]]{5}) Putting it all together into one overall pattern looks like this: '(^[[:alpha:] ]+), ([[:alpha:]]{2}) ([[:digit:]]{5})' NOW—let’s do something different with our replacement pattern. Let’s use the backreference expression to take out three subexpressions from our search, and reposition each subexpression as follows: '\3 \2 \1' This pattern says to replace the search string with the third subexpression, the second subexpression, and then finally the first subexpression, in order. Putting it all together, we get this: SELECT ADDRESS2, REGEXP_REPLACE(ADDRESS2, '(^[[:alpha:] ]+), ([[:alpha:]]{2}) ([[:digit:]]{5})', '\3 \2 \1') THE_STRING FROM ORDER_ADDRESSES WHERE ROWNUM <= 5; 658 Chapter 17: Regular Expression Support ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 THE_STRING -----------------------74103 OK Tulsa 37183 TN Bugscuffle 98027 WA Issaquah 93109 CA Santa Barbara 21078 MD Havre De Grace Notice that the comma that is present after each city name in our source string has been omitted from the result in our output string. This is because the backslash specifies subexpressions, which are enclosed in parentheses. The comma is identified in our original pattern, but not within any set of parentheses, so it is not included in our three subexpression references. We can choose to include it in a subexpression, like this: SELECT ADDRESS2, REGEXP_REPLACE(ADDRESS2, '(^[[:alpha:] ,]+) ([[:alpha:]]{2}) ([[:digit:]]{5})', '\3 \2 \1') THE_STRING FROM ORDER_ADDRESSES WHERE ROWNUM <= 5; We could also choose instead to include the comma within our set of subexpression references. For that matter, we can add any punctuation with our subexpression references. For example, let’s add a dash between subexpressions 2 and 1, and put double-quotation marks around subexpression 1 like this: SELECT ADDRESS2, REGEXP_REPLACE(ADDRESS2, '(^[[:alpha:] ]+), ([[:alpha:]]{2}) ([[:digit:]]{5})', '\3 \2-"\1"') THE_STRING FROM ORDER_ADDRESSES WHERE ROWNUM <= 5; ADDRESS2 ---------------------------------------Tulsa, OK 74103 Bugscuffle, TN 37183 Issaquah, WA 98027 Santa Barbara, CA 93109 Havre De Grace, MD 21078 THE_STRING -------------------------74103 OK-"Tulsa" 37183 TN-"Bugscuffle" 98027 WA-"Issaquah" 93109 CA-"Santa Barbara" 21078 MD-"Havre De Grace" Regular Expressions and CHECK Constraints 659 These are just a few examples of the sort of replacements you can achieve using the REGEXP_REPLACE function and regular expressions. Be sure you are comfortable with mixing and matching different metacharacter operators to form patterns. CertIFIcAtIon ObJectIVe 17.04 Regular Expressions and ChECK Constraints You can incorporate regular expressions into CHECK constraints. By defining a pattern within the CHECK constraint using a regular expression, you can establish something of a template for incoming data, establishing a requirement that all incoming data match, for example, a particular format. As an example, consider the following pattern that defines an e-mail address: CREATE TABLE EMAIL_LIST ( EMAIL_LIST_ID NUMBER(7) PRIMARY KEY, EMAIL1 VARCHAR2(120), CONSTRAINT CK_EL_EMAIL1 CHECK ( REGEXP_LIKE (EMAIL1, '^([[:alnum:]]+)@[[:alnum:]]+.(com|net|org|edu|gov|mil)$' ) ) ); The CHECK constraint here uses the REGEXP_LIKE function to establish input restrictions on the EMAIL1 column. Any incoming data is required to match the pattern specified in the second parameter of the REGEXP_LIKE function. A complete explanation of this pattern is provided in Table 17-7. 660 Chapter 17: TAbLe 17-7 Explanation for the sample CHECK Constraint’s Regular Expression Regular Expression Support # Regular Expression Operator Explanation 1 ^ Anchors the first pattern at the beginning of the string. 2 ( Opens a grouped expression (a subexpression) that is closed with # 7 (see below). 3 [ Opens a bracketed expression containing a matched list of values. 4 [:alnum:] Specifies the character class of alphanumeric characters. 5 ] Closes the bracketed expression that was opened in # 3 (see below). 6 + Specifies that any of the values in the bracketed expression contained within # 3 through # 5 repeat continuously. Any characters encountered that are not in the bracketed expression will end this part of the pattern. 7 ) Closes the grouped expression that was opened with # 2. 8 @ The literal value @. 9 [ Opens a bracketed expression containing a matched list of values. 10 [:alnum:] Specifies the character class of alphanumeric characters. 11 ] Closes the bracketed expression that was opened in # 9. 12 + Specifies that the any of the values in the bracketed expression contained within # 9 through # 11 repeat continuously. Any characters encountered that are not in the bracketed expression will end this part of the pattern. 13 . The literal value of a period (.). 14 ( Opens a grouped expression. 15 com|net|org|edu|gov|mil Identifies a set of expressions separated by the logical OR operator, which means that whatever occurs at this point in the pattern must be one of the options listed in the set of OR values. Regular Expressions and CHECK Constraints TAbLe 17-7 Explanation for the CHECK Constraint’s Regular Expression (Continued) 661 # Regular Expression Operator Explanation 16 ) Closes the grouped expression that was opened in # 14. 17 $ Anchors the final pattern to the end of the string—in other words, no extraneous characters after the completion of the pattern are allowed. Once we’ve created our table with its CHECK constraint, we can try to use it: INSERT INTO EMAIL_LIST VALUES (1, 'someone@corbinian.com'); 1 rows inserted INSERT INTO EMAIL_LIST VALUES (2, 'lellison@oracle.omc'); Error starting at line 1 in command: INSERT INTO EMAIL_LIST VALUES (2, 'lellison@oracle.omc') Error report: SQL Error: ORA-02290: check constraint (EFCODD.CK_EL_EMAIL1) violated 02290. 00000 - "check constraint (%s.%s) violated" *Cause: The values being inserted do not satisfy the named check *Action: do not insert values that violate the constraint. The CHECK constraint will accept valid input and reject invalid e-mail addresses that are not in the correct format. As we have seen, CHECK constraints may include regular expression functions and operators. Remember that CHECK constraints on a table perform as a gateway for incoming data on the constraint column or columns. If the incoming data violates the constraint, the table will not accept the incoming data. 662 Chapter 17: Regular Expression Support CertIFIcAtIon SummArY The language of regular expressions is found throughout the world of software development. Support for regular expressions is found in Unix, C, and many other languages and operating systems. Regular expression operators offer powerful flexibility in defining patterns for performing text searches, text replacement, and related tasks. Oracle SQL offers support for regular expression operators, along with functions that extend the capabilities of SQL to incorporate regular expression patterns into SQL. Regular expression operators include a number of special characters to perform tasks such as anchoring a pattern to the beginning or end of a string; defining a series of a particular set of character literals, defining a range of values, defining a character class, defining equivalent characters that involve accents and other special symbols, and much more. The backslash can be used to precede any operator that you wish to treat as a character literal. Regular expression functions such as REGEXP_SUBSTR extend the capability of SQL functions such as SUBSTR so that regular expression operators may be used to define patterns in performing text searches. The function REGEXP_REPLACE can replace patterns found within a target string. The backreference operator can be used to reference defined patterns within the replacement string, to reorder or otherwise restructure data in a variety of ways. CHECK constraints may be defined with regular expression functions and patterns to apply more flexibility to filtering input data. The REGEXP_LIKE condition is useful in this context, as are any of the regular expression operators. Two-Minute Drill 3 663 Two-MInute DrILL using Metacharacters q Metacharacter operators form the foundation of regular expressions. q Regular expression patterns are built with metacharacter operators. q Depending on the context, certain character literals may be regular expression operators with special capabilities, or they may be character literals. q Regular expressions can include character literals. q Literals enclosed in square brackets represent a set of possible values, or matched list. q Parentheses enclose a grouped expression, or subexpression. q An expression followed by a plus sign, question mark, or asterisk will be interpreted as a pattern that can repeat based on each operator’s rules. q You can specify character ranges. q Character classes can serve as an alternative to ranges and provide better support for multilingual applications. Regular Expression Functions q There are SQL functions that provide support for regular expressions. q REGEXP_SUBSTR, REGEXP_INSTR, REGEXP_LIKE, and REGEXP_ REPLACE have counterparts in SQL and extend the capabilities of those counterparts to provide regular expression support. Replacing Patterns q The REGEXP_REPLACE function can replace substrings within a target string using regular expressions. q The use of regular expressions with a task like string replacement is a much more powerful alternative to the use of a function such as REPLACE, which doesn’t support regular expressions. q The regular expression backreference operator can be used as the third parameter to replace a pattern, and to specify grouped expressions within the pattern as part of the replacement. 664 Chapter 17: Regular Expression Support Regular Expressions and ChECK Constraints q You can create CHECK constraints that use regular expressions. q CHECK constraints can use regular expression patterns to define restrictions and requirements on incoming data for a given table. q The REGEXP_LIKE condition is useful in applying the CHECK constraint to a given table. Self Test 665 SeLF Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one correct answer for each question unless otherwise directed. using Metacharacters 1. You can use regular expression functions: (Choose the best answer.) A. Only in the WHERE clause of SELECT statements B. Only in WHERE clauses and CHECK constraints C. Only in a SELECT statement or a CHECK constraint D. Anywhere you can use a SQL function of a comparable datatype 2. The operator to anchor a pattern to the beginning of a string is: A. ^ B. = C. $ D. * 3. You need to define a regular expression pattern that accepts any one of the string literal values of DC, VA, or MD. Which of the following patterns will do this? A. '(DC, VA, MD)' B. '(DC ? VA ? MD)' C. '(DC * VA * MD)' D. '(DC|VA|MD)' 4. You need to define a regular expression pattern that specifies a string of one or more alphabetic characters. Which of the following patterns will do this? A. '[:alpha:+]' B. '[:alpha:]+' C. '[[:alpha:]+]' D. '[[:alpha:]]+' 5. Which of the following character classes defines only uppercase letters? A. [:upper:] B. [:UPPER:] C. [:ALPHA:] D. None of the above 666 Chapter 17: Regular Expression Support Regular Expression Functions 6. You are tasked to identify the position of a given pattern within a larger string. Which of the following functions will you be sure to use? (Choose the best answer.) A. REGEXP B. REGEXP_INSTR C. REGEXP_SUBSTR D. REGEXP_REPLACE 7. Which of the following may not be used within a parameter of the REGEXP_LIKE function? A. ‘[:alpha:]’ B. ‘%’ as a wildcard operator C. ‘*’ as a regular expression operator D. ‘%’ as a literal value 8. Examine the following SQL statement: SELECT REGEXP_SUBSTR( 'Dickens, Charles. "Our Mutual Friend." '[[:alnum:]]+', 1, 5) THE_ANSWER FROM DUAL; Riverside Press, 1879.', What will be the answer? A. Friend B. Friend. C. Friend." D. None of the above 9. You are tasked to extract the first occurrence of any characters within a character-based column PRESS_RELEASE in a table PR that are enclosed within parentheses. For example: ' when the company Codd Cruise Lines (CCLX, 24.74) was ' Your task is toextract the substring enclosed in parentheses, inclusive, which in this example is ‘(CCLX, 24.74)’. Which of the following SQL statements will you use? A. SELECT REGEXP_SUBSTR(PRESS_RELEASE, '\([^)]+\)') PRESS_RELEASE FROM PR; B. SELECT REGEXP_SUBSTR(PRESS_RELEASE, '([[:alnum:]])') PRESS_RELEASE FROM PR; Self Test 667 C. SELECT REGEXP_SUBSTR(PRESS_RELEASE, '\([[:alpha:]]+\)') PRESS_RELEASE FROM PR; D. SELECT REGEXP_SUBSTR(PRESS_RELEASE, '\([^)]+)') PRESS_RELEASE FROM PR; Replacing Patterns 10. The third parameter of the REGEXP_REPLACE function specifies the replacement for whatever matches the pattern, which is specified in the second parameter. What will replace the pattern if the third parameter is omitted? A. NULL. B. Nothing—the statement will fail. C. The pattern is left in place and the original string remains unchanged. D. None of the above. 11. Examine the following SQL statement and its output: SELECT TEXT_STREAMING FROM ENTRIES WHERE ENTRY_ID = 12; TEXT_STREAMING --------------------------------------------------------------times sun chronicle circulation examiner Which of the following queries will strip out the extra blank spaces from the text above? (Choose two.) A. SELECT REGEXP_REPLACE(TEXT_STREAMING, '( ){2,},' ' ') THE_ANSWER FROM ENTRIES WHERE ENTRY_ID = 12; B. SELECT REGEXP_REPLACE(TEXT_STREAMING, '( )*,' ' ') THE_ANSWER FROM ENTRIES WHERE ENTRY_ID = 12; C. SELECT REGEXP_REPLACE(TEXT_STREAMING, '[[:blank:]]*,' ' ') THE_ANSWER FROM ENTRIES WHERE ENTRY_ID = 12; 668 Chapter 17: Regular Expression Support D. SELECT REGEXP_REPLACE(TEXT_STREAMING, '[[:blank:]]+,' ' ') THE_ANSWER FROM ENTRIES WHERE ENTRY_ID = 12; 12. Examine the following SQL statement: SELECT REGEXP_REPLACE('Charles Dickens','([[:alpha:]]+) ([[:alpha:]]+)', '\2') FROM DUAL; What will this SQL statement return when executed? A. h B. Dickens C. Charles Dickens D. None of the above Regular Expressions and ChECK Constraints 13. You are tasked to create a CHECK constraint on a column to ensure that any incoming data for phone numbers is entered in a format like this: (101)202-3330 Which of the following regular expression patterns will work in the CHECK constraint? (Choose the best answer.) A. '\([[:digit:]]{3}\)[[:digit:]]{3}-[[:digit:]]{4}' B. '[[:digit:]-()]{13}' C. '\([1-9]{3}\)[1-9]{3}-[1-9]{4}' D. '\([1-9]+\)[1-9]+-[1-9]+' 14. Which of the following patterns, if used in a CHECK constraint, will ensure that incoming data to a column will be accepted if it starts with the word “buy” or starts with the word “sell”, and that anything else will be rejected? A. '^(buy|sell)' B. '(^buy|sell)' C. '^[[:buysell:]]' D. '([buysell])' Self Test Answers 669 15. Examine the following SQL code: CREATE TABLE CUSTOMER_COMMENTS (CUSTOMER_COMMENTS_ID NUMBER(7) PRIMARY KEY, INCOMING_REQUEST VARCHAR2(80), CONSTRAINT CK_IR CHECK (REGEXP_LIKE(INCOMING_REQUEST,'([please])$')) ); Which of the following string values will be accepted as input to the INCOMING_REQUEST column by the CHECK constraint? (Choose all that apply.) A. ‘please submit my order’ B. ‘I would like to place an order please’ C. ‘sorry but I fell asleep’ D. ‘be careful with that last one’ 670 Chapter 17: Regular Expression Support SeLF Test Answers using Metacharacters 1. ˛ D. You can use regular expression functions anywhere that SQL functions of a comparable datatype can be used. ˝ A, B, and C are incorrect. Answer D is the best answer. 2. ˛ A. The caret is the beginning-of-line anchor. ˝ B, C, and D are incorrect. The equal sign is part of the equivalence class. The $ operator is the end-of-line anchor. The * operator is intended to repeat the preceding subexpression zero or more times. 3. ˛ D. The parentheses form a grouping, or subexpression, within which the desired values need to be separated by the logical OR operator, which is the pipe literal value of “|”. ˝ A, B, and C are incorrect. 4. ˛ D. The plus sign operator must follow the bracketed expression, which in turn encloses a character class with its own brackets. ˝ A, B, and C are incorrect. Answer A specifies a series of individual characters ‘:, a, l, p, h, a, :, +’. In other words, the attempt to specify the character class [:alpha:] and the plus sign operator all fail because the outer brackets are recognized as a bracketed expression, which encloses a list of individual characters; that is how its contents are recognized. Answer B is the same, but the plus sign operator is in the correct place. Still, the character class is not correctly specified. In Answer C, the character class is correctly specified, but by including the plus sign operator within the bracketed expression, it is not interpreted as the regular expression operator but instead is recognized as a literal plus sign. 5. ˛ A. ˝ B, C, and D are incorrect. Character classes must be specified in lowercase letters. Regular Expression Functions 6. ˛ B. The REGEXP_INSTR function returns a number indicating the position within a string of a given pattern. ˝ A, C, and D are incorrect. There is no REGEXP function. As for the others, while you may find some need to use one or the other of these functions as part of your overall approach, REGEXP_INSTR is the best answer. 7. ˛ B. The REGEXP_LIKE function does not use the same wildcard operators as LIKE. (Note: the % and * characters are accepted as string literals.) ˝ A, C, and D are incorrect. Self Test Answers 671 8. ˛ A. The answer will be the word “Friend” alone. ˝ B, C, and D are incorrect. The pattern identifies alphanumeric values alone. That excludes punctuation marks. 9. ˛ A. Answer A has the correct pattern for the following reasons: characters one and two specify an open parenthesis as a literal, with a preceding backslash to specify the parenthesis as an opening parenthesis rather than as a grouping expression. Character three is an opening square bracket of a bracketed expression, followed by a caret and closing parenthesis, and the closing bracket to the bracketed expression, and the plus sign operator. These characters (three through seven) specify a set of characters which is just one character really, which is “not the closing parenthesis”. It does not require the backslash here because it’s not possible to place a grouping expression within the square brackets, so there’s no confusing this literal closing parenthesis with a grouping expression. The caret indicates that this bracketed expression defines the set of values that shouldn’t be found—as opposed to the list that should be found. In other words, this bracketed expression specifies that we will look for characters that match the list—which is everything other than the closing parentheses. You could call this “not the closing parenthesis”—and since the plus sign operator is present, we will look for one or more characters through the rest of the string until we find a closing parenthesis. When we do, we stop. Finally, we specify a literal parenthesis which, if found, will become part of the returned result of this function. ˝ B, C, and D are incorrect. Answer B is wrong because the parentheses are treated as operators instead of literal values. You should start by looking for the first occurrence of an open parenthesis, but the inclusion at the beginning of the pattern uses an open parenthesis without the backslash preceding it, so it’s treated as the first part of a grouping expression operator. Answer C is wrong because, among other things, it uses the alpha character class within the parentheses, yet our example shows that the parentheses should accept any characters, including numerics and commas. Answer D is close but wrong—its last closing parenthesis is treated as an operator instead of a literal. Replacing Patterns 10. ˛ A. NULL replaces the pattern within the target string if the third parameter is omitted. ˝ B, C, and D are incorrect. 11. ˛ A and D. In answer A, the placement of {2,} specifies that the preceding pattern—a single blank space—may repeat two or more times. In answer D, the + operator specifies that the preceding pattern—a single blank space—may repeat multiple times. ˝ B and C are incorrect. The use of * in this context is erroneous—the asterisk specifies that any occurrence of the previous pattern, which is the single blank space, be replaced for each occurrence of it that appears zero or more times. The replacement is a blank space. The result: each character is replaced with a blank space. 672 Chapter 17: Regular Expression Support 12. ˛ B. The \2 operator identifies the second group in the expression. The group is defined by the grouping operators, which are the parentheses. The second grouped expression is what \2 will return, and in this case, that represents the second full word in the string. ˝ A, C, and D are incorrect. Regular Expressions and ChECK Constraints 13. ˛ A. This is the best answer, as it best preserves the integrity of the format in retaining a pair of literal parentheses enclosing three digits, followed by three digits, followed by a dash, followed by exactly four digits. ˝ B, C, and D are incorrect. Answer B will not exclude numbers that have too many numbers in the area code, or too few numbers in the exchange—it will accept any string of 13 characters in any combination of numbers, parentheses literals, and dashes, including those that do not resemble the stated phone number format at all. Answers C and D omit the number zero. 14. ˛ A. The caret specifies that the expression that follows it is anchored to the start of the string. The parentheses pair ensures that the caret anchors everything contained within to the beginning of the string. The group is defined with a logical OR to be either the literal string “buy” or “sell”. ˝ B, C, and D are incorrect. Answer B is close—it will accept incoming values that start with the word “buy”, and incoming values that use the word “sell” in any position—but it will not require that the word “sell” be in the first position. Answer D is not anchored to the start of the string. Answer C is anchored but references a non-existent character class. 15. ˛ B, C, and D. The CHECK constraint defines a grouping expression, within which is a bracketed list. Inside the bracketed list is a set of letters ‘please’, and within the bracketed list, those letters are considered individually. Finally, the $ operator anchors the entire group to the end of the string. Therefore, the constraint requires any one of the letters ‘p’, ‘l’, ‘e’, ‘a’, ‘s’, or ‘e’ to be present at the end of the string. ˝ A is incorrect. 18 Controlling User Access Certification Objectives 18.01 Differentiate System Privileges from Object Privileges 18.02 Grant Privileges on Tables 18.03 View Privileges in the Data Dictionary 18.04 Grant Roles 18.05 Distinguish Between Privileges and Roles 3 Q&A Two-Minute Drill Self Test 674 Chapter 18: Controlling User Access T his chapter explores the subject of user access and the privileges associated with performing actions in the database. Every action performed by any user account requires a corresponding privilege or set of privileges to perform that action. There are two categories of privileges—system privileges are required to perform a task in the database; object privileges are required to use those system privileges on any given database object in particular. Privileges may be granted to a user account, or to another database object called a role. A role, in turn, can be granted to a user account, which effectively grants the set of privileges collected within the role. Once granted, privileges and roles may later be revoked. Together, privileges and roles are the mechanism for managing and controlling access to the database by user accounts. This chapter looks at how to create and manage privileges and roles. A word of warning about the sample code contained in this chapter: Some of it has the ability to change your database permanently with results that may be undesirable. Some of our code samples will look at SQL code that uses the SYSTEM user account, a very important account that should be controlled by experienced database administrators in any production database. You should always check with your DBA before trying any code samples from any book, but this chapter in particular includes code that you should not execute in a professional installation without first checking with your DBA. Certification Objective 18.01 Differentiate System Privileges from Object Privileges Throughout this book, we’ve looked at how a user account can use SQL statements to create and use a variety of database objects. However, before any user account can execute a SQL statement, it must be granted the privilege to execute that SQL statement. Furthermore, once a database object has been created, any user account that uses the database object must be granted privileges to do so. There are three general categories of privileges, as described in Table 18-1. We’ll review each of the items listed in Table 18-1 in this chapter. Differentiate System Privileges from Object Privileges 675 TabLe 18-1 Type of Privilege Description Types of Privileges System privilege The ability to perform a particular task in the database Object privilege The ability to perform a particular task on a particular database object Role A collection of one or more system privileges and/or object privileges, and/or other roles System Privileges System privileges are the right to perform some task in the database. For example, to log in to the database, a user account is granted the system privilege CREATE SESSION. To create a table, a user account must be granted the system privilege CREATE TABLE. There are over 100 different system privileges. Table 18-2 lists some of the system privileges that are required to perform the tasks we’ve discussed in this book. System privileges differ from object privileges in that system privileges are what a user account must have to create database objects, among other things. Then, once created, object privileges on a particular database object can be granted to other users. TabLe 18-2 System Privilege Description Some System Privileges CREATE SESSION Connect to the database. CREATE TABLE Create a table in your user account. Includes ability to ALTER and DROP TABLE. Also includes ability to CREATE, ALTER, and DROP INDEX objects. CREATE VIEW Create a view in your user account. Includes ALTER and DROP. CREATE SEQUENCE Create a sequence in your user account. Includes ALTER and DROP. CREATE SYNONYM Create a synonym in your user account. Includes ALTER and DROP. Does not include PUBLIC synonyms—see CREATE PUBLIC SYNONYM. CREATE ROLE Create a role. Includes ALTER and DROP. CREATE PUBLIC SYNONYM Create a synonym in the PUBLIC account. Does not include DROP, which is separate. (Continued) 676 Chapter 18: Controlling User Access TabLe 18-2 System Privilege Description Some System Privileges (Continued) DROP PUBLIC SYNONYM Drop a synonym from the PUBLIC account. CREATE ANY TABLE Create a table within any user account. ALTER ANY TABLE Alter a table within any user account. DELETE ANY TABLE Delete from any table within any user account. DROP ANY TABLE Drop any table within any user account. INSERT ANY TABLE Insert into any table within any user account. SELECT ANY TABLE Select from any table within any user account. UPDATE ANY TABLE Update any table within any user account. CREATE ANY VIEW Create a view in any user account. DROP ANY VIEW Drop a view from any user account. CREATE ANY INDEX Create an index in any user account. ALTER ANY INDEX Alter an index in any user account. DROP ANY INDEX Drop an index from any user account. CREATE ANY SEQUENCE Create a sequence in any user account. ALTER ANY SEQUENCE Alter a sequence in any user account. DROP ANY SEQUENCE Drop a sequence from any user account. SELECT ANY SEQUENCE Select from a sequence in any user account. CREATE ANY SYNONYM Create a synonym in any user account. DROP ANY SYNONYM Drop a synonym from any user account. CREATE ANY DIRECTORY Create a directory in any user account. DROP ANY DIRECTORY Drop a directory from any user account. ALTER ANY ROLE Alter a role in the database. DROP ANY ROLE Drop any role in the database. GRANT ANY ROLE Grant any role in the database. FLASHBACK ANY TABLE Perform flashback operations on any table in the database. CREATE USER Create a user account. ALTER USER Alter a user account. DROP USER Drop a user account. GRANT ANY PRIVILEGE Grant any system privilege to any user account in the database. GRANT ANY OBJECT PRIVILEGE Grant, to any user account in the database, any object privilege that the object’s owner is also able to grant. Differentiate System Privileges from Object Privileges 677 For example, the right to execute the SQL statement CREATE TABLE and create a new database table—is a system privilege. But the ability to change rows of data in, for example, a table called BENEFITS owned by a user account named EUNICE—is an object privilege. In other words, an object privilege is the right to do something to a particular object. As an analogy, consider the concept of a driver’s license. A driver’s license is sort of like a system privilege—it’s the right to drive a car in a general sense. Once you have a driver’s license, if you get a car, you can drive it. But you don’t have the right to drive anyone’s car in particular unless the owner specifically authorizes you to do so. The driver’s license is like a system privilege. The right to drive someone else’s car is like an object privilege. You need both in order to drive a car and be in full compliance with the law. The same is true in the database—you need system privileges to perform particular tasks, and object privileges to perform those tasks on an object in particular. Let’s look at some of the syntax for granting privileges. And note: for some of the upcoming examples, we’ll use the SQL*Plus tool and some SQL*Plus commands. These SQL*Plus commands do not require the semicolon termination character that is required in SQL statements. We’ll use the SQL*Plus command CONNECT to log in to another user account. You can also use the SQL*Plus command SHOW USER to confirm which account is currently active in the session. SQL*Plus commands are useful to know and helpful to use in your SQL sessions. But they are not on the exam. Prerequisites Before we get started with GRANT and REVOKE statements, let’s review some supporting statements that aren’t specifically included in the exam objectives but are useful for demonstrating system privileges, object privileges, roles, and their capabilities. CREATE, ALTER, and DROP USER Let’s look at how to create a user account to begin with. Any SQL user with the CREATE USER system privilege may execute the CREATE USER statement, whose syntax looks like this: CREATE USER username IDENTIFIED BY password; In this statement, username is a name you specify according to the rules for naming database objects. The password follows the same rules. (Note: passwords are case sensitive by default starting with Oracle 11g .) 678 Chapter 18: Controlling User Access For example, this statement will create a user name JOAN with a password OFARC: CREATE USER JOAN IDENTIFIED BY OFARC; You can use the ALTER USER statement to change the password, like this: ALTER USER JOAN IDENTIFIED BY HAWAII; Finally, you can remove a user from the database using the DROP USER statement, like this: DROP USER username; If a user account owns any database objects, the preceding statement won’t work, and you’ll need to use this: DROP USER username CASCADE; The CASCADE option directs SQL to drop the user account and all of the objects it owns. Once a user object has been created, it can be granted privileges, as we’ll see in an upcoming section. CONNECT The CONNECT statement is not a SQL statement but a SQL*Plus enhancement you can use within the Oracle SQL*Plus tool. Once you’ve started SQL*Plus, you can use CONNECT to log in or switch login sessions from one user account to another. If, for example, you are using the SQL*Plus tool and have logged in to the EFCODD account and created the user account JOAN, you can log in to the JOAN account directly from EFCODD with this statement: CONNECT JOAN/HAWAII That assumes that the user account JOAN is still using the password HAWAII. It also assumes that JOAN has been granted the minimum system privileges to log in—such as CREATE SESSION. Also note—a semicolon termination character is not required in SQL*Plus statements. It is accepted but not required. The semicolon termination character is required in SQL statements, but is optional in SQL*Plus statements. Tablespaces In the course of setting up a new user account, the topic of tablespaces must be addressed. However, the topic of tablespaces goes beyond our scope and is not Differentiate System Privileges from Object Privileges 679 included in the exam objectives, so we’re going to go with a simple way to address the tablespace requirement, namely: GRANT UNLIMITED TABLESPACE TO username; This would probably not be something that your typical production DBA would do. Tablespaces are controlled by database administrators. A typical DBA generally creates uniquely named tablespaces and carefully allocates space quotas to them. We, however, aren’t concerned with any of that for this book or for the exam. So for us, the preceding statement is what we’ll include. If you wish to learn more, we heartily encourage you to check out any of the outstanding books from Oracle Press on the topic of database administration. In the meantime, if you’re working on your own test system on your own personal machine—this particular statement that grants UNLIMITED TABLESPACE is more than adequate for our purposes going forward. If you’re trying these at work—check with your DBA before trying any of the code samples in this chapter. gRANT and REVOKE Now let’s get down to business. System privileges are granted with the GRANT statement. Here’s an example of a SQL session that logs in to the Oracle SYSTEM account, creates a new user, and grants the new user account some initial system privileges using three GRANT statements (line numbers added): 01 02 03 04 05 CONNECT SYSTEM/MANAGER CREATE USER HAROLD IDENTIFIED BY LLOYD; GRANT CREATE SESSION TO HAROLD; GRANT UNLIMITED TABLESPACE TO HAROLD; GRANT CREATE TABLE TO HAROLD; In these statements, here is what we are doing: n Line 1: Establish a user session with the user account SYSTEM, with a password of MANAGER. The SYSTEM account is installed with every Oracle database, and its initial password at installation defaults to MANAGER. (WARNING: DO NOT TRY THIS on a production system. No self-respecting production system should have a SYSTEM account password still set to the default value of MANAGER anyway, but the point is that if you have installed your own version of the Oracle database on your own local machine, and it is not used for production work, then you can try this, but if you’re trying things out within a system at your workplace or somewhere comparable—then be sure to check with your database administrator before trying this.) 680 Chapter 18: Controlling User Access n Line 2: We create a brand new user account called HAROLD, with the password LLOYD. n Line 3: We use the SQL statement GRANT to give the CREATE SESSION privilege to user HAROLD. This is a minimum requirement in order for us to be able to log in to the database with the HAROLD user account; without this GRANT statement, we couldn’t successfully log in with the user account HAROLD. n Line 4: This is one way to ensure that HAROLD can create objects. See our earlier discussion about tablespaces in the previous section. n Line 5: We GRANT the system privilege CREATE TABLE to user account HAROLD. See Figure 18-1 for the results of these statements in the SQL*Plus window. Now—let’s log in to HAROLD and try out what we’ve done. For that, we’ll try the following SQL statements: CONNECT HAROLD/LLOYD CREATE TABLE CLOCKTOWER (CLOCK_ID NUMBER(11)); CREATE SEQUENCE SEQ_CLOCK_ID; See Figure 18-2 for the results. Note that we aren’t able to create the sequence because we haven’t been granted sufficient privileges to do so. For that, we’ll need to log back in to the SYSTEM account and grant the system privilege CREATE SEQUENCE to HAROLD. Once that has been accomplished, we can log back in to HAROLD and create the sequence (see Figure 18-3). Figure 18-1 SQL*Plus session: GRANT statements Differentiate System Privileges from Object Privileges 681 Figure 18-2 SQL*Plus session: testing system privileges Figure 18-3 SQL*Plus session: creating the sequence In these examples, we have been using the SYSTEM account to grant these privileges, but any qualified database administrator (DBA) account will do and is preferable in any serious installation with multiple Oracle users. In such a situation, the less time a developer or DBA spends in the SYSTEM account—or the other restricted default DBA accounts in the Oracle database such as SYS—the less likely a mistake will accidentally cause some serious damage to the database. The basic syntax for the GRANT statement is simple: GRANT privilege TO user option; where privilege is one of the several dozens of system privileges that are already defined in the database—see the Oracle Database SQL Language Reference Manual for a complete list. Multiple privileges can be granted at once by separating each additional privilege by a comma, as in GRANT privilege, privilege, . . . We’ll discuss option in an upcoming section. 682 Chapter 18: Controlling User Access The basic syntax for REVOKE is comparable: REVOKE privilege FROM user; Note that you grant “TO” and you revoke “FROM”. Once a system privilege is revoked from a user, the effect is immediate. However, any actions taken prior to the revocation stand. In other words, if a user account has been granted the system privilege CREATE TABLE, and then creates some tables, but then has the CREATE TABLE system privilege revoked—the created tables already in existence remain in place. They do not disappear. But the owning user may not create additional tables while the CREATE TABLE system privilege is revoked. We’ve looked at a few system privileges, and we’ve said that they are somewhat like a driver’s license. Now let’s extend the analogy a little bit—imagine what would happen if you could get a universal driver’s license that carried with it the ability to drive anyone’s car legally without the car’s owner express permission. Such a concept exists within the Oracle database, and it’s embodied in the keyword ANY. Let’s look at that next. ANy Some system privileges include the keyword ANY in the title. For example, there is a system privilege CREATE ANY TABLE, which is the ability to create a table in any user account anywhere in the database. Let’s look at a sample session that involves this privilege: CONNECT SYSTEM/MANAGER CREATE USER LAUREL IDENTIFIED BY POKE; GRANT CREATE SESSION TO LAUREL; GRANT UNLIMITED TABLESPACE TO LAUREL; GRANT CREATE TABLE TO LAUREL; CREATE USER HARDY IDENTIFIED BY CLOBBER; GRANT CREATE SESSION TO HARDY; GRANT UNLIMITED TABLESPACE TO HARDY; GRANT CREATE ANY TABLE TO HARDY; CONNECT LAUREL / POKE CREATE TABLE MOVIES (MOVIE_ID NUMBER(7)); CONNECT HARDY / CLOBBER CREATE TABLE LAUREL.TVSHOWS (TVSHOW_ID NUMBER(7)); Differentiate System Privileges from Object Privileges 683 The result of the preceding SQL statements: two user accounts will be created; also, two tables will be created, one table called MOVIES and another table called TVSHOWS. Both tables will exist in the user account LAUREL—the first table was created by LAUREL, but the second table TVSHOWS was created by user account HARDY and created as a table that is owned by LAUREL. The user account HARDY will contain no tables. The official “owner” of both tables is LAUREL, as the data dictionary confirms: SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE OWNER IN ('HARDY','LAUREL'); OWNER -----------------------------LAUREL LAUREL TABLE_NAME -----------------------------MOVIES TVSHOWS When a system privilege includes the keyword ANY in its title, it means that the privilege will authorize a user to perform the task as though they were any user account. In this example, user HARDY was able to create a table and place it in the LAUREL account, a task typically reserved only for user LAUREL. However, since user HARDY has the system privilege CREATE ANY TABLE, then HARDY can create any table in any user account. ADMIN OPTION In a previous section we said we would look at the option in the GRANT statement’s syntax we examined. Here it is: the option is an additional clause that may be included with the GRANT statement, as follows: GRANT privilege TO user WITH ADMIN OPTION; When any system privilege is granted with the WITH ADMIN OPTION option, then the recipient receives the system privilege itself, along with the right to grant the system privilege to another user (see Figure 18-4). The REVOKE statement does not use the WITH ADMIN OPTION clause. Whenever a system privilege is revoked, the entire system privilege is revoked. If a user—let’s call it the first user—grants a system privilege to a second user WITH ADMIN OPTION, and the second user uses the admin option to grant that same system privilege to a third user, then the third user retains the privilege until it is explicitly revoked from the third user. In other words, once the second user has 684 Chapter 18: Controlling User Access Figure 18-4 GRANT versus GRANT WITH ADMIN OPTION The WITH ADMIN OPTION gives USER_2 the authority to extend GRANT without or WITH ADMIN OPTION. SYS PRIV GRANT GRANT SYS PRIV GRANT… WITH ADMIN OPTION SYS PRIV GRANT…WITH ADMIN OPTION USER_1 USER_2 USER_3 granted the third user with the system privilege, it stays with the first user, even if the first user—or any other qualified user—revokes the system privilege from the second user. If that happens, the third user still has the system privilege. The only way the third user will lose the system privilege is if any qualified user revokes the system privilege explicitly from the third user with a REVOKE statement. In other words—the REVOKE statement for system privileges does not “cascade”. It only applies to the user to whom the revocation is applied. ALL PRIVILEgES As an alternative to granting specific system privileges, a qualified user account, such as SYSTEM or some other DBA qualified account, can issue the following statement: GRANT ALL PRIVILEGES TO user; This statement has the effect of granting all system privileges to the user. The WITH ADMIN OPTION clause may be used with this as well. Needless to say, this should only be done with great caution, if at all. It is not easily reversible—in other words, this is not an exact counterpart: REVOKE ALL PRIVILEGES FROM user; Differentiate System Privileges from Object Privileges 685 This statement will reverse all system privileges granted to the user, assuming that all system privileges have been granted to the user. If not, an error message will result. PUBLIC The PUBLIC account is a built-in user account in the Oracle database that represents all users. Any objects owned by PUBLIC are treated as though they are owned by all the users in the database, present and future. The GRANT statement will work with the keyword PUBLIC in the place of a user account name. For example: GRANT CREATE ANY TABLE TO PUBLIC; This statement grants the CREATE ANY TABLE privilege to every user in the database. The CREATE ANY TABLE privilege gives every user the ability to create any table in any other user account. In other words—mass hysteria. Or something like it. Mind you, we’re not recommending you do this—but it’s syntactically possible, and you need to be aware of it. While this sort of an example is unlikely, granting to PUBLIC may be useful with a selected number of object privileges, which we’ll discuss a bit later. Note that if you come to your senses and decide to revoke a system privilege from PUBLIC, you can do so without revoking any other system privileges. In other words, consider this statement: REVOKE CREATE ANY TABLE FROM PUBLIC; Note that if you wish to grant all privileges, you use the keywords ALL PRIVILEGES. But if you wish to grant certain privileges to all users, you do not use the keyword ALL. Instead, you grant to PUBLIC. This statement will reverse the GRANT . . . TO PUBLIC that we issued a few paragraphs earlier, and thankfully will not revoke any individually granted CREATE ANY TABLE system privileges held by any user accounts. It will only revoke the GRANT to PUBLIC. And if you’re even thinking about GRANT ALL PRIVILEGES TO PUBLIC WITH ADMIN OPTION, you can put that thought out of your mind right this second. 686 Chapter 18: Controlling User Access Certification Objective 18.02 grant Privileges on Tables Any user with the system privilege CREATE TABLE can create a table. The table, once created, is owned by the user who created it. The owner does not require any explicitly granted privileges on the table. The table owner can use DML to add rows, change data in the table, query the data in the table, and remove rows from the table. But other users do not have that privilege automatically. Other users must have explicitly granted priviliges on the object—which, in this case, is a table. (Note: The exception, of course, is those users who have the system privileges that allow them to run any DML statements on any table in the database, regardless of who owns it—those system privileges, as we saw in the last section, include SELECT ANY TABLE, INSERT ANY TABLE, UPDATE ANY TABLE, and DELETE ANY TABLE.) Any user who owns a table—or any other database object—may grant object privileges on their database object to other users in the database. Object privileges exist for all DML statements—SELECT, INSERT, UPDATE, and DELETE—as well as any DDL statement that is relevant to an existing object: ALTER, for example. Note: there is no separate set of object privileges for the MERGE statement. Object privileges on a table include all of the DML statements that can be executed against a table. For example, if a user account LISA has the system privilege CREATE TABLE, then LISA can create a table. If LISA takes advantage of this system privilege and creates a table WEBINARS, then LISA can access the new table, but other users are not automatically able to see the table (unless, as we stated earlier, those users possess one of the “ANY” system privileges, such as SELECT ANY TABLE). In order to ensure that other user accounts can execute SQL statements on the table, user account LISA will have to grant object privileges on WEBINARS to other users. See Figure 18-5 for a SQL*Plus session in which we connect to the SYSTEM account, where we create two user accounts, LISA and HENRY. We give LISA sufficient privileges to connect (CREATE SESSION) and create tables. Note how we combined multiple system privileges in a single GRANT statement. Also, we give HENRY sufficient privileges to create a session—but nothing more. Grant Privileges on Tables 687 Figure 18-5 Creating, granting, and testing object privileges—part 1 We continue in Figure 18-6, where we connect to the LISA account and create a table, add data to it, and then grant privileges on the table to HENRY. Then we connect to HENRY, where we can issue SELECT and UPDATE statements, but not INSERT—that particular privilege wasn’t granted to HENRY. Figure 18-6 Creating, granting, and testing object privileges—part 2 688 Chapter 18: Controlling User Access Take another look at Figure 18-6, and note the moment that the GRANT statement is issued. Remember that any DDL statement carries with it an implicit commit event. In other words, the GRANT statement has the effect of making the results of the INSERT statement permanent in the database. Once that GRANT has executed, the option to ROLLBACK the INSERT statement is no longer available. Schema Prefixes Note in Figure 18-6 that when HENRY references a table owned by LISA, HENRY must use the schema prefix to make the reference. In other words, HENRY could not issue a SELECT statement like this: SELECT * FROM WEBINARS; Instead, HENRY uses this sort of reference: SELECT * FROM LISA.WEBINARS; However, you might recall our discussion several chapters ago about the PUBLIC SYNONYM object. Remember that a SYNONYM is an alternative name for a database object. A PUBLIC SYNONYM is a SYNONYM that is owned by the PUBLIC user account, which is an automatically created user account that is maintained by the Oracle database. The PUBLIC user isn’t intended to be an account into which you log in to get access—instead, PUBLIC is a mechanism by which you can create globally owned objects. Specifically, anything that is owned by PUBLIC is automatically owned by all users in the database. The same is true for PUBLIC SYNONYMS. In our earlier example, the user SYSTEM could have given user LISA the system privilege to create public synonyms by issuing the following statement: GRANT CREATE PUBLIC SYNONYM TO LISA; Then, later, the user LISA could have used that system privilege to create a PUBLIC SYNONYM like this: CREATE PUBLIC SYNONYM WEBINARS FOR LISA.WEBINARS; Finally, once user HENRY got around to issuing DML statements on the WEBINARS table, HENRY could have omitted the schema prefix and instead simply executed this statement: SELECT * FROM WEBINARS; Grant Privileges on Tables 689 In this instance, HENRY would be specifying the WEBINARS object PUBLIC SYNONYM, which in turn points to the object LISA.WEBINARS. Note that no object privilege had to be granted on the PUBLIC SYNONYM object to HENRY. All objects owned by PUBLIC are automatically available and accessible to all users in the database, present and future. However, privileges must be granted to whatever object for which the PUBLIC SYNONYM serves as an alias. It’s one thing to have privileges on a PUBLIC SYNONYM that references a table, but it’s another thing to have privileges on the table it references. All users have privileges automatically on any object owned by PUBLIC; they do not have automatically granted privileges on anything a PUBLIC SYNONYM references—such privileges must be granted explicitly. This sort of usage is the most common purpose of the PUBLIC SYNONYM object. Note that in order to create PUBLIC SYNONYM objects, a user account must have the CREATE PUBLIC SYNONYM system privilege. Name Priority, Revisited You may recall our discussion in Chapter 10 about a concept called name priority. When a user makes a reference to an object by name, SQL will use that name to search for that object as follows: n First, SQL looks in the local namespace, which contains objects owned by the user account: tables, views, sequences, private synonyms, and something called user-defined types—which are beyond the scope of the exam. n Next, SQL looks in the database namespace, which contains users, roles, and public synonyms. This concept was demonstrated graphically in Figure 10-3. WITH gRANT OPTION If you wish to grant another user a particular object privilege, and include the ability for the user to grant that same object privilege to yet another user, then include the WITH GRANT OPTION clause in the GRANT statement. For example: CONNECT LISA/POE GRANT SELECT, UPDATE ON WEBINARS TO HENRY WITH GRANT OPTION; This grant gives user HENRY the ability to issue SELECT and UPDATE statements on table WEBINARS, along with the ability to grant those privileges 690 Chapter 18: Controlling User Access to other users. HENRY is not obligated to grant the set of privileges together, HENRY can choose to be selective: CONNECT HENRY/RUSSFUSS GRANT SELECT ON LISA.WEBINARS TO HAROLD WITH GRANT OPTION; Now user HAROLD has the ability to issue SELECT statements on LISA.WEBINARS, as well as the ability to grant that privilege to others. But HENRY did not pass along the UPDATE privilege. reVoKe User LISA may choose to revoke privileges from HENRY, like this: REVOKE SELECT, UPDATE ON WEBINARS FROM HENRY; If user LISA does this, then HENRY and HAROLD lose all privileges, as does anyone to whom they extended privileges with their WITH GRANT OPTION option. In other words, revoking object privileges “cascades”. Note that the REVOKE statement does not require the WITH GRANT OPTION clause. REVOKE doesn’t care whether that option had been included or not, it just revokes all specified privileges and cascades the change throughout all user accounts as required. ALL PrIVILeGes The ALL PRIVILEGES option works with granting and revoking object privileges in much the same way it does with system privileges, with some differences. For example: GRANT ALL PRIVILEGES ON WEBINARS TO HENRY; This statements gives all privileges on the object WEBINARS to HENRY, except for the ability to grant privileges. To grant the ability to grant, use this: GRANT ALL PRIVILEGES ON WEBINARS TO HENRY WITH GRANT OPTION; The keyword PRIVILEGES is not required when granting object privileges: GRANT ALL ON WEBINARS TO HENRY; The same is true with REVOKE when used with object privileges: REVOKE ALL PRIVILEGES ON WEBINARS FROM HENRY; This is also good: REVOKE ALL ON WEBINARS FROM HENRY; View Privileges in the Data Dictionary 691 This shorthand way of revoking object privileges spares the effort of identifying all the individual object privileges that may have already been granted to HENRY on the WEBINARS table, and revokes them all at once. Note that the keyword PRIVILEGES is optional when working with object privileges, but not when working with system privileges. If you use REVOKE ALL to revoke object privileges from a user, and no object privileges exist on the object for that user, then no error message results, and the statement executes successfully with no practical effect. Dependent Privileges If user A owns a view, which is based on a table that user A also owns, and user A grants privileges on the view to user B, then user B can access the view without privileges to the underlying table. If user A creates a table and a public synonym, then user B has immediate visibility of the public synonym, because the synonym is owned by PUBLIC and all users have visibility of all objects owned by PUBLIC. However, user B still requires privileges on the table for which the public synonym is an alias. If the public synonym references a view that user A owns, then user B must have object privileges on the view, but is not required to have access to its underlying table. If you grant privileges on a table, then drop the table, the privileges are dropped with the table. If you later recreate the table, you must also grant the privileges again. However, if you restore a dropped table with the FLASHBACK TABLE . . . BEFORE DROP statement, you will recover the table, its associated indices, and the table’s granted privileges, and you will not need to grant the privileges again. CertiFication obJective 18.03 View Privileges in the Data Dictionary We’ve already looked at the data dictionary, and seen how it provides information about the state of objects in the database, as well as providing some historic information as well. 692 Chapter 18: Controlling User Access There are many views in the data dictionary that present information about system privileges and object privileges. See Table 18-3 for a listing of some of these views. For example, to see what system privileges are granted to your current user account, you can query the data dictionary view USER_SYS_PRIVS. Here’s what the results might look like from user account LISA: SELECT PRIVILEGE, ADMIN_OPTION FROM USER_SYS_PRIVS ORDER BY PRIVILEGE; PRIVILEGE ---------------------------------------CREATE PUBLIC SYNONYM CREATE SESSION CREATE TABLE UNLIMITED TABLESPACE ADMIN_OPTION -----------NO NO NO NO The equivalent data dictionary view DBA_SYS_PRIVS allows you to see the same information for other users. A privilege may be granted directly as a privilege, or indirectly as part of a role. If you intend to DROP a privilege from a USER, use the data dictionary to determine if that same privilege is granted to a ROLE that is also granted to the same USER—if so, then the privilege you dropped directly is still granted to the USER indirectly through the ROLE. TabLe 18-3 Data Dictionary View Explanation Data about Privileges in the Data Dictionary USER_SYS_PRIVS System privileges granted to current user DBA_SYS_PRIVS System privileges granted to users and roles USER_TAB_PRIVS Grants on objects for which the user is the grantor, grantee, or owner ALL_TAB_PRIVS Grants on objects for which the user is the grantor, grantee, owner, or an enabled role or PUBLIC is the grantee DBA_TAB_PRIVS Grants on all objects in the database ALL_TAB_PRIVS_RECD Grants on objects for which the user, PUBLIC, or enabled role is the grantee SESSION_PRIVS Privileges that are enabled to the user Grant Roles 693 To see all of the object privileges that your current user account may have granted to others, or may have been granted by others, you can use the following query. This is what the results might look like within the user account LISA: SELECT GRANTOR, OWNER, GRANTEE, TABLE_NAME, PRIVILEGE, GRANTABLE FROM USER_TAB_PRIVS ORDER BY GRANTOR, OWNER, GRANTEE, TABLE_NAME, PRIVILEGE; GRANTOR ---------EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD LISA LISA OWNER ---------EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD EFCODD LISA LISA GRANTEE --------LISA LISA LISA LISA LISA LISA LISA LISA LISA HENRY HENRY TABLE_NAME -----------PORTS PORTS PORTS PORTS SHIPS SHIPS SHIPS SHIPS SHIPS WEBINARS WEBINARS PRIVILEGE -----------DELETE INSERT SELECT UPDATE ALTER DELETE INSERT SELECT UPDATE SELECT UPDATE GRANTABLE --------NO NO NO NO NO NO NO NO NO NO NO Note that the first several rows show object privileges granted by EFCODD to LISA. The final two rows show object privileges granted by LISA to HENRY. These are just a few examples of the sort of information the data dictionary provides about system privileges and object privileges that have been granted to and from user accounts within the database. When inspecting data dictionary views like DBA_TAB_PRIVS or DBA_SYS_ PRIVS to see what privileges have been granted to a particular user account, you can check the GRANTEE column for the appropriate USER name. However, don’t forget to also check for rows where GRANTEE = ‘PUBLIC’; these privileges are also available to your user account. Certification Objective 18.04 grant Roles A ROLE is a database object that you can create, and to which you can assign system privileges and/or object privileges. You can also assign other roles to a given role. Once it is created, you can grant a ROLE to a user just as you can 694 Chapter 18: Controlling User Access grant privileges to a user. The user is then automatically granted any privileges contained within the ROLE. A ROLE is an excellent way to manage the various privileges required for performing different tasks in the database, and to organize the process of granting and revoking privileges. You may grant the ROLE to as many user accounts as you wish. If any privilege is subsequently revoked from the ROLE, it is also revoked from any users to whom the role has been granted. In other words, changes to roles cascade to the users to whom the role is granted. Three roles in particular have historically been associated with standard Oracle databases, but they are being phased out. On a practical level, though, it’s good to know about them, if you don’t already. The three roles are CONNECT, RESOURCE, and DBA. The CONNECT role consists of the CREATE SESSION system privilege, intended for the typical generic end user. RESOURCE is a collection of system privileges intended for the typical application developer. DBA is intended for the typical database administrator. Each can be seen in detail in the data dictionary view DBA_SYS_PRIVS (see Table 18-4 for details). All three roles are still included in each implementation of the Oracle database as of this writing, but Oracle has stated formally that the use of these roles is now officially discouraged, and their inclusion in future database implementations is not guaranteed. Oracle Corporation’s official position is that you should create your own set of roles as required. You can refer to the data in Table 18-4 to get an idea of the kind of system privileges you may wish to include in your role objects. In order to create a ROLE, a user account needs the CREATE ROLE system privilege. For example, the user account EFCODD owns several tables and wishes to grant privileges on these tables to some users in the database. Some of these users will be performing queries on the tables and nothing more. Others will be responsible for performing changes to the data. Therefore, we wish to create two different roles and grant them the necessary privileges: CONNECT EFCODD/FOUNDER CREATE ROLE CRUISE_ANALYST; GRANT SELECT ON SHIPS TO CRUISE_ANALYST; GRANT SELECT ON PORTS TO CRUISE_ANALYST; GRANT SELECT ON EMPLOYEES TO CRUISE_ANALYST; CREATE ROLE CRUISE_OPERATOR; GRANT SELECT, UPDATE, INSERT, DELETE ON SHIPS TO CRUISE_OPERATOR; GRANT SELECT, UPDATE, INSERT, DELETE ON PORTS TO CRUISE_OPERATOR; GRANT SELECT, UPDATE ON EMPLOYEES TO CRUISE_OPERATOR; Grant Roles TabLe 18-4 Role Privilege The Classic Roles CONNECT, RESOURCE, and DBA CONNECT CREATE SESSION RESOURCE CREATE TRIGGER CREATE SEQUENCE CREATE TYPE CREATE PROCEDURE CREATE CLUSTER CREATE OPERATOR CREATE INDEXTYPE CREATE TABLE DBA Over 100 system privileges, including: CREATE ANY TABLE CREATE PUBLIC SYNONYM CREATE ROLE CREATE SYNONYM CREATE SEQUENCE CREATE USER CREATE VIEW GRANT ANY PRIVILEGE Etc. 695 In the preceding code, we create two role objects: one called CRUISE_ANALYST, to which we grant some SELECT privileges on tables, and another called CRUISE_OPERATOR, to which we grant some other privileges. Once they are created, we can grant these roles to user accounts in the database: GRANT CRUISE_OPERATOR TO LISA; GRANT CRUISE_ANALYST TO HENRY; Once a role is granted, a user has access to all of the privileges within it. A role can be granted to another role. A role can be granted WITH ADMIN OPTION to empower the recipient to grant the role to yet another user. For example: GRANT CRUISE_OPERATOR TO LISA WITH ADMIN OPTION; If a user grants a role to another user and uses the WITH ADMIN OPTION, the second user may further grant the same role to a third user. If the first user revokes the role from the second user, the third user retains the role until it is explicitly revoked from the third user by a qualified user. Table 18-5 lists some of the data dictionary views that provide information about existing roles in the database. 696 Chapter 18: Controlling User Access TabLe 18-5 Data Dictionary View Explanation Data Dictionary Views with Information about ROLE Objects DBA_ROLES All roles that exist in the database DBA_ROLE_PRIVS Roles granted to users and roles DBA_SYS_PRIVS System privileges granted to users and roles DBA_TAB_PRIVS All grants on objects to users and roles ROLE_ROLE_PRIVS Roles that are granted to roles ROLE_SYS_PRIVS System privileges granted to roles ROLE_TAB_PRIVS Table privileges granted to roles SESSION_ROLES Roles that are enabled to the user Roles exist in a namespace that resides outside of any user account. Therefore, you can create roles with names that are the same as objects within a user account, such as tables and views. That’s not necessarily a good idea, but it’s allowed in the database. A user account may be granted multiple roles at once. Let’s say you create an object, then grant a privilege on that object to a role, and then grant the role to a user. If you drop the object, then you also drop the granted object privilege to the role. However, the role still exists, and the grant of the role to the user still exists. If you subsequently re-create the object, then grant the object privilege to the role once again, then you’ve re-created the situation before the object was dropped—in other words, you do not need to re-create the role, nor grant the role to the user once again, since neither was affected by the act of dropping the object on which the privilege had originally been granted. Certification Objective 18.05 Distinguish Between Privileges and Roles A role object does not represent privileges in and of itself. It is merely a collection of privileges. That being said, a role exists independently of the privileges it may—or may not—contain. Furthermore, the relationship a user account has to a granted Distinguish Between Privileges and Roles 697 role is separate from any privileges that may have been granted directly to the user account. In other words, if a user account already has any object privileges granted directly to it as a result of earlier GRANT statements and then later is granted a role that duplicates any of those privileges, then the role exists separately from those originally granted privileges, which exist independently of the role. If the role is later revoked, that revocation does not adversely affect any separately granted privileges given directly to the user account. If user HENRY were already granted a privilege that happens to be duplicated within the role CRUISE_ANALYST, and then subsequently the role is granted— but then later the role is revoked, like this: REVOKE CRUISE_ANALYST FROM HENRY; then any object privileges granted directly to HENRY still exist. For example, examine the following code (line numbers added): 01 02 03 04 05 GRANT SELECT ON INVOICES TO HENRY; CREATE ROLE CRUISE_ACCOUNTANT; GRANT SELECT ON INVOICES TO CRUISE_ACCOUNTANT; GRANT CRUISE_ACCOUNTANT TO HENRY; REVOKE CRUISE_ACCOUNTANT FROM HENRY; User HENRY still has SELECT on INVOICES because of line 1, in spite of lines 2 through 5. Similarly, if the role is restored but the direct object privilege is revoked, HENRY still has access through the role. In other words (line numbers added): 01 02 03 04 05 GRANT SELECT ON INVOICES TO HENRY; CREATE ROLE CRUISE_ACCOUNTANT; GRANT SELECT ON INVOICES TO CRUISE_ACCOUNTANT; GRANT CRUISE_ACCOUNTANT TO HENRY; REVOKE SELECT ON INVOICES FROM HENRY; Remember that “privileges” may refer to either system privileges or object privileges, which are very different. Roles consist of some combination of one or more system and/or object privileges and/or other roles. HENRY still has privileges on INVOICES in spite of line 5. The reason: the CRUISE_ ACCOUNTANT role, from lines 2 through 4. However, if the object privilege revoked from HENRY in line 5 were also to be revoked from the CRUISE_ACCOUNTANT role, then the object privilege would be removed from HENRY altogether. 698 Chapter 18: Controlling User Access Certification Summary A system privilege is the right to perform a task in the database, using a DDL or DML statement on objects in general. The right to perform those tasks on a particular object in the database is an object privilege. Finally, a role combines privileges into a single object, so that a combination of privileges can be managed as a group. The SQL statements GRANT and REVOKE are used to issue system privileges and object privileges, and also to take them away. Privileges are given to—or taken away from—user accounts. Any user in the database must have privileges to perform any task. The act of logging in requires the CREATE SESSION system privilege. Other privileges include the privilege to CREATE PUBLIC SYNONYM or CREATE TABLE. The ANY keyword in a system privilege indicates the ability to work with objects that are owned by any user account. A user account, by default, has object privileges on the objects it owns. Object privileges are required for a user to be able to interact with objects it does not own. Instead of granting privileges to a user, you may create a role, then grant privileges to a role, and then grant the role to one or more users. The advantage is that if you have multiple users, a role is much easier to change, since you can grant or revoke privileges as desired after the role has been assigned to any number of users, and all of the users will automatically have the new privileges granted or revoked automatically. The data dictionary provides information about system privileges, object privileges, and roles, from the perspective of both the grantor and the grantee. Two-Minute Drill 3 699 Two-Minute DriLL Differentiate System Privileges from Object Privileges q The right to use any given SQL statement and/or to generally perform a task in the database is a system privilege. q The right to use a system privilege to perform some task on a specific existing object in the database is an object privilege. q Both system and object privileges are granted to and revoked from users in the database. q System privileges may be granted WITH ADMIN OPTION, which provides the ability for the recipient to grant the same privilege to yet another user. q When a system privilege is revoked, the revocation does not cascade— meaning that it is only revoked from the user from whom it is being revoked, not from other users to whom the revoked user may have extended the privilege. q The ALL PRIVILEGES keywords can be used to grant or revoke all privileges to or from a user. grant Privileges on Tables q Object privileges correspond to DML statements, and to DDL statements that are relevant to existing objects. q Object privileges may be granted WITH GRANT OPTION, which provides the ability for the recipient to grant the same privilege to yet another user. q When an object privilege is revoked, the revocation cascades—meaning that it is revoked from the user from whom it is being revoked, as well as from other users to whom the revoked user may have extended the privilege. q When a user has been granted access to an object, the object name will require a schema name prefix to be correctly identified. q A PUBLIC SYNONYM can provide an alternative name for the schema- prefixed version of the granted object. q The ALL PRIVILEGES keywords can be used to grant or revoke all privileges to or from a user. 700 Chapter 18: Controlling User Access View Privileges in the Data Dictionary q A variety of data dictionary views provide information about system and object privileges. q Users may see privileges granted to them, or granted by them to others, by querying the data dictionary. grant Roles q A role is created with the CREATE ROLE statement. q Roles may be granted WITH ADMIN OPTION, which provides the ability for the recipient to grant the same role to yet another user. q Roles exist in a namespace outside of an individual user account. q A role is a collection of privileges and other roles. q A role may be granted to another role. Distinguish Between Privileges and Roles q A privilege granted directly to a user exists independently from a privilege granted to a role. q If you revoke a privilege directly from a user who also has been granted a role containing the same privilege, the role remains unchanged and the user still has privileges by way of the role. q The same situation is true with regard to revoking privileges directly from roles; if you revoke a privilege from a role that a user already has through a direct grant, the direct grant stays in force. Self Test 701 SeLf Test The following questions will help you measure your understanding of the material presented in this chapter. Choose one answer for each question, unless otherwise directed. Differentiate System Privileges from Object Privileges 1. Which of the following SQL statements will authorize the user account JESSE to create tables in each and every user account in the database? A. GRANT CREATE ALL TABLE TO JESSE; B. GRANT CREATE PUBLIC TABLE TO JESSE; C. GRANT CREATE ANY TABLE TO JESSE; D. GRANT CREATE TABLE TO JESSE WITH PUBLIC OPTION; 2. You are logged in to user account FRED and have been tasked with granting privileges to the user account ETHEL. You execute the following SQL statements: GRANT CREATE ANY TABLE TO ETHEL WITH ADMIN OPTION; REVOKE CREATE ANY TABLE FROM ETHEL; Assuming both statements execute successfully, what is the result? A. ETHEL does not have the system privilege CREATE ANY TABLE, nor the right to grant the CREATE ANY TABLE system privilege to any other user. B. ETHEL has the system privilege CREATE ANY TABLE because the WITH ADMIN OPTION clause wasn’t included in the REVOKE statement. C. ETHEL no longer has the system privilege CREATE ANY TABLE but still has the right to grant the CREATE ANY TABLE system privilege to any other user, since the WITH ADMIN OPTION clause was omitted from the REVOKE statement. However, ETHEL may not grant the CREATE ANY TABLE privilege back to itself. D. ETHEL no longer has the system privilege CREATE ANY TABLE but still has the right to grant the CREATE ANY TABLE system privilege to any other user, since the WITH ADMIN OPTION clause was omitted. Furthermore, ETHEL may grant the CREATE ANY TABLE privilege back to itself because of the WITH ADMIN OPTION clause. 3. Which of the following is the system privilege that is required as a minimum to allow a user account to log in to the database? A. CREATE ANY LOGIN B. CREATE ANY SESSION C. CREATE SESSION D. CREATE TABLE 702 Chapter 18: Controlling User Access 4. Which of the following is the system privilege that empowers the grantee to create an index in his or her own user account—but not in the accounts of others? A. CREATE TABLE B. CREATE ANY TABLE C. CREATE INDEX D. CREATE ANY INDEX grant Privileges on Tables 5. Your user account owns a table BACK_ORDERS, and you wish to grant privileges on the table to a user account named CARUSO, which already has the system privileges CREATE SESSION and UNLIMITED TABLESPACE. Examine the following SQL statement: GRANT SELECT ON BACK_ORDERS TO CARUSO; Once this statement has been executed, which of the following statements will be true for user CARUSO? A. CARUSO will have SELECT privileges on BACK_ORDERS, but not the ability to give other users SELECT privileges on BACK_ORDERS. B. CARUSO will have SELECT privileges on BACK_ORDERS, as well as the ability to give other users SELECT privileges on BACK_ORDERS. C. CARUSO will have SELECT, INSERT, UPDATE, and DELETE privileges on BACK_ ORDERS, but not the ability to give other users those same privileges on BACK_ORDERS. D. CARUSO will have SELECT and ALTER TABLE privileges on BACK_ORDERS, but not the ability to give other users those same privileges on BACK_ORDERS. 6. Your user account owns an updatable view, BACKLOG, which is based on a table, PROJECTS. You are tasked to give SELECT and UPDATE capabilities to another user account named MARINO. Currently, MARINO has no privileges on either the table or the view. You wish for MARINO to have the ability to grant SELECT on the view to other users as well. Examine the following SQL code: GRANT SELECT ON BACKLOG TO MARINO WITH GRANT OPTION; GRANT UPDATE ON BACKLOG TO MARINO; Which of the following statements is true? A. The statements will fail and MARINO will not be able to use the view. B. The statements will execute successfully but MARINO will not be able to SELECT from the view because the PROJECTS table has not been granted to MARINO. Self Test 703 C. The statements will execute successfully and MARINO will be able to SELECT from the view, but not UPDATE the view. D. The statements will execute successfully and perform as intended. 7. User account MUSKIE owns a table CBAY. Which of the following statements can be executed by MUSKIE and enable user ONEILL to execute UPDATE statements on the CBAY table? (Choose three.) A. GRANT ALL ON CBAY TO ONEILL; B. GRANT ALL PRIVILEGES TO ONEILL; C. GRANT ALL TO ONEILL; D. GRANT INSERT, UPDATE ON CBAY TO ONEILL; View Privileges in the Data Dictionary 8. Examine the following two claims: [1] The DBA_TAB_PRIVS data dictionary view allows a user account to see object privileges it has granted to other user accounts. [2] The DBA_TAB_PRIVS data dictionary view allows a user account to see object privileges granted by other user accounts to itself. Which of these claims is true? A. Only [1] B. Only [2] C. Both [1] and [2] D. Neither [1] nor [2] 9. Which of the following data dictionary views contains information about grants on tables that have been made by other users to your user account, as well as grants on tables that have been made by your user account to other user accounts? A. USER_TAB_COLUMNS B. USER_TAB_PRIVS C. USER_TABLES D. ALL_TAB_PRIVS_RECD 704 Chapter 18: Controlling User Access grant Roles 10. What can be granted to a role? (Choose all that apply.) A. System privileges B. Object privileges C. Roles D. None of the above 11. Which of the following statements will grant the role OMBUDSMAN to user JOSHUA in such a way that JOSHUA may grant the role to another user? A. GRANT OMBUDSMAN TO JOSHUA WITH ADMIN OPTION; B. GRANT OMBUDSMAN TO JOSHUA WITH GRANT OPTION; C. GRANT OMBUDSMAN TO JOSHUA WITH ROLE OPTION; D. GRANT OMBUDSMAN TO JOSHUA CASCADE; 12. User HARDING owns a table TEAPOT. User HARDING then executes the following SQL statements to give access to the table to user ALBERT: CREATE PUBLIC SYNONYM TEAPOT FOR HARDING.TEAPOT; CREATE ROLE DOME; GRANT DOME TO ALBERT; GRANT SELECT ON TEAPOT TO DOME; Which of the following statements can user ALBERT now execute on the TEAPOT table? A. SELECT * FROM DOME.HARDING.TEAPOT; B. SELECT * FROM HARDING.DOME.TEAPOT; C. SELECT * FROM HARDING.TEAPOT; D. None of the above. Distinguish Between Privileges and Roles 13. A role: A. Takes the place of privileges automatically, so that any privilege granted to a role supersedes any grants that have already been granted directly to a user. B. Cannot be given the same name as a table. C. Can be granted to a user, who can only be granted one role at a time. D. Can be created by a user only if that user has the CREATE ROLE system privilege. Self Test 705 14. You have a table FURNISHINGS and are told to grant DELETE privileges on the table to user HEARST. Examine the following SQL statements: GRANT DELETE ON FURNISHINGS TO HEARST; CREATE ROLE MGR; GRANT DELETE ON FURNISHINGS TO MGR; GRANT MGR TO HEARST; Now you are told to change the privileges given to HEARST so that HEARST can no longer execute DELETE statements on the FURNISHINGS table. Which of the following will accomplish the goal? (Choose the best answer.) A. REVOKE DELETE ON FURNISHINGS FROM HEARST; B. REVOKE DELETE ON FURNISHINGS FROM MGR; C. REVOKE DELETE ON FURNISHINGS FROM HEARST, MGR; D. None of the above 15. Assume a database with three valid users: NEIL, BUZZ, and MICHAEL. Assume all users have the appropriate privileges they require to perform the tasks shown below. Assume NEIL owns a table PROVISIONS. Examine the following code (line numbers added, and assume all password references are valid): 01 02 03 04 05 06 07 08 09 10 11 CONNECT NEIL/neilPassword GRANT SELECT ON PROVISIONS TO BUZZ, MICHAEL; CONNECT BUZZ/buzzPassword CREATE VIEW PROVISIONS AS SELECT * FROM NEIL.PROVISIONS; GRANT SELECT ON PROVISIONS TO MICHAEL; CREATE PUBLIC SYNONYM PROVISIONS FOR BUZZ.PROVISIONS; CONNECT MICHAEL/michaelPassword CREATE SYNONYM PROVISIONS FOR NEIL.PROVISIONS; SELECT * FROM PROVISIONS; What object is identified in line 11 by the name PROVISIONS? A. The public synonym created in line 7 B. The synonym created in line 10 C. Nothing, because user NEIL did not include WITH GRANT OPTIONS in the GRANT SELECT ON PROVISIONS TO BUZZ statement. D. Something else not listed above 706 Chapter 18: Controlling User Access SeLf Test Answers Differentiate System Privileges from Object Privileges 1. ˛ C. The system privilege CREATE ANY TABLE is the system privilege that you’re looking for in this question. The keyword ANY is found in many system privileges, to indicate that the user authorized with the system privilege may perform the task as though it were any user account in the database. ˝ A, B, and D are incorrect. There is no ALL keyword in this context, nor does PUBLIC apply here. There is no system privilege with the WITH PUBLIC OPTION keywords. 2. ˛ A. The WITH ADMIN OPTION clause is not used in the REVOKE statement. ˝ B, C, and D are incorrect. They are all interesting ideas, but they are all wrong. 3. ˛ C. The CREATE SESSION system privilege is the minimum requirement. ˝ A, B, and D are incorrect. There is no system privilege CREATE ANY LOGIN or CREATE ANY SESSION. CREATE TABLE is not required to establish a user session. 4. ˛ A. The CREATE TABLE privilege also includes the ability to create an index. Remember that a CREATE TABLE statement may include the PRIMARY KEY or UNIQUE constraints, which—if created—will automatically cause the creation of an index to support each constraint. ˝ B, C, and D are incorrect. There isn’t a CREATE INDEX system privilege. The ability is included with CREATE TABLE. CREATE ANY TABLE empowers the grantee the ability to create tables in the accounts of others, which potentially may also create indices in those same accounts. CREATE ANY INDEX is a valid system privilege for creating index objects in user accounts other than your own. grant Privileges on Tables 5. ˛ A. GRANT SELECT ON table TO user—gives the user the ability to SELECT on the table and nothing more. ˝ B, C, and D are incorrect. To give CARUSO the ability to SELECT on the table as well as to grant other users SELECT, the WITH GRANT OPTION clause would have to have been included with the GRANT statement, as in GRANT SELECT ON BACK_ORDERS TO CARUSO WITH GRANT OPTION. To grant the other DML statements on the table, each would have to have been included, as in GRANT SELECT, INSERT, UPDATE, DELETE ON BACK_ORDERS TO CARUSO. To grant SELECT and ALTER, both would have to have been named, as in GRANT SELECT, ALTER ON BACK_ORDERS TO CARUSO. Self Test Answers 707 6. ˛ D. The statements are syntactically correct and will perform as intended. ˝ A, B, and C are incorrect. The PROJECTS table does not need to be granted to MARINO, since the VIEW has been granted. Since the VIEW is updatable, then the UPDATE privilege will work as well. 7. ˛ A, B, and D. All three forms result in the UPDATE privilege being granted to user ONEILL for the CBAY table. ˝ C is incorrect. This statement is an invalid SQL statement. It either needs for the keyword PRIVILEGES to grant all system privileges to ONEILL, or it needs to name an object for which ALL privileges should be granted. The question is specifically asking about granting privileges on the CBAY table, so the ALL PRIVILEGES form would not work. View Privileges in the Data Dictionary 8. ˛ C. The data dictionary view DBA_TAB_PRIVS allows a user to see privileges that have been granted to itself, or by itself to others. ˝ A, B, and D are incorrect. 9. ˛ B. USER_TAB_PRIVS is the answer. ˝ A, C, and D are incorrect. USER_TAB_COLUMNS has no information about grants. Neither does USER_TABLES. The ALL_TAB_PRIVS_RECD view contains data about incoming grants only. grant Roles 10. ˛ A, B, and C. Both system and object privileges, as well as other roles, can be granted to any given role. ˝ D is incorrect. 11. ˛ A. WITH ADMIN OPTION is what is used for roles. ˝ B, C, and D are incorrect. WITH GRANT OPTION works for object privileges, but not roles. There is no such clause as WITH ROLE OPTION. CASCADE does not apply here. 12. ˛ C. The schema name prefix correctly identifies the table. In addition, since the public synonym TEAPOT references the table, then DESC TEAPOT would also have worked—but that was not one of the options listed. ˝ A, B, and D are incorrect. You cannot use the role as a prefix or any other component of the name of a database object. 708 Chapter 18: Controlling User Access Distinguish Between Privileges and Roles 13. ˛ D. The CREATE ROLE privilege is required to create a role. ˝ A, B, and C are incorrect. A role does not replace privileges but instead is granted alongside of them. A role may be used to replace privileges as a management choice, and in fact such an approach is advisable, but it is not done automatically. Roles exist in a different namespace from tables and may duplicate table names. A user may be granted multiple roles at any given time. 14. ˛ C. The SQL statement in answer C accomplishes the goal in one statement. ˝ A, B, and D are incorrect. Answers A and B are helpful but do not completely accomplish the task. D is wrong because Answer C is correct. 15. ˛ B. From within the MICHAEL user account, SQL first searches the local namespace, then the database namespace. The local namespace contains the private synonym and that will be found first, before SQL looks in the database namespace. ˝ A, C, and D are incorrect. The GRANT statement issued by NEIL does not require WITH GRANT OPTION for the synonyms to function. A About the CD 710 Appendix: About the CD T he CD-ROM included with this book comes complete with MasterExam and the electronic version of the book. The software is easy to install on any Windows 2000/ XP/Vista computer and must be installed to access the MasterExam feature.You may, however, browse the electronic book directly from the CD without installation. To register for a second bonus MasterExam, simply click the Online Training link on the Main Page and follow the directions to the free online registration. system requirements Software requires Windows 2000 or higher and Internet Explorer 6.0 or above and 20MB of hard disk space for full installation. The electronic book requires Adobe Acrobat Reader. Installing and running Masterexam If your computer CD-ROM drive is configured to auto run, the CD-ROM will automatically start up upon inserting the disk. From the opening screen you may install MasterExam by pressing the MasterExam button. This will begin the installation process and create a program group named LearnKey. To run MasterExam use Start | All Programs | LearnKey | MasterExam. If the auto run feature did not launch your CD, browse to the CD and click on the LaunchTraining.exe icon. Masterexam MasterExam provides you with a simulation of the actual exam. The number of questions, the type of questions, and the time allowed are intended to be an accurate representation of the exam environment. You have the option to take an open book exam, including hints, references, and answers; a closed book exam; or the timed MasterExam simulation. When you launch MasterExam, a digital clock display will appear in the bottom right-hand corner of your screen. The clock will continue to count down to zero unless you choose to end the exam before the time expires. Appendix: About the CD 711 electronic book The entire contents of the Exam Guide are provided in PDF files. Adobe’s Acrobat Reader has been included on the CD. help A help file is provided through the Help button on the Main Page in the lower lefthand corner. An individual help feature is also available through MasterExam. removing Installation(s) MasterExam is installed to your hard drive. For best results removing programs, use the Start | All Programs | LearnKey | Uninstall option to remove MasterExam. technical support For questions regarding the technical content of the electronic book or MasterExam, please visit www.mhprofessional.com or e-mail customer.service@mcgraw-hill.com. For customers outside the 50 United States, e-mail international_cs@mcgraw-hill.com. LearnKey technical support For technical problems with the software (installation, operation, removing installations), please visit www.learnkey.com, e-mail techsupport@learnkey.com, or call toll free at 1-800-482-8244. This page intentionally left blank Glossary 714 Glossary 1GL First-generation language. The ones and zeros that computers use to communicate. Binary language. 2GL Second-generation language. Assembler language. 3GL Third-generation language. A general category of computer programming languages that tend to support structured or object-oriented programming in a manner that is closer to the spoken word than 2GLs. Common 3GLs: Java, C, FORTRAN, PHP, Perl. 4GL Fourth-generation language. Closer to the spoken word than 3GLs. The most well-known and widely used 4GL is SQL. administrator See database administrator. aggregate A single value representing any number of other values. alias An alternative name for something. Example: “Joe” is an alias for “Joseph”. alphabetic Describes the letters of the alphabet. alphanumeric Describes the letters of the alphabet and numbers. ALter A SQL statement that modifies the structure, the name, or some other attribute of an existing object in the database. (Note: There are exceptions to this definition that occur when ALTER is combined with the keywords SESSION or STATEMENT.) AnsI American National Standards Institute. An organization that oversees a number of voluntary committees that set standards for many industries, including software development and information technology. attribute A property or characteristic. Examples might include a name, ZIP code, or entry date. Corresponds to a column in a table. Also see entity. bLob Binary Large Object. A datatype that stores unstructured binary data, up to 128 terabytes. BLOB datatypes can be rolled back or committed. Suitable for storing multimedia data. Glossary 715 boolean Refers to the valuation of expressions as either true, false, or unknown, and using the logical operators AND, OR, and NOT. Named after the mathematician George Boole. built-in Already present. SQL built-in functions are those that come already installed in a database, as opposed to user-defined functions, that you can create yourself and add to the set of available functions in a database. Cartesian product The combination of each row in one table with every row in another table. The result of two or more tables joined together with no specified join criteria. Also known as a cross-join. case insensitive Without regard for whether a letter is in uppercase or lowercase form. For example, when performing a case-insensitive comparison of the letter ‘A’ and the letter ‘a’, the two are equal. case sensitive With regard for whether a letter is in uppercase or lowercase form. For example, when performing a case-sensitive comparison of the letter ‘A’ and the letter ‘a’, the two are not equal. character The symbols of a writing system. character class Also known as POSIX character classes. Shorthand references in regular expressions for specifying a range of characters. character set An encoding system for representing characters in bytes. CheCK constraint A rule on a table that filters incoming data. Only data that satisfies that rule will be accepted by the table. Also known as a CHECK integrity constraint. child A row or record that is one level below another level in a hierarchical data relationship. For example, if one table contains “orders”, and another contains the “line items” that each order contains, then a table containing those “line items” would be said to be the “child table”. A child table is one that has a foreign key relationship with a parent table, so that rows in the parent table are one level higher in the hierarchy than the rows in the child table. See also orphan; parent. 716 Glossary clause A subset within a larger construct, such as a portion of a statement or command. CLob Character Large Object. A datatype that stores large amounts of character data, up to 128 terabytes. CLOB datatypes can be rolled back or committed. Codd The last name of Dr. E.F. Codd, the person credited with forming the original ideas that led to the creation of modern-day relational database programming. column A vertical space in a database table. Columns have a name and a datatype. command A directive. CoMMent A SQL statement to add comments to the data dictionary for database objects you have created. commit To cause changes within the current session to be made permanent. CoMMIt A SQL statement to save data to the database. condition A expression that evaluates to a meaningful result to indicate the next course of action. Conditions are used to determine if a statement will take a particular action or not; the decision hinges on whether the condition evaluates to true or false. conditional A situation that depends on the evaluation of a condition. connect Establish a user session with the database. constant See literal. constraint A rule defining how data is to be processed. A table can have one or more constraints that may restrict it to having certain kinds of data and rejecting others. See also referential integrity. conversion The act of transforming something from one form to another. Conversion functions in SQL can change data from one datatype to another datatype. Glossary correlated subquery from an outer query. 717 A subquery that uses, as part of its execution logic, data CreAte A reserved word that starts one of many SQL statements, used to create database objects such as tables, views, indexes, sequences, and synonyms. cross-join See Cartesian product. data dictionary A set of tables and views automatically maintained by the Oracle system for documenting the characteristics and status of all objects in the database. data file A physical file in the file system for storing data, located in either the operating system file system, or in an Automated Storage Management disk group. database An organized collection of information. database administrator Often abbreviated DBA. The job of administering the database. The DBA often is tasked with installing the database software and configuring it for use, performing backups and generally making the database system available for use, maintaining at optimal performance, and taking steps to protect against loss of data. datatype A set of rules defining a subset of data. date A calendar date. datetime Any of the set of datatypes DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, or TIMESTAMP WITH LOCAL TIME ZONE. daylight saving time Time defined as a one-hour offset from standard time to provide more daylight at the end of the working day during seasons in which daylight is limited. DbA See database administrator. DbMs Database management system. 718 Glossary DDL Data Definition Language. A subset of SQL. Refers to the set of SQL statements that is used to create database objects, modify their structure, and remove them from the database. default When used in association with a parameter, “default” is the value of that parameter when no specific value is assigned. See parameter. DeLete A SQL statement used to remove data from the database. deprecated Said of a feature that may still exist but is no longer officially supported, and whose use is officially discouraged. developer An individual engaged in the job of creating applications. development The act of creating applications. DML Data Manipulation Language. A subset of SQL. Refers to the set of SQL statements that is used to query existing data in database objects, add data to existing database objects, modify that data, and remove the data from the database. DroP A reserved word used to start one of many SQL statements, all of which are used to remove certain existing database objects from the database. ellison The last name of Larry Ellison, founder of Oracle Corporation, the first company to release a commercial RDBMS product. entity An organized collection of attributes in a data model. Corresponds to a table. See also attribute; ERD. equijoin A join that uses an equality operator (the equal sign) in the join condition. erD Entity-relationship diagram. A diagram that shows entities and how they relate to each other. See also entity. escape character A single character that can take on an alternative purpose separate from its character’s standard meaning. For example, a single quotation Glossary 719 mark is an escape character when preceding another single quotation mark in a text string delimited by single quotes, so that strings such as ‘O’’Brian’ will be correctly interpreted as O’Brian in the database, rather than the truncated string ‘O’ followed by the characters Brian’—which would be meaningless in any SQL statement and would result in a syntax error. explicit commit The COMMIT statement. expression A combination of literal values, operators, variables, and functions, with the intent of computing a value of a particular datatype. external table A SQL table that stores table metadata in the database but stores the table’s data outside of the database. FLAshbACK A SQL statement used to restore older versions of database objects. flashback operations A set of operations that use undo data to support data recovery and the analysis of historical data over time. foreign key A referential integrity constraint in a table. A foreign key specifies one or more attributes in one entity that relate to one or more attributes in another entity. Values entered in the foreign key’s attributes must already exist in the referenced table’s corresponding attributes. See also referential integrity, constraint. function A set of code that performs a particular task and returns a single result. A SQL function can be used within a SQL expression. A function is one type of subprogram, also known as a program unit. There is another form known as a procedure, which is not included on the exam. GrAnt A SQL statement used to give system privileges or object privileges to a user account. hierarchical query A query that specifies multiple levels of relationship. Typically built on a self-join. Note that a typical join of two tables in a parentchild relationship can be said to be a two-level “hierarchy”; technically that would be accurate. But the term “hierarchical query” in Oracle SQL is generally understood to indicate a particular type of query based on a data model that is capable of supporting more than two levels. 720 Glossary Ieee Institute of Electrical and Electronics Engineers. A non-profit organization with the mission to advance technology as it relates to the use of electricity. implicit commit A commit event other than the COMMIT statement. The execution of DDL code will result in an implicit commit. inline view statement. A subquery that performs like a view in support of a single SQL index A database object that copies a subset of data from a table, presorted, and intended to support faster querying on the indexed table. inner join A join of two or more tables in which a join condition is specified, and the result consists exclusively of rows in one table that match rows in the other table according to the join condition. If a row in one table has no matching counterpart in the other table, it is not included in the results. See also outer join. Insert A SQL statement used to store data in a database table. instance One set of Oracle background processes and memory structures used to access a database. integrity constraint See constraint. join The act of connecting rows in one table with rows in one or more other tables, based on some criteria that determine how the data in the tables correlates to each other. key One or more attributes—or columns—used in the definition of an integrity constraint. Keys include primary keys, foreign keys, and unique keys. keyword A special word used in a SQL command or serving some other special purpose. Keywords are often reserved words, but they are not necessarily reserved. literal A fixed data value. Also called a constant. Lob Large Object. Any of a number of datatypes that store large amounts of information. See also BLOB; CLOB; NCLOB. Glossary lowercase 721 The letters of the alphabet in miniscule form, i.e., “a”, “b”, etc. MerGe A SQL statement that performs a combination of INSERT, UPDATE, and/or DELETE statement functionality. metacharacter operators Used to define patterns in regular expressions. metadata Data about data. For example, is the “account number” at a given organization a numeric value, or is it an alphanumeric value? Or perhaps alphabetic? Metadata describes other data in high-level terms. multitable insert A SQL INSERT statement that is able to add rows of data to one or more tables. Multitable inserts can be conditional or unconditional. namespace A virtual location within the database in which no database objects may share the same name. All names must be unique within a given namespace. natural join A join in which the join criteria are implied based on common names of columns in the tables being joined. nCLob National Character Set Large Object. A datatype that stores large amounts of character data in a national database character set. Stores up to 128 terabytes. NCLOB datatypes can be rolled back or committed. nLs National Language Support. nLs parameters Variables that customize the behavior of the database in accordance with a given locale. For example, NLS_SORT. non-equijoin A join condition that uses operators other than the equality operator to specify the join condition—such as greater-than or less-than operators. normalization A specific series of processes intended to support the design of a database to maximize efficiency. nuLL Unknown. The absence of information. number A digit. 722 Glossary numeric Said of a set of datatypes that accept number data. object An item in the database. Objects have properties of structure and security. object privilege The right to perform a particular task on a particular object in the database. See also system privilege. operator precedence The rules defining the order in which operators within an expression are processed. operators Symbols that perform tasks on values within an expression. orA_rowsCn A conservative upper bound of the latest commit time for the transaction that last changed the row. The actual commit SCN of the transaction can be somewhat earlier. See also system change number. oracle The leading RDBMS product on the market today. oracle Corporation The first company to produce a commercial RDBMS product. orphan A child row in a child table for which there is no corresponding parent row in the corresponding parent table. outer join A join of two or more tables in which a join condition is specified, and the result consists of rows in one table that match rows in the other table according to the join condition, as well as rows that do not necessarily match. If a row in one table has no matching counterpart in the other table, it may be included in the results. See also inner join. parameter A variable that is passed to or from a function or procedure. parent A row or record that is one level above another level in a hierarchical data relationship. For example, if one table contains “orders”, and another contains the “line items” that each order contains, then a table containing those “orders” would be said to be the “parent table”. A parent table is one that is referenced by a foreign key in a child table, so that rows in the parent table are one level higher in the hierarchy than the rows in the child table. See also orphan, child. Glossary 723 parse To analyze code for syntactic accuracy. SQL code that is submitted for execution is parsed first and then executed upon successful completion of the parsing process. PosIX Portable Operating System Interface (for Unix). A set of IEEE standards for defining standards and interoperability on a number of issues. precedence A logical prioritization of a set of items. precision Part of the definition of a numeric datatype. Precision specifies the number of significant digits in the numeric value. See also scale. predicates These compare one expression to another to produce a true, false, or NULL result. Can be combined with Boolean operators AND, OR, and NOT. primary key A unique non-NULL attribute in an entity, or a unique non-NULL column in a table. private synonym PRIVATE keyword. A synonym that is not a PUBLIC synonym. There is no privilege The right to perform a task in the database. See also object privilege; system privilege. procedure A set of code that performs a particular task. A procedure may return anywhere from zero to multiple results. Procedures cannot be used within a SQL expression but instead are often invoked in statements by themselves. production Professional use. Database applications in “production” are actively storing data for an ongoing organization, as opposed to database applications that are in development or testing. projection The concept of querying a subset of columns from a table. pseudocolumns Values that are defined automatically by the Oracle system for certain objects in the database, such as tables and sequences. Pseudocolumns can be selected like a column in a table. 724 Glossary PubLIC A special database user automatically maintained by the database. PUBLIC represents all users in the database. Granting privileges to PUBLIC has the effect of granting them to all users. PurGe A SQL statement to remove objects from the recycle bin. query A SELECT statement. A request of the database for some of the data that is contained within it. rDbMs Relational database management system. read consistency The ability for data in the database to be read and joined in a manner that is accurate. Read consistency represents a view of data that is “frozen” in an instant of time. Read consistency becomes important when joining tables that are being modified in real time, so that as the database queries one table and then another, the combined records reflect what was intended. record A set of data elements that are related to each other and represent a meaningful collection of information. One row can be a record; joined rows might also be a record. recycle bin tracked. The structure in the SQL database into which dropped objects are redo logs A set of operating system files that record all changes made to a database, whether those changes have been committed or not. referential integrity A constraint, or rule, on one table’s column that requires any value to be stored in that column to be already present in another particular table’s column. See also foreign key. regular expression A language of pattern matching. Not to be confused with expressions. Oracle’s support for regular expressions is consistent with the POSIX and Unicode standards. relational Having a relation or being related. A database is said to be relational when it is built on data objects that can be joined together based on common criteria within and among the objects. Glossary renAMe database. 725 A SQL statement used to change the name of certain objects in the reserved word Special words set aside for special use and not available for application development. You cannot use reserved words as the names of database objects or variables. restore point A marked point in time, to be recorded for possible future reference in support of flashback operations. reVoKe A SQL statement to remove system privileges or object privileges that have been granted to a user account. role A collection of one or more privileges. rollback An action that restores the database to the most recent commit within the current session. roLLbACK A SQL statement used to restore the database to an earlier state. Cancels the effects of a transaction in progress. row One set of values for the columns of a table. savepoint A marked point in time, to be recorded for possible future rollback. sAVePoInt A SQL statement that marks a point in a session. Future uses of the ROLLBACK statement may choose to restore the database to the point marked by a SAVEPOINT statement. scalar subquery A subquery that returns one column in one row as its output—in other words, a single value, as opposed to rows of values, or columns of values. scale Part of the definition of a numeric datatype. Scale specifies where rounding will occur in the numeric datatype. See also precision. schema A collection of tables owned by a user account. sCn See system change number (SCN). 726 Glossary segment A level of logical database storage. seLeCt A SQL statement used to query one or more database tables. selectivity The degree of uniqueness of values in a column. If all values in the column are identical, selectivity is said to be low. If the values are all unique, selectivity is said to be high. selection The ability to query a subset of rows from a table. self-join A join that connects rows in a table with other rows in the same table. semijoin A query that returns rows that match an EXISTS subquery. sequence A number generator. A database object. session A user process in which the user interacts with the database. set operator MINUS. Any of the operators UNION, UNION ALL, INTERSECT, or sQL See Structured Query Language. standard time Also known as Winter Time zones. Time as defined by UTC. statement A command. string A series of characters. structured Query Language with a database. A worldwide standard language for interacting subquery A SELECT statement contained within another (outer) SELECT statement, so that the data of the subquery feeds into the processing of the outer query. superaggregate An aggregation of aggregate values. synonym An alias, or alternative name, for something in the database. A synonym is itself an object in the database. Glossary 727 syntax The rules for forming a statement, a command, or some other language construct. sYs A built-in user account with DBA privileges that comes with all Oracle installations. SYS owns the data dictionary. sYsteM A built-in user account with DBA privileges that comes with all Oracle installations. system change number (sCn) A marker that specifies a committed version of the database at a particular point in time. Each committed transaction is assigned an SCN. See also transaction. system privilege object privilege. table The right to perform a particular task in the database. See also A storage unit in the database that consists of columns and rows. tablespace A mechanism in the database that is home to one or more tables and stores that data in one or more data files. tCL Transaction Control Language. A subset of SQL. Refers to the set of SQL statements that is used to control a user’s session in which DML statements are used. TCL determines if the results of a DML statement are allowed to be made permanent, or if they are undone from the database. text Character-based data. time zone A region of the earth that uses uniform standard time as an offset from UTC. There are currently 24 such regions defined in the earth, divided roughly by longitudinal lines. Also known as “time zone region”. time zone name The name of a time zone region. Examples: “Pacific/ Auckland”, “America/Indianapolis”. time zone offset A time difference between the local time and UTC. timestamp A value representing the date and time. 728 Glossary transaction A series of one or more SQL statements that are executed between commit events. trunCAte A SQL statement used to remove data from a database table. unconditional Without restriction. undo segments Segments that are maintained automatically by the database to support rollback operations, to assure read consistency, and to otherwise recover from logical corruptions. unicode An industry standard that attempts to create a standardized encoding of every character of every language in existence. unique One of a kind. unique identifier An unambiguous reference to something, leaving no doubt what is being referenced. uPDAte A SQL statement used to modify data in a database table. uppercase The letters of the alphabet in majuscule form, also known as capital letters, i.e., “A”, “B”, etc. user account A process that provides password-protected access to and ownership of a set of database objects and privileges. utC Coordinated Universal Time. The new name for Greenwich Mean Time. The universal standard for measuring time internationally. UTC measures time as it exists at the Royal Observatory of Greenwich, London. variable A small unit of storage, represented by a name and a datatype, for holding values that can be changed. view A named query that is stored in the database. winter time zone See standard time. InDeX sYMboLs AnD NuMbers “ ”...“ ” (double quotation marks), case sensitivity and, 53–55 != (not equal), comparison operator, 172 <= (less than or equal to), comparison operator, 172 % (percent), as wildcard symbol, 175–176 * (wildcard operator), SELECT statement, 146 ^= (not equal), comparison operator, 173 _ (underscore), as wildcard symbol, 175 || (CONCAT) character function, 216–217 < (less than), comparison operator, 172 <> (not equal), comparison operator, 173 = (equal), comparison operator, 172 > (greater than), comparison operator, 172 > = (greater than or equal to), comparison operator, 172 1GLs (first generation languages), 27 1NF (first normal form), 16 2GLs (second generation languages), 27 2NF (second normal form), 16–17 3GLs (third generation languages), 28–30 3NF (third normal form), 16–17 4GL (fourth-generation language), 26–28 4NF (fourth normal form), 16 5NF (fifth normal form), 16 A access control. See privileges Access, Microsoft, 22 ADD_MONTHS date function, 228 aggregate functions. See functions, aggregate aggregate subqueries. See multiple-row subqueries aliases column aliases, 190–192 table aliases, 321–323, 362, 406–408 ALL operator, using with aggregate functions, 279 ALL PRIVILEGES, 684–685, 690–691 ALL_COL_COMMENTS, in data dictionary, 540 ALL_TAB_COMMENTS, in data dictionary, 540 ALTER statements, DDL, 96 ALTER TABLE statement adding columns to tables, 424–426 adding constraints with, 436–438 adding NOT NULL columns to tables, 426–427 adding NOT NULL constraints with, 438 constraint syntax, 452–453 creating constraints in, 69–70 DROP clause, 431–432 modifying columns in tables, 427–430 modifying constraints, 440 removing constraints, 440–442 renaming columns in tables, 430–431 syntax rules for constraints, 438–440 ALTER USER statement, 677–678 ALTER VIEW statement, 391–392 American National Standards Institute (ANSI), 23 AND operator in Boolean logic, 177–179 operator precedence and, 180 730 Index ANSI (American National Standards Institute), 23 ANY keyword, in system privileges, 682–683 arithmetic operators, 149 AS OF clause, SELECT statements, 593 AS SELECT clause, CREATE TABLE statement, 560–563 ASC keyword, for ascending order, 188–189 assembly language, 27 AT LOCAL expression, time zone conversion, 262–263 AT time zone expression, time zone conversion, 261–262 automatic data type conversion, 246–247 non-equijoins and, 328 automatic index creation, 454–455 AVG aggregate function, 281–282 B Backup Recovery, 587 base-10 numbers, 598 base-16 numbers, 598 base-2 numbers, 598 BETWEEN, using with WHERE clause, 182 BLOBs (Binary Large OBjects) overview of, 65–66 restrictions on constraints, 80 Boolean logic AND/OR/NOT operators, 177–179 CONNECT BY clause and, 627 HAVING clause and, 297 operator precedence, 180–181 overview of, 177 branches, in hierarchical structures, 616 built-in functions, 211 C calling functions, 211 capitalization, INITCAP function, 216 Cartesian products (cross-joins), 330–332 overview of, 330 questionable usefulness of, 331–332 CASCADE CONSTRAINTS, in DROP TABLE statement, 449 CASCADE keyword, disabling constraints and, 447–448 case CASE function, 232–233 UPPER/LOWER functions, 215 case sensitivity matching, 644 naming database objects, 53–55 CAST function, time zone conversion, 258–259 change, trackingover time, 586–588 character classes letter ranges compared with, 647–648 POSIX, 642–643 character functions CONCAT, 216–217 INITCAP, 216 INSTR, 220 LENGTH, 219–220 LPAD/RPAD, 217–218 LTRIM/RTRIM, 218–219 overview of, 212, 215 SOUNDEX, 221–222 SUBSTR, 220–221 TRIM, 219 UPPER/LOWER, 215 Character Large OBjects (CLOBs) overview of, 66 restrictions on constraints, 80 Index character strings concatenation, 216–217 extracting substrings, 220–221 length of, 219–220 locating strings within strings (INSTR function), 220 padding, 217–218 translating source string into SOUNDEX code, 221–222 trimming, 218–219 characters character classes, 642–643, 647–648 comparing character data types, 173 converting other data types to, 239 data types, 61–62 ranges of, 642 trimming, 219 CHAR(n) data type LIKE operator for, 175 overview of, 61 CHECK constraints overview of, 79 regular expressions and, 659–661 using with INSERT statement, 104–105 children, in hierarchical structures, 616 CLOBs (Character Large OBjects) overview of, 66 restrictions on constraints, 80 Codd, Dr. E.F., 14–15 column aliases, 190–192 columns adding, 424–426 adding NOT NULL, 426–427 data types for. See data types default column list in INSERT statements, 99–102 dropping, 431–434 enumerated column list in INSERT statement, 103–104 731 expressions for assigning values to, 108 finding, 549 GROUP BY clause used with multiple columns, 291–292 inspecting, 545–546 modifying, 427–428 modifying NOT NULL, 428 modifying populated, 428–430 pseudocolumns, 143 in RDBMS databases, 14 renaming, 430–431 selecting from tables, 142–143 unused, 434–435 Command Line Interface, SQL*Plus, 23–24 commands, vs. statements, 97 COMMENT statement, DDL, 96 comments, data dictionary adding, 541–542 reading, 540 COMMIT statement, 112–116 data recovery options, 588 description of, 98 explicit commit, 113–114 implicit commit, 114 other users and, 115–116 overview of, 112–113 types of TCL statements, 97 comparison conditions, in single-row subqueries, 353–354 comparison operators list of, 172 non-equijoins and, 328 composite constraints PRIMARY KEY, 75–76 UNIQUE, 74 composite indexes overview of, 402–403 skip scanning and, 403 computer languages, 26–28 732 Index CONCAT character function, 216–217 condition, regular expressions, 645 conditional multitable INSERTs overview of, 574–580 pivot technique for changing columns into rows, 580–582 CONNECT BY clause, SELECT statement, 619–621, 627 CONNECT role, 695 CONNECT statement, SQL*Plus, 678 CONNECT_BY_ROOT, in hierarchical queries, 625–626 constraints adding, 436–440 in ALTER TABLE statements, 69–70 cascading, 447–448 certification summary, 83 CHECK constraints, 79 CONSTRAINT object as schema object, 49 in CREATE TABLE statements, 67–69 DEFERRABLE/DEFERRED, 451 ON DELETE CASCADE clause, 450–451 DELETE statement, 450–451 description of CONSTRAINT object, 48 disabling, 442–446 enabling, 447 FOREIGN KEY constraints, 76–79 indexes and, 398–399 INSERT statement and, 104–106 inspecting in USER_CONSTRAINTS view, 547–548 modifying, 440 multiple, 79–80 namespaces and, 56 NOT NULL constraints, 70–72 overview of, 155 PRIMARY KEY constraints, 74–76 removing, 440–442 renaming, 452 restrictions on, 80 restrictions on dropping columns, 432–434 self test, questions, 87–88, 91 UNIQUE constraints, 74 UPDATE statement and, 108–110 validating/invalidating, 448–449 views and, 386 control transactions, 112. See also TCL (Transaction Control Language) conversion functions. See also time zone conversion functions automatic data type conversion, 246–247 date format elements, 242–244 overview of, 213, 235–236 SCN_TO_TIMESTAMP, 467 TIMESTAMP_TO_SCN, 467 TO_CHAR (character), 239 TO_CHAR (date), 240–242 TO_CHAR (number), 240 TO_DATE, 244 TO_DSINTERVAL, 245–246 TO_NUMBER, 236–239 TO_TIMESTAMP, 245 TO_YMINTERVAL, 246 Coordinated Universal Time (UTC), 250 correlated subqueries deleting rows with, 364–365 overview of, 347, 349 problem solving with, 360–362 self test, answers, 379–380 self test, questions, 374–376 two-minute drill, 371 UPDATE statement with, 564–567 updating rows with, 362–364 COUNT aggregate function, 277–279 example of SELECT statement using, 278–279 overview of, 277–278 Index CREATE CONSTRAINT statement. See also constraints creating constraints in ALTER TABLE statements, 69–70 creating constraints in CREATE TABLE statements, 67–69 “Out of Line” constraints, 69 CREATE DIRECTORY statement, 470 CREATE OR REPLACE synonym, 409 CREATE ROLE statement, 694 CREATE SEQUENCE statement, 392–394 CREATE statements, DDL, 96 CREATE TABLE AS SELECT (CTAS), 560–563 CREATE TABLE statement adding columns, 424–426 automatic index creation and, 454–455 case sensitivity and, 54–55 certification summary, 65–66 constraint syntax, 452–453 creating in-line constraints in, 67–68 creating multiple in-line constraints in, 68–69 creating out-of-line constraints in, 69 creating simple table, 50–51 overview of, 58–59 privileges and, 686 self test, questions, 84–86, 89–90 subqueries, 346 subqueries included with, 560–563 system-assigned names and, 57 two-minute drill, 81 USING clause and, 455–456 CREATE USER statement, 677–678 CREATE VIEW statement overview of, 383–386 subqueries, 346 cross-joins. See Cartesian products (cross-joins) crosstabulation values, CUBE operation producing, 515–516 CTAS (CREATE TABLE AS SELECT), 560–563 733 CUBE operation GROUPING function identifying row values created by, 517–518 for producing crosstabulation values, 515–516 CURRENT_DATE time zone function, 254–255 CURRENT_TIMESTAMP time zone function, 254–255 CURRVAL pseudocolumn, sequences, 395 D Data Definition Language. See DDL (Data Definition Language) data dictionary adding comments to, 541–542 certification summary, 549–550 checking privileges, 547 compiling views, 546–547 DICTIONARY view, 542–543 dynamic performance views, 538–539 finding columns, 549 list of views, 538 overview of, 534–535 prefixes of views, 537 privilege views in, 691–693 reading comments in, 540 role views in, 696 self test, answers, 556–557 self test, questions, 553–555 structure of, 535–538 two-minute drill, 551–552 USER_CATALOG view, 543–544 USER_CONSTRAINTS view, 547–548 USER_OBJECTS view, 544 USER_TAB_COLUMNS view, 545–546 data manipulation certification summary, 600 conditional multitable INSERTs, 574–580 734 Index CREATE TABLE statement with subqueries, 560–563 Flashback Queries. See FQs (Flashback Queries) Flashback Transaction Queries, 597–600 Flashback Version Queries, 595–597 INSERT statement with subqueries, 563–564 merging rows in a table, 582–586 multitable INSERTs, 567–571 overview of, 560 pivot technique for changing columns into rows, 580–582 self test, answers, 611–613 self test, questions, 603–610 subqueries for, 560 tracking changes over time, 586–588 two-minute drill, 601–603 unconditional multitable INSERTs, 571–574 UPDATE statement with correlated subqueries, 564–567 Data Manipulation Language. See DML (Data Manipulation Language) data retrieval with SELECT. See SELECT statement from views, 391 data sets, subqueries for manipulating large, 347 data types, 60–66. See also conversion functions adding columns and, 425 aggregate functions and, 277 automatic data type conversion, 246–247 certification summary, 65–66 character types, 61–62 comparing, 172–174 conversion of, 103–104 date types, 63–65 large object types, 65–66 numeric types, 62–63 overview of, 60–61 restrictions on constraints, 80 self test, questions, 86–87, 90 time zone types, 250–253 two-minute drill, 82 database objects certification summary, 81 descriptions of common, 47–48 list of, 46–47 managing schema objects. See schema object management naming. See naming database objects overview of, 46 schema and non-schema objects, 49 schemas and, 48–49 self test, questions, 84, 89 two-minute drill, 82 databases. See also RDBMS (relational database management systems) database time vs. session time, 249–250 design considerations, 16–18 date data types, 63–65 comparing, 173–174 converting character types to, 240–242 DATE, 63–64 datetime fields, 64 overview of, 63–64 date format elements, 242–244 date functions ADD_MONTHS, 228 LAST_DAY, 227 MONTHS_BETWEEN, 228–229 NEXT_DAY, 227 NUMTODSINTERVAL, 229–230 NUMTOYMINTERVAL, 229 overview of, 212–213, 225 ROUND (date), 225–226 SYSDATE, 225 TRUNC (date), 226–227 datetime fields, date data type, 64 DBA role, 695 Index DBtime zone time zone function, 253 DDL (Data Definition Language) ALTER TABLE statements, 69–70 CREATE CONSTRAINT statement, 67–70 CREATE TABLE statement. See CREATE TABLE statement list of DDL statements, 96 subqueries and, 346 as type of SQL statements, 94–95 uses of, 95–96 DECODE function, 231–232 DEFERRABLE/DEFERRED constraints, 451 DELETE statement correlated subqueries in, 362 deleting rows with correlated subqueries, 364–365 description of, 98 as DML statement, 97 overview of, 111–112 removing constraints, 450–451 SQL Fundamentals 1 vs. SQL Expert, 9 subqueries, 346 views, 386–389 WHERE clause and, 111–112 dependent privileges, 691 DESC keyword, for descending order, 188–189 DESCRIBE statement reviewing newly created view, 384 reviewing table structure, 59–60 design considerations, databases, 16–18 DICTIONARY view, 542–543 directory objects, creating, 470 DISTINCT operator used with aggregate functions, 279 used with SELECT statement, 144–145 DML (Data Manipulation Language) certification summary, 122–124 DELETE statement, 111–112 index maintenance and, 401–402 735 INSERT statement. See INSERT statement list of DML statements, 97 privileges and, 686 SELECT statement. See SELECT statement self test, answers, 133–135 self test, questions, 128–131 statements of primary importance, 98 subqueries, 346 two-minute drill, 125–126 types of SQL statements, 94–95 UPDATE statement. See UPDATE statement uses of, 96 documentation,for SQ, 25–26 double quotation marks (“ ”...“ ”), case sensitivity and, 53–55 DROP clause, ALTER TABLE statement, 431–432, 440–442 DROP INDEX statement, 404 DROP statement, DDL, 96 DROP SYNONYM statement, 410 DROP TABLE statement, 449 DROP USER statement, 677–678 DUAL table, 214–215 dynamic performance views (V_$), in data dictionary, 538–539 dynamic views, subqueries for creating, 347 E Ellison, Larry, 21 entity relationship diagram (ERD), 313–314 enumerated column list, INSERT statement, 103–104 equal (=), comparison operator, 172 equijoins inner joins. See inner joins natural joins. See natural joins vs. non-equijoins, 315 736 Index outer joins. See outer joins self-joins and, 328 ERD (entity relationship diagram), 313–314 EXECUTE DBMS_LOCK.SLEEP(s), PL/SQL, 590 EXISTS operator, for testing existing rows in subqueries, 365–366 EXPLAIN PLANs, 402 explicit commits, 113–114 expression list SELECT statements and, 139 selecting columns from tables, 142 expressions. See also regular expressions comparing with WHERE clause, 171–172 functions, 150–151 operators and operator precedence in, 149–150 ORDER BY clause, 189–190 SELECT statement and, 146–148 UPDATE statement using to assign values to columns, 108 uses of, 148 external tables benefits of and restrictions on, 469 certification summary, 475 creating, 471–473 creating directory objects, 470 Oracles utilities for, 471 overview of, 468–469 self test, answers, 486 self test, questions, 483 two-minute drill, 477 using, 473–474 EXTRACT time zone function, 259–260 F fifth normal form (5NF), 16 first generation languages (1GLs), 27 FIRST/LAST aggregate functions, 284 first normal form (1NF), 16 FLASHBACK operations certification summary, 475 data recovery options, 587 DDL statements and, 96 identifying time for restores, 465 overview of, 458–459 purging objects from recycle bin, 462–463 recovering dependent objects of tables, 462 recovering dropped tables, 459–461 recovering tables in time, 463–465 recycle bin and, 461–462 RESTORE POINT and, 468 SCN (System Change Number) and, 465–466 self test, answers, 486 self test, questions, 482–483 statement execution and, 462 two-minute drill, 477 Flashback Queries. See FQs (Flashback Queries) Flashback Transaction Queries (FTQs), 588, 597–600 Flashback Version Queries. See FVQs (Flashback Version Queries) FOREIGN KEYS joins and, 313–314 overview of, 76–79 self-joins and, 329 forks, in hierarchical structures, 616 fourth-generation language (4GL), 26–28 fourth normal form (4NF), 16 FQs (Flashback Queries) defined, 588 overview of, 588–591 syntax of, 592–593 undo retention period, 591–592 FROM clause following WHERE clause in SQL statements, 170 SELECT statements and, 139 Index FROM_TZ time zone function, 257 FTQs (Flashback Transaction Queries), 588, 597–600 FULL OUTER JOIN, 320 function-based indexes, 457–458 functions non-equijoins and, 328 SELECT statement, 150–151 functions, aggregate AVG, 281–282 certification summary, 298 COUNT, 277–279 FIRST/LAST, 284 GROUP BY clause. See GROUP BY clause GROUPING, 284 HAVING clause, 296–297 identifying available group functions, 276–277 MEDIAN, 282–283 MIN/MAX, 280–281 nesting functions, 292–295 overview of, 276–277 RANK, 283 ROLLUP operation used with, 512 vs. scalar, 210 self test, answers, 307–308 self test, questions, 301 SUM, 280 two-minute drill, 299 functions, regular expressions, 643–653 list of, 643–644 match parameter text literals, 644–645 overview of, 643 REGEXP_SUBSTR examples, 645–653 functions, scalar ADD_MONTHS, 228 automatic data type conversion, 246–247 CASE, 232–233 CAST, 258–259 certification summary, 263–264 737 character functions, 212 character manipulation, 215 CONCAT, 216–217 conversion functions, 213, 235–236 CURRENT_DATE and CURRENT_ TIMESTAMP, 254–255 database time vs. session time and, 249–250 date format elements, 242–244 date functions, 212–213, 225 DBtime zone, 253 DECODE, 231–232 EXTRACT, 259–260 FROM_TZ, 257 HAVING clause and, 297 INITCAP, 216 INSTR, 220 LAST_DAY, 227 LENGTH, 219–220 AT LOCAL expression, 262–263 LOCALTIMESTAMP, 255 LPAD/RPAD, 217–218 LTRIM/RTRIM, 218–219 mathematical processing, 223 MOD, 224–225 MONTHS_BETWEEN, 228–229 nesting, 234–235, 293–295 NEW_TIME, 256 NEXT_DAY, 227 NULLIF, 233–234 number functions, 212 NUMTODSINTERVAL, 229–230 NUMTOYMINTERVAL, 229 NVL, 230–231 other, 213 overview of, 210 REMAINDER, 224 ROUND (date), 225–226 ROUND (number), 223 self test, answers, 271–273 738 Index self test, questions, 266–270 SESSIONTIMEZONE, 254 SOUNDEX, 221–222 SUBSTR, 220–221 SYSDATE, 225 SYS_EXTRACT_UTC, 260 SYSTIMESTAMP, 255 time zone conversion, 257 time zone data types, 250–253 AT time zone expression, 261–262 time zone management, 247–249 TO_CHAR (character), 239 TO_CHAR (date), 240–242 TO_CHAR (number), 240 TO_DATE, 244 TO_DSINTERVAL, 245–246 TO_NUMBER, 236–239 TO_TIMESTAMP, 245 TO_TIMESTAMP_TZ, 257–258 TO_YMINTERVAL, 246 TRIM, 219 TRUNC (date), 226–227 TRUNC (number), 223–224 two-minute drill, 265–266 types available in SQL, 210–212 UPPER/LOWER, 215 UTC (Coordinated Universal Time), 250 FVQs (Flashback Version Queries) defined, 588 overview of, 594 pseudocolumns, 596 rules of, 595–597 VERSIONS BETWEEN SCN, 595 VERSIONS BETWEEN TIMESTAMP, 594–595 G grandchildren, in hierarchical structures, 616 GRANT statement WITH ADMIN OPTION, 683–684 ALL PRIVILEGES, 684–685 DDL statements, 96 WITH GRANT OPTION clause, 689–690 privileges, 679–681 privileges on tables, 686–688 roles, 693–696 greater than (>), comparison operator, 172 greater than or equal to (> =), comparison operator, 172 GROUP BY clause calling aggregate functions from, 277 certification summary, 298 example grouping rows of ROOM_TYPES table, 289–291 example grouping rows of SHIP_CABINS table, 285–288 HAVING clause and, 296–297 inline views and, 390 multiple columns and, 291–292 ORDER BY clause and, 292 overview of, 285 rules for forming, 289 SELECT statements and, 151 self test, answers, 308–309 self test, questions, 301–305 SQL Fundamentals 1 vs. SQL Expert, 9 subqueries and, 346 two-minute drill, 299–300 GROUP BY clause, subclauses of certification summary, 522 CUBE operation for producing crosstabulation values, 515–516 Index GROUPING function for identifying row values created by ROLLUP or CUBE, 517–518 GROUPING SETS operation for producing single result sets, 519–521 ROLLUP operation for producing subtotals, 512–515 self test, answers, 530–532 self test, questions, 525–529 two-minute drill, 523–524 group functions. See functions, aggregate GROUPING aggregate function for identifying row values created by ROLLUP or CUBE, 517–518 overview of, 284 GROUPING SETS operation, 519–521 h HAVING clause calling aggregate functions from, 277 certification summary, 298 overview of, 296–297 SELECT statements and, 151 self test, answers, 309–310 self test, questions, 305–306 subqueries and, 346 two-minute drill, 300 hexadecimal numbers (base-16), 597–598 HEXTORAW function, 597 hierarchical data, creating and formatting, 618–621 hierarchical queries, 599 certification summary, 628 choosing query direction, 622–623 CONNECT_BY_ROOT, 625–626 creating and formatting hierarchical data, 618–621 739 creating tree-structured reports, 621 excluding branches from tree structure, 626–627 ordering siblings by, 623–624 overview of, 616–618 self test, answers, 635–637 self test, questions, 631–634 SYS_CONNECT_BY_PATH, 624–625 two-minute drill, 629–630 I IBM DB2 as competitors with Oracle’s RDBMS, 22 role in development of RDBMS, 21 implicit commits, COMMIT statement, 114 implicit data type conversion, 104 implicit index creation, 398–399 in line constraints, 67–68 IN operator comparison operator, 173 single-row subqueries and, 354 WHERE clause and, 181 indexes automatic creation of, 454–455 certification summary, 411 composite, 402–403 creating function-based, 457–458 description of INDEX object, 47 dropping, 404 implicit creation of, 398–399 INDEX object as schema object, 49 namespaces, 56 overview of, 156, 397–398 self test, answers, 421–422 self test, questions, 417–418 single column, 399–402 two-minute drill, 413 740 Index unique, 403–404 USING clause applied to index creation, 455–456 INITCAP character function, 216 inline views, 389–391 inner joins, 316–318 example connecting two tables with, 316–318 natural joins, 324 older syntax for, 318 vs. outer joins, 315 overview of, 316 USING keyword and, 324–325 INSERT statement, 98–106. See also multitable INSERTs conditional multitable INSERTs, 574–580 constraints and, 104–106 default column list, 99–102 description of, 98 as DML statement, 98 enumerated column list, 103–104 inserting rows into a table, 98–99 scalar subqueries in, 359–360 SQL Fundamentals 1 vs. SQL Expert, 9 subqueries and, 346, 563–564 unconditional multitable INSERTs, 571–574 views, 386–388 INSTR character function, 220 INSTR regular expression function, 643 INTERSECT operator description of, 488–489 example of use of, 494–495 SQL Fundamentals 1 vs. SQL Expert, 9 INTERVAL DAY(n) TO SECOND(n2), date data type, 64 INTERVAL YEAR(n) TO MONTH, date data type, 64 INVALIDATE keyword, using with constraints, 448–449 invoking functions, 211 IS NOT NULL, 183–184 IS NULL, 183–184 J joins certification summary, 332–333 generating Cartesian products (cross-joins), 330–332 inline views and, 390–391 inner, 316–318 multitable, 325–326 natural, 323–324 non-equijoins, 326–328 outer, 318–321 overview of, 312 PRIMARY KEYS and FOREIGN KEYS, 313–314 SELECT statements and, 153–154 self-joins, 328–330 self test, answers, 342–344 self test, questions, 336–341 table aliases and, 321–323 two-minute drill, 334–335 types of, 315 USING keyword and, 324–325 views for simplifying, 382 L large objects (LOBs) overview of, 65–66 set operators and, 490 LAST/FIRST aggregate functions, 284 LAST_DAY date function, 227 leaf nodes, in hierarchical structures, 616 LEFT OUTER JOIN, 319 LENGTH character function, 219–220 Index less than (<), comparison operator, 172 less than or equal to (<=), comparison operator, 172 LEVEL, in hierarchical queries, 621 LIKE operator, 174–176 _ (underscore) and % (percent) for wildcard searches, 175–176 as comparison operator, 173 literal expressions, SELECT statement, 146–148 LOBs (large objects) overview of, 65–66 set operators and, 490 LOCALTIMESTAMP time zone function, 255 logistics, of SQL exam, 10–12 LOWER/UPPER functions, characters, 215 LPAD/RPAD functions, characters, 217–218 LTRIM/RTRIM functions, characters, 218–219 M machine language, 27 match parameters, 644 mathematical processing. See number functions MAX/MIN aggregate function, 280–281 MEDIAN aggregate function, 282–283 MERGE statement description of, 98 as DML statement, 97 example of use of, 583–586 merging rows in a table, 582–583 syntax of, 583 metacharacters, 640–643 metadata, 534. See also data dictionary Microsoft Access, 22 Microsoft SQL Server, 22 MIN/MAX aggregate function, 280–281 741 MINUS operator description of, 488–489 example of use of, 495–496 MOD numeric function, 224–225 MODIFY clause modifying columns in tables, 427–430 modifying constraints, 440 MONTHS_BETWEEN date function, 228–229 multiple-column subqueries overview of, 348–349 self test, answers, 379 self test, questions, 374 two-minute drill, 370 writing, 356–358 multiple-row subqueries comparison conditions, 355–356 example of use of, 354–355 overview of, 348 self test, answers, 379 self test, questions, 373 two-minute drill, 370 multirow functions. See functions, aggregate multistage queries, 347 multitable INSERTs conditional, 574–580 overview of, 567 pivot technique for changing columns into rows, 580–582 subqueries used by, 570–571 syntax of, 568–569 types of, 568 unconditional, 571–574 multitable joins, 325–326 N name priority, in namespaces, 408–409, 689 named views, subqueries creating, 348 742 Index names, assigning to subquery blocks, 366–367 namespaces naming database objects, 55–57 privileges and, 689 synonyms and, 408–409 naming database objects, 51–58 case sensitivity and double quotation marks, 53–55 certification summary, 81 overview of, 51–52 rules for, 52–53 self test, answers, 89 self test, questions, 84 system-assigned names, 57–58 unique names and namespaces, 55–57 natural joins overview of, 323–324 USING keyword compared with, 324–325 NCLOBs, 66 nesting functions aggregate functions, 292–295 scalar functions, 234–235 NEW_TIME time zone function, 256 NEXT_DAY date function, 227 NEXTVAL pseudocolumn, in sequences, 394 NLS parameters, 236–239 nodes, in hierarchical structures, 616 non-equijoins, 326–328 vs. equijoins, 315 example of use of, 327–328 overview of, 326 self-joins and, 328 normalization, 15–16 not equal (!=), comparison operator, 172 not equal (<>), comparison operator, 173 not equal (^=), comparison operator, 173 NOT EXISTS operator, 365–366 NOT keyword, combining with BETWEEN, 182 NOT NULL constraints, 70–72 adding NOT NULL columns to tables, 426–427 adding with ALTER TABLE statements, 438 creating “in line”, 68 dropping, 442 modifying NOT NULL columns in tables, 428 not declaring in “out of line” format, 70–71 overview of, 72 NOT operator in Boolean logic, 177–179 operator precedence, 180 preceding IN operator, 182 NULL keyword, 72–73 NULL values NVL function, 230–231 ORDER BY clause and, 194 NULLIF scalar function, 233–234 number format elements, 238 number functions mathematical processing, 223 MOD, 224–225 overview of, 212 REMAINDER, 224 ROUND (number), 223 TRUNC (number), 223–224 numeric data type comparing, 173 conversion to, 236–239 converting character types to, 240 NUMBER(n,m), 62 overview of, 62–63 NUMTODSINTERVAL date function, 229–230 NUMTOYMINTERVAL date function, 229 NVL function, 230–231 Index O object privileges description of, 675 synonyms, 406–408 vs. system privileges, 674 ON DELETE CASCADE clause, removing constraints and, 450–451 one-to-many relationships in RDBMS databases, 15 relationships between two tables, 314 operator precedence Boolean logic, 180–181 SELECT statement, 149–150 operators Boolean. See Boolean logic comparison, 172–173, 328 metacharacters, 640–643 SELECT statement, 149–150 set. See set operators optimizer, Oracle Databases, 399–401 OR operator in Boolean logic, 177–179 operator precedence, 180 Oracle Certification E-Magazine, 33–34 Oracle Corporation as market leader, 21–22 SQL documentation, 25–26 SQL tools, 23–25 SQL*Plus vs. SQL, 23 Oracle Data Pump Export, 471 Oracle Data Pump Import, 471 Oracles utilities, for external tables, 471 ORDER BY clause ASC and DESC and, 188–189 calling aggregate functions from, 277 certification summary, 194–195 column aliases, 190–192 combining referencing options, 193 743 expressions, 189–190 GROUP BY used in conjunction with, 292 in hierarchical queries, 623–624 NULL and, 194 overview of, 184–185 referencing by name, 185–187, 499 referencing by position, 192, 497–499 self test, answers, 206–207 self test, questions, 201–203 two-minute drill, 197 used with SELECT statement, 139, 151 “Out of Line” constraints, 69 outer joins, 318–321 deprecated syntax, 321 FULL OUTER JOIN, 320 vs. inner joins, 315 LEFT OUTER JOIN, 319 overview of, 318 RIGHT OUTER JOIN, 319–320 USING keyword and, 324–325 P padding character strings, 217–218 parameters, functions accepting, 210 patterns, regular expressions identifying and replacing, 653–659 percent symbol (%), as wildcard symbol, 175–176 performance tuning, index design and, 401–402 pivot technique, for multitable INSERTs, 580–582 PL/SQL, 29 Boolean data types in, 179 EXECUTE DBMS_LOCK.SLEEP(s), 590 POSIX character classes, 642–643 PRIMARY KEYS, 74–76 composite, 75–76 creating “in line”, 67–68 creating out-of-line, 69 744 Index dropping, 440–441 joins and, 313–314 overview of, 74–75 RDBMS columns, 14 PRIOR keyword, determining direction in hierarchical queries, 622–623 private synonyms, 405 privileges ADMIN option, 683–684 ALL PRIVILEGES, 684–685, 690–691 ANY, 682–683 certification summary, 698 data dictionary and, 691–693 data dictionary views for checking, 547 dependent, 691 WITH GRANT OPTION clause, 689–690 granting, 382, 679–682 granting on tables, 686–688 object privileges, 406–408 overview of, 674 PUBLIC privileges, 685 revoking, 679–682, 690 vs. roles, 696–697 self test, answers, 706–708 self test, questions, 701–705 SYS account and, 535 system privileges, 675–677 two-minute drill, 699–700 types of, 674–675 projection capability, of SELECT statement, 152 pseudocolumns, 143 Flashback Version Queries and, 596 ROWNUM, 390 sequences and, 394–395 PUBLIC privileges, 685 PUBLIC SYNONYM data dictionary objects renamed via, 535 dropping, 410 object privileges and, 406–408 overview of, 406 privileges and, 688–689 replacing/altering, 409 PURGE statement DDL statements, 96 emptying recycle bin, 462–463 Q queries hierarchical. See hierarchical queries SELECT. See SELECT statement subqueries. See subqueries R RANK aggregate function, 283 RAW data types, 597–598 RAWTOHEX function, 597–598 RDBMS (relational database management systems) 3GLs using SQL for communication with, 29–30 database design considerations, 16–18 normalization and, 15–16 Oracle as market leader, 21–22 overview of, 13–14 role of Dr. E.F. Codd in, 14–15 self test, answers, 42–43 self test, questions, 38–40 SQL as gateway to, 28–30 two-minute drill, 35–36 recovery. See restores recycle bin FLASHBACK operations, 461–462 purging objects from, 462–463 referencing by column alias, ORDER BY clause, 190–192 Index referencing by name, ORDER BY clause, 185–187, 499 referencing by position, ORDER BY clause, 192, 497–499 REGEXP_INSTR function, 643 REGEXP_LIKE condition, 645, 659 REGEXP_REPLACE function regular expression functions, 644 replacing patterns, 653–659 REGEXP_SUBSTR function examples, 645–653 overview of, 643 regular expressions certification summary, 662 check constraints and, 659–661 condition, 645 functions, 643–653 match parameters, 644 metacharacters, 640–643 overview of, 640 pattern identification and replacement, 653–659 self test, answers, 670–672 self test, questions, 665–669 two-minute drill, 663–664 REMAINDER numeric function, 224 RENAME COLUMN clause, ALTER TABLE statement, 431 RENAME CONSTRAINT clause, ALTER TABLE statement, 452 RENAME statement, DDL, 96 reports, creating tree-structured, 621 reserved words, naming database objects and, 52–53 RESOURCE role, 695 restores data recovery options, 587 identifying time for, 465 RESTORE POINT, 468 745 restrictions, on external tables, 469 result sets, GROUPING SETS operation producing single result set, 519–521 REVOKE statement DDL statements, 96 privileges, 682, 690 RIGHT OUTER JOIN, 319–320 roles data dictionary views, 696 description of ROLE object, 48 granting, 693–696 namespaces, 56 vs. privileges, 696–697 types of privileges and, 675 ROLLBACK statement data recovery options, 588 description of, 98 overview of, 116–119 rolling back to SAVEPOINT, 121–122 types of TCL statements, 97 ROLLUP operation GROUPING function identifying row values created by, 517–518 for producing subtotals, 512–515 root node CONNECT_BY_ROOT, 625–626 in hierarchical structures, 616 ROUND date function, 225–226 ROUND numeric function, 223 ROWID pseudocolumn, 143–144 ROWNUM pseudocolumn, 143, 390 rows controlling order of rows returned by set operators, 497 deleting from a table, 111–112 grouping. See GROUP BY clause HAVING clause and, 297 inserting into a table, 98–99 limiting rows retrieved by queries, 170 746 Index merging rows in a table, 582–586 multirow functions. See functions, aggregate in RDBMS databases, 14 regular vs. superaggregated, 515 single-row functions. See functions, scalar sorting. See ORDER BY clause updating in a table, 106–108 RPAD/LPAD character functions, 217–218 RTRIM/LTRIM character functions, 218–219 rules of normalization, 16 s SAVEPOINT statement data recovery options, 588 description of, 98 overview of, 119–121 rolling back to SAVEPOINT, 121–122 types of TCL statements, 97 scalar functions. See functions, scalar scalar subqueries locations where cannot be used, 359 overview of, 349 self test, answers, 379 self test, questions, 374 two-minute drill, 370 using in SQL, 358–359 using within INSERT statement, 359–360 schema object management adding columns, 424–426 adding constraints, 436–440 adding NOT NULL columns, 426–427 automatic index creation, 454–455 cascading constraints, 447–448 certification summary, 474–475 creating function-based indexes, 457–458 disabling constraints, 442–446 dropping columns, 431–434 enabling constraints, 447 external tables. See external tables modifying columns, 427–428 modifying constraints, 440 modifying NOT NULL columns, 428 modifying populated columns, 428–430 overview of, 424 performing flashback operations. See FLASHBACK operations removing constraints, 440–442 renaming columns, 430–431 renaming constraints, 452 self test, answers, 484–486 self test, questions, 478–482 two-minute drill, 476–477 unused columns and, 434–435 USING clause applied to index creation, 455–456 validating/invalidating constraints, 448–449 schema objects constraints, 155 indexes, 156 non-schema objects and, 49 overview of, 154–155 prefixes, 688 relationship to database objects, 48–49 SELECT statement and, 154–157 self test, answers, 168 self test, questions, 164–165 sequences, 156–157 synonyms, 157 tables, 155 two-minute drill, 160 views, 155 SCN (System Change Number) overview of, 465–466 recovery and, 463 SCN_TO_TIMESTAMP, 467 VERSIONS BETWEEN SCN, 595 Index searches metacharacter operators for, 640 wildcard searches with LIKE operator, 174–177 second generation languages (2GLs), 27 security benefits, of views, 382 select list calling aggregate functions from, 277 SELECT statements and, 139 selecting columns from tables, 142 SELECT statement case sensitivity and, 54–55 certification summary, 157–158 AS OF clause, 593 clauses used with, 151–152, 296 correlated subqueries in, 362 description of, 98 DISTINCT and UNIQUE keywords used with, 144–145 as DML statement, 97 example of use of, 139–140 executing basic, 138–139 expressions, 146–148 functions, 150–151 HAVING clause and, 296–297 hierarchical queries and, 619–621 joining capability of, 153–154 limiting rows retrieved by queries, 170 minimum requirements for, 140–141 operators and operator precedence, 149–150 optimizer for, 400–401 options for calling aggregate functions, 277 ORDER BY clause. See ORDER BY clause overview of, 138 projection capability of, 152 pseudocolumns, 143 for retrieving data from multiple tables, 312 schema objects and, 154–157 selecting columns from tables, 142–143 747 selection capability of, 152–153 self test, answers, 166–168 self test, questions, 161–164 set operators and, 488 SQL Fundamentals 1 vs. SQL Expert, 9 subqueries. See subqueries two-minute drill, 159–160 views and, 382 views created from queries, 385–386 WHERE clause. See WHERE clause wildcard operator (*), 146 self-joins, 328–330 example of self-joining SELECT statement, 328–329 FOREIGN KEYS and, 329 hierarchical queries and, 616 overview of, 328 syntax of, 329–330 sequences certification summary, 411 creating, 392–394 description of SEQUENCE object, 47 options for, 393–394 overview of, 156–157, 392 self test, answers, 421 self test, questions, 416–417 SEQUENCE object as schema object, 49 two-minute drill, 412–413 using, 394–397 using with INSERT statement, 105 session time, vs. database time, 249–250 SESSIONTIMEZONE function, 254 set operators certification summary, 500 combining, 496–497 controlling order of rows returned, 497 INTERSECT, 494–495 MINUS, 495–496 ORDER BY—by position, 497–499 748 Index ORDER BY—by reference, 499 overview of, 488–490 self test, answers, 508–510 self test, questions, 502–507 two-minute drill, 501 UNION, 490–493 UNION ALL, 494 WHERE clause, 184 siblings, in hierarchy, 623–624 single column indexes, 399–402 maintaining, 401–402 Oracle Database optimizer and, 399–400 overview of, 399 uses of, 400–401 single-row functions. See functions, scalar single-row subqueries, 350–354 benefits of, 350 comparison conditions, 353–354 example of use of, 350–353 IN keyword and, 354 overview of, 348 self test, answers, 379 self test, questions, 373 two-minute drill, 370 WHERE clause and, 353 skip scanning, composite indexes and, 403 software, study materials needed for 1ZO-047 exam, 32 sorting rows. See ORDER BY clause SOUNDEX character function, 221–222 SQL Developer Oracle tools for working with SQL, 24 software needed for 1ZO-047 exam, 32 SQL exam (IZO-047-Oracle Database SQL Expert) materials need for study, 31–34 Oracle SQL vs. ANSI SQL or vs. Oracle SQL*Plus, 23 overview of, 2–4 self test, answers, 42 self test, questions, 38–40 SQL Fundamentals 1 vs. SQL Expert exam objectives, 4–10 subject areas, 12–13 test logistics, 10–12 two-minute drill, 35 SQL Fundamentals 1 (IZO-051), 4–10 SQL Language Reference Manual, 26 SQL Server, Microsoft, 22 SQL (Structured Query Language) as 4GL, 26–28 basics of, 18–20 challenges of working with (syntax is not enough), 30–31 commonly used commands, 20 as gateway to RDBMS for all languages, 28–30 Oracle documentation for, 25–26 Oracle tools for working with, 23–25 self test, answers, 42–44 self test, questions, 39 two-minute drill, 35–36 types of SQL statements, 94–95 use of Boolean (true/false) logic in, 179 SQL*Loader, 471 SQL*Plus Command Line Interface, 23–24 CONNECT statement, 678 Oracle SQL vs. Oracle SQL*Plus, 23 SELECT statement in, 139 software needed for 1ZO-047 exam, 32 working with system privileges, 677 START WITH clause, SELECT statement, 619–621 statements. See also by individual type vs. commands, 97 FLASHBACK operations executing, 462 optimizer for, 399–401 subqueries, 346 Index in transactions, 599 types of SQL statements, 94–95 strings concatenation, 216–217 regular expression functions, 643 study materials self test, answers, 44 self test, questions, 41 SQL exam, 31–34 two-minute drill, 37 subject areas, of SQL exam, 12–13 subqueries assigning names to subquery blocks, 366–367 certification summary, 367–368 CREATE TABLE statement used with, 560–563 deleting rows with correlated subquery, 364–365 inline views, 389–391 INSERT statement with, 563–564 manipulating data with, 560 multiple-row, 354–356 multitable INSERTs using, 570–571 overview of, 346–347 problem solving with correlated, 360–362 self test, answers, 378–380 self test, questions, 372–377 single-row, 350–354 testing for existing of rows, 365–366 two-minute drill, 369–371 types of, 348–349 updating rows with correlated, 362–364 uses of, 347–348 using scalar subqueries in SQL, 358–360 WHERE clause and, 184 writing multiple-column, 356–358 SUBSTR character function, 220–221 SUBSTR regular expression functions, 643 subtotals, ROLLUP operation producing, 512–515 749 SUM aggregate function overview of, 280 ROLLUP operation used with, 512 super user account, 535 superaggregate rows, 512, 515 synonyms certification summary, 411 description of SYNONYM object, 48 dropping, 410 name priority in namespaces and, 408–409 namespaces, 56 overview of, 157, 404 private, 405 privileges and, 406–408, 688–689 public, 406 replacing/altering, 409 as schema and non-schema objects, 49 self test, answers, 422 self test, questions, 419 two-minute drill, 413 syntax, SQL challenges of working with SQL, 30–31 importance of knowing, 25 SYS account, 535 SYS_CONNECT_BY_PATH, 624–625 SYSDATE date function, 225 SYS_EXTRACT_UTC time zone conversion function, 260 system-assigned names, 57–58 System Change Number. See SCN (System Change Number) system privileges ANY keyword and, 682–683 list of, 675–677 vs. object privileges, 674 SYSTEM user accounts, 674 SYSTIMESTAMP time zone function, 255 750 Index t table aliases object privileges and, 406–408 subqueries and, 362 using with INSERT, UPDATE, DELETE, and SELECT, 323 using with joins, 321–323 tables adding columns to, 424–426 ALTER TABLE statement, 436–440 creating constraints. See CREATE CONSTRAINT statement creating simple table, 50–51 deleting rows from, 111–112 DESCRIBE statement for reviewing structure of, 59–60 description of TABLE object, 47 DROP TABLE statement, 449 DUAL table, 214–215 granting privileges on, 686–688 inserting rows into, 98–99 inspecting, 545–546 joining. See joins merging rows in a table, 582–586 namespaces, 56 naming. See naming database objects overview of, 155 in RDBMS databases, 14–15 recovering dependent objects of, 462 recovering dropped, 459–461 recovering in time, 463–465 schema prefixes, 688 selecting columns from, 142–143 subqueries for populating, 347 TABLE object as schema object, 49 updating rows in, 106–108 tablespaces, creating user accounts and, 678–679 TCL (Transaction Control Language) COMMIT statement, 112–116 control transactions, 112 data recovery options, 587–588 overview of, 97 ROLLBACK statement, 116–119, 121–122 SAVEPOINT statement, 119–121 self test, answers, 135 self test, questions, 132 two-minute drill, 126–127 types of SQL statements, 95 third generation languages (3GLs), 28–30 third normal form (3NF), 16–17 time, tracking changes over time, 586–588 time zone conversion functions CAST, 258–259 EXTRACT, 259–260 FROM_TZ, 257 AT LOCAL expression and, 262–263 overview of, 257 SYS_EXTRACT_UTC, 260 AT time zone expression and, 261–262 TO_TIMESTAMP_TZ, 257–258 time zone data types overview of, 250–252 TIMESTAMP WITH LOCAL TIME ZONE, 64, 80, 253 TIMESTAMP WITH TIME ZONE, 64, 252–253 TIMESTAMP(n), 64 time zone management CURRENT_DATE and CURRENT_ TIMESTAMP functions, 254–255 database time vs. session time and, 249–250 DBtime zone function, 253 LOCALTIMESTAMP function, 255 NEW_TIME function, 256 overview of, 247–249 SESSIONTIMEZONE function, 254 Index SYSTIMESTAMP function, 255 time zone data types, 252–253 time zone offset, 252 Time Zone Region Names, 251 UTC (Coordinated Universal Time), 250 TIMESTAMP WITH LOCAL TIME ZONE data type, 64, 80, 253 TIMESTAMP WITH TIME ZONE data type, 64, 252–253 TIMESTAMP(n) data type, 64 timestamps converting scalar functions to, 245 recovery and, 467, 594–595 scalar functions, 254–258 time zone data types, 64, 80, 252–253 TIMESTAMP_TO_SCN, 467 TO_CHAR converting character types to date types, 240–242 converting character types to number types, 240 overview of, 239 TO_DATE, converting data types to date type, 244 TO_DSINTERVAL conversion function, 245–246 TO_NUMBER conversion function, 236–239 TO_TIMESTAMP conversion function, 245 TO_TIMESTAMP_TZ time zone conversion function, 257–258 TO_YMINTERVAL conversion function, 246 tracking changes, over time, 586–588 Transaction Control Language. See TCL (Transaction Control Language) transactions, statements consisting of, 599 tree structure. See hierarchical queries TRIM character function, 219 TRUNC date function, 226–227 number function, 223–224 TRUNCATE, DDL statements, 96 751 U unconditional multitable INSERTs, 571–574 underscore (_ ), as wildcard symbol, 175 undo. See ROLLBACK statement undo retention period, FQs (Flashback Queries), 591–592 UNDO_MANAGEMENT, 592 UNDO_RETENTION, 592 UNDO_TABLESPACE, 592 Unicode, 66 UNION ALL operator description of, 488–489 example of use of, 494 UNION operator description of, 488–489 example of use of, 490–493 SQL Fundamentals 1 vs. SQL Expert, 9 UNIQUE constraint dropping, 441 overview of, 74 unique indexes compared with, 404 unique identifiers for database records, 15, 17 naming database objects, 55–57 unique indexes, 403–404 UNIQUE keyword, used with SELECT statement, 144–145 UNUSED columns, 434–435 UPDATE statement, 106–110 constraints and, 108–110 correlated subqueries in, 362, 564–567 description of, 98 as DML statement, 97 expressions for assigning values to columns, 108 SQL Fundamentals 1 vs. SQL Expert, 9 subqueries, 346 updating rows in a table, 106–108 752 Index updating rows with correlated subqueries, 362–364 views, 386–389 WHERE clause and, 110 UPPER/LOWER character function, 215 user accounts. See also privileges CONNECT statement and, 678 CREATE, ALTER, and DROP user, 677–678 tablespaces and, 678–679 user-defined functions, 211 USER_CATALOG view, data dictionary, 543–544 USER_CONSTRAINTS view, data dictionary, 547–548 USER_OBJECTS view, data dictionary, 544 users COMMIT statement and, 115–116 controlling access. See privileges description of USER object, 48 identifying owned objects (USER_CATALOG view), 543–544 namespaces, 56 USER object as non-schema object, 49 USER_SYNONYMS view, data dictionary, 537 USER_TAB_COLUMNS view, data dictionary, 545–546 USER_TABLES view, data dictionary, 536 USING clause applied to index creation, 455–456 basing a merge on subqueries, 586 USING keyword, joins and, 324–325 UTC (Coordinated Universal Time), 250 utilities, for external tables, 471 V V_$ (dynamic performance views ), in data dictionary, 538–539 VALIDATE keyword, for constraints, 448–449 VARCHAR2(n) character data type LIKE operator for, 175 overview of, 61–62 V$DATABASE, 539 VERSIONS BETWEEN SCN, Flashback Version Queries, 595 VERSIONS BETWEEN TIMESTAMP, Flashback Version Queries, 594–595 views ALTER VIEW statement, 391–392 certification summary, 410 compiling data dictionary views, 546–547 constraints and, 386 creating, 383–386 description of VIEW object, 47 hierarchical queries and, 616 inline, 389–391 namespaces, 56 overview of, 155, 382 privileges and, 691–693 retrieving data from, 391 self test, answers, 420–421 self test, questions, 414–416 subqueries for creating named views and dynamic views, 347–348 syntax of, 384 two-minute drill, 412 updatable, 386–389 UPDATE statement working with VIEW object, 106 VIEW object, as schema object, 49 V$INSTANCE, 539 V$OBJECT_USAGE, 539 V$PARAMETER, 539 V$RESERVED_WORDS, 539 V$SESSION, 539 V$SYSTEM_PARAMETER, 592 V$time zone_NAMES, 539 Index w WHERE clause BETWEEN and, 182 AND/OR/NOT operators and, 177–179 certification summary, 194–195 comparing data types with, 172–174 comparing expressions with, 171–172 composite indexes and, 403 DELETE statement, 111–112 filtering in hierarchical queries, 626–627 HAVING clause compared with, 296–297 IS NULL, IS NOT NULL, 183–184 LIKE operator, 174–177 IN operator, 181–182 operator precedence, 180–181 overview of, 170–171 753 SELECT statement, 151 selection capability and, 152–153 self test, answers, 204–205 self test, questions, 198–201 single-row subqueries and, 353 subqueries and, 346 subqueries and set operators and, 184 two-minute drill, 196 UPDATE statement, 110 wildcard operator (*), SELECT statement, 146 wildcard searches, with LIKE operator, 174–177 WITH ADMIN OPTION, GRANT statement, 683–684 WITH clause, assigning names to subquery blocks using, 366–367 WITH GRANT OPTION clause, privileges, 689–690 LICENSE AGREEMENT THIS PRODUCT (THE “PRODUCT”) CONTAINS PROPRIETARY SOFTWARE, DATA AND INFORMATION (INCLUDING DOCUMENTATION) OWNED BY THE McGRAW-HILL COMPANIES, INC. (“McGRAW-HILL”) AND ITS LICENSORS. YOUR RIGHT TO USE THE PRODUCT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT. LICENSE: Throughout this License Agreement, “you” shall mean either the individual or the entity whose agent opens this package. You are granted a non-exclusive and non-transferable license to use the Product subject to the following terms: (i) If you have licensed a single user version of the Product, the Product may only be used on a single computer (i.e., a single CPU). If you licensed and paid the fee applicable to a local area network or wide area network version of the Product, you are subject to the terms of the following subparagraph (ii). (ii) If you have licensed a local area network version, you may use the Product on unlimited workstations located in one single building selected by you that is served by such local area network. If you have licensed a wide area network version, you may use the Product on unlimited workstations located in multiple buildings on the same site selected by you that is served by such wide area network; provided, however, that any building will not be considered located in the same site if it is more than five (5) miles away from any building included in such site. In addition, you may only use a local area or wide area network version of the Product on one single server. If you wish to use the Product on more than one server, you must obtain written authorization from McGraw-Hill and pay additional fees. (iii) You may make one copy of the Product for back-up purposes only and you must maintain an accurate record as to the location of the back-up at all times. COPYRIGHT; RESTRICTIONS ON USE AND TRANSFER: All rights (including copyright) in and to the Product are owned by McGraw-Hill and its licensors. You are the owner of the enclosed disc on which the Product is recorded. You may not use, copy, decompile, disassemble, reverse engineer, modify, reproduce, create derivative works, transmit, distribute, sublicense, store in a database or retrieval system of any kind, rent or transfer the Product, or any portion thereof, in any form or by any means (including electronically or otherwise) except as expressly provided for in this License Agreement. You must reproduce the copyright notices, trademark notices, legends and logos of McGraw-Hill and its licensors that appear on the Product on the back-up copy of the Product which you are permitted to make hereunder. All rights in the Product not expressly granted herein are reserved by McGraw-Hill and its licensors. TERM: This License Agreement is effective until terminated. It will terminate if you fail to comply with any term or condition of this License Agreement. Upon termination, you are obligated to return to McGraw-Hill the Product together with all copies thereof and to purge all copies of the Product included in any and all servers and computer facilities. DISCLAIMER OF WARRANTY: THE PRODUCT AND THE BACK-UP COPY ARE LICENSED “AS IS.” McGRAW-HILL, ITS LICENSORS AND THE AUTHORS MAKE NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE RESULTS TO BE OBTAINED BY ANY PERSON OR ENTITY FROM USE OF THE PRODUCT, ANY INFORMATION OR DATA INCLUDED THEREIN AND/OR ANY TECHNICAL SUPPORT SERVICES PROVIDED HEREUNDER, IF ANY (“TECHNICAL SUPPORT SERVICES”). McGRAW-HILL, ITS LICENSORS AND THE AUTHORS MAKE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR USE WITH RESPECT TO THE PRODUCT. McGRAW-HILL, ITS LICENSORS, AND THE AUTHORS MAKE NO GUARANTEE THAT YOU WILL PASS ANY CERTIFICATION EXAM WHATSOEVER BY USING THIS PRODUCT. NEITHER McGRAW-HILL, ANY OF ITS LICENSORS NOR THE AUTHORS WARRANT THAT THE FUNCTIONS CONTAINED IN THE PRODUCT WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION OF THE PRODUCT WILL BE UNINTERRUPTED OR ERROR FREE. YOU ASSUME THE ENTIRE RISK WITH RESPECT TO THE QUALITY AND PERFORMANCE OF THE PRODUCT. LIMITED WARRANTY FOR DISC: To the original licensee only, McGraw-Hill warrants that the enclosed disc on which the Product is recorded is free from defects in materials and workmanship under normal use and service for a period of ninety (90) days from the date of purchase. In the event of a defect in the disc covered by the foregoing warranty, McGraw-Hill will replace the disc. LIMITATION OF LIABILITY: NEITHER McGRAW-HILL, ITS LICENSORS NOR THE AUTHORS SHALL BE LIABLE FOR ANY INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS BUT NOT LIMITED TO, LOSS OF ANTICIPATED PROFITS OR BENEFITS, RESULTING FROM THE USE OR INABILITY TO USE THE PRODUCT 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. Some states do not allow the exclusion or limitation of indirect, special or consequential damages, so the above limitation may not apply to you. U.S. GOVERNMENT RESTRICTED RIGHTS: Any software included in the Product is provided with restricted rights subject to subparagraphs (c), (1) and (2) of the Commercial Computer Software-Restricted Rights clause at 48 C.F.R. 52.227-19. The terms of this Agreement applicable to the use of the data in the Product are those under which the data are generally made available to the general public by McGraw-Hill. Except as provided herein, no reproduction, use, or disclosure rights are granted with respect to the data included in the Product and no right to modify or create derivative works from any such data is hereby granted. GENERAL: This License Agreement constitutes the entire agreement between the parties relating to the Product. The terms of any Purchase Order shall have no effect on the terms of this License Agreement. Failure of McGraw-Hill to insist at any time on strict compliance with this License Agreement shall not constitute a waiver of any rights under this License Agreement. This License Agreement shall be construed and governed in accordance with the laws of the State of New York. If any provision of this License Agreement is held to be contrary to law, that provision will be enforced to the maximum extent permissible and the remaining provisions will remain in full force and effect.
Source Exif Data:
File Type : PDF File Type Extension : pdf MIME Type : application/pdf PDF Version : 1.6 Linearized : Yes Page Mode : UseOutlines XMP Toolkit : 3.1-702 Modify Date : 2010:04:30 23:15:18-04:00 Create Date : 2010:04:30 23:15:13-04:00 Metadata Date : 2010:04:30 23:15:18-04:00 Format : application/pdf Document ID : uuid:9c7a7054-c719-4964-bfae-86c6c5a439bf Instance ID : uuid:3dde85e6-f1f6-4868-ba94-edf9867dc270 Has XFA : No Page Count : 794 Page Layout : SinglePageEXIF Metadata provided by EXIF.tools