Transact-SQL® User’s Guide Adaptive Server® Enterprise 12.5.

 

 

Transact-SQL® User’s Guide Adaptive Server® Enterprise 12.5.1DOCUMENT ID: DC32300-01-1251-01 LAST REVISED: August 2003 Copyright © 1989-2003 by Sybase, Inc. All rights reserved. This publication pertains to Sybase software and to any subsequent release until otherwise indicated in new editions or technical notes. Information in this document is subject to change without notice. The software described herein is furnished under a license agreement, and it may be used or copied only in accordance with the terms of that agreement. To order additional documents, U.S. and Canadian customers should call Customer Fulfillment at (800) 685-8225, fax (617) 229-9845. Customers in other countries with a U.S. license agreement may contact Customer Fulfillment via the above fax number. All other international customers should contact their Sybase subsidiary or local distributor. Upgrades are provided only at regularly scheduled software release dates. No part of this publication may be reproduced, transmitted, or translated in any form or by any means, electronic, mechanical, manual, optical, or otherwise, without the prior written permission of Sybase, Inc. Sybase, the Sybase logo, AccelaTrade, ADA Workbench, Adaptable Windowing Environment, Adaptive Component Architecture, Adaptive Server, Adaptive Server Anywhere, Adaptive Server Enterprise, Adaptive Server Enterprise Monitor, Adaptive Server Enterprise Replication, Adaptive Server Everywhere, Adaptive Server IQ, Adaptive Warehouse, Anywhere Studio, Application Manager, AppModeler, APT Workbench, APT-Build, APT-Edit, APT-Execute, APT-FORMS, APT-Translator, APT-Library, AvantGo, AvantGo Application Alerts, AvantGo Mobile Delivery, AvantGo Mobile Document Viewer, AvantGo Mobile Inspection, AvantGo Mobile Marketing Channel, AvantGo Mobile Pharma, AvantGo Mobile Sales, AvantGo Pylon, AvantGo Pylon Application Server, AvantGo Pylon Conduit, AvantGo Pylon PIM Server, AvantGo Pylon Pro, Backup Server, BizTracker, ClearConnect, Client-Library, Client Services, Convoy/DM, Copernicus, Data Pipeline, Data Workbench, DataArchitect, Database Analyzer, DataExpress, DataServer, DataWindow, DB-Library, dbQueue, Developers Workbench, Direct Connect Anywhere, DirectConnect, Distribution Director, e-ADK, E-Anywhere, e-Biz Integrator, E-Whatever, EC Gateway, ECMAP, ECRTP, eFulfillment Accelerator, Embedded SQL, EMS, Enterprise Application Studio, Enterprise Client/Server, Enterprise Connect, Enterprise Data Studio, Enterprise Manager, Enterprise SQL Server Manager, Enterprise Work Architecture, Enterprise Work Designer, Enterprise Work Modeler, eProcurement Accelerator, EWA, Financial Fusion, Financial Fusion Server, Gateway Manager, GlobalFIX, ImpactNow, Industry Warehouse Studio, InfoMaker, Information Anywhere, Information Everywhere, InformationConnect, InternetBuilder, iScript, Jaguar CTS, jConnect for JDBC, Mail Anywhere Studio, MainframeConnect, Maintenance Express, Manage Anywhere Studio, M-Business Channel, M-Business Network, M-Business Server, MDI Access Server, MDI Database Gateway, media.splash, MetaWorks, My AvantGo, My AvantGo Media Channel, My AvantGo Mobile Marketing, MySupport, Net-Gateway, Net-Library, New Era of Networks, ObjectConnect, ObjectCycle, OmniConnect, OmniSQL Access Module, OmniSQL Toolkit, Open Biz, Open Client, Open ClientConnect, Open Client/Server, Open Client/Server Interfaces, Open Gateway, Open Server, Open ServerConnect, Open Solutions, Optima++, PB-Gen, PC APT Execute, PC Net Library, PocketBuilder, Pocket PowerBuilder, Power++, power.stop, PowerAMC, PowerBuilder, PowerBuilder Foundation Class Library, PowerDesigner, PowerDimensions, PowerDynamo, PowerJ, PowerScript, PowerSite, PowerSocket, Powersoft, PowerStage, PowerStudio, PowerTips, Powersoft Portfolio, Powersoft Professional, PowerWare Desktop, PowerWare Enterprise, ProcessAnalyst, Rapport, Report Workbench, Report-Execute, Replication Agent, Replication Driver, Replication Server, Replication Server Manager, Replication Toolkit, Resource Manager, RW-DisplayLib, S-Designor, SDF, Secure SQL Server, Secure SQL Toolset, Security Guardian, SKILS, smart.partners, smart.parts, smart.script, SQL Advantage, SQL Anywhere, SQL Anywhere Studio, SQL Code Checker, SQL Debug, SQL Edit, SQL Edit/TPU, SQL Everywhere, SQL Modeler, SQL Remote, SQL Server, SQL Server Manager, SQL SMART, SQL Toolset, SQL Server/CFT, SQL Server/DBM, SQL Server SNMP SubAgent, SQL Station, SQLJ, STEP, SupportNow, S.W.I.F.T. Message Format Libraries, Sybase Central, Sybase Client/Server Interfaces, Sybase Financial Server, Sybase Gateways, Sybase MPP, Sybase SQL Desktop, Sybase SQL Lifecycle, Sybase SQL Workgroup, Sybase User Workbench, SybaseWare, Syber Financial, SyberAssist, SyBooks, System 10, System 11, System XI (logo), SystemTools, Tabular Data Stream, TradeForce, Transact-SQL, Translation Toolkit, UltraLite.NET, UNIBOM, Unilib, Uninull, Unisep, Unistring, URK Runtime Kit for UniCode, Viewer, Visual Components, VisualSpeller, VisualWriter, VQL, WarehouseArchitect, Warehouse Control Center, Warehouse Studio, Warehouse WORKS, Watcom, Watcom SQL, Watcom SQL Server, Web Deployment Kit, Web.PB, Web.SQL, WebSights, WebViewer, WorkGroup SQL Server, XA-Library, XA-Server and XP Server are trademarks of Sybase, Inc. 03/03 Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. All other company and product names used herein may be trademarks or registered trademarks of their respective companies. Use, duplication, or disclosure by the government is subject to the restrictions set forth in subparagraph (c)(1)(ii) of DFARS 52.227- 7013 for the DOD and as set forth in FAR 52.227-19(a)-(d) for civilian agencies. Sybase, Inc., One Sybase Drive, Dublin, CA 94568.Contents Transact-SQL User’s Guide iii About This Book ......................................................................................................................... xix CHAPTER 1 SQL Building Blocks....................................................................... 1 SQL in Adaptive Server.................................................................... 1 Queries, data modification, and commands .............................. 2 Tables, columns, and rows........................................................ 3 The relational operations ........................................................... 3 Compiled objects ....................................................................... 4 Naming conventions......................................................................... 6 SQL data characters ................................................................. 7 SQL language characters.......................................................... 7 Identifiers ................................................................................... 7 Expressions in Adaptive Server ..................................................... 13 Arithmetic and character expressions ..................................... 13 Relational and logical expressions .......................................... 19 Transact-SQL extensions............................................................... 20 The compute clause ................................................................ 21 Control-of-flow language ......................................................... 21 Stored procedures ................................................................... 21 Extended stored procedures ................................................... 22 Triggers ................................................................................... 23 Defaults and rules ................................................................... 23 Error handling and set options ................................................ 23 Additional Adaptive Server extensions to SQL........................ 25 Compliance to ANSI standards ...................................................... 26 Federal Information Processing Standards (FIPS) flagger...... 27 Chained transactions and isolation levels ............................... 28 Identifiers ................................................................................. 28 SQL standard-style comments ................................................ 28 Right truncation of character strings........................................ 29 Permissions required for update and delete statements ......... 29 Arithmetic errors ...................................................................... 29 Synonymous keywords ........................................................... 30 Treatment of nulls.................................................................... 30Contents iv Adaptive Server Enterprise Adaptive Server login accounts...................................................... 31 Group membership.................................................................. 31 Role membership .................................................................... 32 Getting information about your Adaptive Server account........ 32 Changing your password......................................................... 33 Understanding remote logins .................................................. 34 How to use Transact-SQL with the isql utility................................. 35 Default databases ................................................................... 36 Using network-based security services with isql ..................... 37 Logging out of isql ................................................................... 37 Using the pubs2 and pubs3 sample databases ............................. 37 What is in the sample databases? .......................................... 38 CHAPTER 2 Queries: Selecting Data from a Table .......................................... 41 What are queries?.......................................................................... 41 select syntax............................................................................ 42 Choosing columns: the select clause............................................. 44 Choosing all columns: select * ............................................... 44 Choosing specific columns...................................................... 45 Rearranging the order of columns........................................... 45 Renaming columns in query results ........................................ 46 Expressions............................................................................. 47 Selecting text and image values.............................................. 53 Select list summary ................................................................. 55 Eliminating duplicate query results with distinct ............................. 55 Specifying tables: the from clause ................................................. 57 Selecting rows: the where clause................................................... 58 Comparison operators............................................................. 59 Ranges (between and not between) ....................................... 61 Lists (in and not in) .................................................................. 62 Pattern matching ............................................................................ 65 Matching character strings: like............................................... 65 Character strings and quotation marks ................................... 71 “Unknown” values: NULL ........................................................ 71 Connecting conditions with logical operators .......................... 77 CHAPTER 3 Using Aggregates, Grouping, and Sorting.................................. 79 Using aggregate functions ............................................................. 79 Aggregate functions and datatypes......................................... 81 count vs. count(*) .................................................................... 82 Using aggregate functions with distinct ................................... 83 Null values and the aggregate functions ................................. 84 Organizing query results into groups: the group by clause ............ 85Contents Transact-SQL User’s Guide v group by syntax ....................................................................... 86 Referencing other columns in queries using group by ............ 88 Expressions and group by ....................................................... 91 Nesting aggregates with group by........................................... 92 Null values and group by......................................................... 93 where clause and group by ..................................................... 94 group by and all....................................................................... 95 Using aggregates without group by......................................... 96 Selecting groups of data: the having clause .................................. 97 How the having, group by, and where clauses interact........... 99 Using having without group by .............................................. 101 Sorting query results: the order by clause.................................... 103 order by and group by ........................................................... 104 order by and group by used with select distinct .................... 105 Summarizing groups of data: the compute clause ....................... 106 Row aggregates and compute .............................................. 109 Specifying more than one column after compute .................. 110 Using more than one compute clause................................... 111 Applying an aggregate to more than one column.................. 111 Using different aggregates in the same compute clause ...... 112 Grand values: compute without by ........................................ 113 Combining queries: the union operator ........................................ 114 Guidelines for union queries.................................................. 116 Using union with other Transact-SQL commands................. 118 CHAPTER 4 Subqueries: Using Queries Within Other Queries ................... 121 How subqueries work................................................................... 121 Subquery syntax.................................................................... 122 Subquery restrictions............................................................. 123 Example of using a subquery ................................................ 124 Qualifying column names ...................................................... 125 Subqueries with correlation names ....................................... 125 Multiple levels of nesting ....................................................... 127 Subqueries in update, delete, and insert statements ............ 128 Subqueries in conditional statements.................................... 129 Using subqueries instead of expressions.............................. 129 Types of subqueries..................................................................... 130 Expression subqueries .......................................................... 131 Quantified predicate subqueries............................................ 134 Subqueries used with in ........................................................ 140 Subqueries used with not in .................................................. 142 Subqueries using not in with NULL ....................................... 142 Subqueries used with exists .................................................. 143 Subqueries used with not exists............................................ 146Contents vi Adaptive Server Enterprise Finding intersection and difference with exists...................... 146 Subqueries using SQL derived tables ................................... 147 Using correlated subqueries ........................................................ 148 Correlated subqueries containing Transact-SQL outer joins. 149 Correlated subqueries with correlation names ...................... 150 Correlated subqueries with comparison operators................ 151 Correlated subqueries in a having clause ............................. 152 CHAPTER 5 SQL Derived Tables..................................................................... 155 Differences from abstract plan derived tables.............................. 155 How SQL derived tables work ...................................................... 155 Advantages of SQL derived tables............................................... 156 SQL derived tables and optimization..................................... 157 SQL derived table syntax ............................................................. 157 Derived column lists .............................................................. 159 Correlated SQL derived tables .............................................. 159 Using SQL derived tables ............................................................ 160 Nesting .................................................................................. 160 Subqueries using SQL derived tables ................................... 160 Unions ................................................................................... 161 Unions in subqueries............................................................. 161 Renaming columns with SQL derived tables......................... 161 Constant expressions............................................................ 162 Aggregate functions .............................................................. 163 Joins with SQL derived tables ............................................... 163 Creating a table from a SQL derived table ............................ 164 Correlated attributes.............................................................. 165 CHAPTER 6 Joins: Retrieving Data from Several Tables.............................. 167 How joins work ............................................................................. 168 Join syntax ............................................................................ 168 Joins and the relational model............................................... 169 How joins are structured .............................................................. 169 The from clause..................................................................... 171 The where clause .................................................................. 172 How joins are processed.............................................................. 174 Equijoins and natural joins ........................................................... 175 Joins with additional conditions .................................................... 176 Joins not based on equality.......................................................... 177 Self-joins and correlation names .................................................. 178 The not-equal join ........................................................................ 179 Not-equal joins and subqueries............................................. 181 Joining more than two tables ....................................................... 182Contents Transact-SQL User’s Guide vii Outer joins.................................................................................... 184 Inner and outer tables ........................................................... 184 Outer join restrictions ............................................................ 185 Views used with outer joins ................................................... 185 ANSI Inner and outer joins .................................................... 186 ANSI outer joins .................................................................... 192 Transact-SQL outer joins ...................................................... 204 How null values affect joins.......................................................... 207 Determining which table columns to join...................................... 208 CHAPTER 7 Using and Creating Datatypes................................................... 211 How Transact-SQL datatypes work ............................................. 211 Using system-supplied datatypes ................................................ 212 Exact numeric types: integers ............................................... 214 Exact numeric types: decimal numbers................................. 214 Approximate numeric datatypes............................................ 215 Money datatypes ................................................................... 215 Date and time datatypes ....................................................... 215 Character datatypes .............................................................. 216 Binary datatypes.................................................................... 221 The bit datatype..................................................................... 222 The timestamp datatype........................................................ 223 The sysname datatype .......................................................... 223 Converting between datatypes..................................................... 223 Mixed-mode arithmetic and datatype hierarchy ........................... 224 Working with money datatypes ............................................. 225 Determining precision and scale ........................................... 226 Creating user-defined datatypes .................................................. 226 Specifying length, precision, and scale ................................. 227 Specifying null type ............................................................... 228 Associating rules and defaults with user-defined datatypes.. 228 Creating a user-defined datatype with the IDENTITY property 228 Creating IDENTITY columns from other user-defined datatypes . 229 Dropping a user-defined datatype ......................................... 229 Getting information about datatypes ............................................ 229 CHAPTER 8 Creating Databases and Tables................................................. 231 What are databases and tables? ................................................. 231 Enforcing data integrity in databases .................................... 232 Permissions within databases ............................................... 233 Using and creating databases...................................................... 234 Choosing a database: use..................................................... 235Contents viii Adaptive Server Enterprise Creating a user database: create database .......................... 236 Altering the sizes of databases .................................................... 239 Dropping databases ..................................................................... 240 Creating tables ............................................................................. 240 Maximum number of columns per table ................................ 241 Example of creating a table................................................... 241 Choosing table names........................................................... 242 create table syntax ................................................................ 242 Allowing null values ............................................................... 244 Using IDENTITY columns ..................................................... 247 Using temporary tables ......................................................... 250 Creating tables in different databases................................... 254 Managing identity gaps in tables .................................................. 254 Parameters for controlling identity gaps ................................ 255 Comparison of identity burning set factor and identity_gap .. 256 Setting the table-specific identity gap.................................... 258 Changing the table-specific identity gap................................ 258 Displaying table-specific identity gap information.................. 259 Gaps due to insertions, deletions, identity grab size, and rollbacks 261 If table inserts reach the IDENTITY column’s maximum value 262 Defining integrity constraints for tables ........................................ 263 Specifying table-level or column-level constraints................. 264 Creating error messages for constraints ............................... 265 After creating a check constraint ........................................... 266 Specifying default column values .......................................... 266 Specifying unique and primary key constraints ..................... 267 Specifying referential integrity constraints............................. 268 Specifying check constraints ................................................. 271 Designing applications that use referential integrity .............. 272 How to design and create a table................................................. 274 Make a design sketch............................................................ 275 Create the user-defined datatypes ........................................ 276 Choose the columns that accept null values ......................... 276 Define the table ..................................................................... 276 Creating new tables from query results: select into ..................... 277 Checking for errors................................................................ 280 Using select into with IDENTITY columns............................. 280 Altering existing tables ................................................................. 283 Objects using select * do not list changes to table ................ 284 Using alter table on remote tables......................................... 285 Adding columns..................................................................... 285 Dropping columns ................................................................. 287 Modifying columns................................................................. 289Contents Transact-SQL User’s Guide ix Adding, dropping, and modifying IDENTITY columns ........... 293 Data copying ......................................................................... 295 Modifying locking schemes and table schema ...................... 297 Altering columns with user defined datatypes ....................... 297 Errors and warnings from alter table ..................................... 298 Renaming tables and other objects....................................... 301 Dropping tables ............................................................................ 302 Assigning permissions to users.................................................... 303 Getting information about databases and tables.......................... 305 Getting help on databases .................................................... 305 Getting help on database objects.......................................... 306 CHAPTER 9 Adding, Changing, and Deleting Data....................................... 313 Introduction .................................................................................. 313 Permissions........................................................................... 314 Referential integrity ............................................................... 314 Transactions.......................................................................... 315 Using the sample databases ................................................. 315 Datatype entry rules ..................................................................... 316 char, nchar, unichar, univarchar, varchar, nvarchar, and text 316 date and time data types ....................................................... 317 binary, varbinary, and image ................................................. 322 money and smallmoney ........................................................ 322 float, real, and double precision ............................................ 323 decimal and numeric ............................................................. 323 int, smallint, and tinyint .......................................................... 324 timestamp.............................................................................. 324 Adding new data .......................................................................... 324 insert syntax .......................................................................... 325 Adding new rows with values ................................................ 325 Inserting data into specific columns ...................................... 326 Adding new rows with select ................................................. 334 Changing existing data................................................................. 337 update syntax ........................................................................ 338 Using the set clause with update........................................... 339 Using the where clause with update...................................... 340 Using the from clause with update ........................................ 341 Updates with joins ................................................................. 341 Updating IDENTITY columns ................................................ 342 Changing text and image data ..................................................... 342 Deleting data ................................................................................ 343 Using the from clause with delete ......................................... 344 Deleting from IDENTITY columns ......................................... 345 Deleting all rows from a table....................................................... 346Contents x Adaptive Server Enterprise truncate table syntax ............................................................. 346 CHAPTER 10 Views: Limiting Access to Data.................................................. 347 How views work ........................................................................... 347 Advantages of views ............................................................. 348 View examples ...................................................................... 350 Creating views.............................................................................. 352 create view syntax................................................................. 352 Using the select statement with create view ......................... 354 After creating a view.............................................................. 358 Validating a view’s selection criteria using with check option 359 Retrieving data through views ...................................................... 360 View resolution ...................................................................... 361 Redefining views ................................................................... 362 Renaming views .................................................................... 363 Altering or dropping underlying objects ................................. 363 Modifying data through views....................................................... 364 Restrictions on updating views.............................................. 365 Dropping views............................................................................. 368 Using views as security mechanisms........................................... 369 Getting information about views ................................................... 369 Getting help on views with sp_help ....................................... 370 Using sp_helptext to display view information....................... 371 Using sp_depends to list dependent objects......................... 371 Listing all views in a database............................................... 372 CHAPTER 11 Using the Built-In Functions in Queries .................................... 373 System functions that return database information...................... 373 Examples of using system functions ..................................... 377 String functions used for character strings or expressions .......... 379 Examples of using string functions........................................ 382 Concatenation ....................................................................... 387 Nested string functions.......................................................... 388 Text functions used for text and image data ................................ 389 Readtext................................................................................ 390 Examples of using text functions........................................... 391 Aggregate functions ..................................................................... 392 Mathematical functions ................................................................ 393 Examples of using mathematical functions ........................... 395 Date functions .............................................................................. 396 Get current date: getdate ...................................................... 399 Find date parts as numbers or names................................... 400 Calculate intervals or increment dates .................................. 401Contents Transact-SQL User’s Guide xi Add date interval: dateadd .................................................... 401 Datatype conversion functions ..................................................... 402 Using the general purpose conversion function: convert ...... 403 Conversion rules ................................................................... 404 Converting binary-like data.................................................... 406 Conversion errors.................................................................. 408 Security functions......................................................................... 412 CHAPTER 12 Creating Indexes on Tables ....................................................... 415 How indexes work ........................................................................ 415 Comparing the two ways to create indexes........................... 416 Guidelines for Using Indexes ................................................ 417 Creating indexes .......................................................................... 418 create index syntax ............................................................... 419 Indexing more than one column: Composite indexes ........... 419 Using the unique option......................................................... 420 Including IDENTITY columns in nonunique indexes ............. 420 Ascending and descending index-column values ................. 421 Using fillfactor, max_rows_per_page, and reservepagegap . 422 Using clustered or nonclustered indexes ..................................... 423 Creating clustered indexes on segments .............................. 425 Creating clustered indexes on partitioned tables .................. 425 Specifying index options .............................................................. 425 Using the ignore_dup_key option.......................................... 426 Using the ignore_dup_row and allow_dup_row options........ 426 Using the sorted_data option ................................................ 427 Using the on segment_name option...................................... 428 Dropping indexes ......................................................................... 428 Determining what indexes exist on a table................................... 429 Updating statistics about indexes................................................. 431 Updating partition statistics ................................................... 432 CHAPTER 13 Defining Defaults and Rules for Data........................................ 433 How defaults and rules work ........................................................ 433 Creating defaults .......................................................................... 434 create default syntax ............................................................. 435 Binding defaults..................................................................... 436 Unbinding defaults................................................................. 438 How defaults affect NULL values .......................................... 439 After creating a default .......................................................... 439 Dropping defaults ......................................................................... 440 Creating rules............................................................................... 440 create rule syntax .................................................................. 440Contents xii Adaptive Server Enterprise Binding rules.......................................................................... 442 Rules and NULL values......................................................... 444 After defining a rule ............................................................... 444 Unbinding rules ..................................................................... 444 Dropping rules.............................................................................. 445 Getting information about defaults and rules ............................... 445 CHAPTER 14 Using Batches and Control-of-Flow Language......................... 447 Introduction .................................................................................. 447 Rules associated with batches ..................................................... 448 Examples of using batches ................................................... 450 Batches submitted as files..................................................... 452 Using control-of-flow language..................................................... 453 if...else ................................................................................... 454 case expression .................................................................... 456 begin...end............................................................................. 466 while and break...continue..................................................... 466 declare and local variables.................................................... 469 goto ....................................................................................... 469 return ..................................................................................... 470 print ....................................................................................... 470 raiserror ................................................................................. 472 Creating messages for print and raiserror ............................. 473 waitfor.................................................................................... 474 Comments ............................................................................. 476 Local variables ............................................................................. 478 Declaring local variables ....................................................... 478 Local variables and select statements .................................. 478 Local variables and update statements................................. 480 Local variables and subqueries............................................. 480 Local variables and while loops and if…else blocks ............. 481 Variables and null values ...................................................... 481 Global variables ........................................................................... 483 Transactions and global variables......................................... 483 Global variables affected by set options................................ 485 Language and character set information in global variables . 487 Global variables for monitoring system activity ..................... 487 Server information stored in global variables ........................ 488 Global variables and text and image data ............................. 490 CHAPTER 15 Using Stored Procedures............................................................ 491 How stored procedures work ....................................................... 491 Examples of creating and using stored procedures .............. 492Contents Transact-SQL User’s Guide xiii Stored procedures and permissions...................................... 494 Stored Procedures and Performance.................................... 495 Creating and executing stored procedures .................................. 495 Parameters............................................................................ 496 Default parameters................................................................ 498 Using more than one parameter............................................ 501 Procedure groups.................................................................. 503 Using with recompile in create procedure ............................. 503 Using with recompile in execute............................................ 504 Nesting procedures within procedures .................................. 504 Using temporary tables in stored procedures........................ 505 Setting options in stored procedures..................................... 506 After creating a stored procedure.......................................... 507 Executing stored procedures................................................. 508 Returning information from stored procedures............................. 509 Return status ......................................................................... 510 Checking roles in procedures ................................................ 512 Return parameters ................................................................ 513 Restrictions associated with stored procedures........................... 517 Qualifying names inside procedures ..................................... 518 Renaming stored procedures....................................................... 519 Renaming objects referenced by procedures........................ 519 Using stored procedures as security mechanisms....................... 519 Dropping stored procedures......................................................... 520 System procedures ...................................................................... 520 Executing system procedures ............................................... 521 Permissions on system procedures ...................................... 521 Types of system procedures ................................................. 521 Other Sybase-supplied procedures....................................... 527 Getting information about stored procedures............................... 528 Getting a report with sp_help ................................................ 529 Viewing the source text of a procedure with sp_helptext ...... 529 Identifying dependent objects with sp_depends.................... 530 Identifying permissions with sp_helprotect............................ 530 CHAPTER 16 Using Extended Stored Procedures.......................................... 533 Overview ...................................................................................... 533 XP Server .............................................................................. 534 Dynamic Link Library Support ............................................... 535 Open Server API ................................................................... 535 Example of creating and using ESPs .................................... 536 ESPs and Permissions .......................................................... 537 ESPs and Performance......................................................... 538 Creating functions for ESPs ......................................................... 539Contents xiv Adaptive Server Enterprise Files for ESP Development ................................................... 539 Open Server data structures ................................................. 539 Open Server return codes ..................................................... 540 Outline of a simple ESP function........................................... 540 ESP function example ........................................................... 541 Building the DLL .................................................................... 547 Registering ESPs ......................................................................... 550 Using create procedure ......................................................... 550 Using sp_addextendedproc................................................... 551 Removing ESPs ........................................................................... 552 Renaming ESPs .................................................................... 552 Executing ESPs ........................................................................... 552 System ESPs ............................................................................... 554 Getting information about ESPs ................................................... 554 ESP exceptions and messages ................................................... 555 Starting XP Server manually ........................................................ 556 CHAPTER 17 Triggers: Enforcing Referential Integrity................................... 557 How triggers work ........................................................................ 557 Using triggers vs. integrity constraints................................... 559 Creating triggers........................................................................... 559 create trigger syntax.............................................................. 560 Using triggers to maintain referential integrity.............................. 561 Testing data modifications against the trigger test tables ..... 563 Insert trigger example............................................................ 564 Delete trigger examples ........................................................ 565 Update trigger examples ....................................................... 567 Multirow considerations................................................................ 573 Insert trigger example using multiple rows ............................ 573 Delete trigger example using multiple rows........................... 574 Update trigger example using multiple rows ......................... 574 Conditional insert trigger example using multiple rows ......... 575 Rolling back triggers..................................................................... 577 Nesting triggers ............................................................................ 579 Trigger self-recursion ............................................................ 580 Rules associated with triggers ..................................................... 581 Triggers and permissions ...................................................... 582 Trigger restrictions................................................................. 582 Implicit and explicit null values .............................................. 583 Triggers and performance ..................................................... 584 set commands in triggers ...................................................... 584 Renaming and triggers .......................................................... 585 Trigger tips ............................................................................ 585 Disabling triggers ......................................................................... 585Contents Transact-SQL User’s Guide xv Dropping triggers.......................................................................... 586 Getting information about triggers................................................ 587 sp_help.................................................................................. 587 sp_helptext ............................................................................ 588 sp_depends........................................................................... 589 CHAPTER 18 Cursors: Accessing Data Row by Row..................................... 591 How cursors work......................................................................... 591 How Adaptive Server processes cursors .............................. 592 Declaring cursors ......................................................................... 596 declare cursor syntax ............................................................ 596 Types of cursors.................................................................... 597 Cursor scope ......................................................................... 598 Cursor scans and the cursor result set.................................. 600 Making cursors updatable ..................................................... 601 Determining which columns can be updated......................... 602 Opening cursors........................................................................... 604 Fetching data rows using cursors ................................................ 604 fetch syntax ........................................................................... 604 Checking the cursor status .................................................... 605 Getting multiple rows with each fetch.................................... 606 Checking the number of rows fetched................................... 607 Updating and deleting rows using cursors ................................... 608 Updating cursor result set rows............................................. 608 Deleting cursor result set rows .............................................. 609 Closing and deallocating cursors ................................................. 610 An example using a cursor........................................................... 611 Using cursors in stored procedures ............................................. 613 Cursors and locking ..................................................................... 615 Cursor locking options ........................................................... 616 Getting information about cursors ................................................ 617 Using browse mode instead of cursors ........................................ 618 Browsing a table.................................................................... 618 Browse-mode restrictions ...................................................... 619 Timestamping a new table for browsing................................ 619 Timestamping an existing table............................................. 619 Comparing timestamp values ................................................ 620 Join cursor processing and data modifications ............................ 620 Updates and deletes that can affect the cursor position ....... 620 Cursor positioning after a delete or update command without joins 621 Effects of updates and deletes on join cursors...................... 621 Effects of join column buffering on join cursors..................... 623 Recommendations ................................................................ 626Contents xvi Adaptive Server Enterprise CHAPTER 19 Transactions: Maintaining Data Consistency and Recovery .. 629 How transactions work ................................................................. 629 Transactions and consistency ............................................... 632 Transactions and recovery .................................................... 632 Using transactions........................................................................ 633 Allowing data definition commands in transactions............... 633 System procedures that are not allowed in transactions....... 634 Beginning and committing transactions................................. 635 Rolling back and saving transactions .................................... 635 Checking the state of transactions ........................................ 637 Nested transactions............................................................... 639 Example of a transaction....................................................... 640 Selecting the transaction mode and isolation level ...................... 641 Choosing a transaction mode................................................ 642 Choosing an isolation level.................................................... 644 Compliance with SQL standards ........................................... 652 Using the lock table command to improve performance ....... 652 Using the wait/nowait options of the lock table command..... 653 Using transactions in stored procedures and triggers.................. 654 Errors and transaction rollbacks............................................ 656 Transaction modes and stored procedures........................... 660 Using cursors in transactions ....................................................... 662 Issues to consider when using transactions................................. 663 Backup and recovery of transactions ........................................... 664 CHAPTER 20 Locking Commands and Options .............................................. 667 Setting a time limit on waiting for locks ........................................ 667 wait/nowait option of the lock table command....................... 668 Setting a session-level lock-wait limit.................................... 669 Setting a server-wide lock-wait limit ...................................... 669 Information on the number of lock-wait timeouts................... 670 Readpast locking for queue processing ....................................... 671 Readpast syntax.................................................................... 671 Incompatible locks during readpast queries .......................... 671 Allpages-locked tables and readpast queries........................ 672 Effects of isolation levels select queries with readpast ......... 672 Data modification commands with readpast and isolation levels . 673 text and image columns and readpast .................................. 674 Readpast-locking examples .................................................. 674 A P P E N D I X A The pubs2 Database.................................................................... 677 Tables in the pubs2 database ...................................................... 677Contents Transact-SQL User’s Guide xvii publishers table ..................................................................... 677 authors table.......................................................................... 678 titles table .............................................................................. 680 titleauthor table...................................................................... 687 salesdetail table..................................................................... 689 sales table ............................................................................. 694 stores table............................................................................ 695 roysched table ....................................................................... 696 discounts table ...................................................................... 700 blurbs table............................................................................ 701 au_pix table ........................................................................... 702 Diagram of the pubs2 database ................................................... 705 A P P E N D I X B The pubs3 Database ................................................................... 707 Tables in the pubs3 database ...................................................... 707 publishers table ..................................................................... 707 authors table.......................................................................... 708 titles table .............................................................................. 710 titleauthor table...................................................................... 717 salesdetail table..................................................................... 719 sales table ............................................................................. 725 stores table............................................................................ 726 store_employees table .......................................................... 727 roysched table ....................................................................... 732 discounts table ...................................................................... 736 blurbs table............................................................................ 737 Diagram of the pubs3 database ................................................... 739 Index ........................................................................................................................................... 741Contents xviii Adaptive Server EnterpriseTransact-SQL User’s Guide xix About This Book This manual, the Transact-SQL User’s Guide, documents TransactSQL®, an enhanced version of the SQL relational database language. The Transact-SQL User’s Guide is intended for both beginners and those who have experience with other implementations of SQL. Audience Users of the Sybase® Adaptive Server™ Enterprise database management systems who are unfamiliar with SQL can consider this guide as a textbook and start at the beginning. Novice SQL users should concentrate on the first part of this book. The second part describes advanced topics. This manual is useful both as a review, for those acquainted with other versions of SQL, and as a guide to Transact-SQL enhancements. SQL experts should study the capabilities and features that Transact-SQL has added to standard SQL, especially the material on stored procedures. How to use this book This book is a complete guide to Transact-SQL. It contains an introductory chapter, which gives an overview of SQL. The remaining chapters are divided into two subjects: Basic Concepts and Advanced Topics. Chapter 1, “SQL Building Blocks,” describes the naming conventions used by SQL and the enhancements (also known as extensions) added by Transact-SQL. It also includes a description of how to get started with Transact-SQL using the isql utility. Sybase recommends that all users read this chapter. Chapters 2–9 introduce you to the basic functionality of SQL. Users new to SQL should become familiar with the concepts described in these chapters before moving on to Chapters 10–18. Experienced users of SQL may want to skim through these chapters to learn about the Transact-SQL extensions introduced there and to review the material. Chapters 10–18 describe Transact-SQL in more detail. Most of the Transact-SQL extensions are described here. Users familiar with SQL, but not Transact-SQL, should concentrate on these chapters.xx Adaptive Server Enterprise The examples in this guide are based on the pubs2 and, where noted, pubs3 sample databases. For best use of the Transact-SQL User’s Guide, new users should work through the examples. Ask your System Administrator how to get a clean copy of pubs2 and pubs3. For a complete description of these databases, see Appendix A, “The pubs2 Database,” and Appendix B, “The pubs3 Database.” You can use Transact-SQL with the Adaptive Server standalone program isql. The isql program is a utility program called directly from the operating system. Related documents The Sybase ® Adaptive Server ® Enterprise documentation set consists of the following: • The release bulletin for your platform – contains last-minute information that was too late to be included in the books. A more recent version of the release bulletin may be available on the World Wide Web. To check for critical product or document information that was added after the release of the product CD, use the Sybase Technical Library. • The Installation Guide for your platform – describes installation, upgrade, and configuration procedures for all Adaptive Server and related Sybase products. • What’s New in Adaptive Server Enterprise? – describes the new features in Adaptive Server version 12.5.1, the system changes added to support those features, and the changes that may affect your existing applications. • ASE Replicator User’s Guide – describes how to use the ASE Replicator feature of Adaptive Server to implement basic replication from a primary server to one or more remote Adaptive Servers. • Component Integration Services User’s Guide – explains how to use the Adaptive Server Component Integration Services feature to connect remote Sybase and non-Sybase databases. • Configuring Adaptive Server Enterprise for your platform – provides instructions for performing specific configuration tasks for Adaptive Server. • EJB Server User’s Guide – explains how to use EJB Server to deploy and execute Enterprise JavaBeans in Adaptive Server. • Error Messages and Troubleshooting Guide – explains how to resolve frequently occurring error messages and describes solutions to system problems frequently encountered by users. About This Book Transact-SQL User’s Guide xxi • Full-Text Search Specialty Data Store User’s Guide – describes how to use the Full-Text Search feature with Verity to search Adaptive Server Enterprise data. • Glossary – defines technical terms used in the Adaptive Server documentation. • Historical Server User’s Guide – describes how to use Historical Server to obtain performance information for SQL Server ® and Adaptive Server. • Java in Adaptive Server Enterprise – describes how to install and use Java classes as data types, functions, and stored procedures in the Adaptive Server database. • Job Scheduler User’s Guide – provides instructions on how to install and configure, and create and schedule jobs on a local or remote Adaptive Server using the command line or a graphical user interface (GUI). • Monitor Client Library Programmer’s Guide – describes how to write Monitor Client Library applications that access Adaptive Server performance data. • Monitor Server User’s Guide – describes how to use Monitor Server to obtain performance statistics from SQL Server and Adaptive Server. • Performance and Tuning Guide – is a series of four books that explains how to tune Adaptive Server for maximum performance: • Basics – the basics for understanding and investigating performance questions in Adaptive Server. • Locking – describes how the various locking schemas can be used for improving performance in Adaptive Server. • Optimizer and Abstract Plans – describes how the optimizer processes queries and how abstract plans can be used to change some of the optimizer plans. • Monitoring and Analyzing – explains how statistics are obtained and used for monitoring and optimizing performance. • Quick Reference Guide – provides a comprehensive listing of the names and syntax for commands, functions, system procedures, extended system procedures, datatypes, and utilities in a pocket-sized book. • Reference Manual – is a series of four books that contains the following detailed Transact-SQL ® information:xxii Adaptive Server Enterprise • Building Blocks – Transact-SQL datatypes, functions, global variables, expressions, identifiers and wildcards, and reserved words. • Commands – Transact-SQL commands. • Procedures – Transact-SQL system procedures, catalog stored procedures, system extended stored procedures, and dbcc stored procedures. • Tables – Transact-SQL system tables and dbcc tables. • System Administration Guide – provides in-depth information about administering servers and databases. This manual includes instructions and guidelines for managing physical resources, security, user and system databases, and specifying character conversion, international language, and sort order settings. • System Tables Diagram – illustrates system tables and their entity relationships in a poster format. Available only in print version. • Transact-SQL User’s Guide – documents Transact-SQL, Sybase’s enhanced version of the relational database language. This manual serves as a textbook for beginning users of the database management system. This manual also contains descriptions of the pubs2 and pubs3 sample databases. • Using Adaptive Server Distributed Transaction Management Features – explains how to configure, use, and troubleshoot Adaptive Server DTM features in distributed transaction processing environments. • Using Sybase Failover in a High Availability System – provides instructions for using Sybase’s Failover to configure an Adaptive Server as a companion server in a high availability system. • Utility Guide – documents the Adaptive Server utility programs, such as isql and bcp, which are executed at the operating system level. • Web Services User’s Guide – explains how to configure, use, and troubleshoot Web Services for Adaptive Server. • XA Interface Integration Guide for CICS, Encina, and TUXEDO – provides instructions for using the Sybase DTM XA interface with X/Open XA transaction managers. • XML Services in Adaptive Server Enterprise – describes the Sybase native XML processor and the Sybase Java-based XML support, introduces XML in the database, and documents the query and mapping functions that comprise XML Services. About This Book Transact-SQL User’s Guide xxiii Other sources of information Use the Sybase Getting Started CD, the Sybase Technical Library CD and the Technical Library Product Manuals Web site to learn more about your product: • The Getting Started CD contains release bulletins and installation guides in PDF format, and may also contain other documents or updated information not included on the Technical Library CD. It is included with your software. To read or print documents on the Getting Started CD you need Adobe Acrobat Reader (downloadable at no charge from the Adobe Web site, using a link provided on the CD). • The Technical Library CD contains product manuals and is included with your software. The DynaText reader (included on the Technical Library CD) allows you to access technical information about your product in an easy-to-use format. Refer to the Technical Library Installation Guide in your documentation package for instructions on installing and starting the Technical Library. • The Technical Library Product Manuals Web site is an HTML version of the Technical Library CD that you can access using a standard Web browser. In addition to product manuals, you will find links to EBFs/Updates, Technical Documents, Case Management, Solved Cases, newsgroups, and the Sybase Developer Network. To access the Technical Library Product Manuals Web site, go to Product Manuals at http://www.sybase.com/support/manuals/. Sybase certifications on the Web Technical documentation at the Sybase Web site is updated frequently. ? Finding the latest information on product certifications 1 Point your Web browser to Technical Documents at http://www.sybase.com/support/techdocs/. 2 Select Products from the navigation bar on the left. 3 Select a product name from the product list and click Go. 4 Select the Certification Report filter, specify a time frame, and click Go. 5 Click a Certification Report title to display the report. ? Creating a personalized view of the Sybase Web site (including support pages) Set up a MySybase profile. MySybase is a free service that allows you to create a personalized view of Sybase Web pages.xxiv Adaptive Server Enterprise 1 Point your Web browser to Technical Documents at http://www.sybase.com/support/techdocs/. 2 Click MySybase and create a MySybase profile. Sybase EBFs and software updates ? Finding the latest information on EBFs and software updates 1 Point your Web browser to the Sybase Support Page at http://www.sybase.com/support. 2 Select EBFs/Updates. Enter user name and password information, if prompted (for existing Web accounts) or create a new account (a free service). 3 Select a product. 4 Specify a time frame and click Go. 5 Click the Info icon to display the EBF/Update report, or click the product description to download the software. Conventions The following sections describe conventions used in this manual. SQL is a free-form language. There are no rules about the number of words you can put on a line or where you must break a line. However, for readability, all examples and most syntax statements in this manual are formatted so that each clause of a statement begins on a new line. Clauses that have more than one part extend to additional lines, which are indented. Complex commands are formatted using modified Backus Naur Form (BNF) notation. Table 1 shows the conventions for syntax statements that appear in this manual: Table 1: Font and syntax conventions for this manual Element Example Command names,procedure names, utility names, and other keywords display in sans serif font. select sp_configure Database names and datatypes are in sans serif font. master database Book names, file names, variables, and path names are in italics. System Administration Guide sql.ini file column_name $SYBASE/ASE directory Variables—or words that stand for values that you fill in—when they are part of a query or statement, are in italics in Courier font. select column_name from table_name where search_conditions Type parentheses as part of the command. compute row_aggregate (column_name) About This Book Transact-SQL User’s Guide xxv • Syntax statements (displaying the syntax and all options for a command) appear as follows: sp_dropdevice [device_name] For a command with more options: select column_name from table_name where search_conditions In syntax statements, keywords (commands) are in normal font and identifiers are in lowercase. Italic font shows user-supplied words. • Examples showing the use of Transact-SQL commands are printed like this: select * from publishers • Examples of output from the computer appear as follows: pub_id pub_name city state ------- --------------------- ----------- ----- 0736 New Age Books Boston MA 0877 Binnet & Hardley Washington DC Double colon, equals sign indicates that the syntax is written in BNF notation. Do not type this symbol. Indicates “is defined as”. ::= Curly braces mean that you must choose at least one of the enclosed options. Do not type the braces. {cash | check | credit} Brackets mean that to choose one or more of the enclosed options is optional. Do not type the brackets. [cash | check | credit] The comma means you may choose as many of the options shown as you want. Separate your choices with commas as part of the command. cash, check, credit The pipe or vertical bar( | ) means you may select only one of the options shown. cash | check | credit An ellipsis (...) means that you can repeat the last unit as many times as you like. buy thing = price [cash | check | credit] [, thing = price [cash | check | credit]]... You must buy at least one thing and give its price. You may choose a method of payment: one of the items enclosed in square brackets. You may also choose to buy additional things: as many of them as you like. For each thing you buy, give its name, its price, and (optionally) a method of payment. Element Examplexxvi Adaptive Server Enterprise 1389 Algodata Infosystems Berkeley CA (3 rows affected) In this manual, most of the examples are in lowercase. However, you can disregard case when typing Transact-SQL keywords. For example, SELECT, Select, and select are the same. Adaptive Server’s sensitivity to the case of database objects, such as table names, depends on the sort order installed on Adaptive Server. You can change case sensitivity for single-byte character sets by reconfiguring the Adaptive Server sort order. For more information, see the System Administration Guide. If you need help Each Sybase installation that has purchased a support contract has one or more designated people who are authorized to contact Sybase Technical Support. If you cannot resolve a problem using the manuals or online help, please have the designated person contact Sybase Technical Support or the Sybase subsidiary in your area.Transact-SQL User’s Guide 1 C H A P T E R 1 SQL Building Blocks This chapter discusses: SQL in Adaptive Server SQL (Structured Query Language) is a high-level language used in relational database systems. Originally developed by IBM’s San Jose Research Laboratory in the late 1970s, SQL has been adopted by, and adapted for, many relational database management systems. It has been approved as the official relational query language standard by the American National Standards Institute (ANSI) and the International Organization for Standardization (ISO). Transact-SQL, Sybase’s extension of SQL, is compatible with IBM SQL and most other commercial implementations of SQL. It provides important extra capabilities and functions, such as summary calculations, stored procedures (predefined SQL statements), and error handling. Topic Page SQL in Adaptive Server 1 Naming conventions 6 Expressions in Adaptive Server 13 Transact-SQL extensions 20 Compliance to ANSI standards 26 Adaptive Server login accounts 31 How to use Transact-SQL with the isql utility 35 Using the pubs2 and pubs3 sample databases 37SQL in Adaptive Server 2 Adaptive Server Enterprise SQL includes commands not only for querying (retrieving data from) a database, but also for creating new databases and database objects, adding new data, modifying existing data, and other functions. Note If Java is enabled on your Adaptive Server, you can install and use Java classes in the database. You can invoke Java operations and store Java classes using standard Transact-SQL commands. Refer to Java in Adaptive Server Enterprise for a complete description of this feature. Queries, data modification, and commands In SQL, a query requests data using the select command. For example, this query asks for a listing of authors who live in the state of California: select au_lname, city, state from authors where state = "CA" Data modification refers to the addition, deletion, or change of data using the insert, delete, or update commands. For example: insert into authors (au_lname, au_fname, au_id) values ("Smith", "Gabriella", "999-03-2346") Other SQL commands, such as dropping tables or adding users, perform administrative operations. For example: drop table authors Each command or SQL statement begins with a keyword, such as insert, that names the basic operation performed. Many SQL commands also have one or more keyword phrases, or clauses, that tailor the command to meet a particular need. When you run a query, Transact-SQL displays the results. If no data meets the criteria specified in the query, the user gets a message to that effect. Data modification statements and administrative statements do not retrieve data, and therefore, do not display results. Transact-SQL provides a message to let the user know whether the data modification or other command has been performed. CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 3 Tables, columns, and rows In relational database management systems, users access and modify data stored in tables. SQL is specifically designed for the relational model of database management. Each row, or record, in a table describes one occurrence of a piece of data—a person, a company, a sale, or some other thing. Each column, or field, describes one characteristic of the data—a person’s name or address, a company’s name or president, quantity of items sold. A relational database is made up of a set of tables that can be related to each other. Figure 1-1: Multiple tables in a database The relational operations The basic query operations in a relational system are selection (also called restriction), projection, and join. These can all be combined in the SQL select command. A selection is a subset of the rows in a table. You specify the limiting conditions in the select query. For example, you might want to look only at the rows for all authors who live in California. select * from authors where state = "CA" A projection is a subset of the columns in a table. For example, this query displays only the name and city of all authors, omitting the street address, the phone number, and other information. select au_fname, au_lname, city from authorsSQL in Adaptive Server 4 Adaptive Server Enterprise A join links the rows in two or more tables by comparing the values in specified fields. For example, suppose you have one table containing information about authors, including the columns au_id (author identification number) and au_lname (author’s last name). A second table contains title information about books, including a column that gives the ID number of the book’s author (au_id). You might join the authors table and the titles table, testing for equality of the values in the au_id columns of each table. Whenever there is a match, a new row—containing columns from both tables—is created and displayed as part of the result of the join. Joins are often combined with projections and selections so that only selected columns of selected matching rows display. select * from authors, publishers where authors.city = publishers.city Compiled objects Adaptive Server uses compiled objects to contain vital information about each database and to help you access and manipulate data. A compiled object is any object that requires entries in the sysprocedures table, including: • Check constraints • Defaults • Rules • Stored procedures • Extended stored procedures • Triggers • Views Compiled objects are created from source text, which are SQL statements that describe and define the compiled object. When a compiled object is created, Adaptive Server: 1 Parses the source text, catching any syntactic errors, to generate a parsed tree. 2 Normalizes the parsed tree to create a normalized tree, which represents the user statements in a binary tree format. This is the compiled object. 3 Stores the compiled object in the sysprocedures table.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 5 4 Stores the source text in the syscomments table. Note If you are upgrading from Adaptive Server version 11.5 or earlier, and you have deleted source text from syscomments, you must restore the deleted portions before you upgrade. To do so, follow the process in the installation documentation for your platform. Saving source text In Adaptive Server version 11.5 and in SQL Server® versions prior to that release, the source text was saved in syscomments so it could be returned to a user who executed sp_helptext. Because this was the only purpose of saving the text, users often deleted the source text from the syscomments table to save disk space and to remove confidential information from this public area. However, you should not delete the source text because this may cause a problem for future upgrades of Adaptive Server. If you have removed the source text from syscomments, use the procedures in this section to restore the source text. Restoring source text If a compiled object does not have matching source text in the syscomments table, you can restore the source text to syscomments using any of the following methods: • Load the source text from a backup. • Re-create the source text manually. • Reinstall the application that created the compiled object. Verifying and encrypting source text Adaptive Server versions 11.5 and later allow you to verify the existence of source text, and encrypt the text if you choose. Use these commands when you are working with source text: • sp_checkresource – verifies that source text is present in syscomments for each compiled object. • sp_hidetext – encrypts the source text of a compiled object in the syscomments table to prevent casual viewing. • sp_helptext – displays the source text if it is present in syscomments, or notifies you of missing source text.Naming conventions 6 Adaptive Server Enterprise • dbcc checkcatalog – notifies you of missing source text. Naming conventions The characters recognized by Adaptive Server are limited in part by the language of the installation and the default character set. Therefore, the characters allowed in SQL statements and in the data contained in the server vary from installation to installation and are determined in part by definitions in the default character set. SQL statements must follow precise syntactical and structural rules, and can contain operators, constants, SQL keywords, special characters, and identifiers. Identifiers are objects within the server, such as database names or table names. Naming conventions vary for some parts of the SQL statement. Operator, constants, SQL keywords, and Transact-SQL extensions must adhere to stricter naming restrictions than identifiers, which themselves cannot contain operators and special characters. However, the data contained within the server can be named following more permissive rules. Figure 1-2 illustrates these relationships. Figure 1-2: Naming conventions governing SQL statements The sections that follow describe the sets of characters that can be used for each part of a statement. The section on identifiers also describes naming conventions for database objects. CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 7 SQL data characters The set of SQL data characters is the larger set from which both SQL language characters and identifier characters are taken. Any character in Adaptive Server’s character set, including both single-byte and multibyte characters, can be used for data values. SQL language characters SQL keywords, Transact-SQL extensions, and special characters such as the comparison operators > and <, can be represented only by 7-bit ASCII values A–Z, a–z, 0–9, and the following ASCII characters: Table 1-1: ASCII characters used in SQL Identifiers Conventions for naming database objects apply throughout Adaptive Server software and documentation. Identifiers can be as many as 30 bytes in length, whether or not multibyte characters are used. The first character of an identifier must be declared as an alphabetic character in the character set definition in use on Adaptive Server. The @ sign or _(underscore character) can also be used. The @ sign as the first character of an identifier indicates a local variable. Temporary table names must either begin with # (the pound sign) if they are created outside tempdb or be preceded by “tempdb.”. Table names for temporary tables that exist outside tempdb should not exceed 13 bytes in length, including the number sign, since Adaptive Server gives them an internal numeric suffix. ; (semicolon) ( (open parenthesis) ) (close parenthesis) , (comma) : (colon) % (percent sign) - (minus sign) ? (question mark) ’ (single quote) " (double quote) + (plus sign) _ (underscore) * (asterisk) / (slash) (space) < (less than operator) > (greater than operator) = (equals operator) & (ampersand) | (vertical bar) ^ (circumflex) [ (left bracket) ] (right bracket) \ (backslash) @ (at sign) ~ (tilde) ! (exclamation point) $ (dollar sign) # (number sign) . (period)Naming conventions 8 Adaptive Server Enterprise After the first character, identifiers can include characters declared as alphabetic, numeric, or the character $, #, @, _, ¥ (yen), or £ (pound sterling). However, you cannot use two @@ symbols together at the beginning of a named object, as in “@@myobject.” This naming convention is reserved for global variables, which are system-defined variables that Adaptive Server updates on an ongoing basis. The case sensitivity of Adaptive Server is set when the server is installed and can be changed only by a System Administrator. To see the setting for your server, execute: sp_helpsort On a server that is not case-sensitive, the identifiers MYOBJECT, myobject, and MyObject (and all combinations of case) are considered identical. You can create only one of these objects, but you can use any combination of case to refer to that object. No embedded spaces are allowed in identifiers, and none of the SQL reserved keywords can be used. The reserved words are listed in the Adaptive Server Reference Manual. You can use the function valid_name to determine if an identifier you have created is acceptable to Adaptive Server. For example: select valid_name (“string") string is the identifier you want to check. If string is not valid as an identifier, Adaptive Server returns a 0 (zero). If string is a valid identifier, Adaptive Server returns a number other than 0. Adaptive Server returns a 0 if illegal characters are used or if string is longer than 30 bytes. Using multibyte character sets In multibyte character sets, a wider range of characters is available for use in identifiers. For example, on a server with the Japanese language installed, the following types of characters can be used as the first character of an identifier: Zenkaku or Hankaku Katakana, Hiragana, Kanji, Romaji, Cyrillic, Greek, or ASCII. Although Hankaku Katakana characters are legal in identifiers on Japanese systems, they are not recommended for use in heterogeneous systems. These characters cannot be converted between the EUC-JIS and Shift-JIS character sets. CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 9 The same is true for some 8-bit European characters. For example, the character “Œ,” the OE ligature, is part of the Macintosh character set (code point 0xCE), but does not exist in the ISO 8859-1 (iso_1) character set. If “Œ” exists in data being converted from the Macintosh to the ISO 8859-1 character set, it causes a conversion error. If an object identifier contains a character that cannot be converted, the client loses direct access to that object. Delimited identifiers Delimited identifiers are object names enclosed in double quotes. Using delimited identifiers allows you to avoid certain restrictions on object names. You can use double quotes to delimit table, view, and column names; you cannot use them for other database objects. Delimited identifiers can be reserved words, can begin with non-alphabetic characters, and can include characters that would not otherwise be allowed. They cannot exceed 28 bytes. A pound sign (#) is illegal as a first character of any quoted identifier. (This restriction applies to Adaptive Server 11.5 and all later versions.) Before you create or reference a delimited identifier, you must execute: set quoted_identifier on This allows Adaptive Server to recognize delimited identifiers. Each time you use the quoted identifier in a statement, you must enclose it in double quotes. For example: create table "1one"(col1 char(3)) select * from "1one" create table "include spaces" (col1 int) Note Delimited identifiers cannot be used with bcp, may not be supported by all front-end products, and can produce unexpected results when used with system procedures. While the quoted_identifier option is turned on, do not use double quotes around character or date strings; use single quotes instead. Delimiting these strings with double quotes causes Adaptive Server to treat them as identifiers. For example, to insert a character string into col1 of 1table, use: insert "1one"(col1) values (’abc’) not:Naming conventions 10 Adaptive Server Enterprise insert "1one"(col1) values ("abc") To insert a single quote into a column, use two consecutive single quotation marks. For example, to insert the characters “a’b” into col1, use: insert "1one"(col1) values(’a’’b’) Syntax that includes quotes When the quoted_identifier option is set to on, you do not need to use double quotes around an identifier if the syntax of the statement requires that a quoted string contain an identifier. For example: create table '1one' (c1 int) The quotes are included in the name of table ’1one’: select object_id('1one') ----------------------- 896003192 You can include an embedded double quote in a quoted identifier by doubling the quote: create table "embedded""quote" (c1 int) However, there is no need to double the quote when the statement syntax requires the object name to be expressed as a string: select object_id('embedded"quote') Uniqueness and qualification conventions The names of database objects do not have to be unique in a database. However, column names and index names must be unique within a table, and other object names must be unique for each owner within a database. Database names must be unique in Adaptive Server. If you try to create a column using a name that is not unique in the table, or to create another database object, such as a table, a view, or a stored procedure, with a name that you have already used in the same database, Adaptive Server responds with an error message. You can uniquely identify a table or column by adding other names that qualify it. The database name, the owner’s name, and, for a column, the table name or view name may be used to create a unique ID. Each of these qualifiers is separated from the next by a period: For example, if the user “sharon” owns the authors table in the pubs2 database, the unique identifier of the city column in that table is: pubs2.sharon.authors.cityCHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 11 The same naming syntax applies to other database objects. You can refer to any object in a similar fashion: pubs2.dbo.titleview dbo.postalcoderule If the quoted_identifier option of the set command is on, you can use double quotes around individual parts of a qualified object name. Use a separate pair of quotes for each qualifier that requires quotes. For example, use: database.owner."table_name"."column_name" rather than: database.owner."table_name.column_name" The full naming syntax is not always allowed in create statements because you cannot create a view, procedure, rule, default, or trigger in a database other than the one you are currently in. The naming conventions are indicated in the syntax as: [[database.]owner.]object_name or [owner.]object_name The default value for owner is the current user, and the default value for database is the current database. When you reference an object in any SQL statement, other than a create statement, without qualifying it with the database name and owner name, Adaptive Server first looks at all the objects you own, and then at the objects owned by the Database Owner. As long as Adaptive Server is given enough information to identify an object, you need not type every element of its name. You can omit intermediate elements and indicate their positions with periods: database..table_name In the example above, you must include the starting element if you are using this syntax to create tables. If you omit the starting element, you would create a table named ..mytable. The naming convention prevents you from performing certain actions on such a table, such as cursor updates. When qualifying a column name and a table name in the same statement, use the same naming abbreviations for each; they are evaluated as strings and must match, or an error is returned. Here are two examples with different entries for the column name. The second example does not run because the syntax for the column name does not match the syntax for the table name. select pubs2.dbo.publishers.city from pubs2.dbo.publishersNaming conventions 12 Adaptive Server Enterprise city ----------------------- Boston Washington Berkeley select pubs2.sa.publishers.city from pubs2..publishers The column prefix "pubs2.sa.publishers" does not match a table name or alias name used in the query. Identifying remote servers You can execute stored procedures on a remote Adaptive Server. The results from the stored procedure display on the terminal that calls the procedure. The syntax for identifying a remote server and the stored procedure is: [execute] server.[database].[owner].procedure_name You can omit the execute keyword when the remote procedure call (RPC) is the first statement in a batch. If other SQL statements precede the RPC, you must use execute or exec. You must give the server name and the stored procedure name. If you omit the database name, Adaptive Server looks for procedure_name in your default database. If you give the database name, you must also give the procedure owner’s name, unless you own the procedure or the procedure is owned by the Database Owner. The following statements execute the stored procedure byroyalty in the pubs2 database located on the GATEWAY server: Statement Notes GATEWAY.pubs2.dbo.byroyalty GATEWAY.pubs2..byroyalty byroyalty is owned by the Database Owner. GATEWAY...byroyalty Use if pubs2 is the default database. declare @var int exec GATEWAY...byroyalty Use when the statement is not the first statement in a batch.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 13 See the System Administration Guide for information on setting up Adaptive Server for remote access. A remote server name (GATEWAY in the previous example) must match a server name in your local Adaptive Server’s interfaces file. If the server name in interfaces is in uppercase letters, you must also use uppercase letters in the RPC. Expressions in Adaptive Server An expression is a combination of one or more constants, literals, functions, column identifiers, and variables, separated by operators, that returns a single value. Expressions can be of several types, including arithmetic, relational, logical (or Boolean), and character string. In some Transact-SQL clauses, a subquery can be used in an expression. A case expression can be used in an expression. Use parentheses to group the elements in an expression. When “expression” is given as a variable in a syntax statement, a simple expression is assumed. “Logical expression” is specified when only a logical expression is acceptable. Arithmetic and character expressions The general pattern for arithmetic and character expressions is: {constant | column_name | function | (subquery) | (case_expression)} [{arithmetic_operator | bitwise_operator | string_operator | comparison_operator } {constant | column_name | function | (subquery) | case_expression}]... Operator precedence Operators have the following precedence levels, where 1 is the highest level and 6 is the lowest: 1 unary (single argument) - + ~ 2 * /% 3 binary (two argument) + - & | ^ 4 notExpressions in Adaptive Server 14 Adaptive Server Enterprise 5 and 6 or When all operators in an expression are of the same level, the order of execution is left to right. You can change the order of execution with parentheses—the most deeply nested expression is handled first. Arithmetic operators Adaptive Server uses these arithmetic operators: Table 1-2: Arithmetic operators You can use addition, subtraction, division, and multiplication on exact numeric, approximate numeric, and money type columns. Author comment: numeric added re CR 315018 4/17/03, rjoly You cannot use the modulo operator on smallmoney, money, float, numeric, or real columns. Modulo finds the integer remainder after a division involving two whole numbers. For example, 21% 11 = 10 because 21 divided by 11 equals 1 with a remainder of 10. When you perform arithmetic operations on mixed datatypes (for example, float and int) Adaptive Server follows specific rules for determining the type of the result. See Chapter 7, “Using and Creating Datatypes,” for more information. Bitwise operators The bitwise operators are a Transact-SQL extension for use with data of the type integer. These operators convert each integer operand into its binary representation and then evaluate the operands column by column. A value of 1 corresponds to true; a value of 0 corresponds to false. Operator Meaning + Addition – Subtraction * Multiplication / Division % Modulo (Transact-SQL extension) CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 15 Table 1-3 and Table 1-4 summarize the results for operands of 0 and 1. If either operand is NULL, the bitwise operator returns NULL: Table 1-3: Truth tables for bitwise operations The following examples use two tinyint arguments: A = 170 (10101010 in binary form) and B = 75 (01001011 in binary form). Table 1-4: Examples of bitwise operations & (and) 1 0 1 1 0 0 0 0 | (or) 1 0 1 1 1 0 1 0 ^ (exclusive or) 1 0 1 0 1 0 1 0 ~ (not) 1 FALSE 0 0 Operation Binary form Result Explanation (A & B) 10101010 01001011 ------------ 00001010 10 Result column equals 1 if both A and B are 1. Otherwise, result column equals 0. (A | B) 10101010 01001011 ------------ 11101011 235 Result column equals 1 if either A or B, or both, is 1. Otherwise, result column equals 0. (A ^ B) 10101010 01001011 ------------ 11100001 225 Result column equals 1 if either A or B, but not both, is 1.Expressions in Adaptive Server 16 Adaptive Server Enterprise The String concatenation operator The string operator + can concatenate two or more character or binary expressions. For example: select Name = (au_lname + ", " + au_fname) from authors Displays author names under the column heading “Name” in last-name, first-name order, with a comma after the last name; for example, “Bennett, Abraham.” select "abc" + "" + "def" Returns the string “abc def”. The empty string is interpreted as a single space in all char, varchar, nchar, nvarchar, and text concatenation, and in varchar insert and assignment statements. When concatenating non-character, non-binary expressions, use convert: select "The date is " + convert(varchar(12), getdate()) The comparison operators Adaptive Server uses these comparison operators: (~A) 10101010 ------------ 01010101 85 All 1s are changed to 0s and all 0s to 1s. Operation Binary form Result ExplanationCHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 17 Table 1-5: Comparison operators In comparing character data, < means closer to the beginning of the server’s sort order and > means closer to the end of the sort order. Uppercase and lowercase letters are equal in a sort order that is not case sensitive. Use sp_helpsort to see the sort order for your Adaptive Server. Trailing blanks are ignored for comparison purposes. In comparing dates, < means earlier than and > means later than. Put single or double quotes around all character and date and time data used with a comparison operator: = "Bennet" > "May 22 1947" Nonstandard operators The following operators are Transact-SQL extensions: • Modulo operator: % • Negative comparison operators: !>, !<, != • Bitwise operators: ~, ^, |, & • Join operators: *= and =* Operator Meaning = Equal to > Greater than < Less than >= Greater than or equal to <= Less than or equal to <> Not equal to != Not equal to (Transact-SQL extension) !> Not greater than (Transact-SQL extension) !< Not less than (Transact-SQL extension) Expressions in Adaptive Server 18 Adaptive Server Enterprise Comparing character expressions Adaptive Server treats character constant expressions as varchar. If they are compared with non-varchar variables or column data, the datatype precedence rules are used in the comparison (that is, the datatype with lower precedence is converted to the datatype with higher precedence). If implicit datatype conversion is not supported, you must use the convert function. See the Reference Manual for more information on supported and unsupported conversions. Comparison of a char expression to a varchar expression follows the datatype precedence rule; the “lower” datatype is converted to the “higher” datatype. All varchar expressions are converted to char (that is, trailing blanks are appended) for the comparison. Using the empty string The empty string (“”) or (‘’) is interpreted as a single blank in insert or assignment statements on varchar data. When varchar, char, nchar, or nvarchar data is concatenated, the empty string is interpreted as a single space. For example, this is stored as “abc def”: "abc" + "" + "def" The empty string is never evaluated as NULL. Including quotation marks in character expressions There are two ways to specify literal quotes within a char or varchar entry. The first method is to use an additional quote with a quote of the same type. This is called “escaping” the quote. For example, if you begin a character entry with a single quote, but you want to include a single quote as part of the entry, use two single quotes: ’I don’t understand.’ Here is an example containing internal double and single quotes. The single quote does not have to be escaped, but the double quote does: "He said, ""It’s not really confusing.""" The second method is to enclose a quote in the opposite kind of quotation mark. In other words, surround an entry containing a double quote with single quotes (or vice versa). Here are some examples: ’George said, "There must be a better way."’ "Isn’t there a better way?" CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 19 ’George asked, "Isn”t there a better way?"’ To continue a character string that would go off the end of one line on your screen, enter a backslash (\) before going to the following line. Note If the quoted_identifier option is set to on, do not use double quotes around character or date data. You must use single quotes, or Adaptive Server treats the data as an identifier. For more information about quoted identifiers, see “Delimited identifiers” on page 9. Relational and logical expressions A logical expression or relational expression returns TRUE, FALSE, or UNKNOWN. The general patterns are: expression comparison_operator [any | all] expression expression [not] in expression [not] exists expression expression [not] between expression and expression expression [not] like “match_string" [escape "escape_character"] not expression like "match_string" [escape "escape_character"] expression is [not] null not logical_expression logical_expression {and | or} logical_expression Using any, all, and in any is used with <, >, or = and a subquery. It returns results when any value retrieved in the subquery matches the value in the where or having clause of the outer statement. all is used with < or > and a subquery. It returns results when all values retrieved in the subquery are less than (<) or greater than (>) the value in the where or having clause of the outer statement. See Chapter 4, “Subqueries: Using Queries Within Other Queries,” for more information. in returns results when any value returned by the second expression matches the value in the first expression. The second expression must be a subquery or a list of values enclosed in parentheses. in is equivalent to = any. Transact-SQL extensions 20 Adaptive Server Enterprise Connecting expressions with and and or and connects two expressions and returns results when both are true. or connects two or more conditions and returns results when either of the conditions is true. When more than one logical operator is used in a statement, and is evaluated before or. Use parentheses to change the order of execution. Table 1-6 shows the results of logical operations, including those that involve null values: Table 1-6: Truth tables for logical expressions The result UNKNOWN indicates that one or more of the expressions evaluates to NULL, and that the result of the operation cannot be determined to be either TRUE or FALSE. Transact-SQL extensions Transact-SQL enhances the power of SQL and minimizes the occasions on which users must resort to a programming language to accomplish a desired task. Transact-SQL’s capabilities go beyond the ISO standards and the many commercial versions of SQL. and TRUE FALSE NULL TRUE TRUE FALSE UNKNOWN FALSE FALSE FALSE FALSE NULL UNKNOWN FALSE UNKNOWN or TRUE FALSE NULL TRUE TRUE TRUE TRUE FALSE TRUE FALSE UNKNOWN NULL TRUE UNKNOWN UNKNOWN not TRUE FALSE FALSE TRUE NULL UNKNOWNCHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 21 Most of the Transact-SQL enhancements (known as extensions) are summarized here. The Transact-SQL extensions for each command are in the Reference Manual. The compute clause The Transact-SQL compute clause extension is used with the row aggregate functions sum, max, min, avg, and count to calculate summary values. Queries that include a compute clause display results with both detail and summary rows. These reports resemble those produced by almost any Database Management System (DBMS) with a report generator. compute displays summary values as additional rows in the results, instead of as new columns. The compute clause is covered in Chapter 3, “Using Aggregates, Grouping, and Sorting.” Control-of-flow language Transact-SQL provides control-of-flow language that can be used as part of any SQL statement or batch. These constructs are available: begin...end, break, continue, declare, goto label, if...else, print, raiserror, return, waitfor, and while. Local variables can be defined with declare and assigned values. A number of predefined global variables are supplied by the system. Transact-SQL also supports case expressions, which include the keywords case, when, then, coalesce, and nullif. case expressions replace the if statements of standard SQL. case expressions are allowed anywhere a value expression is used. Stored procedures One of the most important Transact-SQL extensions is the ability to create stored procedures. A stored procedure is a collection of SQL statements and optional control-of-flow statements stored under a name. The creator of a stored procedure can also define parameters to be supplied when the stored procedure is executed. Transact-SQL extensions 22 Adaptive Server Enterprise The ability to write your own stored procedures greatly enhances the power, efficiency, and flexibility of the SQL database language. Since the execution plan is saved after stored procedures are run, stored procedures can subsequently run much faster than standalone statements. Adaptive Server-supplied stored procedures, called system procedures, aid in Adaptive Server system administration. Chapter 15, “Using Stored Procedures,” discusses system procedures and explains how to create stored procedures. System procedures are discussed in detail in the Reference Manual. Users can execute stored procedures on remote servers. All Transact-SQL extensions support return values from stored procedures, user-defined return status from stored procedures, and the ability to pass parameters from a procedure to its caller. Extended stored procedures An extended stored procedure (ESP) has the interface of a stored procedure, but instead of containing SQL statements and control-of-flow statements, it executes procedural language code that has been compiled into a dynamic link library (DLL). The procedural language in which an ESP function is written can be any language capable of calling C language functions and manipulating C datatypes. ESPs allow Adaptive Server to perform a task outside the RDBMS in response to an event occurring within the database. For example, you could use an ESP to send an e-mail notification or network-wide broadcast in response to an event occurring within the Relational Database Management System (RDBMS). There are some Adaptive Server-supplied ESPs, called system extended stored procedures. One of these, xp_cmdshell, allows you to execute an operating system command from within Adaptive Server. Chapter 16, “Using Extended Stored Procedures,” describes ESPs. The Reference Manual includes detailed information about system ESPs. ESPs are implemented by an Open Server™ application called XP Server™, which runs on the same machine as Adaptive Server. Remote execution of a stored procedure is called a remote procedure call (RPC). Adaptive Server and XP Server communicate through RPCs. XP Server is automatically installed with Adaptive Server.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 23 Triggers A trigger is a stored procedure that instructs the system to take one or more actions when a specific change is attempted. By preventing incorrect, unauthorized, or inconsistent changes to data, triggers help maintain the integrity of a database. Triggers can also protect referential integrity—enforcing rules about the relationships among data in different tables. Triggers go into effect when a user attempts to modify data with an insert, delete, or update command. Triggers can nest to a depth of 16 levels, and can call local or remote stored procedures or other triggers. Defaults and rules Transact-SQL provides keywords for maintaining entity integrity (ensuring that a value is supplied for every column requiring one) and domain integrity (ensuring that each value in a column belongs to the set of legal values for that column). Defaults and rules define integrity constraints that come into play during data entry and modification. A default is a value linked to a particular column or datatype, and inserted by the system if no value is provided during data entry. Rules are user-defined integrity constraints linked to a particular column or datatype, and enforced at data entry time. Rules and defaults are discussed in Chapter 13, “Defining Defaults and Rules for Data.” Error handling and set options A number of error handling techniques are available to the Transact-SQL programmer, including the ability to capture return status from stored procedures, define customized return values from stored procedures, pass parameters from a procedure to its caller, and get reports from global variables such as @@error. The raiserror and print statements, in combination with control-of-flow language, can direct error messages to the user of a TransactSQL application. Developers can localize print and raiserror to use different languages. set options customize the display of results, show processing statistics, and provide other diagnostic aids for debugging your Transact-SQL programs. All set options except showplan and char_convert take effect immediately. Transact-SQL extensions 24 Adaptive Server Enterprise The following paragraphs list the available set options. For more information, refer to the Reference Manual. • parseonly, noexec, prefetch, showplan, rowcount, nocount, and tablecount control the way a query is executed. The statistics options display performance statistics after each query. flushmessage determines when Adaptive Server returns messages to the user. See the Performance and Tuning Guide for more information. • arithabort determines whether Adaptive Server aborts queries with arithmetic overflow and numeric truncation errors. arithignore determines whether Adaptive Server prints a warning message if a query results in an arithmetic overflow. For more information, see “Arithmetic errors” on page 29. • offsets and procid are used in DB-Library™ to interpret results from Adaptive Server. • datefirst, dateformat, and language affect date functions, date order, and message display. • char_convert controls character-set conversion between Adaptive Server and a client. • textsize controls the size of text or image data returned with a select statement. See “Text functions used for text and image data” on page 389. • cursor rows and close on endtran affect the way Adaptive Server handles cursors. See “Fetching data rows using cursors” on page 604. • identity_insert allows or prohibits inserts that affect a table’s IDENTITY column. See “Gaps due to insertions, deletions, identity grab size, and rollbacks” on page 261. • chained and transaction isolation level control how Adaptive Server handles transactions. See “Selecting the transaction mode and isolation level” on page 641. • self_recursion allows Adaptive Server to handle triggers that cause themselves to fire. See “Trigger self-recursion” on page 580. • ansinull, ansi_permissions, and fipsflagger control whether Adaptive Server flags the use of nonstandard SQL. string_rtruncation controls whether Adaptive Server raises an exception error when truncating a char or nchar string. See “Compliance to ANSI standards” on page 26. CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 25 • quoted_identifier controls whether Adaptive Server treats character strings enclosed in double quotes as identifiers. See “Delimited identifiers” on page 9 for more information. • role controls the roles granted to you. For information about roles, see the System Administration Guide. Additional Adaptive Server extensions to SQL Other unique or unusual features of Transact-SQL include: • The following extensions to SQL search conditions: modulo operator (%), negative comparison operators (!>, !<, and !=), bitwise operators (–, ^, |, and &), join operators (*= and =*), wildcard characters ([ ] and -), and the not operator (^). See Chapter 2, “Queries: Selecting Data from a Table.” • Fewer restrictions on the group by clause and the order by clause. See Chapter 3, “Using Aggregates, Grouping, and Sorting.” • Subqueries, which can be used almost anywhere an expression is allowed. See Chapter 4, “Subqueries: Using Queries Within Other Queries.” • Temporary tables and other temporary database objects, which exist only for the duration of the current work session, and disappear thereafter. See Chapter 8, “Creating Databases and Tables.” • User-defined datatypes built on Adaptive Server-supplied datatypes. See Chapter 7, “Using and Creating Datatypes,” and Chapter 13, “Defining Defaults and Rules for Data.” • The ability to insert data from a table into that same table. See Chapter 9, “Adding, Changing, and Deleting Data.” • The ability to extract data from one table and put it into another with the update command. See Chapter 9, “Adding, Changing, and Deleting Data.” • The ability to remove data based on data in other tables using the join in a delete statement. See Chapter 9, “Adding, Changing, and Deleting Data.” • A fast way to delete all rows in a specified table and reclaim the space they took up with the truncate table command. See Chapter 9, “Adding, Changing, and Deleting Data.” • IDENTITY columns, which provide system-generated values that uniquely identify each row within a table. See Chapter 9, “Adding, Changing, and Deleting Data.”Compliance to ANSI standards 26 Adaptive Server Enterprise • Updates and selections through views. Unlike most other versions of SQL, Transact-SQL places no restrictions on retrieving data through views, and few restrictions on updating data through views. See Chapter 10, “Views: Limiting Access to Data.” • Dozens of built-in functions. See Chapter 11, “Using the Built-In Functions in Queries.” • Options to the create index command for fine-tuning aspects of performance determined by indexes, and controlling the treatment of duplicate keys and rows. See Chapter 12, “Creating Indexes on Tables.” • Control over what happens when a user attempts to enter duplicate keys in a unique index, or duplicate rows in a table. See Chapter 12, “Creating Indexes on Tables.” • Bitwise operators for use with integer and bit type columns. See “Bitwise operators” on page 49 and Chapter 7, “Using and Creating Datatypes.” • Support for text and image datatypes. See Chapter 7, “Using and Creating Datatypes.” • The ability to gain access to both Sybase and non-Sybase databases. With Component Integration Services, you can accomplish the following types of actions between tables in remote, heterogeneous servers: access remote tables as if they were local, perform joins, transfer data between tables, maintain referential integrity, provide applications such as PowerBuilder® with transparent access to heterogeneous data, and use native remote server capabilities. For more information, see the Component Integration Services User’s Guide. Compliance to ANSI standards The progression of standards for relational database management systems is ongoing. These standards have been, and are being, adopted by ISO and several national standards bodies. SQL86 was the first of these standards. This was replaced by SQL89, which in turn was replaced by SQL92, which is the current standard. SQL92 defines three levels of conformance: entry, intermediate, and full. In the United States, the National Institute for Standards and Technology (NIST) has defined the transitional level, which falls between the entry and intermediate levels.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 27 Certain behaviors defined by the standards are not compatible with existing SQL Server and Adaptive Server applications. Transact-SQL provides set options that allow you to toggle these behaviors. By default, compliant behavior is enabled for all Embedded SQL™ precompiler applications. Other applications needing to match SQL standard behavior can use the options in Table 1-7 for entry-level SQL92 compliance. For more information on setting these options, see set in the Reference Manual. Table 1-7: Set command flags for entry-level SQL92 compliance The following sections describe the differences between standard behavior and default Transact-SQL behavior. Federal Information Processing Standards (FIPS) flagger For customers writing applications that must conform to the SQL92 standard, Adaptive Server provides a set fipsflagger option. When this option is turned on, all commands containing Transact-SQL extensions that are not allowed in entry-level SQL92 generate an informational message. This option does not disable the extensions. Processing completes when you issue the non-ANSI SQL command. Option Setting ansi_permissions on ansinull on arithabort off arithabort numeric_truncation on arithignore off chained on close on endtran on fipsflagger on quoted_identifier on string_rtruncation on transaction isolation level 3Compliance to ANSI standards 28 Adaptive Server Enterprise Chained transactions and isolation levels Adaptive Server provides SQL standard-compliant “chained” transaction behavior as an option. In chained mode, all data retrieval and modification commands (delete, insert, open, fetch, select, and update) implicitly begin a transaction. Since such behavior is incompatible with many Transact-SQL applications, Transact-SQL style (or “unchained”) transactions remain the default. You can initiate chained transaction mode using the set chained option. The set transaction isolation level option controls transaction isolation levels. See Chapter 19, “Transactions: Maintaining Data Consistency and Recovery,” for more information. Identifiers To be compliant with entry-level SQL92, identifiers cannot: • Begin with a pound sign (#) • Have more than 18 characters • Contain lowercase letters Delimited identifiers Adaptive Server supports delimited identifiers for table, view, and column names. Delimited identifiers are object names enclosed within double quotation marks. Using them allows you to avoid certain restrictions on object names. Use the set quoted_identifier option to recognize delimited identifiers. When this option is on, all characters enclosed in double quotes are treated as identifiers. Because this behavior is incompatible with many existing applications, the default setting for this option is off. SQL standard-style comments In Transact-SQL, comments are delimited by “/*” and “*/”, and can be nested. Transact-SQL also supports SQL standard-style comments, which consist of any string beginning with two connected minus signs, a comment, and a terminating new line:CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 29 select "hello" -- this is a comment The Transact-SQL “/*” and “*/” comment delimiters are fully supported, but “--” within Transact-SQL comments is not recognized. Right truncation of character strings The string_rtruncation set option controls silent truncation of character strings for SQL standard compatibility. Set this option to on to prohibit silent truncation and enforce SQL standard behavior. Permissions required for update and delete statements The ansi_permissions set option determines permissions required for delete and update statements. When this option is on, Adaptive Server uses the more stringent SQL92 permission requirements for these statements. Because this behavior is incompatible with many existing applications, the default setting for this option is off. Arithmetic errors The arithabort and arithignore set options allow compliance with the SQL92 standard as follows: • arithabort arith_overflow specifies behavior following a divide-by-zero error or a loss of precision. The default setting, arithabort arith_overflow on, rolls back the entire transaction in which the error occurs. If the error occurs in a batch that does not contain a transaction, arithabort arith_overflow on does not roll back earlier commands in the batch, but Adaptive Server does not execute statements in the batch that follow the error-generating statement. If you set arithabort arith_overflow off, Adaptive Server aborts the statement that causes the error but continues to process other statements in the transaction or batch.Compliance to ANSI standards 30 Adaptive Server Enterprise • arithabort numeric_truncation specifies behavior following a loss of scale by an exact numeric type. The default setting, on, aborts the statement that causes the error but continues to process other statements in the transaction or batch. If you set arithabort numeric_truncation off, Adaptive Server truncates the query results and continues processing. For compliance with the SQL92 standard, enter set arithabort numeric_truncation on. • arithignore arith_overflow determines whether Adaptive Server displays a message after a divide-by-zero error or a loss of precision. The default setting, off, displays a warning message after these errors. Setting arithignore arith_overflow on suppresses warning messages after these errors. For compliance to the SQL92 standard, enter set arithignore off. Synonymous keywords Several keywords added for SQL standard compatibility are synonymous with existing Transact-SQL keywords. Table 1-8: ANSI-compatible keyword synonyms Treatment of nulls The set option ansinull determines whether or not evaluation of null-valued operands in SQL equality (=) or inequality (!=) comparisons and aggregate functions is SQL standard-compliant. This option does not affect how Adaptive Server evaluates null values in other kinds of SQL statements such as create table. Current syntax Additional syntax commit tran, commit transaction rollback tran, rollback transaction commit work rollback work any some grant all grant all privileges revoke all revoke all privileges max (expression) max ([all | distinct]) expression min (expression) min ([all | distinct]) expression user_name() built-in function user keywordCHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 31 Adaptive Server login accounts Each Adaptive Server user must have a login account identified by a unique login name and a password. The account is established by a System Security Officer. Login accounts have the following characteristics: • A login name, unique on that server. • A password. • A default database (optional). If a default is defined, the user starts each Adaptive Server session in the defined database without having to issue the use command. If no default is defined, each session starts in the master database. • A default language (optional). This specifies the language in which prompts and messages display. If a language is not defined, Adaptive Server’s default language, which is set at installation, is used. • A full name (optional). This is your full name, which can be useful for documentation and identification purposes. Group membership In Adaptive Server, you can use groups to grant and revoke permissions to more than one user at a time within a database. For example, if everyone who works in the “Sales” department needs access to certain tables, all of those users can be put into a group called “sales”. The Database Owner can grant specific access permissions to that group rather than having to grant permission to each user individually. A group is created within a database, not on the server as a whole. The Database Owner is responsible for creating groups and assigning users to them. You are always a member of the “public” group, which includes all users on Adaptive Server. You can also belong to one other group. You can use sp_helpuser to find out what group you are a member of: sp_helpuser user_nameAdaptive Server login accounts 32 Adaptive Server Enterprise Role membership In Adaptive Server, a System Security Officer can define and create roles as a convenient way to grant and revoke permissions to several users at a time, server-wide. For example, clerical staff may need to be able to insert and select from tables in several databases, but they may not need to update them. A System Security Officer could define a role called “clerical_user_role” and grant the role to everyone in the clerical staff. Database object owners could then grant “clerical_user_role” the required privileges. Roles can be defined in a role hierarchy, where a role such as “office_manager_role” contains the “clerical_user_role”. Users who are granted roles in a hierarchy automatically have all the permissions of the roles that are lower in the hierarchy. For example, the Office Manager can perform all the actions permitted for the clerical staff. Hierarchies can include either system or user-defined roles. To find out more about roles assigned to you use: • sp_displayroles – to find out all roles assigned to you, whether or not they are active. • sp_activeroles – to find out which of your assigned roles are active. If you specify the expand_down parameter, Adaptive Server displays any roles contained within your currently active roles. The syntax is: sp_displayroles user_name sp_activeroles expand_down For more information about roles, see the System Administration Guide. Getting information about your Adaptive Server account You can get information about your own Adaptive Server login account by using: sp_displaylogin Adaptive Server returns the following information: • Your server user ID • Your login name • Your full nameCHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 33 • Any roles granted to you (regardless of whether they are currently active) • Whether your account is locked • The date you last changed your password Changing your password It is a good idea to change your password periodically. The System Security Officer can configure Adaptive Server to require that you change your password at preset, regular intervals. If this is the case on your server, Adaptive Server notifies you when it is time to change your password. Note If you use remote servers, you must change your password on all remote servers that you access before you change it on your local server. For more information, see “Changing your password on a remote server” on page 35. You can change your password at any time using sp_password: sp_password old_passwd, new_passwd When you create a new password: • It must be at least six bytes long. • It can be any printable letters, numbers, or symbols. • The maximum size for a password is 30 bytes. If your password exceeds 30 bytes, Adaptive Server uses only the first 30 characters. When you specify a password, enclose it in quotation marks if: • It includes characters other than A–Z, a–z, 0–9, _, #, valid single-byte or multibyte alphabetic characters, or accented alphabetic characters. • It begins with a number 0–9. The following example shows how to change the password “terrible2” to “3blindmice”: sp_password terrible2, "3blindmice" A return status of 0 means that the password was changed. For more information about sp_password, see the Reference Manual. Adaptive Server login accounts 34 Adaptive Server Enterprise Understanding remote logins You can execute stored procedures on a remote Adaptive Server using RPCs if you have been granted access to the remote server and an appropriate database on that server. Remote execution of a stored procedure is a remote procedure call (RPC). To obtain access to a remote server: • The remote server must be known to your local server. This occurs when the System Security Officer executes sp_addserver. • You must acquire a login on the remote server. This happens when the System Administrator executes sp_addremotelogin. • You must be added as a user to the appropriate database on the remote server. This is accomplished when the Database Owner executes sp_adduser. These procedures are discussed in the System Administration Guide. When you can access the remote server, you can execute an RPC by qualifying the stored procedure name with the name of the remote server. For example, to execute sp_help on the GATEWAY server, enter: GATEWAY...sp_help Or, to fully qualify the name of the procedure, include the name of the database containing the procedure and the name of its owner: GATEWAY.sybsystemprocs.dbo.sp_help In addition, if a System Security Officer has set up the local and remote servers to use network-based security services, one or more of the following functions may be in effect when you execute RPCs: • Mutual authentication – the local server authenticates the remote server by retrieving the credential of the remote server and verifying it with the security mechanism. With this service, the credentials of both servers are authenticated and verified. • Message confidentiality via encryption – messages are encrypted when sent to the remote server, and results from the remote server are encrypted. • Message integrity – messages between the servers are checked for tampering.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 35 If you are using the unified login feature of network-based security, a System Security Officer can use sp_remoteoption on the remote server to establish you as a trusted user who does not need to supply a password to the remote server. If you are using Open Client™ Client-Library™/C, you can use ct_remote_pwd to specify a password for the remote server. For more information about network-based security services, see the System Administration Guide. Changing your password on a remote server You must change your password on all remote servers that you access before you change it on your local server. If you change it on the local server first, when you issue the RPC to execute sp_password on the remote server, the command fails because your local and remote passwords do not match. The syntax for changing your password on the remote server is: remote_server...sp_password old_passwd, new_passwd For example: GATEWAY...sp_password terrible2, "3blindmice" For information on changing your password on the local server, review “Changing your password” on page 33. How to use Transact-SQL with the isql utility You can use Transact-SQL directly from the operating system with the standalone utility program isql. You must first set up an account, or login, on Adaptive Server. To use isql, type a command similar to the following at your operating system prompt: isql -Uhoratio -Ptallahassee -Shaze -w300 where “horatio” is the user, “tallahassee” is the password, and “haze” is the name of the Adaptive Server to which you are connecting. The -w parameter displays isql output at a width of 300 characters. Login names and passwords are case-sensitive. How to use Transact-SQL with the isql utility 36 Adaptive Server Enterprise If you start isql without using a login name, Adaptive Server assumes that your login name is the same as your operating system name. For details about specifying your server login name and other parameters for isql, see the Utility Programs manual for your platform. Note Do not use the -P option to isql to specify your password, because another user might see your password. After you start isql, you see: 1> You can now start issuing Transact-SQL commands. To connect to a non-Sybase database using Component Integration Services, use the connect to command. For more information, see the Component Integration Services User’s Guide. See also connect to...disconnect in the Reference Manual. Default databases When your Adaptive Server account was created, you may have been assigned a default database to which you are connected when you log in. For example, your default database might be pubs2, the sample database. If you were not assigned a default database, you are connected to the master database. You can change your default database to any database that you have permission to use, or to any database that allows guests. Any user with an Adaptive Server login can be a guest. To change your default database, use sp_modifylogin, which is described in the Reference Manual. To change to the pubs2 database, which is used for most examples in this manual, enter: 1> use pubs2 2> go Enter the word “go” on a line by itself and do not precede it with blanks or tabs. It is the command terminator; it lets Adaptive Server know that you have finished typing, and you are ready for your command to be executed. In general, examples of Transact-SQL statements shown in this manual do not include the line prompts used by the isql utility, nor do they include the terminator go. CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 37 Using network-based security services with isql You can specify the -V option of isql to use network-based security services such as unified login. With unified login, you can be authenticated with a security mechanism offered by a third-party provider and then log in to Adaptive Server without specifying a login name or a password. Other security services you can use, if they are supported by the third-party security mechanism, include: • Data confidentiality • Data integrity • Mutual authentication • Data origin checking • Data replay detection • Out-of-sequence detection See the System Administration Guide for more information about the options you can specify to use network-based security. Logging out of isql You can log out of isql at any time by typing: quit or exit Either of these commands returns you to the operating system prompt, and do not require the terminator “go”. For more details on isql, see the Utility Guide. Using the pubs2 and pubs3 sample databases The pubs2 sample database is used for most examples in this manual. Where noted, the pubs3 database is used instead. You can try any of the examples on your own workstation. Using the pubs2 and pubs3 sample databases 38 Adaptive Server Enterprise The query results you see on your screen may not look exactly as they do in this manual. That is because some of the examples here have been reformatted (for example, the columns have been realigned) for visual clarity or to take up less space on the page. To change the sample database using create or data modification statements, you may need to get additional permissions from a System Administrator. If you do change the sample database, Sybase suggests that you return it to its original state for the sake of future users. Ask a System Administrator if you need help restoring the sample databases. What is in the sample databases? The sample database, pubs2, contains these tables: publishers, authors, titles, titleauthor, roysched, sales, salesdetail, stores, discounts, au_pix, and blurbs. The pubs3 sample database adds store_employees but does not include au_pix. pubs3 is an updated version of pubs2 and can be used for referential integrity examples. Its tables differ slightly from the tables defined in pubs2. Here is a brief description of each table: • publishers contains the identification numbers, names, cities, and states of three publishing companies. • authors contains an identification number, first and last name, address information, and contract status for each author. • titles contains the book ID, name, type, publisher ID, price, advance, royalty, year-to-date sales, comments, and publication date for each book. • titleauthor links the titles and authors tables together. It contains each book’s title ID, author ID, author order, and the royalty split among the authors of a book. • roysched lists the unit sales ranges and the royalty connected with each range. The royalty is some percentage of the net receipts from sales. • sales records the store ID, order number, and date of book sales. It acts as the master table for the detail rows in salesdetail. • salesdetail records the bookstore sales of titles in the titles table. • stores lists bookstores by store ID. • store_employees lists employees for the stores described in the stores table.CHAPTER 1 SQL Building Blocks Transact-SQL User’s Guide 39 • discounts lists three types of discounts for bookstores. • au_pix contains pictures of the authors in binary form using the image datatype. au_pix is in pubs2 only. • blurbs contains long book descriptions using the text datatype. The pubs2 database is illustrated in Appendix A, “The pubs2 Database,” while pubs3 is illustrated in Appendix B, “The pubs3 Database.”Using the pubs2 and pubs3 sample databases 40 Adaptive Server EnterpriseTransact-SQL User’s Guide 41 C H A P T E R 2 Queries: Selecting Data from a Table The select command retrieves data stored in the rows and columns of database tables using a procedure called a query. A query has three main parts: the select clause, the from clause, and the where clause. This chapter explains queries, provides examples, and discusses: This chapter focuses on basic single-table select statements. Many sections contain sample statements that you can use to practice writing queries. If you want to integrate other Transact-SQL functionality, such as joins, subqueries, and aggregates, you can find more complex query examples later in this book. What are queries? A SQL query requests data from the database and receives the results. This process, also known as data retrieval, is expressed using the select statement. You can use it for selections, which retrieve a subset of the rows in one or more tables, and you can use it for projections, which retrieve a subset of the columns in one or more tables. A simple example of a select statement is: select select_list from table_list where search_conditions Topic Page What are queries? 41 Choosing columns: the select clause 44 Eliminating duplicate query results with distinct 55 Specifying tables: the from clause 57 Selecting rows: the where clause 58 Pattern matching 65What are queries? 42 Adaptive Server Enterprise The select clause specifies the columns you want to retrieve. The from clause specifies the tables to search. The where clause specifies which rows in the tables you want to see. For example, the following select statement finds the first and the last names of writers living in Oakland from the authors table, in the pubs2 database. select au_fname, au_lname from authors where city = "Oakland" Results of this query appear in columnar format: au_fname au_lname -------------- ----------- Marjorie Green Dick Straight Dirk Stringer Stearns MacFeather Livia Karsen (5 rows affected) select syntax The select syntax can be simpler or more complex than shown in the previous example. A simple select statement contains only the select clause; the from clause is almost always included, but is necessary only in select statements that retrieve data from tables. All other clauses, including the where clause, are optional. The full syntax of the select statement includes these phrases and keywords: select [all | distinct] select_list [into [[database.]owner.] table_name] [from [[database.]owner.]{view_name|table_name [(index {index_name | table_name} [parallel [degree_of_parallelism] ] [prefetch size] [lru | mru])]} [holdlock | noholdlock] [shared] [,[[database.]owner.]{view_name| table_name [(index {index_name | table_name} [parallel [degree_of_parallelism] ] [prefetch size] [lru | mru])]} [holdlock | noholdlock] [shared]]...] [where search_conditions] [group by [all] aggregate_free_expressionCHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 43 [, aggregate_free_expression]...] [having search_conditions] [order by {[[[database.]owner.]{table_name.|view_name.}] column_name | select_list_number | expression} [asc | desc] [,{[[[database.]owner.]{table_name|view_name.}] column_name | select_list_number | expression} [asc | desc]]...] [compute row_aggregate(column_name) [, row_aggregate(column_name)]... [by column_name [, column_name]...]] [for {read only | update [of column_name_list]}] [at isolation {read uncommitted | read committed | serializable}] [for browse] Use the clauses in a select statement in the order shown above. For example, if the statement includes a group by clause and an order by clause, the group by clause must precede the order by clause. Qualify the names of database objects if there is ambiguity about which object is being referred to. If several columns in multiple tables are called “name”, you may have to qualify “name” with the database name, owner name, or table name. For example: select au_lname from pubs2.dbo.authors Since the examples in this chapter involve single-table queries, column names in syntax models and examples are usually not qualified with the names of the tables, owners, or databases to which they belong. These elements are left out for readability; it is never wrong to include qualifiers. The remaining sections in this chapter analyze the syntax of the select statement in more detail. This chapter describes only some of the clauses and keywords included in the syntax of the select command. The following clauses are discussed in other chapters: • group by, having, order by, and compute are described in Chapter 3, “Using Aggregates, Grouping, and Sorting.” • into is described in Chapter 8, “Creating Databases and Tables.” • at isolation is described in Chapter 19, “Transactions: Maintaining Data Consistency and Recovery.”Choosing columns: the select clause 44 Adaptive Server Enterprise The holdlock, noholdlock, and shared keywords (which deal with locking in Adaptive Server) and the index clause are described in the Performance and Tuning Guide. For information about the for read only and for update clauses, see the declare cursor command in the Reference Manual. Note The for browse clause is used only in DB-Library applications. See the Open Client DB-Library/C Reference Manual for details. See also “Using browse mode instead of cursors” on page 618. Choosing columns: the select clause The items in the select clause make up the select list. When the select list consists of a column name, a group of columns, or the wildcard character (*), the data is retrieved in the order in which it is stored in the table (create table order). Choosing all columns: select * The asterisk (*) selects all the column names in all the tables specified by the from clause. Use it to save typing time and errors when you want to see all the columns in a table. * retrieves the data in create table order. The syntax for selecting all the columns in a table is: select * from table_list The following statement retrieves all columns in the publishers table and displays them in create table order. This statement retrieves all rows since it contains no where clause: select * from publishers The results look like this: pub_id pub_name city state ----- -------------- --------- ----- 0736 New Age Books Boston WA 0877 Binnet & Hardley Washington DC 1389 Algodata Infosystems Berkeley CA CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 45 (3 rows affected) If you listed all the column names in the table in order after the select keyword, you would get exactly the same results: select pub_id, pub_name, city, state from publishers You can also use “*” more than once in a query: select *, * from publishers This query displays each column name and each piece of column data twice. Like a column name, you can qualify an asterisk with a table name. For example: select publishers.* from publishers However, because select * finds all the columns currently in a table, changes in the structure of a table such as adding, removing, or renaming columns automatically modify the results of select *. Listing columns individually gives you more precise control over the results. Choosing specific columns To select only specific columns in a table, use: select column_name[, column_name]... from table_name Separate column names with commas, for example: select au_lname, au_fname from authors Rearranging the order of columns The order in which you list the column names in the select clause determines the order in which the columns display. The examples that follow show how to specify column order, displaying publisher names and identification numbers from all three rows in the publishers table. The first example prints pub_id first, followed by pub_name; the second reverses that order. The information is the same but the organization changes. Choosing columns: the select clause 46 Adaptive Server Enterprise select pub_id, pub_name from publishers pub_id pub_name ----- --------------- 0736 New Age Books 0877 Binnet & Hardley 1389 Algodata Infosystems (3 rows affected) select pub_name, pub_id from publishers pub_name pub_id --------------------- ------ New Age Books 0736 Binnet & Hardley 0877 Algodata Infosystems 1389 (3 rows affected) Renaming columns in query results When query results display, the default heading for each column is the name given to it when it was created. You can rename a column heading for display purposes by using one of the following instead of only the column name in a select list. column_heading = column_name or: column_name column_heading or: column_name as column_heading This provides a substitute name for the column. For example, to change pub_name to “Publisher” in the previous query, type any of the following statements: select Publisher = pub_name, pub_id from publishers select pub_name Publisher, pub_id from publishers select pub_name as Publisher, pub_id from publishers The results of these statements look like this: CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 47 Publisher pub_id ---------------------- ------ New Age Books 0736 Binnet & Hardley 0877 Algodata Infosystems 1389 (3 rows affected) Expressions The select statement can also include one or more expressions, which allow you to manipulate the data retrieved. select expression [, expression]... from table_list An expression is any combination of constants, column names, functions, subqueries, or case expressions, connected by arithmetic or bitwise operators and parentheses. If any table or column name in the list does not conform to the rules for valid identifiers, set the quoted_identifier option on and enclose the identifier in double quotes. Quoted strings in column headings You can include any characters—even blanks—in a column heading if you enclose the entire heading in quotation marks. You do not need to set the quoted_identifier option on. If the column heading is not enclosed in quotation marks, it must conform to the rules for identifiers. Both of the following queries produce the same result: select "Publisher’s Name" = pub_name from publishers select pub_name "Publisher’s Name" from publishers Publisher’s Name ---------------- New Age Books Binnet & Hardley Algodata Infosystems (3 rows affected)Choosing columns: the select clause 48 Adaptive Server Enterprise In addition, you can use Transact-SQL reserved words in quoted column headings. For example, the following query, using the reserved word sum as a column heading, is valid: select "sum" = sum(total_sales) from titles Quoted column headings cannot be more than 30 bytes long. Note Before using quotes around a column name in a create table, alter table, select into, or create view statement, you must set quoted_identifier on. Character strings in query results The select statements you have seen so far produce results showing data in the database. You can also write queries so that the results contain strings of characters. Enclose the string you want to include in single or double quotation marks and separate it from other elements in the select list with a comma. Use double quotation marks if there is an apostrophe in the string—otherwise, the apostrophe is interpreted as a single quotation mark. Here is a query with a character string: select "The publisher’s name is", Publisher = pub_name from publishers Publisher ------------------------ -------------------- The publisher’s name is New Age Books The publisher’s name is Binnet & Hardley The publisher’s name is Algodata Infosystems (3 rows affected) Computed values in the select list You can perform computations with data from numeric columns or on numeric constants in a select list. CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 49 Bitwise operators The bitwise operators are a Transact-SQL extension that you can use with integers. These operators convert each integer operand into its binary representation, then evaluates the operands column by column. A value of 1 corresponds to true; a value of 0 corresponds to false. Table 2-1 shows the bitwise operators. Table 2-1: Bitwise operators For more information on bitwise operators, see the Reference Manual. Arithmetic operators Table 2-2 shows the available arithmetic operators. Table 2-2: Arithmetic operators With the exception of the modulo operator, you can use any arithmetic operator on any numeric column (int, smallint, tinyint, numeric, decimal, float, or money) A modulo, which can be used on all numeric columns except money, finds the integer remainder after a division involving two whole numbers. For example, 21 % 11 = 10 because 21 divided by 11 equals 1, with a remainder of 10. You can perform certain arithmetic operations on date/time columns using the date functions. See Chapter 11, “Using the Built-In Functions in Queries,” for information. You can use all of these operators in the select list with column names and numeric constants in any combination. For example, to see what a projected sales increase of 100 percent for all the books in the titles table looks like, enter: select title_id, total_sales, total_sales * 2 from titles Operator Meaning & Bitwise and (two operands) | Bitwise or (two operands) ^ Bitwise exclusive or (two operands) ~ Bitwise not (one operand) Operator Operation + Addition - Subtraction / Division * Multiplication % ModuloChoosing columns: the select clause 50 Adaptive Server Enterprise Here are the results: title_id total_sales -------- ----------- --------- BU1032 4095 8190 BU1111 3876 7752 BU2075 18722 37444 BU7832 4095 8190 MC2222 2032 4064 MC3021 22246 44492 MC3026 NULL NULL PC1035 8780 17560 PC8888 4095 8190 PC9999 NULL NULL PS1372 375 750 PS2091 2045 4090 PS2106 111 222 PS3333 4072 8144 PS7777 3336 6672 TC3218 375 750 TC4203 15096 30192 TC7777 4095 8190 (18 rows affected) Notice the null values in the total_sales column and the computed column. Null values have no explicitly assigned values. When you perform any arithmetic operation on a null value, the result is NULL. You can give the computed column a heading, “proj_sales” for example, by entering: select title_id, total_sales, proj_sales = total_sales * 2 from titles title_id total_sales proj_sales --------- ----------- ----------- BU1032 4095 8190 .... Try adding character strings such as “Current sales =” and “Projected sales are” to the select statement. The column from which the computed column is generated does not have to appear in the select list. The total_sales column, for example, is shown in these sample queries only for comparison of its values with the values from the total_sales * 2 column. To see only the computed values, enter: select title_id, total_sales * 2 from titles CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 51 Arithmetic operators also work directly with the data values in specified columns, when no constants are involved. For example: select title_id, total_sales * price from titles title_id -------- ---------- BU1032 81,859.05 BU1111 46,318.20 BU2075 55,978.78 BU7832 81,859.05 MC2222 40,619.68 MC3021 66,515.54 MC3026 NULL PC1035 201,501.00 PC8888 81,900.00 PC9999 NULL PS1372 8,096.25 PS2091 22,392.75 PS2106 777.00 PS3333 81,399.28 PS7777 26,654.64 TC3218 7,856.25 TC4203 180,397.20 TC7777 61,384.05 (18 rows affected) Computed columns can also come from more than one table. The joining and subqueries chapters in this manual include information on multitable queries. As an example of a join, this query multiplies the number of copies of a psychology book sold by an outlet (the qty column from the salesdetail table) by the price of the book (the price column from the titles table). select salesdetail.title_id, stor_id, qty * price from titles, salesdetail where titles.title_id = salesdetail.title_id and titles.title_id = "PS2106" title_id stor_id ---------------- ----------- ------ PS2106 8042 210.00 PS2106 8042 350.00 PS2106 8042 217.00 (3 rows affected) Choosing columns: the select clause 52 Adaptive Server Enterprise Arithmetic operator precedence When there is more than one arithmetic operator in an expression, multiplication, division, and modulo are calculated first, followed by subtraction and addition. If all arithmetic operators in an expression have the same level of precedence, the order of execution is left to right. Expressions in parentheses take precedence over all other operations. For example, the following select statement multiplies the total sales of a book by its price to calculate a total dollar amount, then subtracts from that one half of the author’s advance. select title_id, total_sales * price - advance / 2 from titles The product of total_sales and price is calculated first, because the operator is multiplication. Next, the advance is divided by 2, and the result is subtracted from total_sales * price. To avoid misunderstandings, use parentheses. The following query has the same meaning and gives the same results as the previous one, but it is easier to understand: select title_id,(total_sales * price) - (advance /2) from titles title_id -------- ---------- BU1032 79,359.05 BU1111 43,818.20 BU2075 50,916.28 BU7832 79,359.05 MC2222 40,619.68 MC3021 59,015.54 MC3026 NULL PC1035 198,001.00 PC8888 77,900.00 PC9999 NULL PS1372 4,596.25 PS2091 1,255.25 PS2106 -2,223.00 PS3333 80,399.28 PS7777 24,654.64 TC3218 4,356.25 TC4203 178,397.20 TC7777 57,384.05 (18 rows affected)CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 53 Use parentheses to change the order of execution; calculations inside parentheses are handled first. If parentheses are nested, the most deeply nested calculation has precedence. For example, the result and meaning of the preceding example is changed if you use parentheses to force evaluation of the subtraction before the division: select title_id, (total_sales * price - advance) /2 from titles title_id -------- ----------------------- BU1032 38,429.53 BU1111 20,659.10 BU2075 22,926.89 BU7832 38,429.53 MC2222 20,309.84 MC3021 25,757.77 MC3026 NULL PC1035 97,250.50 PC8888 36,950.00 PC9999 NULL PS1372 548.13 PS2091 10,058.88 PS2106 -2,611.50 PS3333 39,699.64 PS7777 11,327.32 TC3218 428.13 TC4203 88,198.60 TC7777 26,692.03 (18 rows affected) Selecting text and image values text and image values can be quite large. When a select list includes text and image values, the limit on the length of the data returned depends on the setting of the @@textsize global variable. The default setting for @@textsize depends on the software you use to access Adaptive Server; the default value is 32K for isql. To change the value, use the set command: set textsize 25Choosing columns: the select clause 54 Adaptive Server Enterprise With this setting of @@textsize, a select statement that includes a text column displays only the first 25 bytes of the data. Note When you select image data, the returned value includes the characters “0x”, which indicates that the data is hexadecimal. These two characters are counted as part of @@textsize. To reset @@textsize to the Adaptive Server default value, use: set textsize 0 The default display is the actual length of the data when its size is less than textsize. For more information about text and image datatypes, see Chapter 7, “Using and Creating Datatypes.” Using readtext The readtext command provides a way to retrieve text and image values if you want to retrieve only a selected portion of a column’s data. readtext requires the name of the table and column, the text pointer, a starting offset within the column, and the number of characters or bytes to retrieve. This example finds six characters in the copy column in the blurbs table: declare @val binary(16) select @val = textptr(copy) from blurbs where au_id = "648-92-1872" readtext blurbs.copy @val 2 6 using chars In the example, after the @val local variable has been declared, readtext displays characters 3 - 8 of the copy column, since the offset was 2. Instead of storing potentially large text and image data in the table, Adaptive Server stores it in a special structure. A text pointer (textptr) which points to the page where the data is actually stored is assigned. When you retrieve data using readtext, you actually retrieve textptr, which is a 16-byte varbinary string. To avoid this, declare a local variable to hold textptr, and then use the variable with readtext, as in the example above. See “Text functions used for text and image data” on page 389 for an advanced discussion of the readtext command.CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 55 Select list summary The select list can include * (all columns in create table order), a list of column names in any order, character strings, column headings, and expressions including arithmetic operators. You can also include aggregate functions, which are discussed in Chapter 3, “Using Aggregates, Grouping, and Sorting.” Here are some select lists to try with the tables in the pubs2 sample database: • select titles.* from titles • select Name = au_fname, Surname = au_lname from authors • select Sales = total_sales * price, ToAuthor = advance, ToPublisher = (total_sales * price) - advance from titles • select "Social security #", au_id from authors • select this_year = advance, next_year = advance + advance/10, third_year = advance/2, "for book title #", title_id from titles • select "Total income is", Revenue = price * total_sales, "for", Book# = title_id from titles Eliminating duplicate query results with distinct The optional distinct keyword eliminates duplicate rows from the default results of a select statement. For compatibility with other implementations of SQL, Adaptive Server syntax allows the use of all to explicitly ask for all rows. The default for select statements is all. If you do not specify distinct, you will get, by default, all rows including duplicates. For example, here is the result of searching for all the author identification codes in the titleauthor table without distinct:Eliminating duplicate query results with distinct 56 Adaptive Server Enterprise select au_id from titleauthor au_id ----------- 172-32-1176 213-46-8915 213-46-8915 238-95-7766 267-41-2394 267-41-2394 274-80-9391 409-56-7008 427-17-2319 472-27-2349 486-29-1786 486-29-1786 648-92-1872 672-71-3249 712-45-1867 722-51-5454 724-80-9391 724-80-9391 756-30-7391 807-91-6654 846-92-7186 899-46-2035 899-46-2035 998-72-3567 998-72-3567 (25 rows affected) There are some duplicate listings. Use distinct to eliminate them. select distinct au_id from titleauthor au_id ----------- 172-32-1176 213-46-8915 238-95-7766 267-41-2394 274-80-9391 409-56-7008 427-17-2319 472-27-2349 486-29-1786 CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 57 648-92-1872 672-71-3249 712-45-1867 722-51-5454 724-80-9391 756-30-7391 807-91-6654 846-92-7186 899-46-2035 998-72-3567 (19 rows affected) distinct treats multiple null values as duplicates. In other words, when distinct is included in a select statement, only one NULL is returned, no matter how many null values are encountered. When used with the order by clause, distinct can return multiple values. See “order by and group by used with select distinct” on page 105 for more information. Specifying tables: the from clause The from clause is required in every select statement involving data from tables or views. Use it to list all the tables and views containing columns included in the select list and in the where clause. If the from clause includes more than one table or view, separate them with commas. The maximum number of tables and views allowed in a query is 16. This includes tables listed in the from clause, base tables referenced by a view definition, any tables referenced in subqueries, a table being created with the into keyword, and any tables referenced as part of referential integrity constraints. The from syntax looks like this: select select_list [from [[database.]owner.] {table_name |view_name} [holdlock | noholdlock] [shared] [, [[database.]owner.] {table_name | view_name} [holdlock | noholdlock] [shared]]...] Selecting rows: the where clause 58 Adaptive Server Enterprise Table names can be between 1 and 30 bytes long. You can use a letter, @, #, or _ as the first character. The characters that follow can be digits, letters, or @, #, $, _, ¥, or £. Temporary table names must begin either with “#” (pound sign), if they are created outside tempdb, or with “tempdb..”. If you create a temporary table outside tempdb, its name must be less than 13 bytes, since Adaptive Server attaches an internal numeric suffix to the name to ensure that the name is unique. For more information, see Chapter 8, “Creating Databases and Tables.” The full naming syntax for tables and views is always permitted in the from clause: database.owner.table_name database.owner.view_name However, the full naming syntax is necessary only if there is some confusion about the name. You can give table names correlation names to save typing. Assign the correlation name in the from clause by giving the correlation name after the table name, like this: select p.pub_id, p.pub_name from publishers p All other references to that table (for example, in a where clause) must also use the correlation name. Correlation names cannot begin with a numeral. Selecting rows: the where clause The where clause in a select statement specifies the search conditions that determine which rows are retrieved. The general format is: select select_list from table_list where search_conditions Search conditions, or qualifications, in the where clause include: • Comparison operators (=, <, >, and so on) where advance * 2 > total_sales * price • Ranges (between and not between) where total_sales between 4095 and 12000 CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 59 • Lists (in, not in) where state in ("CA", "IN", "MD") • Character matches (like and not like) where phone not like "415%" • Unknown values (is null and is not null) where advance is null • Combinations of search conditions (and, or) where advance < 5000 or total_sales between 2000 and 2500 The where keyword can also introduce: • Join conditions (see Chapter 6, “Joins: Retrieving Data from Several Tables”) • Subqueries (see Chapter 4, “Subqueries: Using Queries Within Other Queries”) Note The only where condition that you can use on text columns is like (or not like). For more information on search conditions, see the “where Clause” section in the Reference Manual. Comparison operators Transact-SQL uses these comparison operators: Selecting rows: the where clause 60 Adaptive Server Enterprise Table 2-3: Comparison operators The operators are used in this syntax: where expression comparison_operator expression An expression is a constant, column name, function, subquery, case expression, or any combination of these, connected by arithmetic or bitwise operators. In comparing character data, < means earlier in the sort order and > means later in the sort order. Use the sp_helpsort to display the sort order for your Adaptive Server. Trailing blanks are ignored for the purposes of comparison. For example, “Dirk” is the same as “Dirk ”. In comparing dates, < means earlier than and > means later than. Put apostrophes or quotation marks around all char, nchar, unichar, varchar, nvarchar, univarchar, text, and date/time data. For more information on entering date and time data, see Chapter 9, “Adding, Changing, and Deleting Data.” Here are some sample select statements that use comparison operators: select * from titleauthor where royaltyper < 50 select authors.au_lname, authors.au_fname from authors where au_lname > "McBadden" select au_id, phone from authors where phone != "415 658-9932" select title_id, newprice = price * $1.15 from pubs2..titles where advance > 5000 Operator Meaning = Equal to > Greater than < Less than >= Greater than or equal to <= Less than or equal to <> Not equal to != Not equal to (Transact-SQL extension) !> Not greater than (Transact-SQL extension) !< Not less than (Transact-SQL extension) CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 61 not negates an expression. Either of the following two queries finds all business and psychology books that have advances of less than $5500. Note the difference in position between the negative logical operator (not) and the negative comparison operator (!>). select title_id, type, advance from titles where (type = "business" or type = "psychology") and not advance >5500 select title_id, type, advance from titles where (type = "business" or type = "psychology") and advance !>5500 title_id type advance -------- ------------ -------- BU1032 business 5,000.00 BU1111 business 5,000.00 BU7832 business 5,000.00 PS2091 psychology 2,275.00 PS3333 psychology 2,000.00 PS7777 psychology 4,000.00 (6 rows affected) Ranges (between and not between) Use the between keyword to specify an inclusive range. For example, to find all the books with sales between and including 4095 and 12,000, you can write this query: select title_id, total_sales from titles where total_sales between 4095 and 12000 title_id total_sales ------ ----------- BU1032 4095 BU7832 4095 PC1035 8780 PC8888 4095 TC7777 4095 (5 rows affected) You can specify an exclusive range with the greater than (>) and less than (<) operators:Selecting rows: the where clause 62 Adaptive Server Enterprise select title_id, total_sales from titles where total_sales > 4095 and total_sales < 12000 title_id total_sales ------ ----------- PC1035 8780 (1 row affected) not between finds all rows outside the specified range. To find all the books with sales outside the $4095 to $12,000 range, type: select title_id, total_sales from titles where total_sales not between 4095 and 12000 title_id total_sales -------- ----------- BU1111 3876 BU2075 18722 MC2222 2032 MC3021 22246 PS1372 375 PS2091 2045 PS2106 111 PS3333 4072 PS7777 3336 TC3218 375 TC4203 15096 (11 rows affected) Lists (in and not in) The in keyword allows you to select values that match any one of a list of values. The expression can be a constant or a column name, and the values list can be a set of constants or a subquery. For example, to list the names and states of all authors who live in California, Indiana, or Maryland, you can use: select au_lname, state from authors where state = "CA" or state = "IN" or state = "MD"CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 63 Or, to get the same results with less typing, use in. Separate items following the in keyword by commas and enclose them in parentheses. Put single or double quotes around char, varchar, unichar, univarchar and datatime values. For example: select au_lname, state from authors where state in ("CA", "IN", "MD") This is what results from either query: au_lname state ----------- ----- White CA Green CA Carson CA O’Leary CA Straight CA Bennet CA Dull CA Gringlesby CA Locksley CA Yokomoto CA DeFrance IN Stringer CA MacFeather CA Karsen CA Panteley MD Hunter CA McBadden CA (17 rows affected) Perhaps the most important use for the in keyword is in nested queries, also called subqueries. For a full discussion of subqueries, see Chapter 4, “Subqueries: Using Queries Within Other Queries.” The following example gives an idea of what you can do with nested queries and the in keyword. Suppose you want to know the names of the authors who receive less than 50 percent of the total royalties on the books they co-author. The authors table gives author names and the titleauthor table gives royalty information. By putting the two tables together using in, but without listing the two tables in the same from clause, you can extract the information you need. The following query: • Searches the titleauthor table for all au_ids of authors making less than 50 percent of the royalty on any one book. Selecting rows: the where clause 64 Adaptive Server Enterprise • Selects from the authors table all the author names with au_ids that match the results from the titleauthor query. The results show that several authors fall into the less than 50 percent category. select au_lname, au_fname from authors where au_id in (select au_id from titleauthor where royaltyper <50) au_lname au_fname -------------- ------------ Green Marjorie O’Leary Michael Gringlesby Burt Yokomoto Akiko MacFeather Stearns Ringer Anne (6 rows affected) not in finds the authors that do not match the items in the list. The following query finds the names of authors who do not make less than 50 percent of the royalties on at least one book. select au_lname, au_fname from authors where au_id not in (select au_id from titleauthor where royaltyper <50) au_lname au_fname --------------- ------------ White Johnson Carson Cheryl Straight Dick Smith Meander Bennet Abraham Dull Ann Locksley Chastity Greene Morningstar Blotchet-Halls Reginald del Castillo Innes DeFrance Michel Stringer Dirk Karsen Livia Panteley Sylvia CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 65 Hunter Sheryl McBadden Heather Ringer Albert Smith Gabriella (18 rows affected) Pattern matching You can include wildcard characters in the where clause to search for unknown characters or to group data according to common features. The sections below describe pattern matching using SQL and Transact-SQL. For more information on pattern matching, see the Reference Manual. Matching character strings: like The like keyword searches for a character string that matches a pattern. like is used with char, varchar, nchar, nvarchar, unichar, univarchar binary, varbinary, text, and date/time data. The syntax for like is: {where | having} [not] column_name [not] like "match_string" match_string can include the symbols in Table 2-4:Pattern matching 66 Adaptive Server Enterprise Table 2-4: Special symbols for matching character strings You can match the column data to constants, variables, or other columns that contain the wildcard characters shown in Table 2-4. When using constants, enclose the match strings and character strings in quotation marks. For example, using like with the data in the authors table: • like “Mc%” searches for every name that begins with ‘‘Mc’’ (McBadden). • like “%inger” searches for every name that ends with ‘‘inger’’ (Ringer, Stringer). • like “%en%” searches for every name containing ‘‘en’’ (Bennet, Green, McBadden). • like “_heryl” searches for every six-letter name ending with ‘‘heryl’’ (Cheryl). • like “[CK]ars[eo]n” searches for ‘‘Carsen,’’ ‘‘Karsen,’’ ‘‘Carson,’’ and ‘‘Karson’’ (Carson). • like “[M-Z]inger” searches for all names ending with ‘‘inger’’ that begin with any single letter from M to Z (Ringer). • like “M[^c]%” searches for all names beginning with ‘‘M’’ that do not have ‘‘c’’ as the second letter. Symbols Meaning % Matches any string of zero or more characters. _ Matches a single character. [specifier] Brackets enclose ranges or sets, such as [a–f] or [abcdef]. specifier can take two forms: • rangespec1-rangespec2: rangespec1 indicates the start of a range of characters. - is a special character, indicating a range. rangespec2 indicates the end of a range of characters. • set: can be composed of any discrete set of values, in any order, such as [a2bR].The range [a–f], and the sets [abcdef] and [fcbdae] return the same set of values. Specifiers are case-sensitive. [^specifier] A caret (^) preceding a specifier indicates non-inclusion. [^a– f] means “not in the range a–f”; [^a2bR] means “not a, 2, b, or R.”CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 67 This query finds all the phone numbers in the authors table that have an area code of 415: select phone from authors where phone like "415%" The only where condition you can use on text columns is like. This query finds all the rows in the blurbs table where the copy column includes the word “computer”: select * from blurbs where copy like "%computer%" Adaptive Server interprets wildcard characters used without like as literals rather than as a pattern; they represent exactly their own values. The following query attempts to find any phone numbers that consist of the four characters “415%” only. It does not find phone numbers that start with 415. select phone from authors where phone = "415%" When you use like with date and time values, Adaptive Server converts the dates to the standard date/time format, and then to varchar or univarchar. Since the standard storage format does not include seconds or milliseconds, you cannot search for seconds or milliseconds with like and a pattern. It is a good idea to use like when you search for date and time values, since these datatype entries may contain a variety of date parts. For example, if you insert the value “9:20” and the current date into a column named arrival_time, this query will not find the value, because Adaptive Server converts the entry into “Jan 1 1900 9:20AM”: where arrival_time = "9:20" However, the clause below finds the 9:20 value: where arrival_time like "%9:20%" You can also use the date and time datatypes for like transactions. Using not like You can use the same wildcard characters with not like, that you can use with like. For example, to find all the phone numbers in the authors table that do not have 415 as the area code, you can use either of these queries: select phone Pattern matching 68 Adaptive Server Enterprise from authors where phone not like "415%" select phone from authors where not phone like "415%" not like and ^ may give different results You cannot always duplicate not like patterns with like and the negative wildcard character [^]. Match strings with negative wildcard characters are evaluated in steps, one character at a time. If the match fails at any point in the evaluation, it is eliminated. For example, this query finds the system tables in a database whose names begin with “sys”: select name from sysobjects where name like "sys%" If you have a total of 32 objects and like finds 13 names that match the pattern, not like will find the 19 objects that do not match the pattern. where name not like "sys%" A pattern such as the following may not produce the same results: like [^s][^y][^s]% Instead of 19, you might get only 14, with all the names that begin with “s” or have “y” as the second letter or have “s” as the third letter eliminated from the results, as well as the system table names. Using wildcard characters as literal characters You can search for wildcard characters by escaping them and searching for them as literals. There are two ways to use the wildcard characters as literals in a like match string: square brackets and the escape clause. The match string can also be a variable or a value in a table that contains a wildcard character. Square brackets (Transact-SQL extension) Use square brackets for the percent sign, the underscore, and right and left brackets. To search for a dash, rather than using it to specify a range, use the dash as the first character inside a set of brackets. CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 69 Table 2-5: Using square brackets to search for wildcard characters escape clause (SQL-compliant) Use the escape clause to specify an escape character in the like clause. An escape character must be a single character string. Any character in the server’s default character set can be used. Table 2-6: Using the escape clause An escape character is valid only within its like clause and has no effect on other like clauses in the same statement. The only characters that are valid following an escape character are the wildcard characters ( _ , % , [ , ] , and [^] ), and the escape character itself. The escape character affects only the character following it. If a pattern contains two literal occurrences of a character that happens to be an escape character, the string must contain four consecutive escape characters (see the last example in Table 2-6). Otherwise, Adaptive Server raises a SQLSTATE error condition and returns an error message. Specifying more than one escape character raises a SQLSTATE error condition, and Adaptive Server returns an error message: like "%XX_%" escape "XX" like "%XX%X_%" escape "XX" like clause Searches for like "5%" 5 followed by any string of 0 or more characters like "5[%]" 5% like "_n" an, in, on, and so forth like "[_]n" _n like "[a-cdf]" a, b, c, d, or f like "[-acdf]" -, a, c, d, or f like "[ [ ]" [ like "[ ] ]" ] like clause Searches for like "5@%" escape "@" 5% like "*_n" escape "*" _n like "%80@%%" escape "@" string containing 80% like "*_sql**%" escape "*" string containing _sql* like "%#####_#%%" escape "#" string containing ##_%Pattern matching 70 Adaptive Server Enterprise Interaction of wildcard characters and square brackets An escape character retains its special meaning within square brackets, unlike the wildcard characters. Do not use existing wildcard characters as escape characters in the escape clause, for these reasons: • If you specify “_” or “%” as an escape character, it loses its special meaning within that like clause and acts only as an escape character. • If you specify “[“or “]” as an escape character, the Transact-SQL meaning of the bracket is disabled within that like clause. • If you specify “-” or “^” as an escape character, it loses the special meaning that it normally has within square brackets and acts only as an escape character. Trailing blanks and % Adaptive Server truncates trailing blanks following “%” in a like clause to a single trailing blank. like ‘‘% ’’ (percent sign followed by 2 spaces) matches ‘‘X ‘’ (one space); ‘‘X ’’ (two spaces); ‘‘X ’’ (three spaces), or any number of trailing spaces. Using wildcard characters in columns You can use wildcard characters for columns and column names. You might want to create a table called special_discounts in the pubs2 database to run a price projection for a special sale: create table special_discounts id_type char(3), discount int) insert into special_discounts values("BU%", 10) ... The table should contain the following data: id_type discount ------- ----------- BU% 10 PS% 12 MC% 15 The following query uses wildcard characters in id_type in the where clause: select title_id, discount, price, price - (price*discount/100) CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 71 from special_discounts, titles where title_id like id_type Here are the results of that query: title_id discount price -------- ----------- -------------- -------------- BU1032 10 19.99 17.99 BU1111 10 11.95 10.76 BU2075 10 2.99 2.69 BU7832 10 19.99 17.99 PS1372 12 21.59 19.00 PS2091 12 10.95 9.64 PS2106 12 7.00 6.16 PS3333 12 19.99 17.59 PS7777 12 7.99 7.03 MC2222 15 19.99 16.99 MC3021 15 2.99 2.54 MC3026 15 NULL NULL (12 rows affected) This permits sophisticated pattern matching without having to construct a series of or clauses. Character strings and quotation marks When you enter or search for character and date data (char, nchar, unichar, varchar, nvarchar, univarchar, datetime, smalldatetime, date and time datatypes), you must enclose it in single or double quotation marks. See Chapter 1, “SQL Building Blocks” for more information on character data and Chapter 7, “Using and Creating Datatypes” for more information on date/time datatypes. “Unknown” values: NULL A NULL in a column means no entry has been made in that column. A data value for the column is “unknown” or “not available.” NULL is not synonymous with “zero” or “blank”. Rather, null values allow you to distinguish between a deliberate entry of zero for numeric columns (or blank for character columns) and a non-entry, which is NULL for both numeric and character columns. Pattern matching 72 Adaptive Server Enterprise NULL can be entered in a column where null values are permitted in two ways: • If you do not enter any data, Adaptive Server automatically enters “NULL”. • Users can explicitly enter the word “NULL” or “null” without quotation marks. If you type the word ‘‘NULL’’ in a character column and include quotation marks, it is treated as data, rather than a null value. Query results display the word NULL. For example, the advance column of the titles table allows null values. By inspecting the data in that column you can tell whether a book had no advance payment by agreement (the row MC2222 has zero in the advance column) or whether the advance amount was not known when the data was entered (the row MC3026 has NULL in the advance column). select title_id, type, advance from titles where pub_id = "0877" title_id type advance -------- ---------- --------- MC2222 mod_cook 0.00 MC3021 mod_cook 15,000.00 MC3026 UNDECIDED NULL PS1372 psychology 7,000.00 TC3218 trad_cook 7,000.00 TC4203 trad_cook 4,000.00 TC7777 trad_cook 8,000.00 (7 rows affected) Testing a column for null values Use is null in where, if, and while clauses (discussed in Chapter 14, “Using Batches and Control-of-Flow Language”) to compare column values to NULL and to select them or perform a particular action based on the results of the comparison. Only columns that return a value of TRUE are selected or result in the specified action; those that return FALSE or UNKNOWN do not. The following example selects only rows for which advance is less than $5000 or NULL: select title_id, advance from titles where advance < $5000 or advance is nullCHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 73 Adaptive Server treats null values in different ways, depending on the operators that you use and the type of values you are comparing. In general, the result of comparing null values is UNKNOWN, since it is impossible to determine whether NULL is equal (or not equal) to a given value or to another NULL. The following cases return TRUE when expression is any column, variable or literal, or combination of these, which evaluates as NULL: • expression is null • expression = null • expression = @x where @x is a variable or parameter containing NULL. This exception facilitates writing stored procedures with null default parameters. • expression != n where n is a literal not containing NULL and expression evaluates to NULL. The negative versions of these expressions return TRUE when the expression does not evaluate to NULL: • expression is not null • expression != null • expression != @x When the keywords like and not like are used instead of the operators = and !=, the opposite occurs. This comparison returns TRUE: • expression not like null While this comparison returns FALSE: • expression like null Note that the far right side of these expressions is a literal null, or a variable or parameter containing NULL. If the far right side of the comparison is an expression (such as @nullvar + 1), the entire expression evaluates to NULL. Null column values do not join with other null column values. Comparing null column values to other null column values in a where clause always returns UNKNOWN, regardless of the comparison operator, and the rows are not included in the results. For example, this query returns no result rows where column1 contains NULL in both tables (although it may return other rows): select column1 from table1, table2 where table1.column1 = table2.column1 These operators return results when used with a NULL: Pattern matching 74 Adaptive Server Enterprise • = returns all rows that contain NULL. • != or <> returns all rows that do not contain NULL. When set ansinull is “on” for SQL compliance, the = and != operators do not return results when used with a NULL. Regardless of the set ansinull option value, the following operators never return values when used with a NULL: <, <=, !<, >, >=, !>. Adaptive Server can determine that a column value is NULL. Thus, this will be considered true: column1 = NULL However, the following comparisons can never be determined, since NULL means “having an unknown value”: where column1 > null There is no reason to assume that two unknown values are the same. This logic also applies when you use two column names in a where clause, that is, when you join two tables. A clause like “where column1 = column2” does not return rows where the columns contain null values. You can also find null values or non-null values with this pattern: where column_name is [not] null For example: where advance < $5000 or advance is null Some of the rows in the titles table contain incomplete data. For example, a book called The Psychology of Computer Cooking (title_id = MC3026) has been proposed and its title, title identification number, and probable publisher have been entered. However, since the author has no contract yet and details are still up in the air, null values appear in the price, advance, royalty, total_sales, and notes columns. Because null values do not match anything in a comparison, a query for all the title identification numbers and advances for books with advances of less than $5000 will not find The Psychology of Computer Cooking. select title_id, advance from titles where advance < $5000 title_id advance -------- ---------- MC2222 0.00 PS2091 2,275.00 PS3333 2,000.00 PS7777 4,000.00 CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 75 TC4203 4,000.00 (5 rows affected) Here is a query for books with an advance of less than $5000 or a null value in the advance column: select title_id, advance from titles where advance < $5000 or advance is null title_id advance -------- ---------- MC2222 0.00 MC3026 NULL PC9999 NULL PS2091 2,275.00 PS3333 2,000.00 PS7777 4,000.00 TC4203 4,000.00 (7 rows affected) See Chapter 8, “Creating Databases and Tables,” for information on NULL in the create table statement and for information on the relationship between NULL and defaults. See Chapter 9, “Adding, Changing, and Deleting Data,” for information on inserting null values into a table. Difference between FALSE and UNKNOWN There is an important logical difference between FALSE and UNKNOWN: the opposite of false (“not false”) is true, while the opposite of UNKNOWN is still UNKNOWN. For example, “1 = 2” evaluates to false and its opposite, “1 != 2”, evaluates to true. But “not unknown” is still unknown. If null values are included in a comparison, you cannot negate the expression to get the opposite set of rows or the opposite truth value. Substituting a value for NULLs Use the isnull built-in function to substitute a particular value for nulls. The substitution is made only for display purposes; actual column values are not affected. The syntax is: isnull(expression, value) Pattern matching 76 Adaptive Server Enterprise For example, use the following statement to select all the rows from titles, and display all the null values in column notes with the value unknown. select isnull(notes, "unknown") from titles Expressions that evaluate to NULL An expression with an arithmetic or bitwise operator evaluates to NULL if any of the operands is null. For example, this evaluates to NULL if column1 is NULL: 1 + column1 Concatenating strings and NULL If you concatenate a string and NULL, the expression evaluates to the string. For example: select "abc" + NULL + "def" ----- abcdef System-generated NULLs In Transact-SQL, system-generated NULLs, such as those that result from a system function like convert, behave differently than user-assigned NULLs. For example, in the following statement, a not equals comparison of the userprovided NULL and 1 returns TRUE: if (1 != NULL) print "yes" else print "no" yes The same comparison with a system-generated NULL returns UNKNOWN: if (1 != convert(integer, NULL)) print "yes" else print "no" no For more consistent behavior, set ansinull on. Then both system-generated and user-provided NULLs cause the comparison to return UNKNOWN.CHAPTER 2 Queries: Selecting Data from a Table Transact-SQL User’s Guide 77 Connecting conditions with logical operators The logical operators and, or, and not are used to connect search conditions in where clauses. The syntax is: {where | having} [not] column_name join_operator column_name where join_operator is a comparison operator and column_name is the column used in the comparison. Qualify the name of the column if there is any ambiguity. and joins two or more conditions and returns results only when all of the conditions are true. For example, the following query finds only the rows in which the author’s last name is Ringer and the author’s first name is Anne. It does not find the row for Albert Ringer. select * from authors where au_lname = "Ringer" and au_fname = "Anne" or also connects two or more conditions, but it returns results when any of the conditions is true. The following query searches for rows containing Anne or Ann in the au_fname column. select * from authors where au_fname = "Anne" or au_fname = "Ann" You can specify as many as 252 and and or conditions. not negates the expression that follows it. The following query selects all the authors who do not live in California: select * from authors where not state = "CA" When more than one logical operator is used in a statement, and operators are normally evaluated before or operators. You can change the order of execution with parentheses. For example: select * from authors where (city = "Oakland" or city = "Berkeley") and state = "CA" Pattern matching 78 Adaptive Server Enterprise Logical operator precedence Arithmetic and bitwise operators are handled before logical operators. When more than one logical operator is used in a statement, not is evaluated first, then and, and finally or. See “Bitwise operators” on page 14 for more information. For example, the following query finds all the business books in the titles table, no matter what their advances are, as well as all psychology books that have an advance of more than $5500. The advance condition pertains only to psychology books because the and is handled before the or. select title_id, type, advance from titles where type = "business" or type = "psychology" and advance > 5500 title_id type advance -------- ---------- ---------- BU1032 business 5,000.00 BU1111 business 5,000.00 BU2075 business 10,125.00 BU7832 business 5,000.00 PS1372 psychology 7,000.00 PS2106 psychology 6,000.00 (6 rows affected) You can change the meaning of the query by adding parentheses to force evaluation of the or first. This query finds all business and psychology books that have advances of more than $5500: select title_id, type, advance from titles where (type = "business" or type = "psychology") and advance > 5500 title_id type advance -------- ---------- --------- BU2075 business 10,125.00 PS1372 psychology 7,000.00 PS2106 psychology 6,000.00 (3 rows affected) Transact-SQL User’s Guide 79 C H A P T E R 3 Using Aggregates, Grouping, and Sorting This chapter addresses the sum, avg, count, count(*), max, and min aggregate functions that enable you to summarize the data retrieved in a query. This chapter also discusses how to organize data into categories and subgroups using the group by, having, and order by clauses. Two TransactSQL extensions—the compute clause and the union operator, are also discussed. This chapter contains the following sections: If your Adaptive Server is not case sensitive, see group by and having Clauses and compute Clause in the Reference Manual for examples on how case sensitivity affects the data returned by these clauses. Using aggregate functions The aggregate functions are: sum, avg, count, min, max, and count(*). You can use aggregate functions to calculate and summarize data. For example, to find out how many books have been sold in the titles table of the pubs2 database, type: select sum(total_sales) from titles ------------- 97746 Topic Page Using aggregate functions 79 Organizing query results into groups: the group by clause 85 Selecting groups of data: the having clause 97 Sorting query results: the order by clause 103 Summarizing groups of data: the compute clause 106 Combining queries: the union operator 114Using aggregate functions 80 Adaptive Server Enterprise (1 row affected) Note that there is no column heading for the aggregate column in the example. An aggregate function take as an argument the column name on whose values it will operate. You can apply aggregate functions to all the rows in a table, to a subset of the table specified by a where clause, or to one or more groups of rows in the table. From each set of rows to which an aggregate function is applied, Adaptive Server generates a single value. Here is the syntax of the aggregate function: aggregate_function ( [all | distinct] expression) Expression is usually a column name. However, it can also be a constant, a function, or any combination of column names, constants, and functions connected by arithmetic or bitwise operators. You can also use a case expression or subquery in an expression. For example, with this statement you can calculate the average price of all books if prices were doubled: select avg(price * 2) from titles ------------- 29.53 (1 row affected) You can use the optional keyword distinct with sum, avg, and count to eliminate duplicate values before the aggregate function is applied. all, which performs the operation on all rows, is the default. The syntax of the aggregate functions and the results they produce are shown in Table 3-1: Table 3-1: Syntax and results of aggregate functions Aggregate Function Result sum([all|distinct] expression) Total of the (distinct) values in the expression avg([all|distinct] expression) Average of the (distinct) values in the expression count([all|distinct] expression) Number of (distinct) non-null values in the expression count(*) Number of selected rows max(expression) Highest value in the expression min(expression) Lowest value in the expressionCHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 81 You can use the aggregate functions in a select list, as shown in the previous example, or in the having clause. For information about the having clause, see “Selecting groups of data: the having clause” on page 97. You cannot use aggregate functions in a where clause, but most select statements with an aggregate function in the select list include a where clause that restricts the rows to which the aggregate is applied. In the examples given earlier in this section, each aggregate function produced a single summary value for the whole table. If a select statement includes a where clause, but not a group by clause (see “Organizing query results into groups: the group by clause” on page 85), an aggregate function produces a single value for the subset of rows, called a scalar aggregate. However, a select statement can also include a column in its select list (a Transact-SQL extension), that repeats the single value for each row in the result table. This query returns the average advance and the sum of sales for business books only, and has a column name preceding it called “advance and sales”: select “advance and sales”, avg(advance), sum(total_sales) from titles where type = "business" ----------------- ----------------- ----------- advance and sales 6,281.25 30788 (1 row affected) Aggregate functions and datatypes You can use the aggregate functions with any type of column, with the following exceptions: • You can use sum and avg with numeric columns only—int, smallint, tinyint, decimal, numeric, float, and money. • You cannot use min and max with bit datatypes. • You cannot use aggregate functions other than count(*) with text and image datatypes. For example, you can use min (minimum) to find the lowest value—the one closest to the beginning of the alphabet—in a character type column: select min(au_lname) Using aggregate functions 82 Adaptive Server Enterprise from authors -------------------------- Bennet (1 row affected) However, you cannot average the contents of a text column: select avg(au_lname) from authors -------------------------- Bennet (1 row affected) Msg 257, Level 16, State 1: Line 1: Implicit conversion from datatype ’VARCHAR’ to ’INT’ is not allowed. Use the CONVERT function to run this query. count vs. count (*) While count finds the number of non-null values in the expression, count(*) finds the total number of rows in a table. This statement finds the total number of books: select count(*) from titles ------------------ 18 (1 row affected) count(*) returns the number of rows in the specified table without eliminating duplicates. It counts each row, including those containing null values. Like other aggregate functions, you can combine count(*) with other aggregates in the select list, with where clauses, and so on: select count(*), avg(price) from titles where advance > 1000 ---------- --------- 15 14.42 (1 row affected) CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 83 Using aggregate functions with distinct You can use the optional keyword distinct only with sum, avg, and count. When you use distinct, Adaptive Server eliminates duplicate values before performing calculations. If you use distinct, you cannot include an arithmetic expression in the argument. The argument must use a column name only. distinct appears inside the parentheses and before the column name. For example, to find the number of different cities in which there are authors, enter: select count(distinct city) from authors ------------- 16 (1 row affected) For an accurate calculation of the average price of all business books, omit distinct. The following statement returns the average price of all business books: select avg(price) from titles where type = "business" ------------- 13.73 (1 row affected) However, if two or more books have the same price and you use distinct, the shared price is included only once in the calculation: select avg(distinct price) from titles where type = "business" ------------- 11.64 (1 row affected)Using aggregate functions 84 Adaptive Server Enterprise Null values and the aggregate functions Adaptive Server ignores any null values in the column on which the aggregate function is operating for the purposes of the function (except count(*), which includes them). If you have set ansinull to on, Adaptive Server returns an error message whenever a null value is ignored. For more information, see the set command in the Reference Manual. For example, the count of advances in the titles table is not the same as the count of title names, because of the null values in the advance column: select count(advance) from titles ------------- 16 (1 row affected) select count(title) from titles ------------- 18 (1 row affected) If all the values in a column are null, count returns 0. If no rows meet the conditions specified in the where clause, count returns 0. The other functions all return NULL. Here are examples: select count(distinct title) from titles where type = "poetry" ------------- 0 (1 row affected) select avg(advance) from titles where type = "poetry" ------------- NULL (1 row affected)CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 85 Organizing query results into groups: the group by clause The group by clause divides the output of a query into groups. You can group by one or more column names, or by the results of computed columns using numeric datatypes in an expression. When used with aggregates, group by retrieves the calculations in each subgroup, and may return multiple rows. The maximum number of columns or expressions you can use in a group by clause is 31. Note You cannot group by columns of text or image datatypes. While you can use group by without aggregates, such a construction has limited functionality and may produce confusing results. The following example groups the results by title type: select type, advance from titles group by type type advance ------------ --------- business 5,000.00 business 5,000.00 business 10,125.00 business 5,000.00 mod_cook 0.00 mod_cook 15,000.00 UNDECIDED NULL popular_comp 7,000.00 popular_comp 8,000.00 popular_comp NULL psychology 7,000.00 psychology 2,275.00 psychology 6,000.00 psychology 2,000.00 psychology 4,000.00 trad_cook 7,000.00 trad_cook 4,000.00 trad_cook 8,000.00 (18 rows affected) With an aggregate for the advance column, the query returns the sum for each group:Organizing query results into groups: the group by clause 86 Adaptive Server Enterprise select type, sum(advance) from titles group by type type ------------ ------------------------ UNDECIDED NULL business 25,125.00 mod_cook 15,000.00 popular_comp 15,000.00 psychology 21,275.00 trad_cook 19,000.00 (6 rows affected) The summary values in a group by clause using aggregates are called vector aggregates, as opposed to scalar aggregates, which result when only one row is returned (see “Using aggregate functions” on page 79). group by syntax The complete syntax of the select statement is repeated here so that you can see the group by clause in context: select [all | distinct] select_list [into [[database.]owner.]table_name] [from [[database.]owner.]{view_name | table_name [(index {index_name | table_name} [parallel [degree_of_parallelism]] [prefetch size ] [lru | mru])]} [holdlock | noholdlock] [shared] [,[[database.]owner.]{view_name | tablel_name [(index {index_name | table_name} [parallel [degree_of_parallelism]] [prefetch size] [lru | mru])]} [holdlock | noholdlock] [shared]]...] [where search_conditions] [group by [all] aggregate_free_expression [, aggregate_free_expression]...] [having search_conditions] [order by {[[[database.]owner.] {table_name. | view_name.}] column_name | select_list_number | expression} [asc | desc] [, {[[[database.]owner.]{table_name|view_name.}] column_name | select_list_number | expressionCHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 87 [asc | desc]]...] [compute row_aggregate (column_name) [, row_aggregate(column_name)]... [by column_name [, column_name]...]] [for {read only | update [of column_name_list]}] [at isolation {read uncommitted | read committed | serializable}] [for browse] Remember that the order of the clauses in the select statement is significant. You can omit any of the optional clauses, but when you use them, they must appear in the order shown above. group by and SQL standards The SQL standards for group by are more restrictive than Sybase’s standard. The SQL standard requires that: • The columns in a select list must be in the group by expression or they must be arguments of aggregate functions. • A group by expression can only contain column names in the select list, but not those used only as arguments for vector aggregates. Several Transact-SQL extensions (described in the following sections) relax these restrictions, however the more complex result sets may be more difficult to understand. If you set the fipsflagger option as follows, you will receive a warning message stating that Transact-SQL extensions are used: set fipsflagger on For more information about the fipsflagger option, see the set command in the Reference Manual. Nesting groups with group by You can list more than one column in the group by clause to nest groups. Once the sets are established with group by, the aggregates are applied. This statement finds the average price and the sum of book sales, grouped first by publisher identification number and then by type: select pub_id, type, avg(price), sum(total_sales) from titles group by pub_id, type pub_id type ------ ------------ ------ ------- 0736 business 2.99 18,722 Organizing query results into groups: the group by clause 88 Adaptive Server Enterprise 0736 psychology 11.48 9,564 0877 UNDECIDED NULL NULL 0877 mod_cook 11.49 24,278 0877 psychology 21.59 375 0877 trad_cook 15.96 19,566 1389 business 17.31 12,066 1389 popular_comp 21.48 12,875 (8 rows affected) You can nest many groups within groups, up to the maximum of 16 columns or expressions specified with group by. Referencing other columns in queries using group by SQL standards state that the group by must contain items from the select list. However, Transact-SQL allows you to specify any valid column name in either the group by or select list, whether they employ aggregates or not. Through the following extensions, Sybase lifts restrictions on what you can include or omit in the select list of a query that includes group by. • The columns in the select list are not limited to the grouping columns and columns used with the vector aggregates. • The columns specified by group by are not limited to those non-aggregate columns in the select list. A vector aggregate must be accompanied by a group by clause. The SQL standards require that the non-aggregate columns in the select list match the group by columns. However, the first bulleted item described above allows you to specify additional, extended columns in the select list of the query. For example, many versions of SQL do not allow the inclusion of the extended title_id column in the select list, but it is legal in Transact-SQL: select type, title_id, avg(price), avg(advance) from titles group by type type title_id ------------ -------- ----- ------- business BU1032 13.73 6,281.25 business BU1111 13.73 6,281.25 business BU2075 13.73 6,281.25 business BU7832 13.73 6,281.25 mod_cook MC2222 11.49 7,500.00 CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 89 mod_cook MC3021 11.49 7,500.00 UNDECIDED MC3026 NULL NULL popular_comp PC1035 21.48 7,500.00 popular_comp PC8888 21.48 7,500.00 popular_comp PC9999 21.48 7,500.00 psychology PS1372 13.50 4,255.00 psychology PS2091 13.50 4,255.00 psychology PS2106 13.50 4,255.00 psychology PS3333 13.50 4,255.00 psychology PS7777 13.50 4,255.00 trad_cook TC3218 15.96 6,333.33 trad_cook TC4203 15.96 6,333.33 trad_cook TC7777 15.96 6,333.33 (18 rows affected) The above example still aggregates the price and advance columns based on the type column, but its results also display the title_id for the books included in each group. The second extension described above allows you to group columns that are not specified as columns in the select list of the query. These columns do not appear in the results, but the vector aggregates still compute their summary values. For example: select state, count(au_id) from authors group by state, city state ----- -------- CA 2 CA 1 CA 5 CA 5 CA 2 CA 1 CA 1 CA 1 CA 1 IN 1 KS 1 MD 1 MI 1 OR 1 TN 1 UT 2Organizing query results into groups: the group by clause 90 Adaptive Server Enterprise (16 rows affected) This example groups the vector aggregate results by both state and city, even though it does not display which city belongs to each group. Therefore, results are potentially misleading. You may think the following query should produce similar results to the previous query, since only the vector aggregate seems to tally the number of each city for each row: select state, count(au_id) from authors group by city However, its results are much different. By not using group by with both the state and city columns, the query tallies the number of each city, but it displays the tally for each row of that city in authors rather than grouping them into one result row per city. state ----- ----------- CA 1 CA 5 CA 2 CA 1 CA 5 KS 1 CA 2 CA 2 CA 1 CA 1 TN 1 OR 1 CA 1 MI 1 IN 1 CA 5 CA 5 CA 5 MD 1 CA 2 CA 1 UT 2 UT 2 (23 rows affected)CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 91 When you use the Transact-SQL extensions in complex queries that include the where clause or joins, the results may become even more difficult to understand. To avoid confusing or misleading results with group by, Sybase suggests that you use the fipsflagger option to identify queries that use TransactSQL extensions. See “group by and SQL standards” on page 87 for details. For more information about Transact-SQL extensions to group by and how they work, see the Reference Manual. Expressions and group by Another Transact-SQL extension allows you to group by an expression that does not include aggregate functions. For example: select avg(total_sales), total_sales * price from titles group by total_sales * price --------- ------------- NULL NULL 111 777.00 375 7,856.25 375 8,096.25 2045 22,392.75 3336 26,654.64 2032 40,619.68 3876 46,318.20 18722 55,978.78 4095 61,384.05 22246 66,515.54 4072 81,399.28 4095 81,859.05 4095 81,900.00 15096 180,397.20 8780 201,501.00 (16 rows affected) The expression “total_sales * price” is allowed. You cannot group by a column heading, also known as an alias, although you can still use one in your select list. This statement produces an error message: select Category = type, title_id, avg(price), avg(advance) from titles group by CategoryOrganizing query results into groups: the group by clause 92 Adaptive Server Enterprise The group by clause should be “group by type”, not “group by Category”. select Category = type, title_id, avg(price), avg(advance) from titles group by type Nesting aggregates with group by Another Transact-SQL extension allows you to nest a vector aggregate inside a scalar aggregate. For example, to find the average price of all types of books using a non-nested aggregate, enter: select avg(price) from titles group by type --------------- NULL 13.73 11.49 21.48 13.50 15.96 (6 rows affected) Nesting the average price inside the max function produces the highest average price of a group of books, grouped by type: select max(avg(price)) from titles group by type ------------- 21.48 (1 row affected) By definition, the group by clause applies to the innermost aggregate—in this case, avg.CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 93 Null values and group by If the grouping column contains a null value, that row becomes its own group in the results. If the grouping column contains more than one null value, the null values form a single group. Here is an example that uses group by and the advance column, which contains some null values: select advance, avg(price * 2) from titles group by advance advance ------------------ ----------------- NULL NULL 0.00 39.98 2000.00 39.98 2275.00 21.90 4000.00 19.94 5000.00 34.62 6000.00 14.00 7000.00 43.66 8000.00 34.99 10125.00 5.98 15000.00 5.98 (11 rows affected) If you are using the count(column_name) aggregate function, grouping by a column that contains null values will return a count of zero for the grouping row, since count(column_name) does not count null values. In most cases, you should use count(*) instead. This example groups and counts on the price column from the titles table, which contains null values, and shows count(*) for comparison: select price, count(price), count(*) from titles group by price price ------------- ----- ----- NULL 0 2 2.99 2 2 7.00 1 1 7.99 1 1 10.95 1 1 11.95 2 2 14.99 1 1 19.99 4 4 20.00 1 1 Organizing query results into groups: the group by clause 94 Adaptive Server Enterprise 20.95 1 1 21.59 1 1 22.95 1 1 (12 rows affected) where clause and group by You can use a where clause in a statement with group by. Rows that do not satisfy the conditions in the where clause are eliminated before any grouping is done. Here is an example: select type, avg(price) from titles where advance > 5000 group by type type ------------- -------- business 2.99 mod_cook 2.99 popular_comp 21.48 psychology 14.30 trad_cook 17.97 (5 rows affected) Only the rows with advances of more than $5000 are included in the groups that are used to produce the query results. However, the way that Adaptive Server handles extra columns in the select list and the where clause may seem contradictory. For example: select type, advance, avg(price) from titles where advance > 5000 group by type type advance ------------- --------- -------- business 5,000.00 2.99 business 5,000.00 2.99 business 10,125.00 2.99 business 5,000.00 2.99 mod_cook 0.00 2.99 mod_cook 15,000.00 2.99 popular_comp 7,000.00 21.48 popular_comp 8,000.00 21.48CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 95 popular_comp NULL 21.48 psychology 7,000.00 14.30 psychology 2,275.00 14.30 psychology 6,000.00 14.30 psychology 2,000.00 14.30 psychology 4,000.00 14.30 trad_cook 7,000.00 17.97 trad_cook 4,000.00 17.97 trad_cook 8,000.00 17.97 (17 rows affected) It only seems as if the query is ignoring the where clause when you look at the results for the advance (extended) column. Adaptive Server still computes the vector aggregate using only those rows that satisfy the where clause, but it also displays all rows for any extended columns that you include in the select list. To further restrict these rows from the results, you must use a having clause (described later in this chapter). group by and all The keyword all in the group by clause is a Transact-SQL enhancement. It is meaningful only if the select statement in which it is used also includes a where clause. If you use all, the query results include all the groups produced by the group by clause, even if some groups do not have any rows that meet the search conditions. Without all, a select statement that includes group by does not show groups for which no rows qualify. Here is an example: select type, avg(advance) from titles where advance > 1000 and advance < 10000 group by type type ------------ ------------------------ business 5,000.00 popular_comp 7,500.00 psychology 4,255.00 trad_cook 6,333.33 (4 rows affected) select type, avg(advance) Organizing query results into groups: the group by clause 96 Adaptive Server Enterprise from titles where advance > 1000 and advance < 10000 group by all type type ------------ ------------------------ UNDECIDED NULL business 5,000.00 mod_cook NULL popular_comp 7,500.00 psychology 4,255.00 trad_cook 6,333.33 (6 rows affected) The first statement produces groups only for those books that commanded advances of more than $1000 but less than $10,000. Since no modern cooking books have an advance within that range, there is no group in the results for the mod_cook type. The second statement produces groups for all types, including modern cooking and “UNDECIDED,” even though the modern cooking group does not include any rows that meet the qualification specified in the where clause. Adaptive Server returns a NULL result for all groups that lack qualifying rows. Using aggregates without group by By definition, scalar aggregates apply to all rows in a table, producing a single value for the whole table for each function. The Transact-SQL extension that allows you to include extended columns with vector aggregates also allows you to include extended columns with scalar aggregates. For example, look at the publishers table: pub_id pub_name city state ------ ------------------ -------------- ----- 0736 New Age Books Boston MA 0877 Binnet & Hardley Washington DC 1389 Algodata Infosystems Berkeley CA It contains three rows. The following query produces a three-row scalar aggregate based on each row of the table: select pub_id, count(pub_id) from publishers pub_id ---------- --------- 0736 3CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 97 0877 3 1389 3 (3 rows affected) Because Adaptive Server treats publishers as a single group, the scalar aggregate applies to the (single-group) table. The results display every row of the table for each column you include in the select list, in addition to the scalar aggregate. The where clause behaves the same way for scalar aggregates as with vector aggregates. The where clause restricts the columns included in the aggregate summary values, but it does not affect the rows that appear in the results for each extended column you specify in the select list. For example: select pub_id, count(pub_id) from publishers where pub_id < "1000" pub_id -------------- ----------- 0736 2 0877 2 1389 2 (3 rows affected) Like the other Transact-SQL extensions to group by, this extension provides results that may be difficult to understand, especially for queries on large tables or queries with multitable joins. Selecting groups of data: the having clause Use the having clause to display or reject rows defined by the group by clause. The having clause sets conditions for the group by clause in the same way where sets conditions for the select clause, except where cannot include aggregates, while having often does. This example is legal: select title_id from titles where title_id like "PS%" having avg(price) > $2.0 But this example is not: select title_idSelecting groups of data: the having clause 98 Adaptive Server Enterprise from titles where avg(price) > $20 having clauses can reference any of the items that appear in the select list. This statement is an example of a having clause with an aggregate function. It groups the rows in the titles table by type, but eliminates the groups that include only one book: select type from titles group by type having count(*) > 1 type ---------------- business mod_cook popular_comp psychology trad_cook (5 rows affected) Here is an example of a having clause without aggregates. It groups the titles table by type and displays only those types that start with the letter “p”: select type from titles group by type having type like "p%" type ------------ popular_comp psychology (2 rows affected) When you include more than one condition in the having clause, combine the conditions with and, or, or not. For example, to group the titles table by publisher, and to include only those publishers who have paid more than $15,000 in total advances, whose books average less than $18 in price, and whose identification numbers (pub_id) are greater than 0800, the statement is: select pub_id, sum(advance), avg(price) from titles group by pub_id having sum(advance) > 15000 and avg(price) < 18 and pub_id > "0800"CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 99 pub_id ------ ---------------- ---------------- 0877 41,000.00 15.41 (1 row affected) How the having, group by, and where clauses interact When you include the having, group by, and where clauses in a query, the sequence in which each clause affects the rows determines the final results: • The where clause excludes rows that do not meet its search conditions. • The group by clause collects the remaining rows into one group for each unique value in the group by expression. • Aggregate functions specified in the select list calculate summary values for each group. • The having clause excludes rows from the final results that do not meet its search conditions. The following query illustrates the use of where, group by, and having clauses in one select statement containing aggregates: select stor_id, title_id, sum(qty) from salesdetail where title_id like "PS%" group by stor_id, title_id having sum(qty) > 200 stor_id title_id ------- -------- ----------- 5023 PS1372 375 5023 PS2091 1,845 5023 PS3333 3,437 5023 PS7777 2,206 6380 PS7777 500 7067 PS3333 345 7067 PS7777 250 (7 rows affected) The query functioned in this order: 1 The where clause identified only rows with title_id beginning with “PS” (psychology books), Selecting groups of data: the having clause 100 Adaptive Server Enterprise 2 group by collected the rows by common stor_id and title_id, 3 The sum aggregate calculated the total number of books sold for each group, and 4 The having clause excluded the groups whose totals do not exceed 200 books from the final results. All of the previous having examples adhere to the SQL standards, which specify that columns in a having expression must have a single value, and must be in the select list or group by clause. However, the Transact-SQL extensions to having allow columns or expressions not in the select list and not in the group by clause. The following example determines the average price for each title type, but it excludes those types that do not have more than $10,000 in total sales, even though the sum aggregate does not appear in the results. select type, avg(price) from titles group by type having sum(total_sales) > 10000 type ------------ ---------- business 13.73 mod_cook 11.49 popular_comp 21.48 trad_cook 15.96 (4 rows affected) The extension behaves as if the column or expression were part of the select list but not part of the displayed results. If you include an non-aggregated column with having, but it is not part of the select list or the group by clause, the query produces results similar to the “extended” column extension described earlier in this chapter. For example: select type, avg(price) from titles group by type having total_sales > 4000 type ------------ ---------- business 13.73 business 13.73 business 13.73 mod_cook 11.49 popular_comp 21.48CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 101 popular_comp 21.48 psychology 13.50 trad_cook 15.96 trad_cook 15.96 (9 rows affected) Unlike an extended column, the total_sales column does not appear in the final results, yet the number of displayed rows for each type depends on the total_sales for each title. The query indicates that three business, one mod_cook, two popular_comp, one psychology, and two trad_cook, titles exceed $4000 in total sales. As mentioned earlier, the way Adaptive Server handles extended columns may seem as if the query is ignoring the where clause in the final results. To make the where conditions affect the results for the extended column, you should repeat the conditions in the having clause. For example: select type, advance, avg(price) from titles where advance > 5000 group by type having advance > 5000 type advance ------------- --------- -------- business 10,125.00 2.99 mod_cook 15,000.00 2.99 popular_comp 7,000.00 21.48 popular_comp 8,000.00 21.48 psychology 7,000.00 14.30 psychology 6,000.00 14.30 trad_cook 7,000.00 17.97 trad_cook 8,000.00 17.97 (8 rows affected) Using having without group by A query with a having clause should also have a group by clause. If you omit group by, all the rows not excluded by the where clause return as a single group. Because no grouping is done between the where and having clauses, they cannot act independently of each other. having acts like where because it affects the rows in a single group rather than groups, except the having clause can still use aggregates. Selecting groups of data: the having clause 102 Adaptive Server Enterprise This example uses the having clause in the following way: it averages the price, excludes from the results titles with advances greater than $4,000, and produces results where price is less than the average price: select title_id, advance, price from titles where advance < 4000 having price > avg(price) title_id advance price ------------- --------- -------- BU1032 5,000.00 19.99 BU7832 5,000.00 19.99 MC2222 0.00 19.99 PC1035 7,000.00 22.95 PC8888 8,000.00 20.00 PS1372 7,000.00 21.59 PS3333 2,000.00 19.99 TC3218 7,000.00 20.95 (8 rows affected) You can also use the having clause with the Transact-SQL extension that allows you to omit the group by clause from a query that includes an aggregate in its select list. These scalar aggregate functions calculate values for the table as a single group, not for groups within the table. In this example, the group by clause is omitted, which makes the aggregate function calculate a value for the whole table. The having clause excludes nonmatching rows from the result group. select pub_id, count(pub_id) from publishers having pub_id < "1000" pub_id ------ ---------------- 0736 3 0877 3 (2 rows affected)CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 103 Sorting query results: the order by clause The order by clause allows you to sort query results by one or more columns, up to 31. Each sort is either ascending (asc) or descending (desc). If neither is specified, asc is the default. The following query orders results by pub_id: select pub_id, type, title_id from titles order by pub_id pub_id type title_id ------ ------------ -------- 0736 business BU2075 0736 psychology PS2091 0736 psychology PS2106 0736 psychology PS3333 0736 psychology PS7777 0877 UNDECIDED MC3026 0877 mod_cook MC2222 0877 mod_cook MC3021 0877 psychology PS1372 0877 trad_cook TC3218 0877 trad_cook TC4203 0877 trad_cook TC7777 1389 business BU1032 1389 business BU1111 1389 business BU7832 1389 popular_comp PC1035 1389 popular_comp PC8888 1389 popular_comp PC9999 (18 rows affected) If you name more than one column in the order by clause, Adaptive Server nests the sorts. The following statement sorts the rows in the stores table first by stor_id in descending order, then by payterms (in ascending order, since desc is not specified), and finally by country (also ascending). Adaptive Server sorts null values first within any group. select stor_id, payterms, country from stores order by stor_id desc, payterms stor_id payterms country ------- ------------ ------------ 8042 Net 30 USA 7896 Net 60 USA 7131 Net 60 USA 7067 Net 30 USA Sorting query results: the order by clause 104 Adaptive Server Enterprise 7066 Net 30 USA 6380 Net 60 USA 5023 Net 60 USA (7 rows affected) You can use the position number of a column in a select list instead of the column name. Column names and select list numbers can be mixed. Both of the following statements produce the same results as the preceding one. select pub_id, type, title_id from titles order by 1 desc, 2, 3 select pub_id, type, title_id from titles order by 1 desc, type, 3 Most versions of SQL require that order by items appear in the select list, but Transact-SQL has no such restriction. You could order the results of the preceding query by title, although that column does not appear in the select list. Note You cannot use order by on text or image columns. Adaptive Server does not allow subqueries, aggregates, variables and constant expressions in the order by list. With order by, null values come before all others. The effects of an order by clause on mixed-case data depend on the sort order installed on your Adaptive Server. The basic choices are binary, dictionary order, and case-insensitive. The system procedure sp_helpsort displays the sort order for your server. See the Reference Manual for more information on sort orders. order by and group by You can use an order by clause to order the results of a group by in a particular way. Put the order by clause after the group by clause. For example, to find the average price of each type of book and order the results by average price, the statement is: select type, avg(price) from titles CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 105 group by type order by avg(price) type ---------- ------------ UNDECIDED NULL mod_cook 11.49 psychology 13.50 business 13.73 trad_cook 15.96 popular_comp 21.48 (6 rows affected) order by and group by used with select distinct A select distinct query with order by or group by can return duplicate values if the order by or group by column is not in the select list. For example: select distinct pub_id from titles order by type pub_id ------ 0877 0736 1389 0877 1389 0736 0877 0877 (8 rows affected) If a query has an order by or group by clause that includes columns not in the select list, Adaptive Server adds those columns as hidden columns in the columns being processed. The columns listed in the order by or group by clause are included in the test for distinct rows. To comply with ANSI standards, include the order by or group by column in the select list. For example: select distinct pub_id, type from titles order by type pub_id type ------ ------------Summarizing groups of data: the compute clause 106 Adaptive Server Enterprise 0877 UNDECIDED 0736 business 1389 business 0877 mod_cook 1389 popular_comp 0736 psychology 0877 psychology 0877 trad_cook (8 rows affected) Summarizing groups of data: the compute clause The compute clause is a Transact-SQL extension. Use it with row aggregates to produce reports that show subtotals of grouped summaries. Such reports, usually produced by a report generator, are called control-break reports, since summary values appear in the report under the control of the groupings (“breaks”) you specify in the compute clause. These summary values appear as additional rows in the query results, unlike the aggregate results of a group by clause, which appear as new columns. A compute clause allows you to see detail and summary rows with one select statement. You can calculate summary values for subgroups and you can calculate more than one row aggregate (see “Row aggregates and compute” on page 109) for the same group. The general syntax for compute is: compute row_aggregate(column_name) [, row_aggregate(column_name)]... [by column_name [, column_name]...] The row aggregates you can use with compute are sum, avg, min, max, and count. You can use sum and avg only with numeric columns. Unlike the order by clause, you cannot use the positional number of a column from the select list instead of the column name. Note You cannot use text or image columns in a compute clause. CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 107 A system test may fail because there are too many aggregates in the compute clause of a query. The number of aggregates that each compute clause can accommodate is limited to 127, and if a compute clause contains more than 127 aggregates, the system generates an error message when you try to execute the query. Each avg() aggregate counts as two aggregates when you are counting toward the limit of 127, because an avg() aggregate is actually a combination of a sum() aggregate and a count() aggregate. Following are two queries and their results. The first one uses group by and aggregates. The second uses compute and row aggregates. Note the difference in the results. select type, sum(price), sum(advance) from titles group by type type ------------ ------- ---------- UNDECIDED NULL NULL business 54.92 25,125.00 mod_cook 22.98 15,000.00 popular_comp 42.95 15,000.00 psychology 67.52 21,275.00 trad_cook 47.89 19,000.00 (6 rows affected) select type, price, advance from titles order by type compute sum(price), sum(advance) by type type price advance ------------ ------------------------ -------- UNDECIDED NULL NULL Compute Result: ------------------------ ------------------------ NULL NULL type price advance ------------ -------------------- ---------- business 2.99 10,125.00 business 11.95 5,000.00 business 19.99 5,000.00 business 19.99 5,000.00 Compute Result:Summarizing groups of data: the compute clause 108 Adaptive Server Enterprise ------------------------ ------------------------ 54.92 25,125.00 type price advance ------------ ----------------------- --------- mod_cook 2.99 15,000.00 mod_cook 19.99 0.00 Compute Result: ------------------------ ------------------------ 22.98 15,000.00 type price advance ------------- ------------------- ------------ popular_comp NULL NULL popular_comp 20.00 8,000.00 popular_comp 22.95 7,000.00 Compute Result: ------------------------ ------------------------ 42.95 15,000.00 type price advance ------------ ------------------------ -------- psychology 7.00 6,000.00 psychology 7.99 4,000.00 psychology 10.95 2,275.00 psychology 19.99 2,000.00 psychology 21.59 7,000.00 Compute Result: ------------------------ ------------------------ 67.52 21,275.00 type price advance ------------ ----------------------- -------- trad_cook 11.95 4,000.00 trad_cook 14.99 8,000.00 trad_cook 20.95 7,000.00 Compute Result: ------------------------ ------------------------ 47.89 19,000.00 (24 rows affected) Each summary value is treated as a row.CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 109 Row aggregates and compute The row aggregates used with compute are listed in Table 3-2: Table 3-2: How aggregates are used with a compute statement These row aggregates are the same aggregates that can be used with group by, except there is no row aggregate function that is the equivalent of count(*). To find the summary information produced by group by and count(*), use a compute clause without the by keyword. Rules for compute clauses • Adaptive Server does not allow the distinct keyword with the row aggregates. • The columns in a compute clause must appear in the select list. • You cannot use select into (see Chapter 8, “Creating Databases and Tables”) in the same statement as a compute clause because statements that include compute do not generate normal rows. • If you use compute with the by keyword, you must also use an order by clause. The columns listed after by must be identical to, or a subset of, those listed after order by, and must be in the same left-to-right order, start with the same expression, and not skip any expressions. For example, suppose the order by clause is: order by a, b, c The compute clause can be any or all of these: compute row_aggregate (column_name) by a, b, c compute row_aggregate (column_name) by a, b compute row_aggregate (column_name) by a The compute clause cannot be any of these: compute row_aggregate (column_name) by b, c Row aggregates Result sum Total of the values in the expression avg Average of the values in the expression max Highest value in the expression min Lowest value in the expression count Number of selected rowsSummarizing groups of data: the compute clause 110 Adaptive Server Enterprise compute row_aggregate (column_name) by a, c compute row_aggregate (column_name) by c You must use a column name or an expression in the order by clause; you cannot sort by a column heading. • The compute keyword can be used without by to generate grand totals, grand counts, and so on. order by is optional if you use the compute keyword without by. The compute keyword without by is discussed under “Grand values: compute without by” on page 113. Specifying more than one column after compute Listing more than one column after the by keyword affects the query by breaking a group into subgroups and applying the specified row aggregate to each level of grouping. For example, this query finds the sum of the prices of psychology books from each publisher: select type, pub_id, price from titles where type = "psychology" order by type, pub_id, price compute sum(price) by type, pub_id type pub_id price ----------- ------- ------------- psychology 0736 7.00 psychology 0736 7.99 psychology 0736 10.95 psychology 0736 19.99 Compute Result: --------------- 45.93 type pub_id price ----------- ------- ------------- psychology 0877 21.59 Compute Result: --------------- 21.59 (7 rows affected) CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 111 Using more than one compute clause You can use different aggregates in the same statement by including more than one compute clause. The following query is similar to the preceding one but adds the sum of the prices of psychology books by publisher: select type, pub_id, price from titles where type = "psychology" order by type, pub_id, price compute sum(price) by type, pub_id compute sum(price) by type type pub_id price ----------- ------- -------------- psychology 0736 7.00 psychology 0736 7.99 psychology 0736 10.95 psychology 0736 19.99 Compute Result: --------------- 45.93 type pub_id price ---------- ------- -------------- psychology 0877 21.59 Compute Result: --------------- 21.59 Compute Result: --------------- 67.52 (8 rows affected) Applying an aggregate to more than one column One compute clause can apply the same aggregate to several columns. This query finds the sum of the prices and advances for each type of cookbook: select type, price, advance from titles where type like "%cook" Summarizing groups of data: the compute clause 112 Adaptive Server Enterprise order by type compute sum(price), sum(advance) by type type price advance --------- ---------------- --------------- mod_cook 2.99 15,000.00 mod_cook 19.99 0.00 Compute Result: --------------- --------------- 22.98 15,000.00 type price advance --------- ---------------- --------------- trad_cook 11.95 4,000.00 trad_cook 14.99 8,000.00 trad_cook 20.95 7,000.00 Compute Result: --------------- --------------- 47.89 19,000.00 (7 rows affected) Remember, the columns to which the aggregates apply must also be in the select list. Using different aggregates in the same compute clause You can use different aggregates in the same compute clause: select type, pub_id, price from titles where type like "%cook" order by type, pub_id compute sum(price), max(pub_id) by type type pub_id price ----------- ------- -------------- mod_cook 0877 2.99 mod_cook 0877 19.99 Compute Result: --------------- ---- 22.98 0877 type pub_id price CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 113 ----------- ------- -------------- trad_cook 0877 11.95 trad_cook 0877 14.99 trad_cook 0877 20.95 Compute Result: --------------- ---- 47.89 0877 (7 rows affected) Grand values: compute without by You can use the compute keyword without by to generate grand totals, grand counts, and so on. This statement finds the grand total of the prices and advances of all types of books that cost more than $20: select type, price, advance from titles where price > $20 compute sum(price), sum(advance) type price advance ------------ ---------------- ------------- popular_comp 22.95 7,000.00 psychology 21.59 7,000.00 trad_cook 20.95 7,000.00 Compute Result: --------------- --------- 65.49 21,000.00 (4 rows affected) You can use a compute with by and a compute without by in the same query. The following query finds the sum of prices and advances by type and then computes the grand total of prices and advances for all types of books. select type, price, advance from titles where type like "%cook" order by type compute sum(price), sum(advance) by type compute sum(price), sum(advance) type price advanceCombining queries: the union operator 114 Adaptive Server Enterprise ----------- ----------------- ------------ mod_ cook 2.99 15,000.00 mod_cook 19.99 0.00 Compute Result: --------------- --------- 22.98 15,000.00 type price advance ----------- ----------------- ------------ trad_cook 11.95 4,000.00 trad_cook 14.99 8,000.00 trad_cook 20.95 7,000.00 Compute Result: --------------- --------- 47.89 19,000.00 Compute Result: --------------- --------- 70.87 34,000.00 (8 rows affected) Combining queries: the union operator The union operator combines the results of two or more queries into a single result set. The Transact-SQL extension to union allows you to: • Use union in the select clause of an insert statement. • Specify new column headings in the order by clause of a select statement when union is present in the select statement. The syntax of the union operator is as follows: query1 [union [all] queryN ] ... [order by clause] [compute clause] where query1 is: select select_list [into clause]CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 115 [from clause] [where clause] [group by clause] [having clause] and queryN is: select select_list [from clause] [where clause] [group by clause] [having clause] Figure 3-1: Union combining queries For example, suppose you have the following two tables containing the data shown: The following query creates a union between the two tables: create table T1 (a char(4), b int) insert T1 values ("abc", 1) insert T1 values ("def", 2) insert T1 values ("ghi", 3) create table T2 (a char(4), b int) insert T2 values ("ghi", 3) insert T2 values ("jkl", 4) insert T2 values ("mno", 5) select * from T1 union select * from T2 a b ---- --------- abc 1 def 2 ghi 3 Combining queries: the union operator 116 Adaptive Server Enterprise jkl 4 mno 5 (5 rows affected) By default, the union operator removes duplicate rows from the result set. Use the all option to include duplicate rows. Notice also that the columns in the result set have the same names as the columns in T1. You can use any number of union operators in a Transact-SQL statement. For example: x union y union z By default, Adaptive Server evaluates a statement containing union operators from left to right. You can use parentheses to specify a different evaluation order. For example, the following two expressions are not equivalent: x union all (y union z) (x union all y) union z In the first expression, duplicates are eliminated in the union between y and z. Then, in the union between that set and x, duplicates are not eliminated. In the second expression, duplicates are included in the union between x and y, but are then eliminated in the subsequent union with z; all does not affect the final result of this statement. Guidelines for union queries When you use union statements: • All select lists in the union statement must have the same number of expressions (such as column names, arithmetic expressions, and aggregate functions). The following statement is invalid because the first select list is longer than the second: create table stores_east (stor_id char(4) not null, stor_name varchar(40) null, stor_address varchar(40) null, city varchar(20) null, state char(2) null, country varchar(12) null, postalcode char(10) null, payterms varchar(12) null)CHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 117 select stor_id, city, state from stores union select stor_id, city from stores_east drop table stores_east • Corresponding columns in all tables, or any subset of columns used in the individual queries, must be of the same datatype, or an implicit data conversion must be possible between the two datatypes, or an explicit conversion should be supplied. For example, a union is not possible between a column of the char datatype and one of the int datatype, unless an explicit conversion is supplied. However, a union is possible between a column of the money datatype and one of the int datatype. See union and “Datatype Conversion Functions” in the Reference Manual for more information about comparing datatypes in a union statement. • You must place corresponding columns in the individual queries of a union statement in the same order, because union compares the columns one to one in the order given in the query. For example, suppose you have the following tables: Figure 3-2: Union comparing columns This query: select a, b from T3 union select b, a from T4 produces: a bCombining queries: the union operator 118 Adaptive Server Enterprise --------- --- 1 abc 2 def 3 ghi (3 rows affected) The following query results in an error message, because the datatypes of corresponding columns are not compatible: select a, b from T3 union select a, b from T4 drop table T3 drop table T4 When you combine different (but compatible) datatypes such as float and int in a union statement, Adaptive Server converts them to the datatype with the most precision. • Adaptive Server takes the column names in the table resulting from a union from the first individual query in the union statement. Therefore, to define a new column heading for the result set, do so in the first query. In addition, to refer to a column in the result set by a new name, for example, in an order by statement, refer to it in that way in the first select statement. The following query is correct: select Cities = city from stores union select city from authors order by Cities Using union with other Transact-SQL commands When you use union statements with other Transact-SQL commands: • The first query in the union statement may contain an into clause that creates a table to hold the final result set. For example, the following statement creates a table called results that contains the union of tables publishers, stores, and salesdetail: use master sp_dboption pubs2, "select into", trueCHAPTER 3 Using Aggregates, Grouping, and Sorting Transact-SQL User’s Guide 119 use pubs2 checkpoint select pub_id, pub_name, city into results from publishers union select stor_id, stor_name, city from stores union select stor_id, title_id, ord_num from salesdetail You can use the into clause only in the first query; if it appears anywhere else, you get an error message. • You can use order by and compute clauses only at the end of the union statement to define the order of the final results or to compute summary values. You cannot use them within the individual queries that make up the union statement. • You can use group by and having clauses within individual queries only; you cannot use them to affect the final result set. • You can also use the union operator within an insert statement. For example: create table tour (city varchar(20), state char(2)) insert into tour select city, state from stores union select city, state from authors drop table tour • Starting with Adaptive Server version 12.5, you can use the union operator within a create view statement. If you are using an earlier version of Adaptive Server, however, you cannot use the union operator within a create view statement. • You cannot use the union operator on text and image columns. • You cannot use the for browse clause in statements involving the union operator. Combining queries: the union operator 120 Adaptive Server EnterpriseTransact-SQL User’s Guide 121 C H A P T E R 4 Subqueries: Using Queries Within Other Queries A subquery is a select statement that is nested inside another select, insert, update, or delete statement, inside a conditional statement, or inside another subquery. This chapter discusses: You can also express subqueries as join operations. See Chapter 6, “Joins: Retrieving Data from Several Tables.” How subqueries work Subqueries, also called inner queries, appear within a where or having clause of another SQL statement or in the select list of a statement. You can use subqueries to handle query requests that are expressed as the results of other queries. A statement that includes a subquery operates on rows from one table, based on its evaluation of the subquery’s select list, which can refer either to the same table as the outer query, or to a different table. In Transact-SQL, a subquery can also be used almost anywhere an expression is allowed, if the subquery returns a single value. A case expression can also include a subquery. For example, this subquery lists the names of all authors whose royalty split is more than $75: select au_fname, au_lname from authors where au_id in (select au_id Topic Page How subqueries work 121 Types of subqueries 130 Using correlated subqueries 148How subqueries work 122 Adaptive Server Enterprise from titleauthor where royaltyper > 75) select statements that contain one or more subqueries are sometimes called nested queries or nested select statements. You can formulate as joins many SQL statements that include a subquery. Other questions can be posed only with subqueries. Some people find subqueries easier to understand. Other SQL users avoid subqueries whenever possible. You can choose whichever formulation you prefer. The result of a subquery that returns no values is NULL. If a subquery returns NULL, the query failed. Subquery syntax Always enclose the select statement of a subquery in parentheses. The select syntax for a subquery is somewhat restricted: (select [all | distinct] subquery_select_list [from_clause] [where search_conditions] [group by aggregate_free_expression [, aggregate_free_expression]...] [having search_conditions]) from_clause ::= from table_reference [,table_reference]... table_reference ::= table_view_name | ANSI_join table_view_name ::= {table_view_reference | derived_table_reference} [holdlock | noholdlock] [shared] table_view_reference ::= [[database.]owner.]{table_name | view_name} [[as] correlation_name ] [index {index_name | table_name }] [prefetch size ] [lru | mru]}} derived_table_reference ::= derived_table [as] correlation_name [‘(‘ derived_column_list’)’] derived_column_list ::= column_name [’,’ column_name] derived_table ::= ’(’ select ’)’CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 123 Subquery restrictions A subquery is subject to the following restrictions: • The subquery_select_list can consist of only one column name, except in the exists subquery, where an (*) is usually used in place of the single column name. Do not specify more than one column name. Qualify column names with table or view names if there is ambiguity about the table or view to which they belong. • Subqueries can be nested inside the where or having clause of an outer select, insert, update, or delete statement, inside another subquery, or in a select list. Alternatively, you can write many statements that contain subqueries as joins; Adaptive Server processes such statements as joins. • In Transact-SQL, a subquery can appear almost anywhere an expression can be used, if it returns a single value. • A subquery can appear almost anywhere an expression can be used. SQL derived tables can therefore be used in the from clause of a subquery wherever the subquery is used. • You cannot use subqueries in an order by, group by, or compute by list. • You cannot include a for browse clause in a subquery. • You cannot include a union clause in a subquery unless it is part of a derived table expression within the subquery. For more information on using SQL derived tables, see Chapter 5, “SQL Derived Tables.”. • The select list of an inner subquery introduced with a comparison operator can include only one expression or column name, and the subquery must return a single value. The column you name in the where clause of the outer statement must be join-compatible with the column you name in the subquery select list. • text and image datatypes are not allowed in subqueries. • Subqueries cannot manipulate their results internally, that is, a subquery cannot include the order by clause, the compute clause, or the into keyword. • Correlated (repeating) subqueries are not allowed in the select clause of an updatable cursor defined by declare cursor. • There is a limit of 16 nesting levels. • The maximum number of subqueries on each side of a union is 16.How subqueries work 124 Adaptive Server Enterprise • The where clause of a subquery can contain an aggregate function only if the subquery is in a having clause of an outer query and the aggregate value is a column from a table in the from clause of the outer query. • The result expression from a subquery is subject to the same limits as for any expression. The maximum length of an expression is 16K. For more information, see Chapter 4, “Expressions, Identifiers, and Wildcard “Characters” in the Adaptive Server Reference Manual. Example of using a subquery Suppose you want to find the books that have the same price as Straight Talk About Computers. First, you find the price of Straight Talk: select price from titles where title = "Straight Talk About Computers" price ------------- $19.99 (1 row affected) You use the results of the first query in a second query to find all the books that cost the same as Straight Talk: select title, price from titles where price = $19.99 title price ------------------------------------------ ----- The Busy Executive’s Database Guide 19.99 Straight Talk About Computers 19.99 Silicon Valley Gastronomic Treats 19.99 Prolonged Data Deprivation: Four Case Studies 19.99 (4 rows affected) You can use a subquery to receive the same results in only one step: select title, price from titles where price = (select price from titles where title = "Straight Talk About Computers") CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 125 title price --------------------------------------- ----- The Busy Executive’s Database Guide 19.99 Straight Talk About Computers 19.99 Silicon Valley Gastronomic Treats 19.99 Prolonged Data Deprivation: Four Case Studies 19.99 (4 rows affected) Qualifying column names Column names in a statement are implicitly qualified by the table referenced in the from clause at the same level. In the following example, the table name publishers implicitly qualifies the pub_id column in the where clause of the outer query. The reference to pub_id in the select list of the subquery is qualified by the subquery’s from clause—that is, by the titles table: select pub_name from publishers where pub_id in (select pub_id from titles where type = "business") This is what the query looks like with the implicit assumptions spelled out: select pub_name from publishers where publishers.pub_id in (select titles.pub_id from titles where type = "business") It is never wrong to state the table name explicitly, and you can override implicit assumptions about table names by using explicit qualifications. Subqueries with correlation names As discussed in Chapter 6, “Joins: Retrieving Data from Several Tables,” table correlation names are required in self-joins because the table being joined to itself appears in two different roles. You can also use correlation names in nested queries that refer to the same table in both an inner query and an outer query.How subqueries work 126 Adaptive Server Enterprise For example, you can find authors who live in the same city as Livia Karsen by using this subquery: select au1.au_lname, au1.au_fname, au1.city from authors au1 where au1.city in (select au2.city from authors au2 where au2.au_fname = "Livia" and au2.au_lname = "Karsen") au_lname au_fname city ----------- --------- ------- Green Marjorie Oakland Straight Dick Oakland Stringer Dirk Oakland MacFeather Stearns Oakland Karsen Livia Oakland (5 rows affected) Explicit correlation names make it clear that the reference to authors in the subquery is not the same as the reference to authors in the outer query. Without explicit correlation, the subquery is: select au_lname, au_fname, city from authors where city in (select city from authors where au_fname = "Livia" and au_lname = "Karsen") Alternatively, you can state the above query, as well as other statements in which the subquery and the outer query refer to the same table, as self-joins: select au1.au_lname, au1.au_fname, au1.city from authors au1, authors au2 where au1.city = au2.city and au2.au_lname = "Karsen" and au2.au_fname = "Livia" A subquery restated as a join may not return the results in the same order; additionally, the join may require the distinct keyword to eliminate duplicates. CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 127 Multiple levels of nesting A subquery can include one or more subqueries. You can nest up to 16 subqueries in a statement. For example: “Find the names of authors who have participated in writing at least one popular computing book:” select au_lname, au_fname from authors where au_id in (select au_id from titleauthor where title_id in (select title_id from titles where type = "popular_comp") ) au_lname au_fname ---------------------- ------------ Carson Cheryl Dull Ann Locksley Chastity Hunter Sheryl (4 rows affected) The outermost query selects all author names. The next query finds the authors’ IDs, and the innermost query returns the title ID numbers PC1035, PC8888, and PC9999. You can also express this query as a join: select au_lname, au_fname from authors, titles, titleauthor where authors.au_id = titleauthor.au_id and titles.title_id = titleauthor.title_id and type = "popular_comp"How subqueries work 128 Adaptive Server Enterprise Subqueries in update, delete, and insert statements You can nest subqueries in update, delete, and insert statements as well as in select statements. Note Running the sample queries in this section changes the pubs2 database. Ask a System Administrator to help you get a clean copy of the sample database. The following query doubles the price of all books published by New Age Books. The statement updates the titles table; its subquery references the publishers table. update titles set price = price * 2 where pub_id in (select pub_id from publishers where pub_name = "New Age Books") An equivalent update statement using a join is: update titles set price = price * 2 from titles, publishers where titles.pub_id = publishers.pub_id and pub_name = "New Age Books" You can remove all records of sales of business books with this nested select statement: delete salesdetail where title_id in (select title_id from titles where type = "business") An equivalent delete statement using a join is: delete salesdetail from salesdetail, titles where salesdetail.title_id = titles.title_id and type = "business" CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 129 Subqueries in conditional statements You can use subqueries in conditional statements. The preceding subquery that removed all records of sales of business books can be rewritten, as shown in the next example, to check for the records before deleting them: if exists (select title_id from titles where type = "business") begin delete salesdetail where title_id in (select title_id from titles where type = "business") end Using subqueries instead of expressions In Transact-SQL, you can substitute a subquery almost anywhere you can use an expression in a select, update, insert, or delete statement. For example, a subquery can compare with a column from the inner table of an outer join. You cannot use a subquery in an order by list or as an expression in the values list in an insert statement. The following statement shows how to find the titles and types of books that have been written by authors living in California and that are also published there: select title, type from titles where title in (select title from titles, titleauthor, authors where titles.title_id = titleauthor.title_id and titleauthor.au_id = authors.au_id and authors.state = "CA") and title in (select title from titles, publishers where titles.pub_id = publishers.pub_id and publishers.state = "CA") title type ----------------------------------- ---------- The Busy Executive’s Database Guide businessTypes of subqueries 130 Adaptive Server Enterprise Cooking with Computers: Surreptitious Balance Sheets business Straight Talk About Computers business But Is It User Friendly? popular_comp Secrets of Silicon Valley popular_comp Net Etiquette popular_comp (6 rows affected) The following statement selects the book titles that have had more than 5000 copies sold, lists their prices, and the price of the most expensive book: select title, price, (select max(price) from titles) from titles where total_sales > 5000 title price ----------------------------------- ----- ------ You Can Combat Computer Stress! 2.99 22.95 The Gourmet Microwave 2.99 22.95 But Is It User Friendly? 22.95 22.95 Fifty Years in Buckingham Palace Kitchens 11.95 22.95 (4 rows affected) Types of subqueries There are two basic types of subqueries: • Expression subqueries are introduced with an unmodified comparison operator, must return a single value, and can be used almost anywhere an expression is allowed in SQL. • Quantified predicate subqueries operate on lists introduced with in or with a comparison operator modified by any or all. Quantified predicate subqueries return 0 or more values. This type is also used as an existence test, introduced with exists. Subqueries of either type are either noncorrelated or correlated (repeating). CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 131 • A noncorrelated subquery can be evaluated as if it were an independent query. Conceptually, the results of the subquery are substituted in the main statement, or outer query. This is not how Adaptive Server actually processes statements with subqueries. Noncorrelated subqueries can alternatively be stated as joins and are processed as joins by Adaptive Server. • A correlated subquery cannot be evaluated as an independent query, but can reference columns in a table listed in the from list of the outer query. Correlated subqueries are discussed in detail at the end of this chapter. Expression subqueries Expression subqueries include: • Subqueries in a select list (introduced with in) • Subqueries in a where or having clause connected by a comparison operator (=, !=, >, >=, <, <=) Expression subqueries take the general form: [Start of select, insert, update, delete statement or subquery] where expression comparison_operator (subquery) [End of select, insert, update, delete statement or subquery] An expression consists of a subquery or any combination of column names, constants, and functions connected by arithmetic or bitwise operators. The comparison_operator is one of: Operator Meaning = Equal to > Greater than < Less than >= Greater than or equal to <= Less than or equal to != Not equal to <> Not equal to !> Not greater than !< Not less thanTypes of subqueries 132 Adaptive Server Enterprise If you use a column name in the where or having clause of the outer statement, make sure a column name in the subquery_select_list is join compatible with it. A subquery that is introduced with an unmodified comparison operator (that is, a comparison operator that is not followed by any or all) must resolve to a single value. If such a subquery returns more than one value, Adaptive Server returns an error message. For example, suppose that each publisher is located in only one city. To find the names of authors who live in the city where Algodata Infosystems is located, write a statement with a subquery that is introduced with the comparison operator =: select au_lname, au_fname from authors where city = (select city from publishers where pub_name = "Algodata Infosystems") au_lname au_fname -------------- -------------- Carson Cheryl Bennet Abraham (2 rows affected) Using scalar aggregate functions to guarantee a single value Subqueries that are introduced with unmodified comparison operators often include scalar aggregate functions, because these return a single value. For example, to find the names of books that are priced higher than the current minimum price: select title from titles where price > (select min(price) from titles) title --------------------------------------------------- The Busy Executive’s Database Guide Cooking with Computers: Surreptitious Balance Sheets Straight Talk About Computers Silicon Valley Gastronomic Treats CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 133 But Is It User Friendly? Secrets of Silicon Valley Computer Phobic and Non-Phobic Individuals: Behavior Variations Is Anger the Enemy? Life Without Fear Prolonged Data Deprivation: Four Case Studies Emotional Security: A New Algorithm Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean Fifty Years in Buckingham Palace Kitchens Sushi, Anyone? (14 rows affected) group by and having in expression subqueries Because subqueries that are introduced by unmodified comparison operators must return a single value, they cannot include group by and having clauses unless you know that the group by and having clauses will return a single value. For example, this query finds the books that are priced higher than the lowest priced book in the trad_cook category: select title from titles where price > (select min(price) from titles group by type having type = "trad_cook") Using distinct with expression subqueries Subqueries that are introduced with unmodified comparison operators often include the distinct keyword to ensure the return of a single value. For example, without distinct, this subquery would fail because it would return more than one value: select pub_name from publishers where pub_id = (select distinct pub_id from titles where pub_id = publishers.pub_id)Types of subqueries 134 Adaptive Server Enterprise Quantified predicate subqueries Quantified predicate subqueries, which return a list of 0 and higher values, are subqueries in a where or having clause that are connected by any, all, in, or exists. The any or all subquery operators modify comparison operators. There are three types of quantified predicate subqueries: • any/all subqueries. Subqueries introduced with a modified comparison operator, which may include a group by or having clause, take the general form: [Start of select, insert, update, delete statement; or subquery] where expression comparison_operator [any | all] (subquery) [End of select, insert, update, delete statement; or subquery] • in/not in subqueries. Subqueries introduced with in or not in take the general form: [Start of select, insert, update, delete statement; or subquery] where expression [not] in (subquery) [End of select, insert, update, delete statement; or subquery] • exists/not exists subqueries. Subqueries introduced by exists or not exists are existence tests which take the general form: [Start of select, insert, update, delete statement; or subquery] where [not] exists (subquery) [End of select, insert, update, delete statement; or subquery] Though Adaptive Server allows the keyword distinct in quantified predicate subqueries, it always processes the subquery as if distinct were not included. Subqueries with any and all The keywords all and any modify a comparison operator that introduces a subquery. When any is used with <, >, or = with a subquery, it returns results when any value retrieved in the subquery matches the value in the where or having clause of the outer statement.CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 135 When all is used with < or > in a subquery, it returns results when all values retrieved in the subquery match the value in the where or having clause of the outer statement. The syntax for any and all is: {where | having} [not] expression comparison_operator {any | all} (subquery) Using the > comparison operator as an example: • > all means greater than every value, or greater than the maximum value. For example, > all (1, 2, 3) means greater than 3. • > any means greater than at least one value, or greater than the minimum value. Therefore, > any (1, 2, 3) means greater than 1. If you introduce a subquery with all and a comparison operator does not return any values, the entire query fails. all and any can be tricky. For example, you might ask “Which books commanded an advance greater than any book published by New Age Books?” You can paraphrase this question to make its SQL “translation” more clear: “Which books commanded an advance greater than the largest advance paid by New Age Books?” The all keyword, not the any keyword, is required here: select title from titles where advance > all (select advance from publishers, titles where titles.pub_id = publishers.pub_id and pub_name = "New Age Books") title ---------------------------------------- The Gourmet Microwave (1 row affected) For each title, the outer query gets the titles and advances from the titles table, and it compares these to the advance amounts paid by New Age Books returned from the subquery. The outer query looks at the largest value in the list and determines whether the title being considered has commanded an even greater advance. Types of subqueries 136 Adaptive Server Enterprise > all means greater than all values The > all operator means that the value in the column that introduces the subquery must be greater than each of the values returned by the subquery, for a row to satisfy the condition in the outer query. For example, to find the books that are priced higher than the highest-priced book in the mod_cook category: select title from titles where price > all (select price from titles where type = "mod_cook") title --------------------------------------------------- But Is It User Friendly? Secrets of Silicon Valley Computer Phobic and Non-Phobic Individuals: Behavior Variations Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean (4 rows affected) However, if the set returned by the inner query contains a NULL, the query returns 0 rows. This is because NULL stands for “value unknown,” and it is impossible to tell whether the value you are comparing is greater than an unknown value. For example, try to find the books that are priced higher than the highest-priced book in the popular_comp category: select title from titles where price > all (select price from titles where type = "popular_comp") title --------------------------------------------------- (0 rows affected) No rows were returned because the subquery found that one of the books, Net Etiquette, has a null price. = all means equal to every value The = all operator means that the value in the column that introduces the subquery must be the same as each value in the list of values returned by the subquery, for a row to satisfy the outer query. CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 137 For example, the following query finds out which authors live in the same city by looking at the postal code: select au_fname, au_lname, city from authors where city = all (select city from authors where postalcode like "946%") > any means greater than at least one value > any means that the value in the column that introduces the subquery must be greater than at least one of the values in the list returned by the subquery, for a row to satisfy the outer query. The following example is introduced with a comparison operator modified by any. It finds each title that has an advance larger than any advance amount paid by New Age Books. select title from titles where advance > any (select advance from titles, publishers where titles.pub_id = publishers.pub_id and pub_name = "New Age Books") title --------------------------------------------------- The Busy Executive’s Database Guide Cooking with Computers: Surreptitious Balance Sheets You Can Combat Computer Stress! Straight Talk About Computers The Gourmet Microwave But Is It User Friendly? Secrets of Silicon Valley Computer Phobic and Non-Phobic Individuals: Behavior Variations Is Anger the Enemy? Life Without Fear Emotional Security: A New Algorithm Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean Fifty Years in Buckingham Palace Kitchens Sushi, Anyone? Types of subqueries 138 Adaptive Server Enterprise (14 rows affected) For each title selected by the outer query, the inner query finds a list of advance amounts paid by New Age Books. The outer query looks at all the values in the list and determines whether the title being considered has commanded an advance that is larger than any of those values. In other words, this example finds titles with advances as large as or larger than the lowest value paid by New Age Books. If the subquery does not return any values, the entire query fails. = any means equal to some value The = any operator is an existence check; it is equivalent to in. For example, to find authors that live in the same city as any publisher, you can use either =any or in: select au_lname, au_fname from authors where city = any (select city from publishers) select au_lname, au_fname from authors where city in (select city from publishers) au_lname au_fname -------------- -------------- Carson Cheryl Bennet Abraham (2 rows affected) However, the != any operator is different from not in. The != any operator means “not = a or not = b or not = c”; not in means “not = a and not = b and not = c”. For example, to find the authors who live in a city where no publisher is located: select au_lname, au_fname from authors where city != any (select city from publishers) The results include all 23 authors. This is because every author lives in some city where no publisher is located, and each author lives in only one city. CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 139 The inner query finds all the cities in which publishers are located, and then, for each city, the outer query finds the authors who do not live there. Here is what happens when you substitute not in in the same query: select au_lname, au_fname from authors where city not in (select city from publishers) au_lname au_fname -------------- ------------ White Johnson Green Marjorie O’Leary Michael Straight Dick Smith Meander Dull Ann Gringlesby Burt Locksley Chastity Greene Morningstar Blotchet-Halls Reginald Yokomoto Akiko del Castillo Innes DeFrance Michel Stringer Dirk MacFeather Stearns Karsen Livia Panteley Sylvia Hunter Sheryl McBadden Heather Ringer Anne Ringer Albert (21 rows affected) These are the results you want. They include all the authors except Cheryl Carson and Abraham Bennet, who live in Berkeley, where Algodata Infosystems is located. You get the same results if you use !=all, which is equivalent to not in: select au_lname, au_fname from authors where city != all (select city from publishers) Types of subqueries 140 Adaptive Server Enterprise Subqueries used with in Subqueries that are introduced with the keyword in return a list of 0 and higher values. For example, this query finds the names of the publishers who have published business books: select pub_name from publishers where pub_id in (select pub_id from titles where type = "business") pub_name ---------------------------------------- New Age Books Algodata Infosystems (2 rows affected) This statement is evaluated in two steps. The inner query returns the identification numbers of the publishers who have published business books, 1389 and 0736. These values are then substituted in the outer query, which finds the names that go with the identification numbers in the publishers table. The query looks like this: select pub_name from publishers where pub_id in ("1389", "0736") Another way to formulate this query using a subquery is: select pub_name from publishers where "business" in (select type from titles where pub_id = publishers.pub_id) Note that the expression following the where keyword in the outer query can be a constant as well as a column name. You can use other types of expressions, such as combinations of constants and column names. The preceding queries, like many other subqueries, can be alternatively formulated as a join query: select distinct pub_name from publishers, titles where publishers.pub_id = titles.pub_id and type = "business" CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 141 Both this query and the subquery versions find publishers who have published business books. All are equally correct and produce the same results, though you may need to use the distinct keyword to eliminate duplicates. However, one advantage of using a join query rather than a subquery for this and similar problems is that a join query shows columns from more than one table in the result. For example, to include the titles of the business books in the result, you would need to use the join version: select pub_name, title from publishers, titles where publishers.pub_id = titles.pub_id and type = "business" pub_name title -------------------- ---------------------------------------- Algodata Infosystems The Busy Executive’s Database Guide Algodata Infosystems Cooking with Computers: Surreptitious Balance Sheets New Age Books You Can Combat Computer Stress! Algodata Infosystems Straight Talk About Computers (4 rows affected) Here is another example of a statement that can be formulated either with a subquery or a join query: “Find the names of all second authors who live in California and receive less than 30 percent of the royalties on a book.” Using a subquery, the statement is: select au_lname, au_fname from authors where state = "CA" and au_id in (select au_id from titleauthor where royaltyper < 30 and au_ord = 2) au_lname au_fname ------------------------ ------------ MacFeather Stearns (1 row affected) The outer query produces a list of the 15 authors who live in California. The inner query is then evaluated, producing a list of the IDs of the authors who meet the qualifications. More than one condition can be included in the where clause of both the inner and the outer query. Types of subqueries 142 Adaptive Server Enterprise Using a join, the query is expressed like this: select au_lname, au_fname from authors, titleauthor where state = "CA" and authors.au_id = titleauthor.au_id and royaltyper < 30 and au_ord = 2 A join can always be expressed as a subquery. A subquery can often be expressed as a join. Subqueries used with not in Subqueries that are introduced with the keyword phrase not in also return a list of 0 and higher values. not in means “not = a and not = b and not = c”. This query finds the names of the publishers who have not published business books, the inverse of the example in “Subqueries used with in” on page 140: select pub_name from publishers where pub_id not in (select pub_id from titles where type = "business") pub_name ---------------------------------------- Binnet & Hardley (1 row affected) The query is the same as the previous one except that not in is substituted for in. However, you cannot convert this statement to a join; the “not equal” join finds the names of publishers who have published some book that is not a business book. The difficulties interpreting the meaning of joins that are not based on equality are discussed in detail in Chapter 6, “Joins: Retrieving Data from Several Tables.” Subqueries using not in with NULL A subquery using not in returns a set of values for each row in the outer query. If the value in the outer query is not in the set returned by the inner query, the not in evaluates to TRUE, and the outer query puts the record being considered in the results.CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 143 However, if the set returned by the inner query contains no matching value, but it does contain a NULL, the not in returns UNKNOWN. This is because NULL stands for “value unknown,” and it is impossible to tell whether the value you are looking for is in a set containing an unknown value. The outer query discards the row. For example: select pub_name from publishers where $100.00 not in (select price from titles where titles.pub_id = publishers.pub_id) pub_name ------ New Age Books (1 row affected) New Age Books is the only publisher that does not publish any books that cost $100. Binnet & Handley and Algodata Infosystems were not included in the query results because each publishes a book for which the price is undecided. Subqueries used with exists Use the exists keyword with a subquery to test for the existence of some result from the subquery: {where | having} [not] exists (subquery) That is, the where clause of the outer query tests for the existence of the rows returned by the subquery. The subquery does not actually produce any data, but returns a value of TRUE or FALSE. For example, this query finds the names of all the publishers who publish business books: select pub_name from publishers where exists (select * from titles where pub_id = publishers.pub_id and type = "business") pub_name ---------------------------------------- New Age Books Types of subqueries 144 Adaptive Server Enterprise Algodata Infosystems (2 rows affected) To conceptualize the resolution of this query, consider each publisher’s name in turn. Does this value cause the subquery to return at least one row? In other words, does it cause the existence test to evaluate to TRUE? In the results of the preceding query, the second publisher’s name is Algodata Infosystems, which has an identification number of 1389. Are there any rows in the titles table in which pub_id is 1389 and type is business? If so, “Algodata Infosystems” should be one of the values selected. The same process is repeated for each of the other publisher’s names. A subquery that is introduced with exists is different from other subqueries, in these ways: • The keyword exists is not preceded by a column name, constant, or other expression. • The subquery exists evaluates to TRUE or FALSE rather than returning any data. • The select list of the subquery usually consists of the asterisk (*). There is no need to specify column names, since you are simply testing for the existence or nonexistence of rows that meet the conditions specified in the subquery. Otherwise, the select list rules for a subquery introduced with exists are identical to those for a standard select list. The exists keyword is very important, because there is often no alternative nonsubquery formulation. In practice, a subquery introduced by exists is always a correlated subquery (see “Using correlated subqueries” on page 148). Although you cannot express some queries formulated with exists in any other way, you can express all queries that use in or a comparison operator modified by any or all with exists. Some examples of statements using exists and their equivalent alternatives follow. Here are two ways to find authors that live in the same city as a publisher: select au_lname, au_fname from authors where city = any (select city from publishers) select au_lname, au_fname from authors where exists CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 145 (select * from publishers where authors.city = publishers.city) au_lname au_fname -------------- -------------- Carson Cheryl Bennet Abraham (2 rows affected) Here are two queries that find titles of books published by any publisher located in a city that begins with the letter “B”: select title from titles where exists (select * from publishers where pub_id = titles.pub_id and city like "B%") select title from titles where pub_id in (select pub_id from publishers where city like "B%") title --------------------------------------------------- You Can Combat Computer Stress! Is Anger the Enemy? Life Without Fear Prolonged Data Deprivation: Four Case Studies Emotional Security: A New Algorithm The Busy Executive’s Database Guide Cooking with Computers: Surreptitious Balance Sheets Straight Talk About Computers But Is It User Friendly? Secrets of Silicon Valley Net Etiquette (11 rows affected) Types of subqueries 146 Adaptive Server Enterprise Subqueries used with not exists not exists is just like exists except that the where clause in which it is used is satisfied when no rows are returned by the subquery. For example, to find the names of publishers who do not publish business books, the query is: select pub_name from publishers where not exists (select * from titles where pub_id = publishers.pub_id and type = "business") pub_name ---------------------------------------- Binnet & Hardley (1 row affected) This query finds the titles for which there have been no sales: select title from titles where not exists (select title_id from salesdetail where title_id = titles.title_id) title ----------------------------------------- The Psychology of Computer Cooking Net Etiquette (2 rows affected) Finding intersection and difference with exists You can use subqueries that are introduced with exists and not exists for two set theory operations: intersection and difference. The intersection of two sets contains all elements that belong to both of the original sets. The difference contains the elements that belong only to the first set. The intersection of authors and publishers over the city column is the set of cities in which both an author and a publisher are located: select distinct city CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 147 from authors where exists (select * from publishers where authors.city = publishers.city) city -------------------- Berkeley (1 row affected) The difference between authors and publishers over the city column is the set of cities where an author lives but no publisher is located, that is, all the cities except Berkeley: select distinct city from authors where not exists (select * from publishers where authors.city = publishers.city) city -------------------- Gary Covelo Oakland Lawrence San Jose Ann Arbor Corvallis Nashville Palo Alto Rockville Vacaville Menlo Park Walnut Creek San Francisco Salt Lake City (15 rows affected) Subqueries using SQL derived tables A SQL derived table can be used in a subquery from clause. For example, this query finds the names of the publishers who have published business books:Using correlated subqueries 148 Adaptive Server Enterprise select pub_name from publishers where "business" in (select type from (select type from titles, publishers where titles.pub_id = publishers.pub_id) dt_titles) Here, dt_titles is the SQL derived table defined by the innermost select statement. SQL derived tables can be used in the from clause of subqueries wherever subqueries are legal. For more information on SQL derived tables, see Chapter 5, “SQL Derived Tables.” Using correlated subqueries You can evaluate many of the previous queries by executing the subquery once and substituting the resulting values into the where clause of the outer query; these are noncorrelated subqueries. In queries that include a repeating subquery, or correlated subquery, the subquery depends on the outer query for its values. The subquery is executed repeatedly, once for each row that is selected by the outer query. This example finds the names of all authors who earn 100 percent royalty on a book: select au_lname, au_fname from authors where 100 in (select royaltyper from titleauthor where au_id = authors.au_id) au_lname au_fname -------------- ---------- White Johnson Green Marjorie Carson Cheryl Straight Dick Locksley Chastity Blotchet-Hall Reginald del Castillo Innes Panteley Sylvia Ringer Albert CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 149 (9 rows affected) Unlike most of the previous subqueries, the subquery in this statement cannot be resolved independently of the main query. It needs a value for authors.au_id, but this value is a variable—it changes as Adaptive Server examines different rows of the authors table. This is how the preceding query is evaluated: Transact-SQL considers each row of the authors table for inclusion in the results, by substituting the value in each row in the inner query. For example, suppose Transact-SQL first examines the row for Johnson White. Then, authors.au_id takes the value “172- 32-1176,” which Transact-SQL substitutes for the inner query: select royaltyper from titleauthor where au_id = "172-32-1176" The result is 100, so the outer query evaluates to: select au_lname, au_fname from authors where 100 in (100) Since the where condition is true, the row for Johnson White is included in the results. If you go through the same procedure with the row for Abraham Bennet, you can see how that row is not included in the results. Correlated subqueries containing Transact-SQL outer joins Adaptive Server version 12.5 does not process correlated subqueries containing Transact-SQL outer joins in the same way that earlier versions of Adaptive Server did. The following is an example of a query using a correlated variable as the outer member of a Transact-SQL outer join: select t2.b1, (select t2.b2 from t1 where t2.b1 *= t1.a1) from t2 Earlier versions of Adaptive Server used trace flag 298 to display error messages for these queries. Depending on whether trace flag 298 was turned on or off and whether the query used the correlated variable as an inner or outer member of an outer join, Adaptive Server displayed the behavior described in Table 4-1: Table 4-1: Behavior in earlier versions of Adaptive Server Type of query Trace flag 298 turned off Trace flag 298 turned on Correlated as an inner member of an outer join Disallowed: produces error message 11013 No errorUsing correlated subqueries 150 Adaptive Server Enterprise Adaptive Server reverses the behavior of trace flag 298. Because Adaptive Server version 12.5 translates Transact-SQL outer joins into ANSI outer joins during the preprocessor stage, there is the potential for different results when allowing such queries to run. Allowing correlated subqueries that contain Transact-SQL outer joins to run with the 298 trace flag turned on is consistent with Sybase’s historical trace flag usage. For version 12.5, the behavior of trace flag 298 is: Table 4-2: Behavior in Adaptive Server version 12.5 Adaptive Server has changed error message 301 to error message 11055, although the text of the message remains the same. Correlated subqueries with correlation names You can use a correlated subquery to find the types of books that are published by more than one publisher: select distinct t1.type from titles t1 where t1.type in (select t2.type from titles t2 where t1.pub_id != t2.pub_id) type -------------------- business psychology (2 rows affected) Correlation names are required in the following query to distinguish between the two roles in which the titles table appears. This nested query is equivalent to the self-join query: Correlated as an outer member of an outer join No error Disallowed: produces error message 301 Type of query Trace flag 298 turned off Trace flag 298 turned on Type of query Trace flag 298 turned off Trace flag 298 turned on Correlated as an inner member of an outer join Disallowed: produces error message 11013 Disallowed: produces error message 11013 Correlated as an outer member of an outer join Disallowed: produces error message 11055 No errorCHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 151 select distinct t1.type from titles t1, titles t2 where t1.type = t2.type and t1.pub_id != t2.pub_id Correlated subqueries with comparison operators Expression subqueries can be correlated subqueries. For example, to find the sales of psychology books where the quantity is less than average for sales of that title: select s1.ord_num, s1.title_id, s1.qty from salesdetail s1 where title_id like "PS%" and s1.qty < (select avg(s2.qty) from salesdetail s2 where s2.title_id = s1.title_id) ord_num title_id qty ------------------ -------- --- 91-A-7 PS3333 90 91-A-7 PS2106 30 55-V-7 PS2106 31 AX-532-FED-452-2Z7 PS7777 125 BA71224 PS7777 200 NB-3.142 PS2091 200 NB-3.142 PS7777 250 NB-3.142 PS3333 345 ZD-123-DFG-752-9G8 PS3333 750 91-A-7 PS7777 180 356921 PS3333 200 (11 rows affected) The outer query selects the rows of the sales table (or “s1”) one by one. The subquery calculates the average quantity for each sale being considered for selection in the outer query. For each possible value of s1, Transact-SQL evaluates the subquery and puts the record being considered in the results, if the quantity is less than the calculated average. Sometimes a correlated subquery mimics a group by statement. To find the titles of books that have prices higher than average for books of the same type, the query is: select t1.type, t1.title Using correlated subqueries 152 Adaptive Server Enterprise from titles t1 where t1.price > (select avg(t2.price) from titles t2 where t1.type = t2.type) type title --------- -------------------------------------- business The Busy Executive’s Database Guide business Straight Talk About Computers mod_cook Silicon Valley Gastronomic Treats popular_comp But Is It User Friendly? psychology Computer Phobic and Non-Phobic Individuals: Behavior Variations psychology Prolonged Data Deprivation: Four Case Studies trad_cook Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean (7 rows affected) For each possible value of t1, Transact-SQL evaluates the subquery and includes the row in the results if the price value of that row is greater than the calculated average. It is not necessary to group by type explicitly, because the rows for which the average price is calculated are restricted by the where clause in the subquery. Correlated subqueries in a having clause Quantified predicate subqueries can be correlated subqueries. This example of a correlated subquery in the having clause of an outer query finds the types of books in which the maximum advance is more than twice the average within a given group: select t1.type from titles t1 group by t1.type having max(t1.advance) >= any (select 2 * avg(t2.advance) from titles t2 where t1.type = t2.type) type ---------- mod_cook CHAPTER 4 Subqueries: Using Queries Within Other Queries Transact-SQL User’s Guide 153 (1 row affected) The subquery above is evaluated once for each group that is defined in the outer query, that is, once for each type of book.Using correlated subqueries 154 Adaptive Server EnterpriseTransact-SQL User’s Guide 155 C H A P T E R 5 SQL Derived Tables A SQL derived table is defined by one or more tables through the evaluation of a query expression. A SQL derived table is used in the query expression in which it is defined and exists only for the duration of the query. It is not described in system catalogs or stored on disk. This chapter discusses: Differences from abstract plan derived tables SQL derived tables should not be confused with abstract plan derived tables. An abstract plan derived table is a derived table used in query processing, the optimization and execution of queries. An abstract plan derived table differs from a SQL derived table in that it exists as part of an abstract plan and is invisible to the end user. How SQL derived tables work A SQL derived table is created with a derived table expression consisting of a nested select statement, as in the following example, which returns a list of cities in the publishers table of the pubs2 database: select city from (select city from publishers) cities Topic Page Differences from abstract plan derived tables 155 How SQL derived tables work 155 Advantages of SQL derived tables 156 SQL derived table syntax 157 Using SQL derived tables 160Advantages of SQL derived tables 156 Adaptive Server Enterprise The SQL derived table is named cities and has one column titled city. The SQL derived table is defined by the nested select statement and persists only for the duration of the query, which returns the following: city -------------------- Boston Washington Berkeley Advantages of SQL derived tables A user interested in viewing only the titles of books written in Colorado might create a view like the following: create view vw_colorado_titles as select title from titles, titleauthor, authors where titles.title_id = titleauthor.title_id and titleauthor.au_id = authors.au_id and authors.state = “CO” The view vw_colorado_titles, stored in memory, can be used repeatedly to display its results: select * from vw_colorado_titles Once the view is no longer needed, it is dropped: drop view vw_colorado_titles If the query results are only needed once, the user might instead use a SQL derived table: select title from (select title from titles, titleauthor, authors where titles.title_id = titleauthor.title_id and titleauthor.au_id = authors.au_id and authors.state = “CO”) dt_colo_titles The SQL derived table created is named dt_colo_titles. The SQL derived table persists only for the duration of the query, in contrast with a temporary table, which exists for the entire session.CHAPTER 5 SQL Derived Tables Transact-SQL User’s Guide 157 In the previous example for query results that are only needed once, a view is less desirable than a SQL derived table query because the view is more complicated, requiring both create and drop statements in addition to a select statement. The benefits of creating a view for only one query are additionally offset by the overhead of administrative tasks such as dealing with system catalogs. SQL derived tables eliminate this overhead by enabling queries to spontaneously create non-persistent tables without needing to drop the tables or make insertions into the system catalog. Consequently, no administrative tasks are required. A SQL derived table used multiple times performs comparably to a query using a view with a cached definition. SQL derived tables and optimization Queries expressed as a single SQL statement exploit the optimizer better than queries expressed in two or more SQL statements. SQL derived tables enable one to concisely express in a single step what might otherwise require several SQL statements and temporary tables, especially where intermediate aggregate results must be stored. For example, select dt_1.* from (select sum(total_sales) from titles_west group by total_sales) dt_1(sales_sum), (select sum(total_sales) from titles_east group by total_sales) dt_2(sales_sum) where dt_1.sales_sum = dt_2.sales_sum Here aggregate results are obtained from the SQL derived tables dt_1 and dt_2, and a join is computed between the two SQL derived tables. Everything is accomplished in a single SQL statement. SQL derived table syntax The query expression for a SQL derived table is specified in the from clause of the select or select into command in place of a table or view name: from_clause ::= from table_reference [,table_reference]... table_reference ::= table_view_name | ANSI_joinSQL derived table syntax 158 Adaptive Server Enterprise table_view_name ::= {table_view_reference | derived_table_reference} [holdlock | noholdlock] [readpast] [shared] table_view_reference ::= [[database.]owner.] {table_name | view_name} [[as] correlation_name] [index {index_name | table_name }] [parallel [degree_of_parallelism]] [prefetch size ] [lru | mru] derived_table_reference ::= derived_table [as] correlation_name [’(’ derived_column_list’)’] derived_column_list ::= column_name [’,’ column_name] ... derived_table ::= ’(’ select ’)’ A derived table expression is similar to the select in a create view statement and follows the same rules, with the following exceptions: • Temporary tables are permitted in a derived table expression except when it is part of a create view statement. • A local variable is permitted in a derived table expression except when it is part of a create view statement. You cannot assign a value to a variable within a derived table expression. • A correlation_name, which must follow the derived table expression to specify the name of the SQL derived table, may omit a derived column list, whereas a view cannot have unnamed columns: select * from (select sum(advance) from total_sales) dt For information on view restrictions, refer to "Restrictions on views" in the section describing the create view command. CHAPTER 5 SQL Derived Tables Transact-SQL User’s Guide 159 Derived column lists If a derived column list is not included in a SQL derived table, the names of the SQL derived table columns must match the names of the columns specified in the target list of the derived table expression. If a column name is not specified in the target list of the derived table expression, as in the case where a constant expression or an aggregate is present in the target list of the derived table expression, the resulting column in the SQL derived table has no name. If a derived column list is included in a SQL derived table, it must specify names for all columns in the target list of the derived table expression. These column names must be used in the query block in place of the natural column names of the SQL derived table. The columns must be listed in the order in which they occur in the derived table expression, and a column name cannot be specified more than once in the derived column list. Correlated SQL derived tables Correlated SQL derived tables, which are not ANSI standard, are not supported. For example, the following query is not supported because it references the SQL derived table dt_publishers2 inside the derived table expression for dt_publishers1: select * from (select * from titles where titles.pub_id = dt_publishers2.pub_id) dt_publishers1, (select * from publishers where city = "Boston") dt_publishers2 where dt_publishers1.pub_id = dt_publishers2.pub_id Similarly, the following query is not supported because the derived table expression for dt_publishers references the publishers_pub_id column, which is outside the scope of the SQL derived table: select * from publishers where pub_id in (select pub_id from (select pub_id from titles where pub_id = publishers.pub_id) dt_publishers) The following query illustrates proper referencing and is supported: select * from publishers where pub_id in (select pub_id from (select pub_id from titles)Using SQL derived tables 160 Adaptive Server Enterprise dt_publishers where pub_id = publishers.pub_id) Using SQL derived tables SQL derived tables can be used to form part of a larger integrated query using assorted SQL clauses and operators. Nesting A query can use numerous nested derived table expressions, SQL expressions that define a SQL derived table. In the following example, the innermost derived table expression defines SQL derived table dt_1, the select from which forms the derived table expression defining SQL derived table dt_2. select postalcode from (select postalcode from (select postalcode from authors) dt_1) dt_2 The degree of nesting is limited to 25. Subqueries using SQL derived tables A SQL derived table can be used in a subquery from clause. For example, this query finds the names of the publishers who have published business books: select pub_name from publishers where "business" in (select type from (select type from titles, publishers where titles.pub_id = publishers.pub_id) dt_titles) Here, dt_titles is the SQL derived table defined by the innermost select statement. SQL derived tables can be used in the from clause of subqueries wherever subqueries are legal. For more information on subqueries, see Chapter 4, “Subqueries: Using Queries Within Other Queries”.CHAPTER 5 SQL Derived Tables Transact-SQL User’s Guide 161 Unions A union clause is allowed within a derived table expression. For example, the following query yields the contents of the stor_id and ord_num columns of both the sales and sales_east tables: select * from (select stor_id, ord_num from sales union select stor_id, ord_num from sales_east) dt_sales_info Here, the union of two select operations defines the SQL derived table dt_sales_info. Unions in subqueries A union clause is allowed in a subquery inside a derived table expression. The following example uses a union clause in a subquery within a SQL derived table to list the titles of books sold at stores listed in the sales and sales_east tables: select title_id from salesdetail where stor_id in (select stor_id from (select stor_id from sales union select stor_id from sales_east) dt_stores) Renaming columns with SQL derived tables While a view cannot have unnamed columns, column naming is optional for a SQL derived table. If a derived column list is included for a SQL derived table, it follows the name of the SQL derived table and is enclosed in parentheses, as in the following example: select dt_b.book_title, dt_b.tot_sales from (select title, total_sales from titles) dt_b (book_title, tot_sales) where dt_b.book_title like "%Computer%"Using SQL derived tables 162 Adaptive Server Enterprise Here the column names title and total_sales in the derived table expression are respectively renamed to book_title and tot_sales using the derived column list. The book_title and tot_sales column names are used in the rest of the query. Constant expressions If a column name is not specified in the target list of the derived table expression, as in the case where a constant expression is used for the column name, the resulting column in the SQL derived table has no name: 1> select * from 2> (select title_id, (lorange + hirange)/2 3> from roysched) as dt_avg_range 4> go title_id --------- ----------- BU1032 2500 BU1032 27500 PC1035 1000 PC1035 2500 You can specify column names for the target list of a derived table expression using a derived column list: 1> select * from 2> (select title_id, (lorange + hirange)/2 3> from roysched) as dt_avg_range (title, avg_range) 4> go title avg_range --------- ----------- BU1032 2500 BU1032 27500 PC1035 1000 PC1035 2500 Alternately, you can specify column names by renaming the column in the target list of the derived table expression: 1> select * from 2> (select title_id, (lorange + hirange)/2 avg_range 3> from roysched) as dt_avg_range 4> goCHAPTER 5 SQL Derived Tables Transact-SQL User’s Guide 163 title avg_range --------- ----------- BU1032 2500 BU1032 27500 PC1035 1000 PC1035 2500 Note If you specify column names in both a derived column list and in the target list of the derived table expression, the resulting columns are named by the derived column list. The column names in a derived column list take precedence over the names specified in the target list of the derived table expression. If you use a constant expression within a create view statement, you must specify a column name for the constant expression results. Aggregate functions Derived table expressions may use aggregate functions, such as sum, avg, max, min, and count. The following example selects columns pub_id and adv_sum from the SQL derived table dt_a. The second column is created in the derived table expression using the sum function over the advance column of the titles table. select dt_a.pub_id, dt_a.adv_sum from (select pub_id, sum(advance) adv_sum from titles group by pub_id) dt_a If you use an aggregate function within a create view statement, you must specify a column name for the aggregate results. Joins with SQL derived tables The following example illustrates a join between a SQL derived table and an existing table. The join is specified by the where clause. The two tables joined are dt_c, a SQL derived table, and publishers, an existing table in the pubs2 database. select dt_c.title_id, dt_c.pub_id from (select title_id, pub_id from titles) as dt_c,Using SQL derived tables 164 Adaptive Server Enterprise publishers where dt_c.pub_id = publishers.pub_id The following example illustrates a join between two SQL derived tables. The two tables joined are dt_c and dt_d. select dt_c.title_id, dt_c.pub_id from (select title_id, pub_id from titles) as dt_c, (select pub_id from publishers) as dt_d where dt_c.pub_id = dt_d.pub_id Outer joins involving SQL derived tables are also possible. Sybase supports both left and right outer joins. The following example illustrates a left outer join between two SQL derived tables. select dt_c.title_id, dt_c.pub_id from (select title_id, pub_id from titles) as dt_c, (select title_id, pub_id from publishers) as dt_d where dt_c.title_id *= dt_d.title_id The following example illustrates a left outer join within a derived table expression. select dt_titles.title_id from (select * from titles, titleauthor where titles.title_id *= titleauthor.title_id) dt_titles Creating a table from a SQL derived table Data obtained from a SQL derived table can then be inserted into a new table, as in the following example. select pubdate into pub_dates from (select pubdate from titles) dt_e where pubdate = "450128 12:30:1PM" Here data from the SQL derived table dt_e is inserted into the new table pub_dates.CHAPTER 5 SQL Derived Tables Transact-SQL User’s Guide 165 Using views with SQL derived tables The following example creates a view, view_colo_publishers, using a SQL derived table, dt_colo_pubs, to display publishers based in Colorado: create view view_colo_publishers (Pub_Id, Publisher, City, State) as select pub_id, pub_name, city, state from (select * from publishers where state="CO") dt_colo_pubs Data can be inserted through a view that contains a SQL derived table if the insert rules and permission settings for the derived table expression follow the insert rules and permission settings for the select part of the create view statement. For example, the following insert statement inserts a row through the view_colo_publishers view into the publishers table on which the view is based: insert view_colo_publishers values (’1799’, ’Gigantico Publications’, ’Denver’, ’CO’) You can also update existing data through a view that uses a SQL derived table: update view_colo_publishers set Publisher = "Colossicorp Industries" where Pub_Id = "1699" Note You must specify the column names of the view definition, not the column names of the underlying table. Views that use a SQL derived table are dropped in the standard manner: drop view view_colo_publishers Correlated attributes Correlated attributes that exceed the scope of a SQL derived table cannot be referenced from a SQL derived table expression. For example, the following query will result in an error: select * from publishers where pub_id in (select pub_id from (select pub_id from titlesUsing SQL derived tables 166 Adaptive Server Enterprise where pub_id = publishers.pub_id) dt_publishers) Here, the column publishers.pub_id is referenced in the SQL derived table expression, but it is outside the scope of the SQL derived table dt_publishers.Transact-SQL User’s Guide 167 C H A P T E R 6 Joins: Retrieving Data from Several Tables A join operation compares two or more tables (or views) by specifying a column from each, comparing the values in those columns row by row, and linking the rows that have matching values. It then displays the results in a new table. The tables specified in the join can be in the same database or in different databases. This chapter discusses: You can state many joins as subqueries, which also involve two or more tables. See Chapter 4, “Subqueries: Using Queries Within Other Queries.” When Component Integration Services is enabled, you can perform joins across remote servers. For more information, see the Component Integration Services User’s Guide. Topic Page How joins work 168 How joins are structured 169 How joins are processed 174 Equijoins and natural joins 175 Joins with additional conditions 176 Joins not based on equality 177 Self-joins and correlation names 178 The not-equal join 179 Joining more than two tables 182 Outer joins 184 Transact-SQL outer joins 204 How null values affect joins 207 Determining which table columns to join 208How joins work 168 Adaptive Server Enterprise How joins work When you join two or more tables, the columns being compared must have similar values—that is, values using the same or similar datatypes. There are several types of joins, such as equijoins, natural joins, and outer joins. The most common join, the equijoin, is based on equality. The following join finds the names of authors and publishers located in the same city: select au_fname, au_lname, pub_name from authors, publishers where authors.city = publishers.city au_fname au_lname pub_name -------- -------- -------------------- Cheryl Carson Algodata Infosystems Abraham Bennet Algodata Infosystems (2 rows affected) Because the query draws on information contained in two separate tables, publishers and authors, you need a join to retrieve the requested information. This statement joins the publishers and authors tables using the city column as the link.: where authors.city = publishers.city Join syntax You can embed a join in a select, update, insert, delete, or subquery. Other join restrictions and clauses may follow the join conditions. Joins use the following syntax: start of select, update, insert, delete, or subquery from {table_list | view_list} where [not] [table_name. | view_name.]column_name join_operator [table_name. | view_name.]column_name [{and | or} [not] [table_name.|view_name.]column_name join_operator [table_name.|view_name.]column_name]... End of select, update, insert, delete, or subqueryCHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 169 Joins and the relational model The join operation is the hallmark of the relational model of database management. More than any other feature, the join distinguishes relational database management systems from other types of database management systems. In structured database management systems, often known as network and hierarchical systems, relationships between data values are predefined. Once a database has been set up, it is difficult to make queries about unanticipated relationships among the data. In a relational database management system, on the other hand, relationships among data values are left unstated in the definition of a database. They become explicit when the data is manipulated—when you query the database, not when you create it. You can ask any question that comes to mind about the data stored in the database, regardless of what was intended when the database was set up. According to the rules of good database design, called normalization rules, each table should describe one kind of entity—a person, place, event, or thing. That is why, when you want to compare information about two or more kinds of entities, you need the join operation. Relationships among data stored in different tables are discovered by joining them. A corollary of this rule is that the join operation gives you unlimited flexibility in adding new kinds of data to your database. You can always create a new table that contains data about a different kind of entity. If the new table has a field with values similar to those in some field of an existing table or tables, it can be linked to those other tables by joining. How joins are structured A join statement, like a select statement, starts with the keyword select. The columns named after the select keyword are the columns to be included in the query results, in their desired order. The previous example specified the columns that contained the authors’ names from the authors table, and publishers’ names from the publishers tables: select au_fname, au_lname, pub_name from authors, publishersHow joins are structured 170 Adaptive Server Enterprise You do not have to qualify the columns au_fname, au_lname, and pub_name by a table name because there is no ambiguity about the table to which they belong. But the city column used for the join comparison does need to be qualified, because there are columns of that name in both the authors and publishers tables: select au_fname, au_lname, pub_name from authors, publishers where authors.city = publishers.city Though neither of the city columns is printed in the results, Adaptive Server needs the table name to perform the comparison. To specify that all the columns of the tables involved in the query be included in the results, use an asterisk (*) with select. For example, to include all the columns in authors and publishers in the preceding join query, the statement is: select * from authors, publishers where authors.city = publishers.city au_id au_lname au_fname phone address city state postalcode contract pub_id pub_name city state ----------- -------- -------- ------------ --------------------- ---------- ----- ---------- -------- ------ -------------------- ---------- ----- 238-95-7766 Carson Cheryl 415 548-7723 589 Darwin Ln. Berkeley CA 94705 1 1389 Algodata Infosystems Berkeley CA 409-56-7008 Bennet Abraham 415 658-9932 223 Bateman St Berkeley CA 94705 1 1389 Algodata Infosystems Berkeley CA (2 rows affected) The display shows a total of 2 rows with 13 columns each. Because of the length of the rows, each takes up multiple horizontal lines in this display. Whenever “*” is used, the columns in the results are displayed in the order in which they were stated in the create statement that created the table. The select list and the results of a join need not include columns from both of the tables being joined. For example, to find the names of the authors that live in the same city as one of the publishers, your query need not include any columns from publishers: select au_lname, au_fname from authors, publishers where authors.city = publishers.city CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 171 Remember, just as in any select statement, column names in the select list and table names in the from clause must be separated by commas. The from clause Use the from clause to specify which tables and views to join. This is the clause that indicates to Adaptive Server that a join is desired. You can list the tables or views in any order. The order of tables affects the results displayed only when you use select * to specify the select list. More than two tables or views can be named in the from clause. At most, a query can reference 16 tables. This maximum includes: • Base tables or views listed in the from clause • Each instance of multiple references to the same table (self-joins) • Tables referenced in subqueries • Base tables referenced by the views listed in the from clause • Tables being created with into • Work tables created as a result of the query If the join is part of an update or delete statement, the query can only refer to 15 tables. The following example joins columns from the titles and publishers tables, doubling the price of all books published in California: begin tran update titles set price = price * 2 from titles, publishers where titles.pub_id = publishers.pub_id and publishers.state = "CA" rollback tran See “Joining more than two tables” on page 182 for information on joins involving more than two tables or views. As explained in Chapter 2, “Queries: Selecting Data from a Table,” table or view names can be qualified by the names of the owner and database, and can be given correlation names for convenience. For example: select au_lname, au_fname from pubs2.blue.authors, pubs2.blue.publishers How joins are structured 172 Adaptive Server Enterprise where authors.city = publishers.city You can join views in exactly the same way as tables and use views wherever tables are used. Chapter 10, “Views: Limiting Access to Data” discusses views; this chapter uses only tables in its examples. The where clause Use the where clause to determine which rows are included in the results. where specifies the connection between the tables and views named in the from clause. Be sure to qualify column names if there is ambiguity about the table or view to which they belong. For example: where authors.city = publishers.city This where clause gives the names of the columns to be joined, qualified by table names if necessary, and the join operator—often equality, sometimes “greater than” or “less than.” For details of where clause syntax, see Chapter 2, “Queries: Selecting Data from a Table”. Note You will get unexpected results if you omit the where clause of a join. Without a where clause, any of the join queries discussed so far will produce 69 rows instead of 2. “How joins are processed” on page 174 explains this unexpected result. The where clause of a join statement can include other conditions in addition to the one that links columns from different tables. In other words, you can include a join operation and a select operation in the same SQL statement. See “How joins are processed” on page 174 for an example. Join operators Joins that match columns on the basis of equality are called equijoins. A more precise definition of an equijoin is given under “Equijoins and natural joins” on page 175, along with examples of joins not based on equality. Equijoins use the following comparison operators: CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 173 Table 6-1: Join operators Joins that use the relational operators are collectively called theta joins. Another set of join operators is used for outer joins, also discussed in detail later in this chapter. The outer join operators are Transact-SQL extensions, as shown in Table 6-2: Table 6-2: Outer join operators Datatypes in join columns The columns being joined must have the same or compatible datatypes. Use the convert function when comparing columns whose datatypes cannot be implicitly converted. Columns being joined need not have the same name, although they often do. If the datatypes used in the join are compatible, Adaptive Server automatically converts them. For example, Adaptive Server converts among any of the numeric type columns—int, smallint, tinyint, decimal, or float, and among any of the character type and date columns—char, varchar, unichar, univarchar, nchar, nvarchar, datetime, date and time. For details on datatype conversion, see Chapter 11, “Using the Built-In Functions in Queries,” and the “Datatype Conversion Functions” section of the Reference Manual. Operator Meaning = Equal to > Greater than >= Greater than or equal to < Less than <= Less than or equal to != Not equal to !> Less than or equal to !< Greater than or equal to Operator Action *= Include in the results all the rows from the first table, not just the ones where the joined columns match. =* Include in the results all the rows from the second table, not just the ones where the joined columns match. How joins are processed 174 Adaptive Server Enterprise Joins and text and image columns You cannot use joins for columns containing text or image values. You can, however, compare the lengths of text columns from two tables with a where clause. For example: where datalength(textab_1.textcol) > datalength(textab_2.textcol) How joins are processed Knowing how joins are processed helps to understand them—and to figure out why, when you incorrectly state a join, you sometimes get unexpected results. This section describes the processing of joins in conceptual terms. Adaptive Server’s actual procedure is more sophisticated. Conceptually speaking, the first step in processing a join is to form the Cartesian product of the tables—all the possible combinations of the rows from each of the tables. The number of rows in a Cartesian product of two tables is equal to the number of rows in the first table multiplied by the number of rows in the second table. The Cartesian product of the authors table and the publishers table is 69 (23 authors multiplied by 3 publishers). You can have a look at a Cartesian product with any query that includes columns from more than one table in the select list, more than one table in the from clause, and no where clause. For example, if you leave the where clause off the join used in previous examples, Adaptive Server combines each of the 23 authors with each of the 3 publishers, and returns all 69 rows. This Cartesian product does not contain any particularly useful information. In fact, it is downright misleading, because it implies that every author in the database has a relationship with every publisher in the database—which is not true at all. That is why you must include a where clause in the join, which specifies the columns to be matched and the basis on which to match them. It may also include other restrictions. Once Adaptive Server forms the Cartesian product, it eliminates the rows that do not satisfy the join by using the conditions in the where clause. For example, the where clause in the previous example eliminates from the results all rows in which the author’s city is not the same as the publisher’s city:CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 175 where authors.city = publishers.city Equijoins and natural joins Joins based on equality (=) are called equijoins. Equijoins compare the values in the columns being joined for equality and then include all the columns in the tables being joined in the results. This earlier query is an example of an equijoin: select * from authors, publishers where authors.city = publishers.city In the results of that statement, the city column appears twice. By definition, the results of an equijoin contain two identical columns. Because there is usually no point in repeating the same information, one of these columns can be eliminated by restating the query. The result is called a natural join. The query that results in the natural join of publishers and authors on the city column is: select publishers.pub_id, publishers.pub_name, publishers.state, authors.* from publishers, authors where publishers.city = authors.city The column publishers.city does not appear in the results. Another example of a natural join is: select au_fname, au_lname, pub_name from authors, publishers where authors.city = publishers.city You can use more than one join operator to join more than two tables or to join more than two pairs of columns. These “join expressions” are usually connected with and, although or is also legal. Following are two examples of joins connected by and. The first lists information about books (type of book, author, and title), ordered by book type. Books with more than one author have multiple listings, one for each author. select type, au_lname, au_fname, title from authors, titles, titleauthor where authors.au_id = titleauthor.au_id Joins with additional conditions 176 Adaptive Server Enterprise and titles.title_id = titleauthor.title_id order by type The second finds the names of authors and publishers that are located in the same city and state: select au_fname, au_lname, pub_name from authors, publishers where authors.city = publishers.city and authors.state = publishers.state Joins with additional conditions The where clause of a join query can include selection criteria as well as the join condition. For example, to retrieve the names and publishers of all the books for which advances of more than $7500 were paid, the statement is: select title, pub_name, advance from titles, publishers where titles.pub_id = publishers.pub_id and advance > $7500 title pub_name advance ----------------------------- -------------------- --------- You Can Combat Computer Stress! New Age Books 10,125.00 The Gourmet Microwave Binnet & Hardley 15,000.00 Secrets of Silicon Valley Algodata Infosystems 8,000.00 Sushi, Anyone? Binnet & Hardley 8,000.00 (4 rows affected) The columns being joined (pub_id from titles and publishers) do not need to appear in the select list and, therefore, do not show up in the results. You can include as many selection criteria as you want in a join statement. The order of the selection criteria and the join condition is not important.CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 177 Joins not based on equality The condition for joining the values in two columns does not need to be equality. You can use any of the other comparison operators: not equal (!=), greater than (>), less than (<), greater than or equal to (>=), and less than or equal to (<=). Transact-SQL also provides the operators !> and !<, which are equivalent to <= and >=, respectively. This example of a greater-than join finds New Age authors who live in states that come after New Age Books’ state, Massachusetts, in alphabetical order. select pub_name, publishers.state, au_lname, au_fname, authors.state from publishers, authors where authors.state > publishers.state and pub_name = "New Age Books" pub_name state au_lname au_fname state ------------- ------ -------------- ----------- ----- New Age Books MA Greene Morningstar TN New Age Books MA Blotchet-Halls Reginald OR New Age Books MA del Castillo Innes MI New Age Books MA Panteley Sylvia MD New Age Books MA Ringer Anne UT New Age Books MA Ringer Albert UT (6 rows affected) The following example uses a >= join and a < join to look up the correct royalty from the roysched table, based on the book’s total sales. select t.title_id, t.total_sales, r.royalty from titles t, roysched r where t.title_id = r.title_id and t.total_sales >= r.lorange and t.total_sales < r.hirange title_id total_sales royalty -------- ----------- ------- BU1032 4095 10 BU1111 3876 10 BU2075 1872 24 BU7832 4095 10 MC2222 2032 12 MC3021 22246 24 PC1035 8780 16 PC8888 4095 10 PS1372 375 10 PS2091 2045 12 Self-joins and correlation names 178 Adaptive Server Enterprise PS2106 111 10 PS3333 4072 10 PS7777 3336 10 TC3218 375 10 TC4203 15096 14 TC7777 4095 10 (16 rows affected) Self-joins and correlation names Joins that compare values within the same column of one table are called selfjoins. To distinguish the two roles in which the table appears, use aliases, or correlation names. For example, you can use a self-join to find out which authors in Oakland, California, live in the same postal code area. Since this query involves a join of the authors table with itself, the authors table appears in two roles. To distinguish these roles, you can temporarily and arbitrarily give the authors table two different correlation names—such as au1 and au2—in the from clause. These correlation names qualify the column names in the rest of the query. The self-join statement looks like this: select au1.au_fname, au1.au_lname, au2.au_fname, au2.au_lname from authors au1, authors au2 where au1.city = "Oakland" and au2.city = "Oakland" and au1.state = "CA" and au2.state = "CA" and au1.postalcode = au2.postalcode au_fname au_lname au_fname au_lname --------- ----------- -------- -------- Marjorie Green Marjorie Green Dick Straight Dick Straight Dick Straight Dirk Stringer Dick Straight Livia Karsen Dirk Stringer Dick Straight Dirk Stringer Dirk Stringer Dirk Stringer Livia Karsen Stearns MacFeather Stearns MacFeather Livia Karsen Dick Straight Livia Karsen Dirk Stringer Livia Karsen Livia Karsen CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 179 (11 rows affected) List the aliases in the from clause in the same order as you refer to them in the select list, as in this example. Depending on the query, the results may be ambiguous if you list them in a different order. To eliminate the rows in the results where the authors match themselves, and are identical except that the order of the authors is reversed, you can make this addition to the self-join query: select au1.au_fname, au1.au_lname, au2.au_fname, au2.au_lname from authors au1, authors au2 where au1.city = "Oakland" and au2.city = "Oakland" and au1.state = "CA" and au2.state = "CA" and au1.postalcode = au2.postalcode and au1.au_id < au2.au_id au_fname au_lname au_fname au_lname --------- ----------- --------- --------- Dick Straight Dirk Stringer Dick Straight Livia Karsen Dirk Stringer Livia Karsen (3 rows affected) It is now clear that Dick Straight, Dirk Stringer, and Livia Karsen all have the same postal code. The not-equal join The not-equal join is particularly useful in restricting the rows returned by a self-join. In the following example, a not-equal join and a self-join find the categories in which there are two or more inexpensive (less than $15) books of different prices: select distinct t1.type, t1.price from titles t1, titles t2 where t1.price < $15 and t2.price < $15 and t1.type = t2.type and t1.price != t2.price type price ---------- ----- business 2.99 The not-equal join 180 Adaptive Server Enterprise business 11.95 psychology 7.00 psychology 7.99 psychology 10.95 trad_cook 11.95 trad_cook 14.99 (7 rows affected) The expression “not column_name = column_name” is equivalent to “column_name != column_name.” The following example uses a not-equal join, combined with a self-join. It finds all the rows in the titleauthor table where there are two or more rows with the same title_id, but different au_id numbers that is, books which have more than one author. select distinct t1.au_id, t1.title_id from titleauthor t1, titleauthor t2 where t1.title_id = t2.title_id and t1.au_id != t2.au_id order by t1.title_id au_id title_id ----------- -------- 213-46-8915 BU1032 409-56-7008 BU1032 267-41-2394 BU1111 724-80-9391 BU1111 722-51-5454 MC3021 899-46-2035 MC3021 427-17-2319 PC8888 846-92-7186 PC8888 724-80-9391 PS1372 756-30-7391 PS1372 899-46-2035 PS2091 998-72-3567 PS2091 267-41-2394 TC7777 472-27-2349 TC7777 672-71-3249 TC7777 (15 rows affected) For each book in titles, the following example finds all other books of the same type that have a different price: select t1.type, t1.title_id, t1.price, t2.title_id, t2.price from titles t1, titles t2 CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 181 where t1.type = t2.type and t1.price != t2.price Be careful when interpreting the results of a not-equal join. For example, it would be easy to think you could use a not-equal join to find the authors who live in a city where no publisher is located: select distinct au_lname, authors.city from publishers, authors where publishers.city != authors.city However, this query finds the authors who live in a city where no publishers are located, which is all of them. The correct SQL statement is a subquery: select distinct au_lname, authors.city from publishers, authors where authors.city not in (select city from publishers where authors.city = publishers.city) Not-equal joins and subqueries Sometimes a not-equal join query is not sufficiently restrictive and needs to be replaced by a subquery. For example, suppose you want to list the names of authors who live in a city where no publisher is located. For the sake of clarity, let us also restrict this query to authors whose last names begin with “A”, “B”, or “C”. A not-equal join query might be: select distinct au_lname, authors.city from publishers, authors where au_lname like "[ABC]%" and publishers.city != authors.city The results are not an answer to the question that was asked: au_lname city ---------------- ------------ Bennet Berkeley Carson Berkeley Blotchet-Halls Corvallis (3 rows affected) The system interprets this version of the SQL statement to mean: “find the names of authors who live in a city where some publisher is not located.” All the excluded authors qualify, including the authors who live in Berkeley, home of the publisher Algodata Infosystems. Joining more than two tables 182 Adaptive Server Enterprise In this case, the way that the system handles joins (first finding every eligible combination before evaluating other conditions) causes this query to return undesirable results. You must use a subquery to get the results you want. A subquery can eliminate the ineligible rows first and then perform the remaining restrictions. Here is the correct statement: select distinct au_lname, city from authors where au_lname like "[ABC]%" and city not in (select city from publishers where authors.city = publishers.city) Now, the results are what you want: au_lname city ------------- ------------ Blotchet-Halls Corvallis (1 row affected) Subqueries are covered in greater detail in Chapter 4, “Subqueries: Using Queries Within Other Queries.” Joining more than two tables The titleauthor table of pubs2 offers a good example of a situation in which joining more than two tables is helpful. To find the titles of all the books of a particular type and the names of their authors, the query is: select au_lname, au_fname, title from authors, titles, titleauthor where authors.au_id = titleauthor.au_id and titles.title_id = titleauthor.title_id and titles.type = "trad_cook" au_lname au_fname title -------------- ----------- ------------------------ Panteley Sylvia Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean Blotchet-Halls Reginald Fifty Years in Buckingham PalaceCHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 183 Kitchens O’Leary Michael Sushi, Anyone? Gringlesby Burt Sushi, Anyone? Yokomoto Akiko Sushi, Anyone? (5 rows affected) Notice that one of the tables in the from clause, titleauthor, does not contribute any columns to the results. Nor do any of the columns that are joined—au_id and title_id—appear in the results. Nonetheless, this join is possible only by using titleauthor as an intermediate table. You can also join more than two pairs of columns in the same statement. For example, here is a query that shows the title_id, its total sales and the range in which they fall, and the resulting royalty: select titles.title_id, total_sales, lorange, hirange, royalty from titles, roysched where titles.title_id = roysched.title_id and total_sales >= lorange and total_sales < hirange title_id total_sales lorange hirange royalty -------- ----------- ------- ------- ------- BU1032 4095 0 5000 10 BU1111 3876 0 4000 10 BU2075 18722 14001 50000 24 BU7832 4095 0 5000 10 MC2222 2032 2001 4000 12 MC3021 2224 12001 50000 24 PC1035 8780 4001 10000 16 PC8888 4095 0 5000 10 PS1372 375 0 10000 10 PS2091 2045 1001 5000 12 PS2106 111 0 2000 10 PS3333 4072 0 5000 10 PS7777 3336 0 5000 10 TC3218 375 0 2000 10 TC4203 15096 8001 16000 14 TC7777 4095 0 5000 10 (16 rows affected) When there is more than one join operator in the same statement, either to join more than two tables or to join more than two pairs of columns, the “join expressions” are almost always connected with and, as in the earlier examples. However, it is also legal to connect them with or. Outer joins 184 Adaptive Server Enterprise Outer joins Joins that include all rows, regardless of whether there is a matching row, are called outer joins. Adaptive Server supports both left and right outer joins. For example, the following query joins the titles and the titleauthor tables on their title_id column: select * from titles, titleauthor where titles.title_id *= titleauthor.title_id Sybase supports both Transact-SQL and ANSI outer joins. Transact-SQL outer joins (shown in the previous example) use the *= command to indicate a left outer join and the =* command to indicate a right outer join. Transact-SQL outer joins were created by Sybase as part of the Transact-SQL language. See “Transact-SQL outer joins” on page 204 for more information about TransactSQL outer joins. ANSI outer joins use the keywords left join and right join to indicate a left and right join, respectively. Sybase implemented the ANSI outer join syntax to fully comply with the ANSI standard. See “ANSI Inner and outer joins” on page 186 for more information about ANSI outer joins. This is the previous example rewritten as an ANSI outer join: select * from titles left join titleauthor on titles.title_id = titleauthor.title_id Inner and outer tables The terms outer table and inner table describe the placement of the tables in an outer join: • In a left join, the outer table and inner table are the left and right tables respectively. The outer table and inner table are also referred to as the rowpreserving and null-supplying tables, respectively. • In a right join, the outer table and inner table are the right and left tables respectively. For example, in the queries below, T1 is the outer table and T2 is the inner table: T1 left join T2 T2 right join T1 Or, using Transact-SQL syntax:CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 185 T1 *= T2 T2 =* T1 Outer join restrictions If a table is an inner member of an outer join, it cannot participate in both an outer join clause and a regular join clause. The following query fails because the salesdetail table is part of both the outer join and a regular join clause: select distinct sales.stor_id, stor_name, title from sales, stores, titles, salesdetail where qty > 500 and salesdetail.title_id =* titles.title_id and sales.stor_id = salesdetail.stor_id and sales.stor_id = stores.stor_id Msg 303, Level 16, State 1: Server ’FUSSY’, Line 1: The table ’salesdetail’ is an inner member of an outerjoin clause. This is not allowed if the table also participates in a regular join clause. If you want to know the name of the store that sold more than 500 copies of a book, you would have to use a second query. If you submit a query with an outer join and a qualification on a column from the inner table of the outer join, the results may not be what you expect. The qualification in the query does not restrict the number of rows returned, but rather affects which rows contain the null value. For rows that do not meet the qualification, a null value appears in the inner table’s columns of those rows. Views used with outer joins If you define a view with an outer join, and then query the view with a qualification on a column from the inner table of the outer join, the results may not be what you expect. The query returns all rows from the inner table. Rows that do not meet the qualification show a NULL value in the appropriate columns of those rows. The following rules determine what types of updates you can make to columns through join views: • delete statements are not allowed on join views. • insert statements are not allowed on join views created with check option.Outer joins 186 Adaptive Server Enterprise • update statements are allowed on join views with check option. The update fails if any of the affected columns appears in the where clause, in an expression that includes columns from more than one table. • If you insert or update a row through a join view, all affected columns must belong to the same base table. ANSI Inner and outer joins This is the ANSI syntax for joining tables: left_table [inner | left [outer] | right [outer]] join right_table on left_column_name = right_column_name The result of the join between the left and the right tables is called a joined table. Joined tables are defined in the from clause. For example: select titles.title_id, title, ord_num, qty from titles left join salesdetail on titles.title_id = salesdetail.title_id title_id title ord_num qty ----------------------------- -------------------- --- -- BU1032 The Busy Executive AX-532-FED-452-2Z7 200 BU1032 The Busy Executive NF-123-ADS-642-9G3 1000 . . . TC7777 Sushi, Anyone? ZD-123-DFG-752-9G8 1500 TC7777 Sushi, Anyone? XS-135-DER-432-8J2 1090 (118 rows affected) ANSI join syntax allows you to write either: • Inner joins, in which the joined table includes only the rows of the inner and outer tables that meet the conditions of the on clause. For information, see “ANSI inner joins” on page 189. The result set of a query that includes an inner join does not include any null-supplied rows for the rows of the outer table that do not meet the conditions of the on clause.CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 187 • Outer joins, in which the joined table includes all the rows from the outer table whether or not they meet the conditions of the on clause. If a row does not meet the conditions of the on clause, values from the inner table are stored in the joined table as null values. The where clause of an ANSI outer join restricts the rows that are included in the query result. For more information, see “ANSI outer joins” on page 192. Note You can also use ANSI syntax to join views. Sybase ANSI join syntax does not support the using clause. Correlation name and column referencing rules for ANSI joins The following are the correlation name and column reference rules specifically for ANSI joins. For more information about correlation names, see “Self-joins and correlation names” on page 178. • If a table or view uses a correlation name reference to the column or view it must always use the same correlation name, rather than the table name or view name. That is, you cannot name a table in a query with a correlation name and then use its table name later. The following example correctly uses the correlation name t to specify the table where its pub_id column is specified: select title, t.pub_id, pub_name from titles t left join publishers p on t.pub_id = p.pub_id However, the following example incorrectly uses the table name instead of the correlation name for the titles table (t.pub_id) in the on clause of the query and produces the subsequent error message: select title, t.pub_id, pub_name from titles t left join publishers p on titles.pub_id = p.pub_id Msg 107, Level 15, State 1: Server ‘server_name’, Line 1: The column prefix ‘t’ does not match with a table name or alias name used in the query. Either the table is not specified in the FROM clause or it has a correlation name which must be used instead. • The restriction specified in the on clause can reference: • Columns that are specified in the joined table’s referenceOuter joins 188 Adaptive Server Enterprise • Columns that are specified in joined tables that are contained in the ANSI join (for example, in a nested join) • Correlation names in subqueries for tables specified in outer query blocks • The condition specified in the on clause cannot reference columns that are introduced in ANSI joins that contain another ANSI join (typically when the joined table produced by the second join is joined with the first join). Here is an example of an illegal column reference that produces an error: select * from titles left join titleauthor on titles.title_id=roysched.title_id /*join #1*/ left join roysched on titleauthor.title_id=roysched.title_id /*join #2*/ where titles.title_id != "PS7777" The first left join cannot reference the roysched.title_id column because this column is not introduced until the second join. You can correctly rewrite this query as: select * from titles left join (titleauthor left join roysched on titleauthor.title_id = roysched.title_id) /*join #1*/ on titles.title_id = roysched.title_id /*join #2*/ where titles.title_id != "PS7777" And another example: select title, price, titleauthor.au_id, titleauthor.title_id, pub_name, publishers.city from roysched, titles left join titleauthor on roysched.title_id=titleauthor.title_id left join authors on titleauthor.au_id=roysched.au_id, publishers In this query, neither the roysched table or the publishers table are part of either left join. Because of this, neither left join can refer to columns in either the roysched or publishers tables as part of their on clause condition.CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 189 ANSI inner joins Joins that produce a result set that includes only the rows of the joining tables that meet the restriction are called inner joins. Rows that do not meet the join restriction are not included in the joined table. If you require the joined table to include all the rows from one of the tables, regardless of whether they meet the restriction, use an outer join. See “ANSI outer joins” on page 192, for more information. Adaptive Server supports the use of both Transact-SQL inner joins and ANSI inner joins. Queries using Transact-SQL inner joins separate the tables being joined by commas and list the join comparisons and restrictions in the where clause. For example: select au_id, titles.title_id, title, price from titleauthor, titles where titleauthor.title_id = titles.title_id and price > $15 For information about writing Transact-SQL inner joins, see “How joins are structured” on page 169. ANSI-standard inner joins syntax is: select select_list from table1 inner join table2 on join_condition For example, the following use of inner join is equivalent to the Transact SQL join above: select au_id, titles.title_id, title, price from titleauthor inner join titles on titleauthor.title_id = titles.title_id and price > 15 au_id title_id title price ---------- -------- ------------------------ -- --- 213-46-8915 BU1032 The Busy Executive’s Datab 19.99 409-56-7008 BU1032 The Busy Executive’s Datab 19.99 . . . 172-32-1176 PS3333 Prolonged Data Deprivation 19.99 807-91-6654 TC3218 Onions, Leeks, and Garlic: 20.95 (11 rows affected) The two methods of writing joins, ANSI or Transact-SQL, are equivalent. For example, there is no difference between the result sets produced by the following queries:Outer joins 190 Adaptive Server Enterprise select title_id, pub_name from titles, publishers where titles.pub_id = publishers.pub_id and select title_id, pub_name from titles left join publishers on titles.pub_id = publishers.pub_id An inner join can be part of an update or delete statement. For example, the following query multiplies the price for all the titles published in California by 1.25: begin tran update titles set price = price * 1.25 from titles inner join publishers on titles.pub_id = publishers.pub_id and publishers.state = "CA" The join table of an inner join An ANSI join specifies which tables or views to join in the query. The table references specified in the ANSI join comprise the joined table. For example, the join table of the following query includes the title, price, advance, and royaltyper columns: select title, price, advance, royaltyper from titles inner join titleauthor on titles.title_id = titleauthor.title_id title price advance royaltyper ----------- ------- ---------- ---------- The Busy... 19.99 5,000.00 40 The Busy... 19.99 5,000.00 60 . . . Sushi, A... 14.99 8,000.00 30 Sushi, A... 14.99 8,000.00 40 (25 rows affected) If a joined table is used as a table reference in an ANSI inner join, it becomes a nested inner join. ANSI nested inner joins follow the same rules as ANSI outer joins. A query can reference a maximum of 50 user tables (or 14 work tables) on each side of a union, including: • Base tables or views listed in the from clauseCHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 191 • Each correlated reference to the same table (self-join) • Tables referenced in subqueries • Base tables referenced by the views or nested views • Tables being created with into The on clause of an ANSI inner join The on clause of an ANSI inner join specifies the conditions used when the tables or views are joined. Although you can join on any column of a table, your performance may be better if these columns are indexed. Often, you must use qualifiers (table or correlation names) to uniquely identify the columns and the tables to which they belong. For example: from titles t left join titleauthor ta on t.title_id = ta.title_id This on clause eliminates rows from both tables where there is no matching title_id. For more information about correlation names, see “Self-joins and correlation names” on page 178. The on clause often compares the ANSI joins tables, as in the third and fourth line of the following query: select title, price, pub_name from titles inner join publishers on titles.pub_id = publishers.pub_id and total_sales > 300 The join restriction specified in this on clause removes all rows from the join table that do not have sales greater than 300. The on clause can also specify search arguments, as illustrated in the fourth line of the query. ANSI inner joins restrict the result set similarly whether the condition is placed in the on clause or the where clause (unless they are nested in an outer join). That is, the following queries produce the same result sets: select stor_name, stor_address, ord_num, qty from salesdetail inner join stores on salesdetail.stor_id = stores.stor_id where qty > 3000 and select stor_name, stor_address, ord_num, qty from salesdetail inner join stores on salesdetail.stor_id = stores.stor_id and qty > 3000Outer joins 192 Adaptive Server Enterprise A query is usually more readable if the restriction is placed in the where clause; this explicitly tells users which rows of the join table are included in the result set. ANSI outer joins Joins that produce a joined table that includes all rows from the outer table, regardless of whether the on clause produces matching rows or not, are called outer joins. Inner joins and equijoins produce a result set that includes only the rows from the tables where there are matching values in the join clause. There are times, however, when you want to include not only the matching rows, but also the rows from one of the tables where there are no matching rows in the second table. This type of join is an outer join. In an outer join, rows that do not meet the on clause conditions are included in the joined table with nullsupplied values for the inner table of the outer join. The inner table is also referred to as the null-supplying member. The roles of the inner and outer tables are described in Figure 4-1:CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 193 Figure 6-1: The roles of an outer and inner table in an outer join Sybase recommends that applications use ANSI outer joins because they unambiguously specify whether the on or where clause contains the predicate. This section discusses only the ANSI outer joins; for information about Transact-SQL outer joins, see “Transact-SQL outer joins” on page 204. Note Queries that contain ANSI outer joins cannot contain Transact-SQL outer joins, and vice versa. However, a query with ANSI outer joins can reference a view that contains a Transact-SQL outer join, and vice versa. ANSI outer join syntax is: select select_list from table1 {left | right} [outer] join table2 on predicate [join restriction]Outer joins 194 Adaptive Server Enterprise Left joins retain all the rows of the table reference listed on the left of the join clause; right joins retain all the rows of the table reference on the right of the join clause. In left joins, the left table reference is referred to as the outer table or row-preserving table. The following example determines the authors who live in the same city as their publishers: select au_fname, au_lname, pub_name from authors left join publishers on authors.city = publishers.city au_fname au_lname pub_name --------- ---------- ------------- Johnson White NULL Marjorie Green NULL Cheryl Carson Algodata Infosystems . . . Abraham Bennet Algodata Infosystems . . . Anne Ringer NULL Albert Ringer NULL (23 rows affected) The result set contains all the authors from the authors table. The authors who do not live in the same city as their publishers produce null values in the pub_name column. Only the authors who live in the same city as their publishers, Cheryl Carson and Abraham Bennet, produce a non-null value in the pub_name column. You can rewrite a left outer join as a right outer join by reversing the placement of the tables in the from clause. Also, if the select statement specifies “select *”, you must write an explicit list of all the column names, otherwise the columns in the result set may not be in the same order for the rewritten query. Here is the previous example rewritten as a right outer join, which produces the same result set as the left outer join above: select au_fname, au_lname, pub_name from publishers right join authors on authors.city = publishers.cityCHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 195 Should the predicate be in the on or where clause? The result set of an ANSI outer join depends on whether you place the restriction in the on or the where clause. The on clause defines the result set of a joined table and which rows of this joined table have null-supplied values; the where clause defines which rows of the joined table are included in the result set. Whether you use an on or a where clause in your join condition depends on what you want your result set to include. The following examples may help you decide whether to place the predicate in the on or the where clause. Predicate restrictions on an outer table The following query places a restriction on the outer table in the where clause. Because the restriction is applied to the result of the outer join, it removes all the rows for which the condition is not true: select title, titles.title_id, price, au_id from titles left join titleauthor on titles.title_id = titleauthor.title_id where titles.price > $20.00 title title_id price au_id ------------------- -------- ---------- ----------------- But Is It User F... PC1035 22.95 238-95-7766 Computer Phobic ... PS1372 21.59 724-80-9391 Computer Phobic ... PS1372 21.59 756-30-7391 Onions, Leeks, a... TC3218 20.95 807-91-6654 (4 rows affected) Four rows meet the criteria and only these are included in the result set. However, if you move this restriction on the outer table to the on clause, the result set includes all the rows that meet the on clause condition. Rows from the outer table that do not meet the condition are null-extended: select title, titles.title_id, price, au_id from titles left join titleauthor on titles.title_id = titleauthor.title_id and titles.price > $20.00 title title_id price au_id -------------------- --------- ------ --------------- The Busy Executive’s BU1032 19.99 NULL Cooking with Compute BU1111 11.95 NULL You Can Combat Compu BU2075 2.99 NULL Straight Talk About BU7832 19.99 NULL Silicon Valley Gastro MC2222 19.99 NULL The Gourmet Microwave MC3021 2.99 NULL The Psychology of Com MC3026 NULL NULL But Is It User Friend PC1035 22.95 238-95-7766Outer joins 196 Adaptive Server Enterprise Secrets of Silicon Va PC8888 20.00 NULL Net Etiquette PC9999 NULL NULL Computer Phobic and PS1372 21.59 724-80-9391 Computer Phobic and PS1372 21.59 756-30-7391 Is Anger the Enemy? PS2091 10.95 NULL Life Without Fear PS2106 7.00 NULL Prolonged Data Depri PS3333 19.99 NULL Emotional Security: PS7777 7.99 NULL Onions, Leeks, and Ga TC3218 20.95 807-91-6654 Fifty Years in Buckin TC4203 11.95 NULL Sushi, Anyone? TC7777 14.99 NULL (19 rows affected) Moving the restriction to the on clause added 15 null-supplied rows to the result set. Generally, if your query uses a restriction on an outer table, and you want the result set to remove only the rows for which the restriction is false, you should probably place the restriction in the where clause to limit the rows of the result set. Outer table predicates are not used for index keys if they are in the on clause. Whether you place the restriction on an outer table in the on or where clause ultimately depends on the information you need the query to return. If you only want the result set to include only the rows for which the restriction is true, you should place the restriction in the where clause. However if you require the result set to include all the rows of the outer table, regardless of whether they satisfy the restriction, you should place the restriction in the on clause. Restrictions on an inner table The following query includes a restriction on an inner table in the where clause: select title, titles.title_id, titles.price, au_id from titleauthor left join titles on titles.title_id = titleauthor.title_id where titles.price > $20.00 title title_id price au_id ------------- -------- ----- ----------- But Is It U... PC1035 22.95 238-95-7766 Computer Ph... PS1372 21.59 724-80-9391 Computer Ph... PS1372 21.59 756-30-7391 Onions, Lee... TC3218 20.95 807-91-6654 (4 rows affected)CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 197 Because the restriction of the where clause is applied to the result set after the join is made, it removes all the rows for which the restriction is not true. Put another way, the where clause is not true for all null-supplied values and removes them. A join that places its restriction in the where clause is effectively an inner join. However, if you move the restriction to the on clause, it is applied during the join and is utilized in the production of the joined table. In this case, the result set includes all the rows of the inner table for which the restriction is true, plus all the rows of the outer table, which are null-extended if they do not meet the restriction criteria: select title, titles.title_id, price, au_id from titleauthor left join titles on titles.title_id = titleauthor.title_id and price > $20.00 title title_id price au_id --------- --------- ----------- ----------- NULL NULL NULL 172-32-1176 NULL NULL NULL 213-46-8915 . . . Onions, TC3218 20.95 807-91-6654 . . . NUL NULL NULL 998-72-3567 NULL NULL NULL 998-72-3567 (25 rows affected) This result set includes 21 rows that the previous example did not include. Generally, if your query requires a restriction on an inner table (for example “and price > $20.00” in query above), you probably want to place the condition in the on clause; this preserves the rows of the outer table. If you include a restriction for an inner table in the where clause, the result set might not include the rows of the outer table. Like the criteria for the placement of a restriction on an outer table, whether you place the restriction for an inner table in the on or where clause ultimately depends on the result set you want. If you are interested only in the rows for which the restriction is true, and not including the full set of rows for the outer table, place the restriction in the where clause. However, if you require the result set to include all the rows of the outer table, regardless of whether they satisfy the restriction, you should place the restriction in the on clause. Restrictions included in both an inner and outer table The restriction in the where clause of the following query includes both the inner and outer tables: select title, titles.title_id, price, price*qty, qty Outer joins 198 Adaptive Server Enterprise from salesdetail left join titles on titles.title_id = salesdetail.title_id where price*qty > $30000.00 title title_id price qty ----------------- -------- ----- --------- ----- Silicon Valley Ga MC2222 19.99 40,619.68 2032 But Is It User Fr PC1035 22.95 45,900.00 2000 But Is It User Fr PC1035 22.95 45,900.00 2000 But Is It User Fr PC1035 22.95 49,067.10 2138 Secrets of Silico PC8888 20.00 40,000.00 2000 Prolonged Data De PS3333 19.99 53,713.13 2687 Fifty Years in Bu TC4203 11.95 32,265.00 2700 Fifty Years in Bu TC4203 11.95 41,825.00 3500 (8 rows affected) Placing the restriction in the where clause eliminates the following rows from the result set: • The rows for which the restriction “price*qty>$30000.0” is false • The rows for which the restriction “price*qty>$30000.0” is unknown because price is null To keep the unmatched rows of the outer table, move the restriction into the on clause, as in this example: select title, titles.title_id, price, price*qty, qty from salesdetail left join titles on titles.title_id = salesdetail.title_id and price*qty > $30000.00 title title_id price qty ----------------- -------- ----- --------- ----- NULL NULL NULL NULL 75 NULL NULL NULL NULL 75 . . . Secrets of Silico PC8888 20.00 40,000.00 2000 . . . NULL NULL NULL NULL 300 NULL NULL NULL NULL 400 (116 rows affected) This query retains all 116 rows of the salesdetail table in the result set, and nullextends the rows that do not meet the restriction.CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 199 Where you place the restriction that includes both the inner and outer table depends on the result set you want. If you are interested in only the rows for which the restriction is true, place the restriction in the where clause. However, if you want to include all the rows of the outer table, regardless of whether they satisfy the restriction, place the restriction in the on clause. Nested ANSI outer joins Nested outer joins use the result set of one outer join as the table reference for another. For example: select t.title_id, title, ord_num, sd.stor_id, stor_name from (salesdetail sd left join titles t on sd.title_id = t.title_id) /*join #1*/ left join stores on sd.stor_id = stores.stor_id /*join #2*/ title_id title ord_num stor_id stor_name -------- ------------ ------- ------- ------------------------ TC3218 Onions, L... 234518 7896 Fricative Bookshop TC7777 Sushi, An... 234518 7896 Fricative Bookshop . . . TC4203 Fifty Yea... 234518 6380 Eric the Read Books MC3021 The Gourmet... 234518 6380 Eric the Read Books (116 rows affected) In this example, the joined table between the salesdetail and titles tables is logically produced first and is then joined with the columns of the stores table where salesdetail.stor_id equals stores.stor_id. Semantically, each level of nesting in a join creates a joined table and is then used for the next join. In the query above, because the first outer join becomes an operator of the second outer join, this query is a left-nested outer join. This example shows a right nested outer join: select stor_name, qty, date, sd.ord_num from salesdetail sd left join (stores /*join #1 */ left join sales on stores.stor_id = sales.stor_id) /*join #2 */ on stores.stor_id = sd.stor_id where date > "1/1/1990" stor_name qty date ord_num ------------ ---- ------------------ -------------------- News & Brews 200 Jun 13 1990 12:00AM NB-3.142 News & Brews 250 Jun 13 1990 12:00AM NB-3.142 News & Brews 345 Jun 13 1990 12:00AM NB-3.142 . . .Outer joins 200 Adaptive Server Enterprise Thoreau Read 1005 Mar 21 1991 12:00AM ZZ-999-ZZZ-999-0A0 Thoreau Read 2500 Mar 21 1991 12:00AM AB-123-DEF-425-1Z3 Thoreau Read 4000 Mar 21 1991 12:00AM AB-123-DEF-425-1Z3 In this example, the second join (between the stores and the sales tables) is logically produced first, and is joined with the salesdetail table. Because the second outer join is used as the table reference for the first outer join, this query is a right-nested outer join. If the on clause for the first outer join (“from salesdetail. . .”) fails, it supplies null values to both the stores and sales tables in the second outer join. Parentheses in nested outer joins Nested outer joins produce the same result set with or without parenthesis. Large queries with many outer joins can be much more readable for users if the joins are structured using parentheses. The on clause in nested outer joins The placement of the on clause in a nested outer join determines which join is logically processed first. Reading from left to right, the first on clause is the first join to be defined. In this example, the position of the on clause in the first join (in parentheses indicates that it is the table reference for the second join, so it is defined first, producing the table reference to be joined with the authors table: select title, price, au_fname, au_lname from (titles left join titleauthor on titles.title_id = titleauthor.title_id) /*join #1*/ left join authors on titleauthor.au_id = authors.au_id /*join #2*/ and titles.price > $15.00 title price au_fname au_lname --------------- --------- ------------ ------------- The Busy Exe... 19.99 Marjorie Green The Busy Exe... 19.99 Abrahame Bennet . . . Sushi, Anyon... 14.99 Burt Gringlesby Sushi, Anyon... 14.99 Akiko Yokomoto (26 rows affected) However, if the on clauses are in different locations, the joins are evaluated in a different sequence, but still produce the same result set (this is for explanatory purposes only; if joined tables are logically produced in a different order, it is highly unlikely that they will produce the same result set):CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 201 select title, price, au_fname, au_lname from titles left join (titleauthor left join authors on titleauthor.au_id = authors.au_id) /*join #2*/ on titles.title_id = titleauthor.title_id /*join #1*/ and au_lname like “Yokomoto” title price au_fname au_lname ---------------------- ------- ----------- ----------- The Busy Executive’s 19.99 Marjorie Green The Busy Executive’s 19.99 Abraham Bennet . . . Sushi, Anyone? 14.99 Burt Gringlesby Sushi, Anyone? 14.99 Akiko Yokomoto (26 rows affected) The position of the on clause of the first join (the last line of the query) indicates that the second left join is a table reference of the first join, so it is performed first. That is, the result of the second left join is joined with the titles table. Converting outer joins with join-order dependency Almost all Transact-SQL outer joins written for earlier versions of Adaptive Server that are run on a version 12.0 and later Adaptive Server produce the same result set. However, there is a category of outer join queries whose result sets depend on the join order chosen during optimization. Depending on where in the query the predicate is evaluated, these queries may produce different result sets when they are issued using the current version of Adaptive Server. The result sets they return are determined by the ANSI rules for assigning predicates to joins. Predicates cannot be evaluated until all the tables they reference are processed. That is, in the following query the predicate “and titles.price > 20” cannot be evaluated until the titles table is processed: select title, price, au_ord from titles, titleauthor where titles.title_id *= titleauthor.title_id and titles.price > 20 Predicates in earlier versions of Adaptive Server were evaluated according to the following semantics:Outer joins 202 Adaptive Server Enterprise • If the predicate was evaluated on the inner table of an outer join, the predicate had on clause semantics. • If the predicate was evaluated with a table that is outer to all outer joins, or is join-order independent, the predicate had where clause semantics. Note Before you run Adaptive Server in a production environment, make sure you start it with traceflag 4413 and run any queries that you think may be join-order dependent in pre-12.0 versions of Adaptive Server. Adaptive Server started with trace flag 4413 issues a message similar to the following when you run a query that is join-order dependent in a pre-12.0 version of Adaptive Server: Warning: The results of the statement on line %d are join-order independent. Results may differ on pre- 12.0 releases, where the query is potentially joinorder dependent. Make sure you resolve dependencies your applications have on result sets of join-order queries produced by pre-12.0 Adaptive Server. When do join-order dependent outer joins affect me? Generally, you will not have any problem from join-order dependent queries because predicates typically only reference: • An outer table, which is evaluated using where clause semantics • An inner table, which is evaluated using on clause semantics • The inner table and tables upon which the inner table is dependent These do not produce join-order dependent outer joins. However, TransactSQL queries that have any of the following characteristics may produce a different result set after they are translated to an ANSI outer join: • Predicates that contain or statements and reference an inner table of an outer join and another table that this inner table is not dependent on • Inner table attributes that are referenced in the same predicate as a table which is not in the inner table’s join-order dependency • An inner table referenced in a subquery as a correlated reference The following examples demonstrate the issues of translating Transact-SQL queries with join-order dependency to ANSI outer join queries. Example:CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 203 select title, price, authors.au_id, au_lname from titles, titleauthor, authors where titles.title_id =* titleauthor.title_id and titleauthor.au_id = authors.au_id and (titles.price is null or authors.postalcode = ’94001’) This query is join-order independent because the outer join references both the titleauthor and the titles tables, and the authors table can be joined with these tables according to three join orders: • authors, titleauthors, titles (as part of the on clause) • titleauthors, authors, titles (as part of the on clause) • titleauthors, titles, authors (as part of the where clause) This query produces the following message: Warning: The results of the statement on line 1 are join-order independent. Results may differ on pre-12.0 releases, where the query is potentially joinorder dependent. Use trace flag 4413 to suppress this warning message. Following is the ANSI equivalent: select title, price, authors.au_id, au_lname from titles right join (titleauthor inner join authors on titleauthor.au_id = authors.au_id) on titles.title_id = titleauthor.title_id where (titles.price is null or authors.postalcode = ’94001’) Another example: select title, au_fname, au_lname, titleauthor.au_id, price from titles, titleauthor, authors where authors.au_id *= titleauthor.au_id and titleauthor.au_ord*titles.price > 40 The query is join-order dependent for the same reason as the previous example. Here is the ANSI equivalent: select title, au_fname, au_lname, titleauthor.au_id, price from titles,(authors left join titleauthor on titleauthor.au_id = authors.au_id) where titleauthor.au_ord*titles.price > 40Outer joins 204 Adaptive Server Enterprise Transact-SQL outer joins Transact-SQL includes syntax for both left and right outer joins. The left outer join, *=, selects all rows from the first table that meet the statement’s restrictions. The second table generates values if there is a match on the join condition. Otherwise, the second table generates null values. For example, the following left outer join lists all authors and finds the publishers (if any) in their city: select au_fname, au_lname, pub_name from authors, publishers where authors.city *= publishers.city The right outer join, =*, selects all rows from the second table that meet the statement’s restrictions. The first table generates values if there is a match on the join condition. Otherwise, the first table generates null values. Note You cannot include a Transact-SQL outer join in a having clause. A table is either an inner or an outer member of an outer join. If the join operator is *=, the second table is the inner table; if the join operator is =*, the first table is the inner table. You can compare a column from the inner table to a constant as well as using it in the outer join. For example, if you want to find out which title has sold more than 4000 copies: select qty, title from salesdetail, titles where qty > 4000 and titles.title_id *= salesdetail.title_id However, the inner table in an outer join cannot also participate in a regular join clause. An earlier example used a join to find the names of authors who live in the same city as a publisher returned two names: Abraham Bennet and Cheryl Carson. To include all the authors in the results, regardless of whether a publisher is located in the same city, use an outer join. Here is what the query and the results of the outer join look like: select au_fname, au_lname, pub_name from authors, publishers where authors.city *= publishers.city au_fname au_lname pub_name --------- -------------- --------------- Johnson White NULL Marjorie Green NULL Cheryl Carson Algodata Infosystems CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 205 Michael O’Leary NULL Dick Straight NULL Meander Smith NULL Abraham Bennet Algodata Infosystems Ann Dull NULL Burt Gringlesby NULL Chastity Locksley NULL Morningstar Greene NULL Reginald Blotche-Halls NULL Akiko Yokomoto NULL Innes del Castillo NULL Michel DeFrance NULL Dirk Stringer NULL Stearns MacFeather NULL Livia Karsen NULL Sylvia Panteley NULL Sheryl Hunter NULL Heather McBadden NULL Anne Ringer NULL Albert Ringer NULL (23 rows affected) The comparison operator *= distinguishes the outer join from an ordinary join. This “left” outer join tells Adaptive Server to include all the rows in the authors table in the results, whether or not there is a match on the city column in the publishers table. Notice that in the results, there is no matching data for most of the authors listed, so these rows contain NULL in the pub_name column. The “right” outer join is specified with the comparison operator =*, which indicates that all the rows in the second table are to be included in the results, regardless of whether there is matching data in the first table. Substituting this operator in the outer join query shown earlier gives this result: select au_fname, au_lname, pub_name from authors, publishers where authors.city =* publishers.city au_fname au_lname pub_name --------- --------- --------------- NULL NULL New Age Books NULL NULL Binnet & Hardley Cheryl Carson Algodata Infosystems Abraham Bennet Algodata Infosystems (4 rows affected) Outer joins 206 Adaptive Server Enterprise You can further restrict an outer join by comparing it to a constant. This means that you can zoom in on precisely the values you really want to see and use the outer join to list the rows that did not make the cut. Let us look at the equijoin first and compare it to the outer join. For example, to find out which titles had a sale of more than 500 copies from any store, use this query: select distinct salesdetail.stor_id, title from titles, salesdetail where qty > 500 and salesdetail.title_id = titles.title_id stor_id title ------- -------------------------------------------- 5023 Sushi, Anyone? 5023 Is Anger the Enemy? 5023 The Gourmet Microwave 5023 But Is It User Friendly? 5023 Secrets of Silicon Valley 5023 Straight Talk About Computers 5023 You Can Combat Computer Stress! 5023 Silicon Valley Gastronomic Treats 5023 Emotional Security: A New Algorithm 5023 The Busy Executive’s Database Guide 5023 Fifty Years in Buckingham Palace Kitchens 5023 Prolonged Data Deprivation: Four Case Studies 5023 Cooking with Computers: Surreptitious Balance Sheets 7067 Fifty Years in Buckingham Palace Kitchens (14 rows affected) Also, to show the titles that did not have a sale of more than 500 copies in any store, you can use an outer join query: select distinct salesdetail.stor_id, title from titles, salesdetail where qty > 500 and salesdetail.title_id =* titles.title_id stor_id title ------- ------------------------------------------- NULL Net Etiquette NULL Life Without Fear 5023 Sushi, Anyone? 5023 Is Anger the Enemy? 5023 The Gourmet Microwave 5023 But Is It User Friendly? 5023 Secrets of Silicon Valley 5023 Straight Talk About Computers NULL The Psychology of Computer Cooking CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 207 5023 You Can Combat Computer Stress! 5023 Silicon Valley Gastronomic Treats 5023 Emotional Security: A New Algorithm 5023 The Busy Executive’s Database Guide 5023 Fifty Years in Buckingham Palace Kitchens 7067 Fifty Years in Buckingham Palace Kitchens 5023 Prolonged Data Deprivation: Four Case Studies 5023 Cooking with Computers: Surreptitious Balance Sheets NULL Computer Phobic and Non-Phobic Individuals: Behavior Variations NULL Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean (19 rows affected) You can restrict an inner table with a simple clause. The following example lists the authors who live in the same city as a publisher, but excludes the author Cheryl Carson, who would normally be listed as an author living in a publisher’s city: select au_fname, au_lname, pub_name from authors, publishers where authors.city =* publishers.city and authors.au_lname != "Carson" au_fname au_lname pub_name --------- --------- --------------- NULL NULL New Age Books NULL NULL Binnet & Hardley Abraham Bennet Algodata Infosystems (3 rows affected) How null values affect joins Null values in tables or views being joined will never match each other. Since bit columns do not permit null values, a value of 0 appears in an outer join when there is no match for a bit column that is in the inner table. The result of a join of NULL with any other value is NULL. Because null values represent unknown or inapplicable values, Transact-SQL has no reason to believe that one unknown value matches another. Determining which table columns to join 208 Adaptive Server Enterprise You can detect the presence of null values in a column from one of the tables being joined only by using an outer join. Here are two tables, each of which has a NULL in the column that will participate in the join. A left outer join displays the null value in the first table. Figure 6-2: Null values in outer join Here is the left outer join: select * from t1, t2 where a *= c a b c d ----------- ------ ----------- ------ 1 one NULL NULL NULL three NULL NULL 4 join4 4 four (3 rows affected) The results make it difficult to distinguish a null in the data from a null that represents a failure to join. When null values are present in data being joined, it is usually preferable to omit them from the results by using a regular join. Determining which table columns to join sp_helpjoins lists the columns in two tables or views that are likely join candidates. Its syntax is: sp_helpjoins table1, table2CHAPTER 6 Joins: Retrieving Data from Several Tables Transact-SQL User’s Guide 209 For example, here is how to use sp_helpjoins to find the likely join columns between titleauthor and titles: sp_helpjoins titleauthor, titles first_pair ----------------------------- -------------------- title_id title_id The column pairs that sp_helpjoins displays come from two sources. First, sp_helpjoins checks the syskeys table in the current database to see if any foreign keys have been defined on the two tables with sp_foreignkey, and then checks to see if any common keys have been defined on the two tables with sp_commonkey. If it does not find any common keys there, the procedure applies less restrictive criteria to identify any keys that may be reasonably joined. It checks for keys with the same user datatypes, and if that fails, for columns with the same name and datatype. For complete information on the system procedures, see the Reference Manual.Determining which table columns to join 210 Adaptive Server EnterpriseTransact-SQL User’s Guide 211 C H A P T E R 7 Using and Creating Datatypes A datatype defines the kind of information each column in a table holds, and how that information is stored. You can use Adaptive Server system datatypes when you are defining columns, or you can create and use userdefined datatypes. This chapter discusses: How Transact-SQL datatypes work In Transact-SQL, datatypes specify the type of information, size, and storage format of table columns, stored procedure parameters, and local variables. For example, the int (integer) datatype stores whole numbers in the range of plus or minus 2 31 , and the tinyint (tiny integer) datatype stores whole numbers between 0 and 255 only. Adaptive Server supplies several system datatypes, and two user-defined datatypes, timestamp and sysname. You can use sp_addtype to build userdefined datatypes based on the system datatypes. You must specify a system datatype or user-defined datatype when declaring a column, local variable, or parameter. The following example uses the system datatypes char, numeric, and money to define the columns in the create table statement: create table sales_daily (stor_id char(4), ord_num numeric(10,0), Topic Page How Transact-SQL datatypes work 211 Using system-supplied datatypes 212 Converting between datatypes 223 Mixed-mode arithmetic and datatype hierarchy 224 Creating user-defined datatypes 226 Getting information about datatypes 229Using system-supplied datatypes 212 Adaptive Server Enterprise ord_amt money) The next example uses the bit system datatype to define the local variable in the declare statement: declare @switch bit Subsequent chapters describe in more detail how to declare columns, local variables, and parameters using the datatypes described in this chapter. You can determine which datatypes have been defined for columns of existing tables by using sp_help. Using system-supplied datatypes Table 7-1 lists the system-supplied datatypes provided for various types of information, the synonyms recognized by Adaptive Server, and the range and storage size for each. The system datatypes are printed in lowercase characters, although Adaptive Server allows you to enter them in either uppercase or lowercase. Most Adaptive Server-supplied datatypes are not reserved words and can be used to name other objects. Table 7-1: Adaptive Server system datatypes Datatypes by category Synonyms Range Bytes of storage Exact numeric: integers tinyint 0 to 255 (Negative numbers are not permitted.) 1 smallint 2 15 -1 (32,767) to -2 15 (-32,768) 2 int integer 2 31 -1 (2,147,483,647) to -2 31 (-2,147,483,648 4 Exact numeric: decimals numeric (p, s) 10 38 -1 to -10 38 2 to 17 decimal (p, s) dec 10 38 -1 to -10 38 2 to 17 Approximate numeric float (precision) machine dependent 4 for default precision < 16, 8 for default precision >= 16 double precision machine dependent 8 real machine dependent 4 Money smallmoney 214,748.3647 to -214,748.3648 4Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 213 money 922,337,203,685,477.5807 to -922,337,203,685,477.5808 8 Date/time smalldatetime January 1, 1900 to June 6, 2079 4 datetime January 1, 1753 to December 31, 9999 8 date January 1, 0001 to December 31, 9999 4 time 12:00:00AM to 11:59:59:999PM 4 Character char(n) character pagesize n varchar(n) character varying, char varying pagesize actual entry length unichar Unicode character pagesize n * @@unicharsize (@@unicharsize equals 2) univarchar Unicode character varying, char varying pagesize actual number of characters * @@unicharsize nchar(n) national character, national char pagesize n * @@ncharsize nvarchar(n) nchar varying, national char varying, national character varying pagesize @@ncharsize * number of characters text 2 31 -1 (2,147,483,647) bytes or fewer 0 when uninitialized; multiple of 2K after initialization Binary binary(n) pagesize n varbinary(n) pagesize actual entry length image 2 31 -1 (2,147,483,647) bytes or fewer 0 when uninitialized; multiple of 2K after initialization Bit bit 0 or 1 1 (one byte holds up to 8 bit columns)) Datatypes by category Synonyms Range Bytes of storageUsing system-supplied datatypes 214 Adaptive Server Enterprise Exact numeric types: integers Adaptive Server provides three datatypes, tinyint, smallint, and int, to store integers (whole numbers). These types are exact numeric types; they preserve their accuracy during arithmetic operations. Choose among the integer types based on the expected size of the numbers to be stored. Internal storage size varies by datatype. Exact numeric types: decimal numbers Use the exact numeric types, numeric and decimal, for numbers that include decimal points. Data stored in numeric and decimal columns is packed to conserve disk space and preserves its accuracy to the least significant digit after arithmetic operations. The numeric and decimal types are identical in all respects but one: Only numeric types with a scale of 0 can be used for the IDENTITY column. The exact numeric types accept two optional parameters, precision and scale, enclosed within parentheses and separated by a comma: datatype [(precision [, scale ])] Adaptive Server defines each combination of precision and scale as a distinct datatype. For example, numeric(10,0) and numeric(5,0) are two separate datatypes. The precision and scale determine the range of values that can be stored in a decimal or numeric column: • The precision specifies the maximum number of decimal digits that can be stored in the column. It includes all digits to the right or left of the decimal point. You can specify a precision of 1–38 digits or use the default precision of 18 digits. • The scale specifies the maximum number of digits that can be stored to the right of the decimal point. The scale must be less than or equal to the precision. You can specify a scale of 0–38 digits or use the default scale of 0 digits. Exact numeric types with a scale of 0 display without a decimal point. You cannot enter a value that exceeds either the precision or the scale for the column. The storage size for a numeric or decimal column depends on its precision. The minimum storage requirement is 2 bytes for a 1- or 2-digit column. Storage size increases by 1 byte for each additional 2 digits of precision, to a maximum of 17 bytes.Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 215 Approximate numeric datatypes The numeric types float, double precision, and real store numeric data that can tolerate rounding during arithmetic operations. Approximate numeric datatypes store, as binary tractions, slightly inaccurate representations of real numbers, stored as binary fractions. Anytime an approximate numeric value is displayed, printed, transferred between hosts, or used in calculations, the numbers lose precision. Note that isql displays only six significant digits after the decimal point and rounds the remainder. For more information on precision and approximate numeric datatypes, see the Reference Manual. Use the approximate numeric types for data that covers a wide range of values. They support all aggregate functions and all arithmetic operations except modulo (%). The real and double precision types are built on types supplied by the operating system. The float type accepts an optional precision in parentheses. float columns with a precision of 1–15 are stored as real; those with higher precision are stored as double precision. The range and storage precision for all three types is machine dependent. Money datatypes The money datatypes, money and smallmoney, store monetary data. You can use these datatypes for U.S. dollars and other decimal currencies, although Adaptive Server provides no means to convert from one currency to another. You can use all arithmetic operations except modulo, and all aggregate functions, with money and smallmoney data. Both money and smallmoney are accurate to one ten-thousandth of a monetary unit, but round values up to two decimal places for display purposes. The default print format places a comma after every three digits. Date and time datatypes Use the datetime and smalldatetime datatypes to store date and time information from January 1, 1753 through December 31, 9999. Use date for dates from January 1, 0001 to December 31, 9999 or time for 12:00:00 AM to 11:59:59:999. Dates outside this range must be entered, stored, and manipulated as char or varchar values.Using system-supplied datatypes 216 Adaptive Server Enterprise • datetime columns hold dates between January 1, 1753 and December 31, 9999. datetime values are accurate to 1/300 second on platforms that support this level of granularity. Storage size is 8 bytes: 4 bytes for the number of days since the base date of January 1, 1900 and 4 bytes for the time of day. • smalldatetime columns hold dates from January 1, 1900 to June 6, 2079, with accuracy to the minute. Its storage size is 4 bytes: 2 bytes for the number of days after January 1, 1900, and 2 bytes for the number of minutes after midnight. • date is a literal value consisting of a date portion in single or double quotes. This column can hold dates between January 1, 0001 to December 31, 9999. Storage size is 4 bytes. • time is a literal value consisting of a time portion enclosed in single or double quotes. This column holds time from 12:00:00AM to 11:59:59:999PM. Enclose date and time information in single or double quotes. You can enter it in either uppercase or lowercase letters and include spaces between data parts. Adaptive Server recognizes a wide variety of data entry formats, which are described in Chapter 9, “Adding, Changing, and Deleting Data.” However, Adaptive Server rejects values such as 0 or 00/00/00, which are not recognized as dates. The default display format for dates is “Apr 15 1987 10:23PM”. You can use the convert function for other styles of date display. You can also do some arithmetic calculations on datetime values with the built-in date functions, though Adaptive Server may round or truncate millisecond values, unless you use the time datatype. Character datatypes Use the character datatypes to store strings consisting of letters, numbers, and symbols entered within single or double quotes. You can use the like keyword to search these strings for particular characters and the built-in string functions to manipulate their contents. Strings consisting of numbers can be converted to exact and approximate numeric datatypes with the convert function, and then used for arithmetic.Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 217 The char(n) datatype stores fixed-length strings, and the varchar(n) datatype stores variable-length strings, in single-byte character sets such as English. Their national character counterparts, nchar(n) and nvarchar(n), store fixed- and variable-length strings in multibyte character sets such as Japanese.The unichar and univarchar datatypes store Unicode characters, which are a constant size. You can specify the maximum number of characters with n or use the default column length of one character. For strings larger than the page size, use the text datatype. Table 7-2: Character datatypes Adaptive Server truncates entries to the specified column length without warning or error, unless you set string_rtruncation on. See the set command in the Reference Manual for more information. The empty string, ““or ‘’, is stored as a single space rather than as NULL. Thus, “abc” + ““ + “def” is equivalent to “abc def”, not to “abcdef”. Fixed- and variable-length columns behave somewhat differently: • Data in fixed-length columns is blank-padded to the column length. For the char and unichar datatypes, storage size is n bytes, (unichar = n*@@unicharsize); for the nchar datatype, n times the average national character length (@@ncharsize). When you create a char, unichar, or nchar column that allows nulls, Adaptive Server converts it to a varchar, univarchar, or nvarchar column and uses the storage rules for those datatypes. This is not true of char and nchar variables and parameters. • Data in variable-length columns is stripped of trailing blanks; storage size is the actual length of the data. For varchar or univarchar columns, this is the number of characters; for nvarchar columns, it is the number of characters times the average character length. Variable-length character data may require less space than fixed-length data, but it is accessed somewhat more slowly. Datatype Stores char(n) Fixed-length data, such as social security numbers or postal codes varchar(n) Data, such as names, that is likely to vary greatly in length unichar Fixed-length Unicode data, comparable to Char univarchar Unicode data that is likely to vary greatly in length, comparable to varchar nchar(n) Fixed-length data in multibyte character sets nvarchar(n) Variable-length data in multibyte character sets text Up to 2,147,483,647 bytes of printable characters on linked lists of data pages Using system-supplied datatypes 218 Adaptive Server Enterprise Unichar datatype The unichar and univarchar datatypes support the UTF-16 encoding of Unicode in the Adaptive Server. These datatypes are independent of the char and varchar datatypes, but mirror their behavior. For example, the built-in functions that operate on char and varchar also operate on unichar and univarchar. However, unichar and univarchar store only UTF-16 characters and have no connection to the default character set ID or the default sortorder ID as char and varchar do. To use the unichar and univarchar datatypes, the default character set for the server must be set to UTF-8. Each unichar/univarchar character requires two bytes of storage. The declaration of a unichar/univarchar column is the number of 16-bit Unicode values. The following example creates a table with one unichar column for 10 Unicode values requiring 20 bytes of storage: create table unitbl (unicol unichar(10)) The length of a unichar/univarchar column is limited by the size of a data page, just as the length of char/varchar columns. Note that Unicode surrogate pairs use the storage of two 16-bit Unicode values (i.e., four bytes). Be aware of this when declaring columns intended to store Unicode surrogate pairs. By default, Adaptive Server Enterprise correctly handles surrogates, taking care not to split the pair. Truncation of Unicode data is handled in a manner similar to that of char and varchar data. Unichar expressions can be used anywhere char expressions are used, including comparison operators, joins, subqueries, etc. Note however, that mixed-mode expressions of both unichar and char are performed as unichar. The number of Unicode values that can participate in such operations is limited to the maximum size of a unichar string. The normalization process modifies Unicode data so there is only a single representation in the database for a given sequence of abstract characters. Often, characters followed by combined diacritics are replaced by precombined forms. This allows significant performance optimizations. By default, the server assumes all Unicode data should be normalized.Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 219 Relational expressions All relational expressions involving at least one expression of unichar or univarchar, will be based on the default Unicode sort order. If one expression is unichar and the other is varchar (nvarchar, char, or nchar), the latter will be implicitly converted to unichar. The following expressions are most often used in where clauses, where it may be combined with logical operators. When comparing Unicode character data “less than” means closer to the beginning of the default Unicode default sort order, and “greater than” means closer to the end. “Equality “means the Unicode default sort order makes no distinction between two values (although they need not be identical). For example, the precomposed character ê must be considered equal to the combining sequence consisting of the letter e followed by U+0302. If the Unicode normalization feature is turned on (the default), the Unicode data is automatically normalized and the server never sees unnormalized data. Table 7-3: Relational expressions Join operators Join operators appear in the same manner as comparison operators. In fact, any comparison operator can be used in a join. Expressions involving at least one expression of type unichar will be based on the default Unicode sort order. If one expression is of type unichar and the other type varchar (nvarchar, char, or nchar), the latter will be implicitly converted to unichar. expr1 op_compare [any | all] (subquery) The use of any or all with comparison operators and expr2 being a subquery, implicitly invokes min or max. For instance “expr1> any expr2” means, in effect, “expr1> min(expr2)”. expr1 [not] in (expression list) expr1 [not] in (subquery) The in operator checks for equality with each of the elements in expr2, which can be a list of constants, or the results of a subquery. expr1 [not] between expr2 and expr3 The between operator specifies a range. It is, in effect, shorthand for “expr1 = expr2 and expr1<= expr3”. expr1 [not] like “match_string” [escape “esc_char”] The like operator specifies a pattern to be matched. The semantics for pattern matching with Unicode data are the same for regular character data. If expr1 is a unichar column name, then “match_string” may be either a unichar string or a varchar string. In the latter case, an implicit conversion will take place between varchar and unicharUsing system-supplied datatypes 220 Adaptive Server Enterprise Union operators The union operator will operate with unichar data much like it does with varchar data. Corresponding columns from individual queries must be implicitly convertible to unichar, or explicit conversion must be used. Clauses and modifiers When unichar and univarchar columns are used in group by and order by clauses, equality is judged according to the default Unicode sort order. This is also true when using the distinct modifier. text datatype The text datatype stores up to 2,147,483,647 bytes of printable characters on linked lists of separate data pages. Each page stores a maximum of 1800 bytes of data. To save storage space, define text columns as NULL. When you initialize a text column with a non-null insert or update, Adaptive Server assigns a text pointer and allocates an entire 2K data page to hold the value. You cannot use the text datatype: • For parameters to stored procedures, as values passed to these parameters, or for local variables • For parameters to remote procedure calls (RPCs) • In order by, compute, group by, or union clauses • In an index • In subqueries or joins • In a where clause, except with the keyword like • With the + concatenation operator If you are using databases connected with Component Integration Services, there are several differences in the way text datatypes are handled. See the Component Integration Services User’s Guide for more information. For more information about the text datatype, see “Changing text and image data” on page 342.Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 221 Binary datatypes The binary datatypes store raw binary data, such as pictures, in a hexadecimallike notation. Binary data begins with the characters “0x” and includes any combination of digits and the uppercase and lowercase letters A–F. The two digits following “0x” in binary and varbinary data indicate the type of number: “00” represents a positive number and “01” represents a negative number. If the input value does not include the “0x”, Adaptive Server assumes that the value is an ASCII value and converts it. Note Adaptive Server manipulates the binary types in a platform-specific manner. For true hexadecimal data, use the hextoint and inttohex functions. See Chapter 11, “Using the Built-In Functions in Queries.” Use the binary(n) and varbinary(n) datatypes to store data up to 255 bytes in length. Each byte of storage holds 2 binary digits. Specify the column length with n, or use the default length of 1 byte. If you enter a value longer than n, Adaptive Server truncates the entry to the specified length without warning or error. • Use the fixed-length binary type, binary(n), for data in which all entries are expected to have a similar length. Because entries in binary columns are zero-padded to the column length, they may require more storage space than those in varbinary columns, but they are accessed somewhat faster. • Use the variable-length binary type, varbinary(n), for data that is expected to vary greatly in length. Storage size is the actual size of the data values entered, not the column length. Trailing zeros are truncated. When you create a binary column that allows nulls, Adaptive Server converts it to a varbinary column and uses the storage rules for that datatype. You can search binary strings with the like keyword and operate on them with the built-in string functions. Because the exact form in which you enter a particular value depends upon the hardware you are using, calculations involving binary data may produce different results on different platforms. image datatype Use the image datatype to store larger blocks of binary data on external data pages. An image column can store up to 2,147,483,647 bytes of data on linked lists of data pages separate from other data storage for the table. Using system-supplied datatypes 222 Adaptive Server Enterprise When you initialize an image column with a non-null insert or update, Adaptive Server assigns a text pointer and allocates an entire 2K data page to hold the value. Each page stores a maximum of 1800 bytes. To save storage space, define image columns as NULL. To add image data without saving large blocks of binary data in your transaction log, use writetext. See the Reference Manual for details on writetext. You cannot use the image datatype: • For parameters to stored procedures, as values passed to these parameters, or for local variables • For parameters to remote procedure calls (RPCs) • In order by, compute, group by, or union clauses • In an index • In subqueries or joins • In a where clause, except with the keyword like • With the + concatenation operator • In the if update clause of a trigger If you are using databases connected with Component Integration Services, there are several differences in the way image datatypes are handled. See the Component Integration Services User’s Guide for more information. For more information about the image datatype, see “Changing text and image data” on page 342. The bit datatype Use bit columns for true and false or yes and no types of data. bit columns hold either 0 or 1. Integer values other than 0 or 1 are accepted, but are always interpreted as 1. Storage size is 1 byte. Multiple bit datatypes in a table are collected into bytes. For example, 7-bit columns fit into 1 byte; 9-bit columns take 2 bytes. Columns of datatype bit cannot be NULL and cannot have indexes on them. The status column in the syscolumns system table indicates the unique offset position for bit columns.Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 223 The timestamp datatype The timestamp user-defined datatype is necessary for columns in tables that are to be browsed in Open Client™ DB-Library applications. Every time a row containing a timestamp column is inserted or updated, the timestamp column is automatically updated. A table can have only one column of the timestamp datatype. A column named timestamp automatically has the system datatype timestamp. Its definition is: varbinary(8) "NULL" Because timestamp is a user-defined datatype, you cannot use it to define other user-defined datatypes. You must enter it as “timestamp” in all lowercase letters. The sysname datatype sysname is a user-defined datatype that is used in the system tables. Its definition is: varchar(30) "NULL" You cannot use the sysname datatype to create a column. You can, however, create a user-defined datatype with a base type of sysname. You can then use this user-defined datatype to create columns. For more information about user-defined datatypes, see “Creating user-defined datatypes” on page 226. Converting between datatypes Adaptive Server automatically handles many conversions from one datatype to another. These are called implicit conversions. You can explicitly request other conversions with the convert, inttohex, and hextoint functions. Other conversions cannot be done, either explicitly or automatically, because of incompatibilities between the datatypes. For example, Adaptive Server automatically converts char expressions to datetime for the purposes of a comparison, if they can be interpreted as datetime values. However, for the purposes of display, you must use the convert function to convert char to int. Similarly, you must use convert on integer data if you want Adaptive Server to treat it as character data so that you can use the like keyword with it. Mixed-mode arithmetic and datatype hierarchy 224 Adaptive Server Enterprise The syntax for the convert function is: convert (datatype, expression, [style]) In the following example, convert displays the total_sales column using the char datatype, in order to display all sales beginning with the digit 2: select title, total_sales from titles where convert (char(20), total_sales) like "2%" The optional style parameter is used to convert datetime values to char or varchar datatypes to get a wide variety of date display formats. See Chapter 11, “Using the Built-In Functions in Queries” for details on the convert, inttohex, and hextoint functions. Mixed-mode arithmetic and datatype hierarchy When you perform arithmetic on values with different datatypes, Adaptive Server must determine the datatype and, in some cases, the length and precision, of the result. Each system datatype has a datatype hierarchy, which is stored in the systypes system table. User-defined datatypes inherit the hierarchy of the system type on which they are based. The following query ranks the datatypes in a database by hierarchy. In addition to the information shown below, your query results will include information about any user-defined datatypes in the database: select name, hierarchy from systypes order by hierarchy name hierarchy --------------------------- --------- floatn 1 float 2 datetimn 3 datetime 4 real 5 numericn 6 numeric 7 decimaln 8 decimal 9Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 225 moneyn 10 money 11 smallmoney 12 smalldatetime 13 intn 14 int 15 smallint 16 tinyint 17 bit 18 univarchar 19 unichar 20 reserved 21 varchar 22 sysname 22 nvarchar 22 char 23 nchar 23 varbinary 24 timestamp 24 binary 25 text 26 image 27 (30 rows affected) The datatype hierarchy determines the results of computations using values of different datatypes. The result value is assigned the datatype that is closest to the top of the list. In the following example, qty from the sales table is multiplied by royalty from the roysched table. qty is a smallint, which has a hierarchy of 16; royalty is an int, which has a hierarchy of 15. Therefore, the datatype of the result is an int. smallint(qty) * int(royalty) = int Working with money datatypes If you are combining money and literals or variables, and you need results of money type, use money literals or variables: create table mytable (moneycol money,) insert into mytable values ($10.00) select moneycol * $2.5 from mytableCreating user-defined datatypes 226 Adaptive Server Enterprise If you are combining money with a float or numeric datatype from column values, use the convert function: select convert (money, moneycol * percentcol) from debits, interest drop table mytable Determining precision and scale For the numeric and decimal types, each combination of precision and scale is a distinct Adaptive Server datatype. If you perform arithmetic on two numeric or decimal values, n1 with precision p1 and scale s1, and n2 with precision p2 and scale s2, Adaptive Server determines the precision and scale of the results as shown in Table 7-4: Table 7-4: Precision and scale after arithmetic operations Creating user-defined datatypes A Transact-SQL enhancement to SQL allows you to name and design your own datatypes to supplement the system datatypes. A user-defined datatype is defined in terms of system datatypes. You can give one name to a frequently used datatype definition. This makes it easy for you to custom fit datatypes to columns. Note To use a user-defined datatype in more than one database, create it in the model database. The user-defined datatype definition then becomes known to all new databases you create. Once you define a datatype, it can be used as the datatype for any column in the database. For example, tid is used as the datatype for columns in several pubs2 tables: titles.title_id, titleauthor.title_id, sales.title_id, and roysched.title_id. Operation Precision Scale n1 + n2 max(s1, s2) + max(p1 -s1, p2 - s2) + 1 max(s1, s2) n1 - n2 max(s1, s2) + max(p1 -s1, p2 - s2) + 1 max(s1, s2) n1 * n2 s1 + s2 + (p1 - s1) + (p2 - s2) + 1 s1 + s2 n1 / n2 max(s1 + p2 + 1, 6) + p1 - s1 + p2 max(s1 + p2 -s2 + 1, 6)Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 227 The advantage of user-defined datatypes is that you can bind rules and defaults to them for use in several tables. For more about this topic, see Chapter 13, “Defining Defaults and Rules for Data.” Use sp_addtype to create user datatypes. It takes as parameters the name of the user datatype being created, the Adaptive Server-supplied datatype from which it is being built, and an optional NULL, NOT NULL, or IDENTITY specification. You can build a user-defined datatype using any system datatype other than timestamp. User-defined datatypes have the same datatype hierarchy as the system datatypes on which they are based. Unlike Adaptive Server-supplied datatypes, user-defined datatype names are case-sensitive. Here is the syntax for sp_addtype: sp_addtype datatypename, phystype [ (length) | (precision [, scale] ) ] [, "identity" |nulltype] Here is how tid was defined: sp_addtype tid, "char(6)", "not null" You must enclose a parameter within single or double quotes if it includes a blank or some form of punctuation, or if it is a keyword other than null (for example, identity or sp_helpgroup). In this example, quotes are required around char(6) because of the parentheses, but around “not null” because of the blank. They are not required around tid. Specifying length, precision, and scale When you build a user-defined datatype based upon certain Adaptive Server datatypes, you must specify additional parameters: • The char, nchar, varchar, nvarchar, binary, and varbinary datatypes expect a length in parentheses. If you do not supply one, Adaptive Server assumes the default length of 1 character. • The float datatype expects a precision in parentheses. If you do not supply one, Adaptive Server uses the default precision for your platform. • The numeric and decimal datatypes expect a precision and scale, in parentheses and separated by a comma. If you do not supply them, Adaptive Server uses a default precision of 18 and scale of 0.Creating user-defined datatypes 228 Adaptive Server Enterprise You cannot change the length, precision, or scale specification when you include the user-defined datatype in a create table statement. Specifying null type The null type determines how the user-defined datatype treats nulls. You can create a user-defined datatype with a null type of “null”, “NULL”, “nonull”, “NONULL”, “not null”, or “NOT NULL”. bit and IDENTITY types do not allow null values. If you omit the null type, Adaptive Server uses the null mode defined for the database (by default, NOT NULL). For compatibility with the SQL standards, use sp_dboption to set the allow nulls by default option to true. You can override the null type when you include the user-defined datatype in a create table statement. Associating rules and defaults with user-defined datatypes Once you have created a user-defined datatype, use sp_bindrule and sp_bindefault to associate rules and defaults with the datatype. Use sp_help to print a report that lists the rules, defaults, and other information associated with the datatype. Rules and defaults are discussed in Chapter 13, “Defining Defaults and Rules for Data.” For complete information on, and syntax for, system procedures, see the Reference Manual. Creating a user-defined datatype with the IDENTITY property To create a user-defined datatype with the IDENTITY property, use sp_addtype. The new type must be based on a physical type of numeric with a scale of 0: sp_addtype typename, "numeric (precision, 0)", "identity" The following example creates a user-defined type, IdentType, with the IDENTITY property: sp_addtype IdentType, "numeric(4,0)", "identity"Chapter 7 Using and Creating Datatypes Transact-SQL User’s Guide 229 When you create a column from an IDENTITY type, you can specify either identity or not null—or neither one—in the create or alter table statement. The column automatically inherits the IDENTITY property. Here are three different ways to create an IDENTITY column from the IdentType user-defined type: create table new_table (id_col IdentType) drop table new_table create table new_table (id_col IdentType identity) drop table new_table create table new_table (id_col IdentType not null) drop table new_table Note If you try to create a column that allows nulls from an IDENTITY type, the create table or alter table statement fails. Creating IDENTITY columns from other user-defined datatypes You can create IDENTITY columns from user-defined datatypes that do not have the IDENTITY property. The user-defined types must have a physical datatype of numeric with a scale of 0 and must be defined as not null. Dropping a user-defined datatype To drop a user-defined datatype, execute sp_droptype: sp_droptype typename Note You cannot drop a datatype that is already in use in any table. Getting information about datatypes Use sp_help to display information about the properties of a system datatype or a user-defined datatype. The report indicates the base type from which the datatype was created, whether it allows nulls, the names of any rules and defaults bound to the datatype, and whether it has the IDENTITY property.Getting information about datatypes 230 Adaptive Server Enterprise The following examples display the information about the money system datatype and the tid user-defined datatype: sp_help money Type_name Storage_type Length Prec Scale ---------- ------------ ------ ----- ----- money money 8 NULL NULL Nulls Default_name Rule_name Identity ----- ------------ --------- -------- 1 NULL NULL NULL (return status = 0) sp_help tid Type_name Storage_type Length Prec Scale ---------- ------------ ------ ----- ----- tid varchar 6 NULL NULL Nulls Default_name Rule_name Identity ----- ------------ --------- -------- 0 NULL NULL 0 (return status = 0)Transact-SQL User’s Guide 231 C H A P T E R 8 Creating Databases and Tables This chapter describes how to create databases and tables. This chapter includes these sections: For information on managing databases, see the System Administration Guide. What are databases and tables? A database stores information (data) in a set of database objects, such as tables, that relate to each other. A table is a collection of rows that have associated columns containing individual data items. You define how your data is organized when you create your databases and tables. This process is called data definition. Adaptive Server database objects include: • Tables Topic Page What are databases and tables? 231 Using and creating databases 234 Altering the sizes of databases 239 Dropping databases 240 Creating tables 240 Managing identity gaps in tables 254 Defining integrity constraints for tables 263 How to design and create a table 274 Creating new tables from query results: select into 277 Altering existing tables 283 Dropping tables 302 Assigning permissions to users 303 Getting information about databases and tables 305What are databases and tables? 232 Adaptive Server Enterprise • Rules • Defaults • Stored procedures • Triggers • Views • Referential integrity constraints • Check integrity constraints This chapter covers the creation, modification, and deletion of databases and tables, including integrity constraints. Columns and datatypes define the type of data included in tables and are discussed in this chapter. Indexes describe how data is organized in tables. They are not considered database objects by Adaptive Server and are not listed in sysobjects. Indexes are discussed in Chapter 12, “Creating Indexes on Tables.” Enforcing data integrity in databases Data integrity refers to the correctness and completeness of data within a database. To enforce data integrity, you can constrain or restrict the data values that users can insert, delete, or update in the database. For example, the integrity of data in the pubs2 and pubs3 databases requires that a book title in the titles table must have a publisher in the publishers table. You cannot insert books that do not have a valid publisher into titles, because it violates the data integrity of pubs2 or pubs3. Transact-SQL provides several mechanisms for integrity enforcement in a database such as rules, defaults, indexes, and triggers. These mechanisms allow you to maintain these types of data integrity: • Requirement – requires that a table column must contain a valid value in every row; it cannot allow null values. The create table statement allows you to restrict null values for a column. • Check or Validity – limits or restricts the data values inserted into a table column. You can use triggers or rules to enforce this type of integrity. • Uniqueness – no two table rows can have the same non-null values for one or more table columns. You can use indexes to enforce this integrity.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 233 • Referential – data inserted into a table column must already have matching data in another table column or another column in the same table. A single table can have up to 192 references. Consistency of data values in the database is another example of data integrity, which is described in Chapter 19, “Transactions: Maintaining Data Consistency and Recovery.” As an alternative to using rules, defaults, indexes, and triggers, Transact-SQL provides a series of integrity constraints as part of the create table statement to enforce data integrity as defined by the SQL standards. These integrity constraints are described later in this chapter. Permissions within databases Whether or not you can create and drop databases and database objects depends on your permissions or privileges. Ordinarily, a System Administrator or Database Owner sets up the permissions for you, based on the kind of work you do and the functions you need. These permissions can be different for each user in a given installation or database. You can determine what your permissions are by executing: sp_helprotect user_name user_name is your Adaptive Server login name. To make your experiments with database objects as convenient as possible, the pubs2 and pubs3 databases have a “guest” user name in their sysusers system tables. The scripts that create pubs2 and pubs3 grant a variety of permissions to “guest”. The “guest” mechanism means that anyone who has a login on Adaptive Server, that is, anyone who is listed in master..syslogins, has access to pubs2 and pub3, and permission to create and drop such objects as tables, indexes, defaults, rules, procedures, and so on. The “guest” user name also allows you to use certain stored procedures, create user-defined datatypes, query the database, and modify the data in it. Using and creating databases 234 Adaptive Server Enterprise To use the pubs2 or pubs3 database, issue the use command. Adaptive Server checks whether you are listed under your own name in pubs2.sysusers or pubs3..sysusers. If not, you are admitted as a guest without any action on your part. If you are listed in the sysusers table for pubs2 or pubs3, Adaptive Server admits you as yourself, but may give you different permissions from those of “guest.” Note All the examples in this chapter assume you are being treated as “guest.” Most users can look at the system tables in the master database by means of the “guest” mechanism previously described. Users who are not recognized by name in the master database are allowed in and treated as a user named “guest.” The “guest” user is added to the master database in the script that creates the master database when it is installed. A Database Owner, “dbo”, can add a “guest” user to any user database using sp_adduser. System Administrators automatically become the Database Owner in any database they use. For more information, see the System Administration Guide and the Reference Manual. Using and creating databases A database is a collection of related tables and other database objects—views, indexes, and so on. When you install Adaptive Server, it contains these system databases: • The master database controls the user databases and the operation of Adaptive Server as a whole. • The sybsystemprocs database contains the system stored procedures. • The sybsystemdb database contains information about distributed transactions. • The temporary database, tempdb, stores temporary objects, including temporary tables created with the name prefix “tempdb..”. • The model database is used by Adaptive Server as a template for creating new user databases. In addition, System Administrators can install these optional databases:CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 235 • pubs2 – a sample database that contains data representing a publishing operation. You can use this database to test your server connections and learn Transact-SQL. Most of the examples in the Adaptive Server documentation query the pubs2 database. • pubs3 – a version of pubs2 that uses referential integrity examples. pubs3 has a table, store_employees, that uses a self-referencing column. pubs3 also includes an IDENTITY column in the sales table. Additionally, the primary keys in its master tables use nonclustered unique indexes, and the titles table has an example of the numeric datatype. • interpubs – similar to pubs2, but contains French and German data. • jpubs – similar to pubs2, but contains Japanese data. Use it if you have installed the Japanese Language Module. These optional databases are user databases. All of your data is stored in user databases. Adaptive Server manages each database by means of system tables. The data dictionary tables in the master database and in other databases are considered system tables. Choosing a database: use The use command lets you access an existing database. Its syntax is: use database_name For example, to access the pubs2 database, type: use pubs2 This command allows you to access the pubs2 database only if you are a known user in pubs2. Otherwise, you see an error message. It is likely that you will be automatically connected to the master database when you log in to Adaptive Server, so if you want to use another database, issue the use command. You or a System Administrator can change the database to which you initially connect by using sp_modifylogin. Only a System Administrator can change the default database for another user. Using and creating databases 236 Adaptive Server Enterprise Creating a user database: create database You can create a new database if a System Administrator has granted you permission to use create database. You must be using the master database when you create a new database. In many enterprises, a System Administrator creates all databases. The creator of a database is its owner. Another user who creates a database for you can transfer ownership of it using sp_changedbowner. The Database Owner is responsible for giving users access to the database and for granting and revoking certain other permissions to users. In some organizations, the Database Owner is also responsible for maintaining regular backups of the database and for reloading it in case of system failure. The Database Owner can temporarily attain any other user’s permissions on a database by using the setuser command. Because each database is allocated a significant amount of space, even if it contains only small amounts of data, you may not have permission to use create database. The simplest form of create database is: create database database_name To create a new database called newpubs database, first verify you are using the master database rather than pubs2, and then type this command: use master create database newpubs drop database newpubs use pubs2 A database name must be unique on Adaptive Server, and must follow the rules for identifiers described under “Identifiers” on page 7. Adaptive Server can manage up to 32,767 databases. You can create only one database at a time. The maximum number of segments for any database is 32. Adaptive Server creates a new database as a copy of the model database, which contains the system tables that belong in every user database. The creation of a new database is recorded in the master database tables sysdatabases and sysusages. The full syntax of create database is: create database database_name [on {default | database_device} [= size] [, database_device [= size]]...] [log on database_device [= size] [, database_device [= size]]...]CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 237 [with override] [for load] This chapter describes all the create database options except with override. For information about with override, see the System Administration Guide. The on clause The optional on clause allows you to specify where to store the database and how much space in megabytes to allocate for it. If you use the keyword default, the database is assigned to an available database device in the pool of default database devices indicated in the master database table sysdevices. Use sp_helpdevice to see which devices are in the default list. Note A System Administrator may have made certain storage allocations based on performance statistics and other considerations. Before creating databases, you should check with a System Administrator. To specify a size of 5MB for a database to be stored in this default location, use on default = size: use master create database newpubs on default = 5 drop database newpubs use pubs2 To specify a different location for the database, give the logical name of the database device where you want it stored. A database can be stored on more than one database device, with different amounts of space on each. This example creates the newpubs database and allocates 3MB to it on pubsdata and 2MB on newdata: create database newpubs on pubsdata = 3, newdata = 2 If you omit the on clause and the size, the database is created with 2MB of space from the pool of default database devices indicated in sysdevices. A database allocation can range in size from 2MB to 2 23 MB.Using and creating databases 238 Adaptive Server Enterprise The log on clause Unless you are creating very small, noncritical databases, always use the log on database_device extension to create database. This places the transaction logs on a separate database device. There are several reasons for placing the logs on a separate device: • It allows you to use dump transaction rather than dump database, thus saving time and tapes. • It allows you to establish a fixed size for the log, keeping it from competing with other database activity for space. Additional reasons for placing the log on a separate physical device from the data tables are: • It improves performance. • It ensures full recovery in the event of hard disk failures. The following command places the log for newpubs on the logical device pubslog, with a size of 1MB: create database newpubs on pubsdata = 3, newdata = 2 log on pubslog = 1 Note When you use the log on extension, you are placing the database transaction log on a segment named “logsegment”. To add more space for an existing log, use alter database and, in some cases, sp_extendsegment. See the Reference Manual or the System Administration Guide for details. The size of the device required for the transaction log varies according to the amount of update activity and the frequency of transaction log dumps. As a rule of thumb, allocate to the log between 10 and 25 percent of the space you allocate to the database. The for load option The optional for load clause invokes a streamlined version of create database that you can use only for loading a database dump. Use the for load option for recovery from media failure or for moving a database from one machine to another. See the System Administration Guide for more information.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 239 Altering the sizes of databases If a database has filled its allocated storage space, you cannot add new data or updates to it. Existing data, of course, is always preserved. If the space allocated for a database proves to be too small, the Database Owner can increase it with the alter database command. alter database permission defaults to the Database Owner, and cannot be transferred. You must be using the master database to use alter database. The default increase is 2MB from the default pool of space. This statement adds 2MB to newpubs on the default database device: alter database newpubs The full alter database syntax allows you to extend a database by a specified number of megabytes (minimum 1MB) and to specify where the storage space is to be added: alter database database_name [on {default | database_device} [= size] [, database_device [= size]]...] [log on {default | database_device} [ = size ] [, database_device [= size]]...] [with override] [for load] The on clause in the alter database command is just like the on clause in create database. The for load clause is just like the for load clause in create database and can be used only on a database created with the for load clause. To increase the space allocated for newpubs by 2MB on the database device pubsdata, and by 3MB on the database device newdata, type: alter database newpubs on pubsdata = 2, newdata = 3 When you use alter database to allocate more space on a device already in use by the database, all of the segments already on that device use the added space fragment. All the objects already mapped to the existing segments can now grow into the added space. The maximum number of segments for any database is 32. Dropping databases 240 Adaptive Server Enterprise When you use alter database to allocate space on a device that is not yet in use by a database, the system and default segments are mapped to the new device. To change this segment mapping, use sp_dropsegment to drop the unwanted segments from the device. Note Using sp_extendsegment automatically unmaps the system and default segments. For information about with override, see the System Administration Guide. Dropping databases Use the drop database command to remove a database. drop database deletes the database and all of its contents from Adaptive Server, frees the storage space that had been allocated for it, and deletes references to it from the master database. The syntax is: drop database database_name [, database_name]... You cannot drop a database that is in use, that is, open for reading or writing by any user. As indicated, you can drop more than one database in a single command. For example: drop database newpubs, newdb You cannot remove damaged database with drop database. Use dbcc dbrepair instead. Creating tables When you create a table, you name its columns and supply a datatype for each column. You can also specify whether a particular column can hold null values or specify integrity constraints for columns in the table. There can be as many as 2,000,000,000 tables per database.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 241 Maximum number of columns per table The maximum number of columns in a table depends on many factors, including, among others, your server’s logical page size and whether the tables are configured for allpages- or data only-locking. For a complete description of the maximum number of columns per table, see the create table command in the Reference Manual. Example of creating a table Use the newpubs database you created in the previous section if you want to try these examples. Otherwise, these changes will affect another database, like pubs2 or pubs3. The simplest form of |create|table| is: create table table_name (column_name datatype) For example, to create a table named names with one column named some_name, and a fixed length of 11 bytes, enter: create table names (some_name char(11)) drop table names If you have set quoted_identifier on, both the table name and the column names can be delimited identifiers. Otherwise, they must follow the rules for identifiers described under “Identifiers” on page 7. Column names must be unique within a table, but you can use the same column name in different tables in the same database. There must be a datatype for each column. The word “char” after the column name in the example above refers to the datatype of the column—the type of value that column will contain. Datatypes are discussed in Chapter 7, “Using and Creating Datatypes.” The number in parentheses after the datatype gives the maximum number of bytes that can be stored in the column. You give a maximum length for some datatypes. Others have a system-defined length.Creating tables 242 Adaptive Server Enterprise Be sure to put parentheses around the list of column names, and commas after each column definition. The last column definition does not need a comma after it. Note A variable cannot be used in a default if the default is part of a create table statement. Choosing table names The create table command builds the new table in the currently open database. Table names must be unique for each user. You can create temporary tables either by preceding the table name in a create table statement with a pound sign (#) or by specifying the name prefix “tempdb..”. For more information, see “Using temporary tables” on page 250. You can use any tables or other objects that you have created without qualifying their names. You can also use objects created by the Database Owner without qualifying their names, as long as you have the appropriate permissions on them. These rules hold for all users, including the System Administrator and the Database Owner. Different users can create tables of the same name. For example, a user named “jonah” and a user named “sally” can each create a table named info. Users who have permissions on both tables have to qualify them as jonah.info and sally.info. Sally must qualify references to Jonah’s table as jonah.info, but she can refer to her own table simply as info. create table syntax The syntax of create table is: create table [database.[owner].]table_name (column_name datatype [default {constant_expression | user | null}] {[{identity | null | not null}] [off row | in row] [[constraint constraint_name] {{unique | primary key} [clustered | nonclustered] [asc | desc] [with {fillfactor = pct, max_rows_per_page = num_rows, reservepagegap = num_pages}]CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 243 [on segment_name] | references [[database.]owner.]ref_table [ ref_column)] | check (search_condition)}]}... | [constraint constraint_name] {{unique | primary key} [clustered | nonclustered] (column_name [asc | desc] [{, column_name [asc | desc]}...]) [with {fillfactor = pct max_rows_per_page = num_rows , reservepagegap = num_pages }] [on segment_name] |foreign key (column_name [{,column_name}...]) references [[database.]owner.]ref_table [(ref_column [{, ref_column}...])] | check (search_condition) ...} [{, {next_column | next_constraint}}...]) [lock {datarows | datapages | allpages}] [with {max_rows_per_page = num_rows, exp_row_size = num_bytes, reservepagegap = num_pages, identity_gap = num_values}] [on segment_name ] [[external table] at pathname] Note For a complete discussion of the syntax, see create table in the Reference Manual. The create table statement: • Defines each column in the table. • Provides the column name and datatype and specifies how each column handles null values. • Specifies which column, if any, has the IDENTITY property. • Defines column-level integrity constraints and table-level integrity constraints. Each table definition can have multiple constraints per column and per table. For example, the create table statement for the titles table in the pubs2 database is: create table titles (title_id tid, title varchar(80) not null, type char(12), Creating tables 244 Adaptive Server Enterprise pub_id char(4) null, price money null, advance money null, royalty int null, total_sales int null, notes varchar(200) null, pubdate datetime, contract bit not null) The following sections describe components of table definition: systemsupplied datatypes, user-defined datatypes, null types, and IDENTITY columns. Note The on segment_name extension to create table allows you to place your table on an existing segment. segment_name points to a specific database device or a collection of database devices. Before creating a table on a segment, see a System Administrator or the Database Owner for a list of segments that you can use. Certain segments may be allocated to specific tables or indexes for performance reasons, or for other considerations. Allowing null values For each column, you can specify whether to allow null values. A null value is not the same as “zero” or “blank.” NULL means no entry has been made, and usually implies “value unknown” or “value not applicable.” It indicates that the user did not make any entry, for whatever reason. For example, a null entry in the price column of the titles table does not mean that the book is being given away free, but that the price is not known or has not yet been set. If the user does not make an entry in a column defined with the keyword null, Adaptive Server supplies the value “NULL”. A column defined with the keyword null also accepts an explicit entry of NULL from the user, no matter what datatype it is. Be careful when you enter null values in character columns. If you put the word “null” inside single or double quotes, Adaptive Server interprets the entry as a character string rather than as the value NULL. If you omit null or not null in the create table statement, Adaptive Server uses the null mode defined for the database (by default, NOT NULL). Use sp_dboption to set the allow nulls by default option to true. You must make an entry in a column defined as NOT NULL; otherwise, Adaptive Server displays an error message. CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 245 Defining columns as NULL provides a placeholder for data you may not yet know. For example, in the titles table, price, advance, royalty, and total_sales are set up to allow NULL. However, title_id and title are not, because the lack of an entry in these columns would be meaningless and confusing. A price without a title makes no sense, whereas a title without a price simply means that the price has not been set yet or is not available. In create table , use the keywords not null when the information in the column is critical to the meaning of the other columns. Constraints and rules used with null values You cannot define a column to allow null values, and then override this definition with a constraint or a rule that prohibits null values. For example, if a column definition specifies NULL and a rule specifies: @val in (1,2,3) An implicit or explicit NULL does not violate the rule. The column definition overrides the rule, even a rule that specifies: @val is not null See “Defining integrity constraints for tables” on page 263 for more information on constraints. Rules are covered in detail in Chapter 13, “Defining Defaults and Rules for Data.” Defaults and null values You can use defaults, that is, values that are supplied automatically when no entry is made, with both NULL and NOT NULL columns. A default counts as an entry. However, you cannot designate a NULL default for a NOT NULL column. You can specify null values as defaults using the default constraint of create table or using create default. The default constraint is described later in this chapter; create default is described in Chapter 13, “Defining Defaults and Rules for Data.” If you specify NOT NULL when you create a column and do not create a default for it, an error message occurs when a user fails to make an entry in that column during an insert. In addition, the user cannot insert or update such a column with NULL as a value. Creating tables 246 Adaptive Server Enterprise Table 8-1illustrates the interaction between a column’s default and its null type when a user specifies no column value or explicitly enters a NULL value. The three possible results are a null value for the column, the default value for the column, or an error message. Table 8-1: Column definition and null defaults Nulls require variable length datatypes Only columns with variable-length datatypes can store null values. When you create a NULL column with a fixed-length datatype, Adaptive Server converts it to the corresponding variable-length datatype. Adaptive Server does not inform you of the type change. Table 8-2 lists the fixed-length datatypes and the variable-length datatypes to which Adaptive Server converts them. Certain variable-length datatypes, such as moneyn, are reserved; you cannot use them to create columns, variables, or parameters. Column definition User entry Result Null and default defined Enters no value Enters NULL value Default used NULL used Null defined, no default defined Enters no value Enters NULL value NULL used NULL used Not null, default defined Enters no value Enters NULL value Default used NULL used Not null, no default defined Enters no value Enters NULL value Error ErrorCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 247 Table 8-2: Conversion of fixed-length to variable-length datatypes Data entered into char, nchar, and binary columns follows the rules for variablelength columns, rather than being padded with spaces or zeros to the full length of the column specification. text and image columns text and image columns created with insert and NULL are not initialized and contain no value. They do not use storage space and cannot be accessed with readtext or writetext. When a NULL value is written in a text or image column with update, the column is initialized, a valid text pointer to the column is inserted into the table, and a 2K data page is allocated to the column. Once the column is initialized, it can be accessed by readtext and writetext. See the Adaptive Server for more information. Using IDENTITY columns An IDENTITY column contains a value for each row, generated automatically by Adaptive Server, that uniquely identifies the row within the table. Each table can have only one IDENTITY column. You can define an IDENTITY column when you create a table with a create table or select into statement, or add it later with an alter table statement. IDENTITY columns cannot be updated and do not allow nulls. Original Fixed-Length Datatype Converted To char varchar nchar nvarchar binary datetime datetimn float floatn int, smallint, and tinyint intn decimal decimaln numeric numericn money and smallmoney moneynCreating tables 248 Adaptive Server Enterprise You define an IDENTITY column by specifying the keyword identity, instead of null or not null, in the create table statement. IDENTITY columns must have a datatype of numeric and scale of 0. Define the IDENTITY column with any desired precision, from 1 to 38 digits, in a new table: create table table_name (column_name numeric(precision ,0) identity) The maximum possible column value is 10 precision - 1. For example, this command creates a table with an IDENTITY column that allows a maximum value of 10 5 - 1, or 9999: create table sales_daily (sale_id numeric(5,0) identity, stor_id char(4) not null) You can create automatic IDENTITY columns by using the auto identity database option and the size of auto identity configuration parameter. To include IDENTITY columns in nonunique indexes, use the identity in nonunique index database option. Note By default, Adaptive Server begins numbering rows with the value 1, and continues numbering rows consecutively as they are added. Some activities, such as manual insertions, deletions, or transaction rollbacks, and server shutdowns or failures, can create gaps in IDENTITY column values. Adaptive Server provides several methods of controlling identity gaps described in “Managing identity gaps in tables” on page 254. Creating IDENTITY columns with user-defined datatypes You can use user-defined datatypes to create IDENTITY columns. The userdefined datatype must have an underlying type of numeric and a scale of 0. If the user-defined datatype was created with the IDENTITY property, you do not have to repeat the identity keyword when creating the column. This example shows a user-defined datatype with the IDENTITY property: sp_addtype ident, "numeric(5)", "identity" This example shows an IDENTITY column based on the ident datatype: create table sales_monthly (sale_id ident, stor_id char(4) not null)CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 249 If the user-defined type was created as not null, you must specify the identity keyword in the create table statement. You cannot create an IDENTITY column from a user-defined datatype that allows null values. Referencing IDENTITY columns When you create a table column that references an IDENTITY column, as with any referenced column, make sure it has the same datatype definition as the IDENTITY column. For example, in the pubs3 database, the sales table is defined using the ord_num column as an IDENTITY column: create table sales (stor_id char(4) not null references stores(stor_id), ord_num numeric(6,0) identity, date datetime not null, unique nonclustered (ord_num)) Notice that the ord_num IDENTITY column is defined as a unique constraint, which it needs for referencing the ord_num column in salesdetail. salesdetail is defined as follows: create table salesdetail (stor_id char(4) not null references storesz(stor_id), ord_num numeric(6,0) references salesz(ord_num), title_id tid not null references titles(title_id), qty smallint not null, discount float not null) An easy way to insert a row into salesdetail after inserting a row into sales is to use the @@identity global variable to insert the IDENTITY column value into salesdetail. The @@identity global variable stores the most recently generated IDENTITY column value. For example: begin tran insert sales values ("6380", "04/25/97") insert salesdetail values ("6380", @@identity, "TC3218", 50, 50) commit tran This example is in a transaction because both inserts depend on each other to succeed. For example, if the sales insert fails, the value of @@identity will be different, resulting in an erroneous row being inserted into salesdetail. Because the two inserts are in a transaction, if one fails, the entire transaction is rejected.Creating tables 250 Adaptive Server Enterprise For more information on IDENTITY columns, see “Retrieving IDENTITY column values with @@identity” on page 331. For information on transactions, see Chapter 19, “Transactions: Maintaining Data Consistency and Recovery.” Referring to IDENTITY columns with syb_identity Once you have defined an IDENTITY column, you do not have to remember the actual column name. You can use the syb_identity keyword, qualified by the table name where necessary, in a select, insert, update, or delete statement on the table. For example, this query selects the row for which sale_id equals 1: select * from sales_monthly where syb_identity = 1 Creating “hidden” IDENTITY columns automatically System Administrators can use the auto identity database option to automatically include a 10-digit IDENTITY column in new tables. To turn this feature on in a database, use: sp_dboption database_name, "auto identity", "true" Each time a user creates a new table without specifying either a primary key, a unique constraint, or an IDENTITY column, Adaptive Server automatically defines an IDENTITY column. The IDENTITY column is not visible when you use select * to retrieve all columns from the table. You must explicitly include the column name, SYB_IDENTITY_COL (all uppercase letters), in the select list. If Component Integration Services is enabled, the automatic IDENTITY column for proxy tables is called OMNI_IDENTITY_COL. To set the precision of the automatic IDENTITY column, use the size of auto identity configuration parameter. For example, to set the precision of the IDENTITY column to 15 use: sp_configure "size of auto identity", 15 Using temporary tables Temporary tables are created in the tempdb database. To create a temporary table, you must have create table permission in tempdb. create table permission defaults to the Database Owner.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 251 To make a table temporary, use the pound sign (#) or “tempdb..” before the table name in the create table statement. There are two kinds of temporary tables: • Tables that can be shared among Adaptive Server sessions You create a shareable temporary table by specifying tempdb as part of the table name in the create table statement. For example, the following statement creates a temporary table that can be shared among Adaptive Server sessions: create table tempdb..authors (au_id char(11)) drop table tempdb..authors Adaptive Server does not change the names of temporary tables created this way. The table exists until the current session ends or until its owner drops it using drop table. • Tables that are accessible only by the current Adaptive Server session or procedure You create a nonshareable temporary table by specifying a pound sign (#) before the table name in the create table statement. For example: create table #authors (au_id char (11)) The table exists until the current session or procedure ends, or until its owner drops it using drop table. If you do not use the pound sign or “tempdb..” before the table name, and you are not currently using tempdb, the table is created as a permanent table. A permanent table stays in the database until it is explicitly dropped by its owner. This statement creates a nonshareable temporary table: create table #myjobs (task char(30), start datetime, stop datetime, notes varchar(200)) You can use this table to keep a list of today’s chores and errands, along with a record of when you start and finish, and any comments you may have. This table and its data will automatically be deleted at the end of the current work session. Temporary tables are not recoverable.Creating tables 252 Adaptive Server Enterprise You can associate rules, defaults, and indexes with temporary tables, but you cannot create views on temporary tables or associate triggers with them. You can use a user-defined datatype when creating a temporary table only if the datatype exists in tempdb..systypes. To add an object to tempdb for the current session only, execute sp_addtype while using tempdb. To add an object permanently, execute sp_addtype in model, then restart Adaptive Server so model is copied to tempdb. Ensuring that the temporary table name is unique To ensure that a temporary table name is unique for the current session, Adaptive Server: • Truncates the table name to 13 characters, including the pound sign (#) • Pads shorter names to 13 characters, using underscores (_) • Appends a 17-digit numeric suffix that is unique for an Adaptive Server session The following example shows a table created as #temptable and stored as #temptable___00000050010721973: use pubs2 go create table #temptable (task char(30)) go use tempdb go select name from sysobjects where name like "#temptable%" go name ------------------------------ #temptable___00000050010721973 (1 row affected) Manipulating temporary tables in stored procedures Stored procedures can reference temporary tables that are created during the current session. Within a stored procedure, you cannot create a temporary table, drop it, and then create a new temporary table with the same name. CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 253 Temporary tables with names beginning with “#” Temporary tables with names beginning with “#” that are created within stored procedures disappear when the procedure exits. A single procedure can: • Create a temporary table • Insert data into the table • Run queries on the table • Call other procedures that reference the table Since the temporary table must exist in order to create procedures that reference it, here are the steps to follow: 1 Use create table to create the temporary table. 2 Create the procedures that access the temporary table, but do not create the procedure that creates the table. 3 Drop the temporary table. 4 Create the procedure that creates the table and calls the procedures created in step 2. tables with names beginning with tempdb.. You can create temporary tables without the # prefix, using create table tempdb..tablename from inside a stored procedure. These tables do not disappear when the procedure completes, so they can be referenced by independent procedures. Follow the steps above to create these tables. Warning! Create temporary tables with the “tempdb..” prefix from inside a stored procedure only if you intend to share the table among users and sessions. Stored procedures that create and drop a temporary table should use the # prefix to avoid inadvertent sharing. General rules on temporary tables Temporary tables with names that begin with # are subject to the following restrictions: • You cannot create views on these tables. • You cannot associate triggers with these tables. • You cannot tell which session or procedure has created these tables.Managing identity gaps in tables 254 Adaptive Server Enterprise These restrictions do not apply to shareable, temporary tables created in tempdb. Rules that apply to both types of temporary tables: • You can associate rules, defaults, and indexes with temporary tables. Indexes created on a temporary table disappear when the temporary table disappears. • System procedures such as sp_help work on temporary tables only if you invoke them from tempdb. • You cannot use user-defined datatypes in temporary tables unless the datatypes exist in tempdb; that is, unless the datatypes have been explicitly created in tempdb since the last time Adaptive Server was restarted. • You do not have to set the select into/bulkcopy option on to select into a temporary table. Creating tables in different databases As the create table syntax shows, you can create a table in a database other than the current one by qualifying the table name with the name of the other database. However, you must be an authorized user of the database in which you are creating the table, and you must have create table permission in it. If you are using pubs2 or pubs3 and there is another database called newpubs, you can create a table called newtab in newpubs like this: create table newpubs..newtab (col1 int) You cannot create other database objects—views, rules, defaults, stored procedures, and triggers—in a database other than the current one. Managing identity gaps in tables The IDENTITY column contains a unique ID number, generated by Adaptive Server, for each row in a table. Because of the way the server generates ID numbers by default, you may occasionally have large gaps in the ID numbers. The identity_gap parameter gives you control over ID numbers, and potential gaps in them, for a specific table.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 255 By default, Adaptive Server allocates a block of ID numbers in memory instead of writing each ID number to disk as it is needed, which requires more processing time. The server writes the highest number of each block to the table’s object allocation map (OAM) page. This number is used as the starting point for the next block after the currently allocated block of numbers is used or “burned”. The other numbers of the block are held in memory, but are not saved to disk. Numbers are considered burned when they are allocated to memory, then deleted from memory either because they were assigned to a row, or because they were erased from memory due to some abnormal occurrence such as a system failure. Allocating a block of ID numbers improves performance by reducing contention for the table. However, if the server fails or is shut down with no wait before all the ID numbers are assigned, the unused numbers are burned. When the server is running again, it starts numbering with the next block of numbers based on the highest number of the previous block that the server wrote to disk. Depending on how many allocated numbers were assigned to rows before the failure, you may have a large gap in the ID numbers. Identity gaps can also result from dumping and loading an active database. When dumping, database objects are saved to the OAM page. If an object is currently being used, the ‘maximum used identity value’ is not be in the OAM page and, therefore, is not dumped. Parameters for controlling identity gaps Adaptive Server provides parameters that allow you to control gaps in identity numbers as described in Table 8-3. Table 8-3: Parameters for controlling identity gaps Parameter Name Scope Used with Description identity_gap table-specific create table or select into Creates ID number blocks of a specific size for a specific table. Overrides identity burning set factor for the table. Works with identity grab size.Managing identity gaps in tables 256 Adaptive Server Enterprise Comparison of identity burning set factor and identity_gap The identity_gap parameter gives you control over the size of identity gaps for a particular table as illustrated in the following examples. In the examples, we have created a table named books to list all the books in our bookstore. We want each book to have a unique ID number, and we want Adaptive Server to automatically generate the ID numbers. Example of using identity burning set factor When defining the IDENTITY column for the books table, we used the default numeric value of (18, 0), which provides a total of 999,999,999,999,999,999 ID numbers. For the identity burning set factor configuration parameter, we are using the default setting of 5000 (.05 percent of 999,999,999,999,999,999), which means that Adaptive Server allocates blocks of 500,000,000,000,000 numbers. identity burning set factor server-wide sp_configure Indicates a percentage of the total available ID numbers you want to have allocated for each block. Works with identity grab size. If the identity_gap for a table is set to 1 or higher, identity burning set factor has no effect on that table. The burning set factor is used for all tables for which identity_gap is set to 0. When you set identity burning set factor, you express the number in decimal form, and then multiply it by 10,000,000 (10 7 ) to get the correct value to use with sp_configure. For example, to release 15 percent (.15) of the potential IDENTITY column values at one time, you specify a value of .15 times 10 7 (or 1,500,000): sp_configure "identity burning set factor", 1500000 identity grab size server-wide sp_configure Reserves a block of contiguous ID numbers for each process. Works with identity burning set factor and identity_gap. Parameter Name Scope Used with DescriptionCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 257 The server allocates the first 500,000,000,000,000 numbers in memory and stores the highest number of the block (500,000,000,000,000) on the table’s OAM page. When all the numbers are assigned to rows or burned, the server takes the next block of numbers (the next 500,000,000,000,000), starting with 500,000,000,000,001, and stores the number 1,000,000,000,000,000 as the highest number of the block. Let’s say, after row number 500,000,000,000,022 the server fails. Only numbers 1 through 500,000,000,000,022 were used as ID numbers for books. Numbers 500,000,000,000,023 through 1,000,000,000,000,000 are burned. When the server is running again, it creates ID numbers starting from the highest number stored on the table’s OAM page plus one (1,000,000,000,000,001),which leaves a gap of 499,999,999,999,978 ID numbers. To reduce this large gap in identity numbers for a specific table, you can set the identity gap as described in “Example of using identity_gap.” Example of using identity_gap In this case, we create the books table with an identity_gap value of 1000. This overrides the server-wide identity burning set factor setting that resulted in blocks of 500,000,000,000,000 ID numbers. Instead, ID numbers are allocated in memory in blocks of 1000. The server allocates the first 1000 numbers and stores the highest number of the block (1000) to disk. When all the numbers are used, the server takes the next 1000 numbers, starting with 1001, and stores the number 2000 as the highest number. Now, let’s say that after row number 1002 we lose power, which causes the server to fail. Only the numbers 1000 through 1002 were used, and numbers 1003 through 2000 are lost. When the server is running again, it creates ID numbers starting from the highest number stored on the table’s OAM page plus one (2000), which leaves a gap of only 998 numbers. You can significantly reduce the gap in ID numbers by setting the identity_gap for a table instead of using the server-wide table burning set factor. However, there may be a performance cost to setting this value too low. Each time the server must write the highest number of a block to disk, performance is affected. For example, if identity_gap is set to 1, which means you are allocating one ID number at a time, the server must write the new number every time a row is created, which may reduce performance because of page lock contention on the table. You must find the best setting to achieve the optimal performance with the lowest gap value acceptable for your situation.Managing identity gaps in tables 258 Adaptive Server Enterprise Setting the table-specific identity gap Set the table-specific identity gap when you create a table using either create table or select into. Setting identity gap with create table The syntax is: create table table_name (column_name datatype(constant_expression) identity) with identity_gap = value For example: create table mytable (IdNum numeric(12,0) identity) with identity_gap = 10 This statement creates a table named mytable with an identity column. The identity gap is set to 10, which means ID numbers will be allocated in memory in blocks of ten. If the server fails or is shut down with no wait, the maximum gap between the last ID number assigned to a row and the next ID number assigned to a row is ten numbers. Setting identity gap with select into If you are creating a table in a select into statement from a table that has a specific identity gap setting, the new table does not inherit the identity gap setting from the parent table. Instead, the new table uses the identity burning set factor setting. To give the new table a specific identity_gap setting, specify the identity gap in the select into statement. You can give the new table an identity gap that is the same as or different from the parent table. For example, to create a new table (newtable) from the existing table (mytable) with an identity gap: select identity into newtable with identity_gap = 20 from mytable Changing the table-specific identity gap To change the identity gap for a specific table, use sp_chgattribute: sp_chgattribute "table_name", "identity_gap", set_numberCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 259 where: • table_name is the name of the table for which you want to change the identity gap. • identity_gap indicates that you want to change the identity gap. • set_number is the new size of the identity gap. For example: sp_chgattribute "mytable", "identity_gap", 20 To change mytable to use the identity burning set factor setting instead of the identity_gap setting, set identity_gap to 0: sp_chgattribute "mytable", "identity_gap", 0 Displaying table-specific identity gap information To see the identity_gap setting for a table, use sp_help. For example, the zero value in the identity_gap column (towards the end of the output) indicates that no table-specific identity gap is set. mytable uses the server-wide identity burning set factor value. sp_help mytable Name Owner Type ------------------------------ ----------------------- ------- ---------------------- mytable dbo user table (1 row affected) Data_located_on_segment When_created ------------------------------ ----------------------- --- default Jun 8 1999 5:35PM Column_name Type Length Prec Scale Nulls Default_name Rule_name Identity --------------- --------------- ------ ---- ----- ---- - --------------- --------------- --------Managing identity gaps in tables 260 Adaptive Server Enterprise idnum numeric 6 12 0 0 NULL NULL 1 Object does not have any indexes. No defined keys for this object. Object is not partitioned. Lock scheme Allpages The attribute ’exp_row_size’ is not applicable to tables with allpages lock scheme. The attribute ’concurrency_opt_threshold’ is not applicable to tables with allpages lock scheme. exp_row_size reservepagegap fillfactor max_rows_per_page identity_gap ------------ -------------- ---------- -------------- --- ------------ 1 0 0 0 0 concurrency_opt_threshold ------------------------- 0 If you change the identity_gap of mytable to 20, the sp_help output for the table shows 20 in the identity_gap column. This setting overrides the server-wide identity burning set factor value. sp_help mytable Name Owner Type ------------------------------ ----------------------- ------- ---------------------- mytable dbo user table (1 row affected) Data_located_on_segment When_created ------------------------------ ----------------------- --- default Jun 8 1999 5:35PM Column_name Type Length Prec Scale Nulls Default_name Rule_name Identity --------------- --------------- ------ ---- ----- ---- - --------------- CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 261 --------------- -------- idnum numeric 6 12 0 0 NULL NULL 1 Object does not have any indexes. No defined keys for this object. Object is not partitioned. Lock scheme Allpages The attribute ’exp_row_size’ is not applicable to tables with allpages lock scheme. The attribute ’concurrency_opt_threshold’ is not applicable to tables with allpages lock scheme. exp_row_size reservepagegap fillfactor max_rows_per_page identity_gap ------------ -------------- ---------- --------------- -- ------------ 1 0 0 0 2 0 concurrency_opt_threshold ------------------------- 0 Gaps due to insertions, deletions, identity grab size, and rollbacks Manual insertions into the IDENTITY column, deletion of rows, the value of the identity grab size configuration parameter, and transaction rollbacks can create gaps in IDENTITY column values. These gaps are not affected by the setting of the identity burning set factor configuration parameter. For example, assume that you have an IDENTITY column with these values: select syb_identity from stores_cal id_col ------- 1 2 3 4 5 (5 rows affected) You can delete all rows for which the IDENTITY column falls between 2 and 4, leaving gaps in the column values:Managing identity gaps in tables 262 Adaptive Server Enterprise delete stores_cal where syb_identity between 2 and 4 select syb_identity from stores_cal id_col ------ 1 5 (2 rows affected) After setting identity_insert on for the table, the table owner, Database Owner, or System Administrator can manually insert any legal value greater than 5. For example, inserting a value of 55 would create a large gap in IDENTITY column values: insert stores_cal (syb_identity, stor_id, stor_name) values (55, "5025", "Good Reads") select syb_identity from stores_cal id_col ------- 1 5 55 (3 rows affected) If identity_insert is then set to off, Adaptive Server assigns an IDENTITY column value of 55 + 1, or 56, for the next insertion. If the transaction that contains the insert statement is rolled back, Adaptive Server discards the value 56 and uses a value of 57 for the next insertion. If table inserts reach the IDENTITY column’s maximum value The maximum number of rows you can insert into a table depends on the precision set for the IDENTITY column. If a table reaches that limit, you can either re-create the table with a larger precision or, if the table’s IDENTITY column is not used for referential integrity, use the bcp utility to remove the gaps. See “Reaching the IDENTITY column’s maximum value” on page 333 for more information.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 263 Defining integrity constraints for tables Transact-SQL provides two methods for maintaining data integrity in a database: • Defining rules, defaults, indexes, and triggers • Defining create table integrity constraints Choosing one method over the other depends on your requirements. Integrity constraints offer the advantages of defining integrity controls in one step during the table creation process (as defined by the SQL standards) and of simplifying the process to create those integrity controls. However, integrity constraints are more limited in scope and less comprehensive than defaults, rules, indexes, and triggers. For example, triggers provide more complex handling of referential integrity than those declared in create table. Also, the integrity constraints defined by a create table are specific for that table; you cannot bind them to other tables, and you can only drop or change them using alter table. Constraints cannot contain subqueries or aggregate functions, even on the same table. The two methods are not mutually exclusive. You can use integrity constraints along with defaults, rules, indexes, and triggers. This gives you the flexibility to choose the best method for your application. This section describes the create table integrity constraints. Defaults, rules, indexes, and triggers are described in later chapters. You can create the following types of constraints: • unique and primary key constraints require that no two rows in a table have the same values in the specified columns. In addition, a primary key constraint requires that there not be a null value in any row of the column. • Referential integrity (references) constraints require that data being inserted in specific columns already have matching data in the specified table and columns. Use sp_helpconstraint to find a table’s referenced tables. • check constraints limit the values of data inserted into columns. You can also enforce data integrity by restricting the use of null values in a column (the null or not null keywords) and by providing default values for columns (the default clause). See “Allowing null values” on page 244 for information about the null and not null keywords.Defining integrity constraints for tables 264 Adaptive Server Enterprise For information about any constraints defined for a table, see “Using sp_helpconstraint to find a table’s constraint information” on page 307. Warning! Do not define or alter the definitions of constraints for system tables. Specifying table-level or column-level constraints You can declare integrity constraints at the table or column level. Although the difference is rarely noticed by users, column-level constraints are only checked if a value in the column is being modified, while the table-level constraints are checked if there is any modification to a row, regardless of whether or not it changes the column in question. You place column-level constraints after the column name and datatype, but before the delimiting comma. You enter table-level constraints as separate comma-delimited clauses. Adaptive Server treats table-level and column-level constraints the same way; both ways are equally efficient However, you must declare constraints that operate on more than one column as table-level constraints. For example, the following create table statement has a check constraint that operates on two columns, pub_id and pub_name: create table my_publishers (pub_id char(4), pub_name varchar(40), constraint my_chk_constraint check (pub_id in ("1389", "0736", "0877") or pub_name not like "Bad News Books")) You can declare constraints that operate on just one column as column-level constraints, but it is not required. For example, if the above check constraint uses only one column (pub_id), you can place the constraint on that column: create table my_publishers (pub_id char(4) constraint my_chk_constraint check (pub_id in ("1389", "0736", "0877")), pub_name varchar(40))CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 265 In either case, the constraint keyword and accompanying constraint_name are optional. The check constraint is described under “Specifying check constraints” on page 271. Note You cannot issue create table with a check constraint and then insert data into the table in the same batch or procedure. Either separate the create and insert statements into two different batches or procedures, or use execute to perform the actions separately. Creating error messages for constraints You can create error messages and bind them to constraints by creating messages with sp_addmessage and binding them to constraints with sp_bindmsg. For example: sp_addmessage 25001, "The publisher ID must be 1389, 0736, or 0877" sp_bindmsg my_chk_constraint, 25001 insert my_publishers values ("0000", "Reject This Publisher") Msg 25001, Level 16, State 1: Server ‘snipe’, Line 1: The publisher ID must be 1389, 0736, or 0877 Command has been aborted. To change the message for a constraint, bind a new message. The new message replaces the old message. Unbind messages from constraints using sp_unbindmsg; drop user-defined messages using sp_dropmessage. For example: sp_unbindmsg my_chk_constraint sp_dropmessage 25001 To change the text of a message but keep the same error number, unbind it, drop it with sp_dropmessage, add it again with sp_addmessage, and bind it with sp_bindmsg. Defining integrity constraints for tables 266 Adaptive Server Enterprise After creating a check constraint After you create a check constraint, the source text describing the check constraint is stored in the text column of the syscomments system table. Do not remove this information from syscomments; doing so can cause problems for future upgrades of Adaptive Server. If you have security concerns, encrypt the text in syscomments by using sp_hidetext, described in the Reference Manual. For more information, see “Compiled objects” on page 4. Specifying default column values Before you define any column-level integrity constraints, you can specify a default value for the column with the default clause. The default clause assigns a default value to a column as part of the create table statement. When a user does not enter a value for the column, Adaptive Server inserts the default value. You can use the following values with the default clause: • constant_expression – specifies a constant expression to use as a default value for the column. It cannot include the name of any columns or other database objects, but you can include built-in functions that do not reference database objects. This default value must be compatible with the datatype of the column. • user – specifies that Adaptive Server insert the user name as the default. The datatype of the column must be either char(30) or varchar(30) to use this default. • null – specifies that Adaptive Server insert the null value as the default. You cannot define this default for columns that do not allow null values (using the notnull keyword). For example, this create table statement defines two column defaults: create table my_titles (title_id char(6), title varchar(80), price money default null, total_sales int default 0) You can include only one default clause per column in a table. Using the default clause to assign defaults is simpler than the two-step Transact-SQL method. In Transact-SQL, you can use create default to declare the default value and then bind it to the column with sp_bindefault.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 267 Specifying unique and primary key constraints You can declare unique or primary key constraints to ensure that no two rows in a table have the same values in the specified columns. Both constraints create unique indexes to enforce this data integrity. However, primary key constraints are more restrictive than unique constraints. Columns with primary key constraints cannot contain a NULL value. You normally use a table’s primary key constraint in conjunction with referential integrity constraints defined on other tables. The definition of unique constraints in the SQL standards specifies that the column definition shall not allow null values. By default, Adaptive Server defines the column as not allowing null values (if you have not changed this using sp_dboption) when you omit null or not null keywords in the column definition. In Transact-SQL, you can define the column to allow null values along with the unique constraint, since the unique index used to enforce the constraint allows you to insert a null value. Note Do not confuse the unique and primary key integrity constraints with the information defined by sp_primarykey, sp_foreignkey, and sp_commonkey. The unique and primary key constraints actually create indexes to define unique or primary key attributes of table columns. sp_primarykey, sp_foreignkey, and sp_commonkey define the logical relationship of keys (in the syskeys table) for table columns, which you enforce by creating indexes and triggers. unique constraints create unique nonclustered indexes by default; primary key constraints create unique clustered indexes by default. You can declare either clustered or nonclustered indexes with either type of constraint. For example, the following create table statement uses a table-level unique constraint to ensure that no two rows have the same values in the stor_id and ord_num columns: create table my_sales (stor_id char(4), ord_num varchar(20), date datetime, unique clustered (stor_id, ord_num)) There can be only one clustered index on a table, so you can specify only one unique clustered or primary key clustered constraint. Defining integrity constraints for tables 268 Adaptive Server Enterprise You can use the unique and primary key constraints to create unique indexes (including the with fillfactor, with max_rows_per_page, and on segment_name options) when enforcing data integrity. However, indexes provide additional capabilities. For information about indexes and their options, including the differences between clustered and nonclustered indexes, see Chapter 12, “Creating Indexes on Tables.” Specifying referential integrity constraints Referential integrity refers to the methods used to manage the relationships between tables. When you create a table, you can define constraints to ensure that the data inserted into a particular column has matching values in another table. There are three types of references you can define in a table: references to another table, references from another table, and self-references, that is, references within the same table. The following two tables from the pubs3 database illustrate how declarative referential integrity works. The first table, stores, is a “referenced” table: create table stores (stor_id char(4) not null, stor_name varchar(40) null, stor_address varchar(40) null, city varchar(20) null, state char(2) null, country varchar(12) null, postalcode char(10) null, payterms varchar(12) null, unique nonclustered (stor_id)) The second table, store_employees, is a “referencing table” because it contains a reference to the stores table. It also contains a self-reference: create table store_employees (stor_id char(4) null references stores(stor_id), emp_id id not null, mgr_id id null references store_employees(emp_id), emp_lname varchar(40) not null, emp_fname varchar(20) not null, phone char(12) null, address varchar(40) null,CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 269 city varchar(20) null, state char(2) null, country varchar(12) null, postalcode varchar(10) null, unique nonclustered (emp_id)) The references defined in the store_employees table enforce the following restrictions: • Any store specified in the store_employees table must be included in the stores table. The references constraint enforces this by saying that any value inserted into the stor_id column in store_employees must already exist in the stor_id column in my_stores. • All managers must have employee identification numbers. The references constraint enforces this by saying that any value inserted into the mgr_id column must already exist in the emp_id column. Table-level or column-level referential integrity constraints You can define referential integrity constraints at the column level or the table level. The referential integrity constraints in the preceding examples were defined at the column level, using the references keyword in the create table statement. When you define table-level referential integrity constraints, include the foreign key clause and a list of one or more column names. foreign key specifies that the listed columns in the current table are foreign keys whose target keys are the columns listed the following references clause. For example: constraint sales_detail_constr foreign key (stor_id, ord_num) references my_salesdetail(stor_id, ord_num) The foreign key syntax is permitted only for table-level constraints, and not for column-level constraints. For more information, see “Specifying table-level or column-level constraints” on page 264. After defining referential integrity constraints at the column level or the table level, you can use sp_primarykey, sp_foreignkey, and sp_commonkey to define the keys in the syskeys system table.Defining integrity constraints for tables 270 Adaptive Server Enterprise Maximum number of references allowed for a table The maximum number of references allowed for a table is 192. You can check a table’s references by using sp_helpconstraint, described under “Using sp_helpconstraint to find a table’s constraint information” on page 307. Using create schema for cross-referencing constraints You cannot create a table that references a table that does not yet exist. To create two or more tables that reference each other, use create schema. A schema is a collection of objects owned by a particular user, and the permissions associated with those objects. If any of the statements within a create schema statement fail, the entire command is rolled back as a unit, and none of the commands take effect. The create schema syntax is: create schema authorization authorization name create_object_statement [create_object_statement ...] [permission_statement ...] For example: create schema authorization dbo create table list1 (col_a char(10) primary key, col_b char(10) null references list2(col_A)) create table list2 (col_A char(10) primary key, col_B char(10) null references list1(col_a)) General rules for creating referential integrity constraints When you define referential integrity constraints in a table: • Make sure you have references permission on the referenced table. For information about permissions, see the System Administration Guide. • Make sure that the referenced columns are constrained by a unique index in the referenced table. You can create that unique index using either the unique or primary key constraint or the create index statement. For example, the referenced column in the stores table is defined as: stor_id char(4) primary keyCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 271 • Make sure the columns used in the references definition have matching datatypes. For example, the stor_id columns in both my_stores and store_employees were created using the char(4) datatype. The mgr_id and emp_id columns in store_employees were created with the id datatype. • You can omit column names in the references clause only if the columns in the referenced table are designated as a primary key through a primary key constraint. • You cannot delete rows or update column values from a referenced table that match values in a referencing table. Delete or update from the referencing table first, and then delete it from the referenced table. Similarly, you cannot use truncate table on a referenced table. Truncate the referencing table first, and then truncate the referenced table. • You must drop the referencing table before you drop the referenced table; otherwise, a constraint violation occurs. • Use sp_helpconstraint to find a table’s referenced tables. Referential integrity constraints provide a simpler way to enforce data integrity than triggers. However, triggers provide additional capabilities to enforce referential integrity between tables. For more information, see Chapter 17, “Triggers: Enforcing Referential Integrity.” Specifying check constraints You can declare a check constraint to limit the values users insert into a column in a table. Check constraints are useful for applications that check a limited, specific range of values. A check constraint specifies a search_condition that any value must pass before it is inserted into the table. A search_condition can include: • A list of constant expressions introduced with in • A range of constant expressions introduced with between • A set of conditions introduced with like, which may contain wildcard characters An expression can include arithmetic operations and Transact-SQL built-in functions. The search_condition cannot contain subqueries, a set function specification, or a target specification. For example, this statement ensures that only certain values can be entered for the pub_id column:Defining integrity constraints for tables 272 Adaptive Server Enterprise create table my_new_publishers (pub_id char(4) check (pub_id in ("1389", "0736", "0877", "1622", "1756") or pub_id like "99[0-9][0-9]"), pub_name varchar(40), city varchar(20), state char(2)) Column-level check constraints can reference only the column on which the constraint is defined; they cannot reference other columns in the table. Tablelevel check constraints can reference any columns in the table. create table allows multiple check constraints in a column definition. Because check constraints do not override column definitions, you cannot use a check constraint to prohibit null values if the column definition permits them. If you declare a check constraint on a column that allows null values, you can insert NULL into the column, implicitly or explicitly, even though NULL is not included in the search_condition. For example, suppose you define the following check constraint on a table column that allows null values: check (pub_id in ("1389", "0736", "0877", "1622", "1756")) You can still insert NULL into that column. The column definition overrides the check constraint because the following expression always evaluates to true: col_name != null Designing applications that use referential integrity When you design applications that use referential integrity features: • Do not create unnecessary referential constraints. The more referential constraints a table has, the slower a statement requiring referential integrity runs on that table. • Use as few self-referencing constraints on a table as possible. • Use the check constraint rather than the references constraint for applications that check a limited, specific range of values. Using the check constraint eliminates the need for Adaptive Server to scan other tables to complete the query, since there are no references. Therefore, queries on such tables run faster than on tables using references. For example, this table uses a check constraint to limit the authors to California:CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 273 create table cal_authors (au_id id not null, au_lname varchar(40) not null, au_fname varchar(20) not null, phone char(12) null, address varchar(40) null, city varchar(20) null, state char(2) null check(state = "CA"), country varchar(12) null, postalcode char(10) null) • Bind commonly scanned foreign key indexes to their own caches, to optimize performance. Unique indexes are created automatically on columns declared as primary keys. These indexes are usually selected to scan the referenced table when their corresponding foreign keys are updated or inserted. • Keep multi-row updates of candidate keys at a minimum. • Put referential integrity queries into procedures that use constraint checks. Constraint checks are compiled into the execution plan; when a referential constraint is altered, the procedure that has the constraint compiled is automatically recompiled when that procedure is executed. • If you cannot embed referential integrity queries in a procedure and you frequently have to run referential integrity queries in an ad hoc batch, bind the system catalog sysreferences to its own cache. This improves performance when Adaptive Server needs to recompile referential integrity queries. • After you create a table that has referential constraints, test it by using set showplan, noexec on before running a query using the table. The showplan output indicates the number of auxiliary scan descriptors required to run the query; scan descriptors manage the scan of a table whenever queries are run on it. If the number of auxiliary scan descriptors is very high, either redesign the table so it uses fewer scan descriptors, or increase the value of the number of auxiliary scan descriptors configuration parameter.How to design and create a table 274 Adaptive Server Enterprise How to design and create a table This section gives an example of a create table statement you can use to create a practice table of your own. If you do not have create table permission, see a System Administrator or the owner of the database in which you are working. Creating a table usually implies creating indexes, defaults, and rules to go with it. Custom datatypes, triggers, and views are frequently involved, too. Of course, you can create a table, input some data, and work with it for a while before you create indexes, defaults, rules, triggers, or views. This allows you to see what kind of transactions are most common and what kind of data is frequently entered. On the other hand, it is often most efficient to design a table and all the components that go with it at once. Here is an outline of the steps you go through. You might find it easiest to sketch your plans on paper before you actually create a table and its accompanying objects. First, plan the table’s design: 1 Decide what columns you need in the table, and the datatype, length, precision, and scale, for each. 2 Create any new user-defined datatypes before you define the table where they are to be used. 3 Decide which column, if any, should be the IDENTITY column. 4 Decide which columns should and which should not accept null values. 5 Decide what integrity constraints or column defaults, if any, you need to add to the columns in the table. This includes deciding when to use column constraints and defaults instead of defaults, rules, indexes, and triggers to enforce data integrity. 6 Decide whether you need defaults and rules, and if so, where and what kind. Consider the relationship between the NULL and NOT NULL status of a column and defaults and rules. 7 Decide what kind of indexes you need and where. Indexes are discussed in Chapter 12, “Creating Indexes on Tables.” Now, create the table and its associated objects: 1 Create the table and its indexes using create table and create index. 2 Create the defaults and rules you need with the create default and create rule. These commands are discussed in Chapter 13, “Defining Defaults and Rules for Data.”CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 275 3 Bind any defaults and rules you need with sp_bindefault and sp_bindrule. If there were any defaults or rules on a user-defined datatype that you used in a create table statement, they are automatically in force. These system procedures are discussed in Chapter 15, “Using Stored Procedures.” 4 Create triggers using create trigger. Triggers are discussed in Chapter 17, “Triggers: Enforcing Referential Integrity.” 5 Create views using create view. Views are discussed in Chapter 10, “Views: Limiting Access to Data.” Make a design sketch The table called friends_etc is used in this chapter and subsequent chapters to illustrate how to create indexes, defaults, rules, triggers, and so forth. It can hold names, addresses, telephone numbers, and personal information about your friends. It does not define any column defaults or integrity constraints, so as to not conflict with those objects. If another user has already created the friends_etc table, check with a System Administrator or the Database Owner if you plan to follow the examples and create the objects that go with friends_etc. The owner of friends_etc will need to drop its indexes, defaults, rules, and triggers so that there will be no conflict when you create these objects. Table 8-4 shows the proposed structure of the friends_etc table and the indexes, defaults, and rules that go with each column. Table 8-4: Sample table design Column Datatype Null? Index Default Rule pname nm NOT NULL nmind(composite) sname nm NOT NULL nmind(composite) address varchar(30) NULL city varchar(30) NOT NULL citydflt state char(2) NOT NULL statedflt zip char(5) NULL zipind zipdflt ziprule phone p# NULL phonerule age tinyint NULL agerule bday datetime NOT NULL bdflt gender bit NOT NULL gndrdflt debt money NOT NULL gndrdflt notes varchar(255) NULLHow to design and create a table 276 Adaptive Server Enterprise Create the user-defined datatypes The first two columns are for the personal (first) name and surname. They are defined as nm datatype. Before you create the table, you need to create the datatype. The same is true of the p# datatype for the phone column: execute sp_addtype nm, "varchar(30)" execute sp_addtype p#, "char(10)" The nm datatype allows for a variable-length character entry with a maximum of 30 bytes. The p# datatype allows for a char datatype with a fixed-length size of 10 bytes. Choose the columns that accept null values Except for columns that are assigned user-defined datatypes, each column has an explicit NULL or NOT NULL entry. You do not need to specify NOT NULL in the table definition, because it is the default. This table design specifies NOT NULL explicitly, for readability. The NOT NULL default means that an entry is required for that column, for example, for the two name columns in this table. The other data is meaningless without the names. In addition, the gender column must be NOT NULL because you cannot use NULL with bit columns. If a column is designated NULL and a default is bound to it, the default value, rather than NULL, is entered when no other value is given on input. If a column is designated NULL and a rule is bound to it that does not specify NULL, the column definition overrides the rule when no value is entered for the column. Columns can have both defaults and rules. The relationship between these two is discussed in Chapter 13, “Defining Defaults and Rules for Data.” Define the table Now, write the create table statement: create table friends_etc (pname nm not null, sname nm not null, address varchar(30) null, city varchar(30) not null, state char(2) not null, postalcode char(5) null, phone p# null, CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 277 age tinyint null, bday datetime not null, gender bit not null, debt money not null, notes varchar(255) null) You have now defined columns for the personal name and surname, address, city, state, postal code, telephone number, age, birthday, gender, debt information, and notes. Later, you will create the rules, defaults, indexes, triggers, and views for this table. Creating new tables from query results: select into The select into command lets you create a new table based on the columns specified in the select statement’s select list and the rows chosen in the where clause. The into clause is useful for creating test tables, new tables as copies of existing tables, and for making several smaller tables out of one large table. You can use select into on a permanent table only if the select into/bulkcopy/pllsort database option is set to on. A System Administrator can turn on this option using sp_dboption. Use sp_helpdb to see if this option is on. Here is what sp_helpdb and its results look like when the select into/bulkcopy/pllsort database option is set to on: sp_helpdb pubs2 name db_size owner dbid created status --------- ------- ------ ----- ----------- ------ ------ pubs 2 MB sa 5 Jun 5 1997 select into /bulkcopy/pllsort (1 row affected) device size usage ----------------- --------- -------------- master 2 MB data and log (1 row affected) sp_helpdb output indicates whether the option is set to on or off. Only the System Administrator or the Database Owner can set the database options.Creating new tables from query results: select into 278 Adaptive Server Enterprise If the select into/bulkcopy/pllsort database option is on, you can use the select into clause to build a new permanent table without using a create table statement. You can select into a temporary table, even if the select into/bulkcopy/pllsort option is not on. Note Because select into is a minimally logged operation, use dump database to back up your database following a select into. You cannot dump the transaction log following a minimally logged operation. Unlike a view that displays a portion of a table, a table created with select into is a separate, independent entity. See Chapter 10, “Views: Limiting Access to Data,” for more information. The new table is based on the columns you specify in the select list, the tables you name in the from clause, and the rows you choose in the where clause. The name of the new table must be unique in the database and must conform to the rules for identifiers. A select statement with an into clause allows you to define a table and put data into it, based on existing definitions and data, without going through the usual data definition process. The following example shows a select into statement and its results. A table called newtable is created, using two of the columns in the four-column table publishers. Because this statement includes no where clause, data from all the rows (but only the two specified columns) of publishers is copied into newtable. select pub_id, pub_name into newtable from publishers (3 rows affected) “3 rows affected” refers to the three rows inserted into newtable. Here’s what newtable looks like: select * from newtable pub_id pub_name ------ ------------------------------------ 0736 New Age Books 0877 Binnet & Hardley 1389 Algodata Infosystems (3 rows affected) The new table contains the results of the select statement. It becomes part of the database, just like its parent table. CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 279 You can create a skeleton table with no data by putting a false condition in the where clause. For example: select * into newtable2 from publishers where 1=2 (0 rows affected) select * from newtable2 pub_id pub_name city state ------ -------------- -------- ----- (0 rows affected) No rows are inserted into the new table, because 1 never equals 2. You can also use select into with aggregate functions to create tables with summary data: select type, "Total_amount" = sum(advance) into #whatspent from titles group by type (6 rows affected) select * from #whatspent type Total_amount ------------ ------------------------ UNDECIDED NULL business 25,125.00 mod_cook 15,000.00 popular_comp 15,000.00 psychology 21,275.00 trad_cook 19,000.00 (6 rows affected) Always supply a name for any column in the select into result table that results from an aggregate function or any other expression. Examples are: • Arithmetic aggregates, for example, amount * 2 • Concatenation, for example, lname + fname • Functions, for example, lower(lname) Here is an example of using concatenation: select au_id, "Full_Name" = au_fname + ’ ’ + au_lnameCreating new tables from query results: select into 280 Adaptive Server Enterprise into #g_authortemp from authors where au_lname like "G%" (3 rows affected) select * from #g_authortemp au_id Full_Name ----------- ------------------------- 213-46-8915 Marjorie Green 472-27-2349 Burt Gringlesby 527-72-3246 Morningstar Greene (3 rows affected) Because functions allow null values, any column in the table that results from a function other than convert() or isnull() allows null values. Checking for errors select into is a two-step operation. The first step creates the new table and the second step inserts the specified rows into the table. Because select into operations are not logged, they cannot be issued within user-defined transactions and cannot be rolled back. If a select into statement fails after creating a new table, Adaptive Server does not automatically drop the table or deallocate its first data page. This means that any rows inserted on the first page before the error occurred remain on the page. Check the value of the @@error global variable after a select into statement to be sure that no error occurred. If an error occurs from a select into operation, drop table to remove the new table, then reissue the select into statement. Using select into with IDENTITY columns This section describes special rules for using the select into command with tables containing IDENTITY columns. Selecting an IDENTITY column into a new table To select an existing IDENTITY column into a new table, include the column name (or the syb_identity keyword) in the select statement’s column_list: CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 281 select column_list into table_name from table_name The following example creates a new table, stores_cal_pay30, based on columns from the stores_cal table: select record_id, stor_id, stor_name into stores_cal_pay30 from stores_cal where payterms = "Net 30" The new column inherits the IDENTITY property, unless any of the following conditions is true: • The IDENTITY column is selected more than once. • The IDENTITY column is selected as part of an expression. • The select statement contains a group by clause, aggregate function, union operator, or join. Selecting the IDENTITY column more than once A table cannot have more than one IDENTITY column. If an IDENTITY column is selected more than once, it is defined as NOT NULL in the new table. It does not inherit the IDENTITY property. In the following example, the record_id column, which is selected once by name and once by the syb_identity keyword, is defined as NOT NULL in stores_cal_pay60: select syb_identity, record_id, stor_id, stor_name into stores_cal_pay60 from stores_cal where payterms = "Net 60" Adding a new IDENTITY column with select into To define a new IDENTITY column in a select into statement, add the column definition before the into clause. The definition includes the column’s precision but not its scale: select column_list identity_column_name = identity(precision) into table_name from table_nameCreating new tables from query results: select into 282 Adaptive Server Enterprise The following example creates a new table, new_discounts, from the discounts table and adds a new IDENTITY column, id_col: select *, id_col=identity(5) into new_discounts from discounts If the column_list includes an existing IDENTITY column, and you add a description of a new IDENTITY column, the select into statement fails. Defining a column whose value must be computed IDENTITY column values are generated by Adaptive Server. New columns that are based on IDENTITY columns, but whose values must be computed rather than generated, cannot inherit the IDENTITY property. If a table’s select statement includes an IDENTITY column as part of an expression, the resulting column value must be computed. The new column is created as NULL if any column in the expression allows a NULL value. Otherwise, it is NOT NULL. In the following example, the new_id column, which is computed by adding 1000 to the value of record_id, is created NOT NULL: select new_id = record_id + 1000, stor_name into new_stores from stores_cal Column values are also computed if the select statement contains a group by clause or aggregate function. If the IDENTITY column is the argument of the aggregate function, the resulting column is created NULL. Otherwise, it is NOT NULL. IDENTITY columns selected into tables with unions or joins The value of the IDENTITY column uniquely identifies each row in a table. However, if a table’s select statement contains a union or join, individual rows can appear multiple times in the result set. An IDENTITY column that is selected into a table with a union or join does not retain the IDENTITY property. If the table contains the union of the IDENTITY column and a NULL column, the new column is defined as NULL. Otherwise, it is NOT NULL. For more information, see “Using IDENTITY columns” on page 247 and “Updating IDENTITY columns” on page 342. See also select in the Reference Manual. CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 283 Altering existing tables Use the alter table command to change the structure of an existing table. You can: • Add columns and constraints • Change column default values • Add either null or non-null columns • Drop columns and constraints • Change locking scheme • Partition or unpartition tables • Convert column datatypes • Convert the null default value of existing columns • Increase or decrease column length alter table includes the following syntax for modifying tables: alter table table_name [add column_name datatype [identity | null | not null] [, column_name datatype [identity |null | not null]]] [drop column_name [, column_name] [modify column_name {[data_type] [[null] | [not null]]} [, column_name datatype [null | not null]]] Where: • table_name is the table you are altering. • datatype is the datatype of the altered column. You must have the sa_role or be the object owner to run alter table. See the Reference Manual for the complete alter table syntax. For example, by default, the au_lname column of the authors table uses a varchar(50) datatype. To alter the au_lname to use a varchar(60), enter: alter table authors modify au_lname varchar(60) Note A variable cannot be used as the argument to a default that is part of an alter table statement.Altering existing tables 284 Adaptive Server Enterprise Dropping, modifying, and adding non-null columns may perform a data copy, which has implications for required space and the locking scheme. See “Data copying” on page 295. The modified table’s page chains inherits the table’s current configuration options (for example, if fillfactor is set to 50 percent, the new pages have this same fillfactor). Note Adaptive Server does partial logging (of page allocations) for alter table operations. However, because alter table is performed as a transaction, you cannot dump the transaction log after running alter table; you must dump the database to ensure it is recoverable. If the server encounters any problems during the alter table operation, Adaptive Server rolls back the transaction. alter table acquires an exclusive table lock while it is modifying the table schema. This lock is released as soon as the command is done. alter table does not fire any triggers. Objects using select * do not list changes to table If a database has any objects (stored procedures, triggers, and so on) that perform a select * on a table from which you have dropped a column, an error message lists the missing column. This occurs even if you create the objects using the with recompile option. For example, if you dropped the postalcode column from the authors table, any stored procedure that performed a select * on this table issues this error message: Msg 207, Level 16, State 4: Procedure ‘columns’, Line 2: Invalid column name ‘postalcode’. (return status = -6) This message does not appear if you add a new column and then run an object containing a select *; in this case, the new column does not appear in the output. You must drop and re-create any objects that reference a dropped column.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 285 Using alter table on remote tables You can use alter table to modify a remote table using Component Integration Services (CIS). Before you modify a remote table, make sure that CIS is running by entering: sp_configure "enable cis" If CIS is enabled, the output of this command is “1.” By default, CIS is enabled when you install Adaptive Server. See the System Administration Guide for information about enabling configuration parameters. See the Component Integration Services User’s Guide for information about using CIS. Adding columns To add a column to an existing table, use: alter table table_name add column_name datatype [default {constant_expression} | user | null}] {[{identity | null | not null}] | [constraint constraint_name {constraint_clause}] [, column_name] Where: • table_name is the table to which you are adding a column. • column_name is the column you are adding. • constant_expression is the constant you want placed in the row if a user does not specify a value (this value must be in quotes, unless the character type is int, tinyint, smallint, numeric, or decimal). • constraint_name is the constraint you are adding to the table. • constraint_clause is the full text of the constraint you are adding. You can add any number of columns using a single alter table statement. For example, the following adds a non-null column named author_type, which includes the constant “primary_author” as the default value, and a null column named au_publisher to the authors table: alter table authors add author_type varchar(20) default "primary_author" not null, au_publisher varchar(40) nullAltering existing tables 286 Adaptive Server Enterprise Adding columns appends column IDs alter table adds a column to the table with a column ID that is one greater than the current maximum column ID. For example, Table 8-5 lists the default column IDs of the salesdetail table: Table 8-5: Column IDs of the salesdetail table This command appends the store_name column to the end of the salesdetail table with a column ID of 6: alter table salesdetail add store_name varchar(40) default “unknown” not null If you add another column, it will have a column ID of 7. Note Because a table’s column IDs change as columns are added and dropped, your applications should never rely on them. Adding NOT NULL columns You can add a NOT NULL column to a table. This means that a constant expression, and not a null value, is placed in the column when the column is added. This also ensures that, for all existing rows, the new column is populated with the specified constant expression when the table is created. Adaptive Server issues an error message if a user fails to enter a value for a NOT NULL column. The following adds the column owner to the stores table with a default value of “unknown:” alter table stores add owner_lname varchar(20) default "unknown" not null The default value can be a constant expression when adding NULL columns, but it can be a constant value only when adding a NOT NULL column (as in the example above). Column name stor_id ord_num title_id qty discount Col ID 1 2 3 4 5CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 287 Adding constraints To add a constraint to an existing column, use: alter table table_name add constraint constraint_name {constraint_clause} Where: • table_name is the name of the table to which you are adding a constraint. • constraint_name is the constraint you are adding. • constraint_clause is the rule the constrain enforces. For example, to add a constraint to the titles table that does not allow an advance in excess of 10,000: alter table titles add constraint advance_chk check (advance < 10000) If a user attempts to insert a value greater than 10,000 into the titles table, Adaptive Server produces an error message similar to this: Msg 548, Level 16, State 1: Line 1:Check constraint violation occurred, dbname = ‘pubs2’,table name= ‘titles’, constraint name = ‘advance_chk’. Command has been aborted. Adding a constraint does not affect the existing data. Also, if you add a new column with a default value and specify a constraint on that column, the default value is not validated against the constraint. For information about dropping a constraint, see “Dropping constraints” on page 289. Dropping columns Drop a column from an existing table using: alter table table_name drop column_name [, column_name] Where: • table_name is the table that contains the column you are dropping,. • column_name is the column you are dropping. Altering existing tables 288 Adaptive Server Enterprise You can drop any number of columns using a single alter table statement. However, you cannot drop the last remaining column from a table (for example, if you drop four columns from a five-column table, you cannot then drop the remaining column). For example, to drop the advance and the contract columns from the titles table: alter table titles drop advance, contract alter table rebuilds all indexes on the table when it drops a column. Dropping columns renumbers the column ID alter table renumbers column IDs when you drop a column from a table. Columns with IDs above the number of the dropped column move up one column ID to fill the gap that the dropped column leaves behind. For example, the titleauthor table contains these column names and column IDs: Table 8-6: titleauthor column IDs If you drop the au_ord column from the table: alter table titleauthor drop au_ord titleauthor now has these column names and column IDs: Table 8-7: Column IDs after dropping au_ord The royaltyper column now has the column ID of 3. The nonclustered index on both title_id and royaltyper are also rebuilt when au_ord is dropped. Also, all instances of column IDs in different system catalogs are renumbered. You will not generally notice the renumbering of column IDs. Note Because a table’s column IDs are renumbered as columns are added and dropped, your applications should never rely on them. If you have stored procedures or applications that depend on column IDs, you must rewrite these so they access the correct column IDs. Column Name au_id title_id au_ord royaltyper Column ID 1 2 3 4 Column Name au_id title_id royaltyper Column ID 1 2 3CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 289 Dropping constraints To drop a constraint, use: alter table table_name drop constraint constraint_name table_name and constraint_name have the same values as described in Adding constraintsabove. For example, to drop the constraint created above: alter table titles drop constaint advance_chk To find detailed information about a table’s constraints, see “Using sp_helpconstraint to find a table’s constraint information” on page 307. Modifying columns To modify an existing column, use: alter table table_name modify column_name datatype [null | not null] [null | not null] [, column_name...] Where: • table_name is the table that contains the column you are modifying. • column_name is the column you are modifying. • data_type is the datatype to which you are modifying the column. You can modify any number of columns in a single alter table statement. For example, this command changes the datatype of the type column in the titles table from char(12) to varchar(20) and makes it nullable: alter table titles modify type varchar(20) null Warning! You may have objects (stored procedures, triggers, and so on) that depend on a column having a particular datatype. Before you modify a column, make sure that any objects that reference it will be able to run successfully after the modification. Use sp_depends to determine a table’s dependent objects.Altering existing tables 290 Adaptive Server Enterprise Which datatypes can I convert? You can only convert datatypes that are either implicitly or explicitly convertible to the new datatype, or if there is an explicit conversion function in Transact-SQL. See the Reference Manual for a list of the supported datatype conversions. If you attempt an illegal datatype modification, Adaptive Server raises an error message and the operation is aborted. Note You cannot convert an existing column datatype to the timestamp datatype, nor can you modify a column that uses the timestamp datatype to any other datatype. If you issue the same alter table command more than once, Adaptive Server issues a message similar to this: Warning: ALTER TABLE operation did not affect column ‘au_lname’. Msg 13905, Level 16, State 1: Server ‘SYBASE1’, Line 1: Warning: no columns to drop, add or modify. ALTER TABLE ‘authors’ was aborted. Modifying tables may prevent successful bulk copy of previous dump Modifying either the length or datatype of a column may prevent you from successfully using bulk copy to copy in older dumps of the table. The older table schema may not be compatible with the new table schema. Before you modify a column’s length or datatype, verify that it will not prevent you from copying in a previous dump of the table. Decreasing column length may truncate data If you decrease the length of a column, make sure the reduced column length does not result in truncated data. For example, you could use alter table to reduce the length of the title column of the titles table from a varchar(80) to a varchar(2), but the data is meaningless: select title from titles title ----- Bu Co Co EmCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 291 Fi Is Li Ne On Pr Se Si St Su Th Th Th Yo Adaptive Server issues error messages about truncating the column data only if the set string_rtruncation option is turned on. If you need to truncate character data, set the appropriate string-truncation option and modify the column to decrease its length. Modifying datetime columns If you modify a column from a char datatype to datetime, smalldatetime or date, you cannot specify the order that the month, day, and year appear in the output. Nor can you specify the language used in the output. Instead, both of these settings are given a default value. However, you can use set dateformat or set language to alter the output to match the setting of the information stored in the column. Also, Adaptive Server does not support modifying a column from smalldatetime to char datatype. See the Reference Manual for more information. Modifying the NULL default value of a column If you are changing only the NULL default value of a column, you do not need to specify a column’s datatype. For example, this command modifies the address column in the authors table from NULL to NOT NULL: alter table authors modify address not nullAltering existing tables 292 Adaptive Server Enterprise If you modify a column and specify the datatype as NOT NULL, the operation succeeds as long as none of the rows have NULL values. If, however, any of the rows have a NULL value, the operation fails and any incomplete transactions are rolled back. For example, the following statement fails because the titles table contains NULL values for the The Psychology of Computer Cooking: alter table titles modify advance numeric(15,5) not null Attempt to insert NULL value into column ‘advance’, table ‘pubs2.dbo.titles’; column does not allow nulls. Update fails. Command has been aborted. To run this command successfully, update the table to change all NULL values of the modified column to NOT NULL, then reissue the command. Modifying columns that have precision or scale Check the length of your data before you modify the column’s scale. If an alter table command causes a column value to lose precision (say from numeric(10,5) to numeric(5,5)), Adaptive Server aborts the statement. If this statement is part of a batch, the batch is aborted if the option is turned on. If an alter table command causes a column value to lose scale (say from numeric(10, 5) to numeric(10,3), the rows are truncated without warning. This occurs whether or not arithabort numeric_truncation is on or off. If arithignore arith_overflow is on and alter table causes a numeric overflow, Adaptive Server issues a warning. However, if arithignore arith_overflow is off, Adaptive Server does not issue a warning if alter table causes a numeric overflow. By default, arithignore arith_overflow is off when you install Adaptive Server. Note Make sure you review the data truncation rules and fully understand their implications before issuing commands that may truncate the length of the columns in your production environment. You should first perform the commands on a set of test columns. Modifying text and image columns text columns can only be converted to:CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 293 • nchar • varchar image columns can only be converted to: • varbinary • binary You cannot modify char or varchar datatype columns to text columns. If you are converting from text to char or varchar, the maximum length of the column is governed by page size. If you do not specify a column length, alter table uses the default length of one byte. If you are modifying a multibyte character text or image column, and you do not specify a column length that is sufficient to contain the data, Adaptive Server truncates the data to fit the column length. Adding, dropping, and modifying IDENTITY columns This section describes adding, dropping, and modifying IDENTITY columns using alter table. For a general discussion of IDENTITY columns, see “Using IDENTITY columns” on page 247. Adding IDENTITY columns You can add IDENTITY columns only with a default value of NOT NULL. You cannot specify a default clause for a new IDENTITY column. To add an IDENTITY column to a table, specify the identity keyword in the alter table statement: alter table table_name add column_name numeric(precision ,0) identity not null The following example adds an IDENTITY column, record_id, to the stores table: alter table stores add record_id numeric(5,0) identity not null When you add an IDENTITY column to a table, Adaptive Server assigns a unique sequential value, beginning with the value 1, to each row. If the table contains a large number of rows, this process can be time consuming. If the number of rows exceeds the maximum value allowed for the column (in this case, 10 5 - 1, or 99,999), the alter table statement fails. Altering existing tables 294 Adaptive Server Enterprise Dropping IDENTITY columns You can drop IDENTITY columns just like any other column. For example, to drop the IDENTITY column created in the previous section: alter table stores drop record_id However, the following restrictions apply to dropping an identity column: • If sp_dboption “identity in nonunique index” is turned on in the database. You must first drop all indexes, then drop the IDENTITY column, and then re-create the indexes. If the IDENTITY column is hidden, you must first identify it using the syb_identity keyword. See “Referring to IDENTITY columns with syb_identity” on page 250. • To drop an IDENTITY column from a table that has set identity_insert turned on, first issue sp_helpdb to determine if set identity_insert is turned on. You must turn off the set identity_insert option by issuing: set identity_insert table_name off Drop the IDENTITY column, then add the new IDENTITY column, and turn on the set identity_insert option by entering: set identity_insert table_name on Modifying IDENTITY columns You can modify the size of an IDENTITY column to increase its range. This might be necessary if either your current range is too small, or the range was used up because of a server shutdown. For example, you can increase the range of record_id by entering: alter table stores modify record_id numeric(9,0) You can decrease the range by specifying a smaller precision for the target datatype. Note that if the IDENTITY value in the table is too large for the range of the target IDENTITY column, an arithmetic conversion is raised and alter table aborts the statement.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 295 You cannot add a non-null IDENTITY column to a partitioned table using alter table commands that require a data copy. Data copy is done in parallel for partitioned tables, and cannot guarantee unique IDENTITY values. Data copying Adaptive Server performs a data copy only if it must temporarily copy data out of a table before it changes the table’s schema. If the table has any indexes, Adaptive Server rebuilds the indexes when the data copy finishes. Note If alter table is performing a data copy, the database that contains the table must have select into/bulkcopy/pllsort turned on. See the Reference Manual for information about this option. Adaptive Server performs a data copy when: • You drop a column. • You modify any of these properties of a column: • The datatype (except when you increase the length of varchar, varbinary, or NULL char or NULL binary columns. • From NULL to NOT NULL, or vice-versa. • Decrease length. If you decrease a column’s length, you may not know beforehand if all the data will fit in the reduced column length. For example, if you decrease au_lname to a varchar(30), it may contain a name that requires a varchar(35). When you decrease a column’s data length, Adaptive Server first performs a data copy to ensure that the change in the column length is successful. • You increase the length of a number column (for example, from tinyint to int). Adaptive Server performs data copying in case one row has a NOT NULL value for this column. • You add a NOT NULL column. alter table does not perform a data copy when: • You change the length of either a varchar or a varbinary column.Altering existing tables 296 Adaptive Server Enterprise • You change the user-defined datatype ID but the physical datatype does not change. For example, if your site has two datatypes mychar1 and mychar2 that have different user-defined datatypes but the same physical datatype, data copy does not happen if you change mychar1 to mychar2. • You change the NULL default value of a variable length column from NOT NULL to NULL. To identify if alter table performs a data copy: 1 Set showplan on to report whether Adaptive Server will perform a data copy. 2 Set noexec on to ensure that no work will be performed. 3 Perform the alter table command if no data copy is required, only catalog updates are performed to reflect the changes made by the alter table command. Changing exp_row_size If you perform a data copy, you can also change the exp_row_size, which allows you to specify how much space to allow per row. You can change the exp_row_size only if the modified table schema contains variable length columns, and only to within the range specified by the maxlen and minlen values in sysindexes for the modified table schema. If the column has fixed-length columns, you can change the exp_row_size to only 0 or 1. If you drop all the variable-length columns from a table, you must specify an exp_row_size of 0 or 1. Also, if you do not supply an exp_row_size with the alter table command, the old exp_row_size is used. Adaptive Server raises an error if the table contains only fixed-length columns and the old exp_row_size is not compatible with the modified schema. You cannot use the exp_row_size clause with any of the other alter table subclauses (for example, defining a constraint, changing the locking scheme, and so on). You can also use sp_chgattribute to change the exp_row_size. For more information about changing the exp_row_size for both alter table and sp_chgattribute, see the Reference Manual.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 297 Modifying locking schemes and table schema If alter table performs a data copy, you can also include a command to change the locking scheme of a table. For example, to modify the au_lname column of the authors table and change the locking scheme of the table from allpages locking to datarows locking: alter table authors modify au_lname varchar(10) lock datarows However, you cannot use alter table to change table schema and the locking scheme of a table that has a clustered index. If a table has a clustered index you can: 1 Drop the index. 2 Modify the table schema and change the locking scheme in the same statement (if the change in the table schema also includes a data copy). 3 Rebuild the clustered index. Alternately, you can issue an alter table command to change the locking scheme, then issue another alter table command to change the table’s schema. Altering columns with user defined datatypes You can use alter table to add, drop, or modify columns that use user-defined datatypes. Adding a column with user-defined datatypes Use the same syntax to add a column with a user-defined datatype as with a system-defined datatype. For example, to add a column to the authors table of pubs2 using the usertype datatype: alter table titles add newcolumn usertype not null The NULL or NOT NULL default you specify takes precedence over the default specified by the user-defined datatype. That is, if you add a column and specify NOT NULL as the default, the new column has a default of NOT NULL even if the user-defined datatype specifies NULL. If you do not specify NULL or NOT NULL, the default specified by the user-defined datatype is used. Altering existing tables 298 Adaptive Server Enterprise You must supply a default clause when you add columns that are not null, unless the user-defined datatype already has a default bound to it. If the user-defined datatype specifies IDENTITY column properties (precision and scale), the column is added as an IDENTITY column. Dropping a column with user-defined datatypes Drop a column with a user-defined datatype the same as you drop a column with a system-defined datatype. Modifying a column with user-defined datatypes The syntax to modify a column to include user-defined datatypes is the same as modifying a column to include system-defined datatypes. For example, to modify the au_lname of the authors table to use the user-defined newtype datatype: alter table authors modify au_lname newtype(60) not null If you do not specify either NULL or NOT NULL as the default, columns use the default specified by the user-defined datatype. Modifying the table does not affect any current rules or defaults bound to the column. However, if you specify new rules or defaults, any old rules or defaults bound to the user-defined datatype are dropped. If there are no previous rules or defaults bound to the column, any user-defined rules and defaults are applied. You cannot modify an existing column to an IDENTITY column. You can only modify an existing IDENTITY column with user-defined datatypes that have IDENTITY column properties (precision and scale). Errors and warnings from alter table Most errors you encounter when running alter table inform you of schema constructs that prevent the requested command (for example, if you try to drop a column that is part of an index). You must fix the errors or warnings that refer to schema objects that depend on the affected column before you reissue the command. To report error conditions: 1 Set showplan on.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 299 2 Set noexec on. 3 Perform the alter table command. After you have changed the command to address any reported errors, set showplan and noexec to off so that Adaptive Server actually performs the work. alter table detects and reports certain errors when actually running the command (for example, if you are dropping a column, the presence of a referential constraint). All runtime data-dependent errors (for example, errors of numeric overflow, character truncation, and so on) can be identified only when the statement is executed. You must change the command to fit the data available, or fix the data value(s) to work with the required target datatypes the statement specifies. To identify these errors, you will have to run the command with noexec turned off. Errors and warnings generated by alter table modify Certain errors are generated only by the alter table modify command. Although alter table modify is used to convert columns to compatible datatypes, alter table may issue errors if the columns you are converting have certain restrictions. Note Make sure you understand the implications of modifying a datatype before you issue the command. Generally, use alter table modify only to implicitly convert between convertible datatypes. This ensures that any hidden conversions required during processing of insert and update statements do not fail because of datatype incompatibility. For example, if you add a second_advance column to the titles table with a datatype of int, and create a clustered index on second_advance, you cannot then modify this column to a char datatype. This would cause the int values to be converted from integers (1, 2, 3) to strings (‘1’, ‘2’, ‘3’). When the index is rebuilt with sorted data, the data values are expected to be in sorted order. But in this example, the datatype has changed from int to char and is no longer in sorted order for the char datatype’s ordering sequence. So, the alter table command fails during the index rebuild phase. Be very cautious when choosing a new datatype for columns that are part of index key columns of clustered indexes. alter table modify must specify a target datatype that will not violate the ordering sequence of the modified data values after its data copy phase. Altering existing tables 300 Adaptive Server Enterprise alter table modify also issues a warning message if you modify the datatype to an incompatible datatype in a column that contains a constraint. For example, if you try to modify from datatype char to datatype int, and the column includes a constraint, alter table modify issues this warning: Warning: a rule or constraint is defined on column ‘new_col’ being modified. Verify the validity of rules and constraints after this ALTER TABLE operation. This warning indicates that there might be some datatype inconsistency in the value that the constraint expects and the modified datatype of the column new_col: Warning: column ‘new_col’ is referenced by one or more rules or constraints. Verify the validity of the rules/constraints after this ALTER TABLE operation. If you attempt to insert data that is a datatype char into this table, it fails with this message: Msg 257, Level 16, State 1: Line 1: Implicit conversion from datatype ‘CHAR’ to ‘INT’ is not allowed. Use the CONVERT function to run this query. The check constraint was defined to expect the column to be a datatype int, but the data being inserted is a datatype char. Furthermore, you cannot insert the data as type int because column now uses a datatype of char. The insert returns this message: Msg 257, Level 16, State 1: Line 1: Implicit conversion from datatype ‘INT’ to ‘CHAR’ is not allowed. Use the CONVERT function to run this query. The modify operation is very flexible, but must be used with caution. In general, modifying to an implicitly convertible datatype works without errors. Modifying to an explicitly convertible datatype may lead to inconsistencies in the tables schema. Use sp_depends to identify all column-level dependencies before modifying a column’s datatype. Scripts generated by if exists()...alter table Scripts that include constructs like the following may produce errors if the table described in the script does not include the specified column: if exists (select 1 from syscolumns where id = object_id("some_table") and name = "some_column") beginCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 301 alter table some_table drop some_column end In this example, some_column must exist in some_table for the batch to succeed. If some_column exists in some_table, the first time you run the batch, alter table drops the column. On subsequent executions, the batch will not compile. Adaptive Server raises these errors while preprocessing this batch, which are similar to those that are raised when a normal select tries to access a nonexistent column. These errors are raised when you modify a table’s schema using clauses that require a data copy. If you add a null column, and use the above construct, Adaptive Server does not raise these errors. To avoid such errors when you modify a table’s schema, include alter table in an execute immediate command: if exists (select 1 from syscolumns where id = object_id("some_table") and name = "some_column") begin exec ("alter table some_table drop some_column") end Because the execute immediate statement is run only if the if exists() function succeeds, Adaptive Server does not raise any errors when it compiles this script. You also need to use the execute immediate construct for other uses of alter table, for example, to change the locking scheme, and for any other cases when the command does not require data copy. Renaming tables and other objects To rename tables and other database objects—columns, constraints, datatypes, views, indexes, rules, defaults, procedures, and triggers—use sp_rename. You must own an object to rename it. You cannot change the name of system objects or system datatypes. The Database Owner can change the name of any user’s objects. Also, the object whose name you are changing must be in the current database. To rename the database, use sp_renamedb. See sp_renamedb in the Reference Manual.Dropping tables 302 Adaptive Server Enterprise The syntax of sp_rename is: sp_rename objname, newname For example, to change the name of friends_etc to infotable: sp_rename friends_etc, infotable To rename a column, use: sp_rename "table.column", newcolumnname You must leave off the table name prefix from the new column name, or the new name will not be accepted. To change the name of an index, use: sp_rename "table.index", newindexname Do not include the table name in the new name. To change the name of the user datatype tid to t_id, use: exec sp_rename tid, "t_id" Renaming dependent objects When you rename objects, you must also change the text of any dependent procedure, trigger, or view to reflect the new object name. The original object name continues to appear in query results until you change the name of, and compile the procedure, trigger, or view. The safest course is to change the definitions of any dependent objects when you execute sp_rename. You can get a list of dependent objects using sp_depends. You can use the defncopy utility program to copy the definitions of procedures, triggers, rules, defaults, and views into an operating system file. Edit this file to correct the object names, then use defncopy to copy the definition back into Adaptive Server. For more information on defncopy, refer to The Utility Guide. Dropping tables Use drop table to remove a table from a database. drop table [[database.]owner.] table_name [, [[database.]owner.] table_name]... CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 303 This command removes the specified tables from the database, together with their contents and all indexes and privileges associated with them. Rules or defaults bound to the table are no longer bound, but are otherwise not affected. You must be the owner of a table in order to drop it. However, no one can drop a table while it is being read or written to by a user or a front-end program. You cannot use drop table on any system tables, either in the master database or in a user database. You can drop a table in another database as long as you are the table owner. If you delete all the rows in a table or use truncate table on it, the table exists until you drop it. drop table and truncate table permission cannot be transferred to other users. Assigning permissions to users The grant and revoke commands control the Adaptive Server command and object protection system. You can give various kinds of permissions to users, groups, and roles with the grant command and rescind them with the revoke command including: • Creating databases • Creating objects in a database • Accessing tables, views, and columns • Executing stored procedures Some commands can be used at any time by any user, with no permissions required. Others can be used only by users of certain status (for example, a System Administrator) and cannot be transferred. The ability to assign permissions for commands that can be granted and revoked is determined by each user’s status (as System Administrator, Database Owner, or database object owner) and by whether a particular user has been granted a permission with the option to grant that permission to other users. Assigning permissions to users 304 Adaptive Server Enterprise Database owners do not automatically receive permissions on objects that are owned by other users. But a Database Owner or System Administrator can acquire any permission by using the setuser command to temporarily assume the identity of the object owner, and then writing the appropriate grant or revoke statement. You can assign two kinds of permissions with grant and revoke: object access permissions and object creation permissions. Object access permissions regulate the use of certain commands that access certain database objects. For example, you must be granted permission to use the select command on the authors table. Object access permissions are granted and revoked by object owners. To grant Mary and Joe the object access permission to insert into and delete from the titles table: grant insert, delete on titles to mary, joe Object creation permissions regulate the use of commands that create objects. These permissions can be granted only by a System Administrator or Database Owner. For example, to revoke from Mary permission to create tables and rules in the current database: revoke create table, create rule from mary For complete information about using grant and revoke, see the System Administration Guide. A System Security Officer can also use roles to simplify the task of granting and revoking access permissions. For example, instead of having object owners grant privileges on each object individually to each employee, the System Security Officer can create roles, request object owners to grant privileges to each role, and grant these userdefined roles to individual employees, based on the functions they perform in the organization. The System Security Officer can also revoke user-defined roles granted to the employee. For complete information about user-defined roles, see the System Administration Guide.CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 305 Getting information about databases and tables Adaptive Server includes several procedures and functions you can use to get information about databases, tables, and other database objects. This section describes some of them. For complete information, see the Reference Manual. Getting help on databases sp_helpdb can report information about a specified database or about all Adaptive Server databases. It reports the name, size, and usage of each fragment you have assigned to the database. sp_helpdb [dbname] For example, to display a report on pubs2: sp_helpdb pubs2 name db_size owner dbid created status ----- ------- ------ ---- --------------- ------ ------- pubs2 2 MB sa 4 Jun 18 1997 no options set (1 row affected) device size usage ----------------- ----------- -------------- pubsdev 2 MB data + log (1 row affected) sp_databases lists all the databases on a server. For example: sp_databases database_name database_size remarks ----------------- ------------- ------------ master 5120 NULL model 2048 NULL pubs2 2048 NULL pubs3 2048 NULL sybsecurity 5120 NULL sybsystemprocs 30720 NULL tempdb 2048 NULL (7 rows affected, return status = 0) To find out who owns a database, use sp_helpuser:Getting information about databases and tables 306 Adaptive Server Enterprise sp_helpuser dbo Users_name ID_in_db Group_name Login_name ------------- -------- ------------ ------------ dbo 1 public sa (return status = 0) Use db_id() and db_name() to identify the current database. For example: select db_name(), db_id() ------------------------------ ------ master 1 Getting help on database objects Adaptive Server provides system procedures, catalog stored procedures, and built-in functions that return helpful information about database objects such as tables, columns, and constraints. Using sp_help on database objects Use sp_help to display information about a specified database object (that is, any object listed in sysobjects), a specified datatype (listed in systypes), or all objects and datatypes in the current database. sp_help [objname] Here is the output for the publishers table: Name Owner Type -------------------------- ----------- ---------- publisher dbo user table (1 row affected) Data_located_on_segment When_created ------------------------------ -------------------- default Jul 7 1997 1:43PM Column_name Type Length Prec Scale ----------- ------- ------ ----- ----- pub_id char 4 NULL NULL pub_name varchar 40 NULL NULL city varchar 20 NULL NULL state char 2 NULL NULLCHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 307 Nulls Default_name Rule_name Identity ----- ------------- --------- -------- 0 NULL pub_idrule 0 1 NULL NULL 0 1 NULL NULL 0 1 NULL NULL 0 index_name index_description index_keys index_max_rows_per_page ---------- ------------------ ---------- ------------ ----------- pubind clustered, unique pub_id 0 located on default (1 row affected) keytype object related_object related_keys ------- ---------- -------------- ------------ primary publishers -- none -- pub_id, *, *, *, *, * foreign titles publishers pub_id, *, *, *, *, * (1 row affected) Object is not partitioned. (return status = 0) If you execute sp_help without supplying an object name, the resulting report shows each object in sysobjects, along with its name, owner, and object type. Also shown is each user-defined datatype in systypes and its name, storage type, length, whether null values are allowed, and any defaults or rules bound to it. The report also notes if any primary or foreign key columns have been defined for a table or view. sp_help lists any indexes on a table, including those created by defining unique or primary key constraints. However, it does not describe any information about the integrity constraints defined for a table. Use sp_helpconstraint to display information about any integrity constraints. Using sp_helpconstraint to find a table’s constraint information sp_helpconstraint reports information about the declarative referential integrity constraints specified for a table, including the constraint name and definition of the default, unique or primary key constraint, referential, or check constraint. sp_helpconstraint also reports the number of references associated with the specified tables. Getting information about databases and tables 308 Adaptive Server Enterprise Its syntax is: sp_helpconstraint [objname] [, detail] objname is the name of the table being queried. If you do not include a table name, sp_helpconstraint displays the number of references associated with each table in the current database. With a table name, sp_helpconstraint reports the name, definition, and number of integrity constraints associated with the table. The detail option also returns information about the constraint’s user or error messages. For example, suppose you run sp_helpconstraint on the store_employees table in pubs3. name defn --------------------------- ------------------------- ------- store_empl_stor_i_272004000 store_employees FOREIGN KEY (stor_id) REFERENCES stores(stor_id) store_empl_mgr_id_288004057 store_employees FOREIGN KEY (mgr_id) SELF REFERENCES store_employees(emp_id) store_empl_2560039432 UNIQUE INDEX( emp_id) : NONCLUSTERED, FOREIGN REFERENCE (3 rows affected) Total Number of Referential Constraints: 2 Details: -- Number of references made by this table: 2 -- Number of references to this table: 1 -- Number of self references to this table: 1 Formula for Calculation: Total Number of Referential Constraints = Number of references made by this table + Number of references made to this table - Number of self references within this table To find the largest number of referential constraints associated with any table in the current database, run sp_helpconstraint without specifying a table name, for example: sp_helpconstraint id name CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 309 Num_referential_constraints ----------- ------------------------ ----------------- ---------- 80003316 titles 4 16003088 authors 3 176003658 stores 3 256003943 salesdetail 3 208003772 sales 2 336004228 titleauthor 2 896006223 store_employees 2 48003202 publishers 1 128003487 roysched 1 400004456 discounts 1 448004627 au_pix 1 496004798 blurbs 1 (11 rows affected) In this report, the titles table has the largest number of referential constraints in the pubs3 database. Finding out how much space a table uses Use sp_spaceused to find out how much space a table uses: sp_spaceused [objname] sp_spaceused computes and displays the number of rows and data pages used by a table or a clustered or nonclustered index. To display a report on the space used by the titles table: sp_spaceused titles name rows reserved data index_size unused ------- ----- --------- ----- --------- ------ titles 18 48 KB 6 KB 4 KB 38 KB (0 rows affected) If you do not include an object name, sp_spaceused displays a summary of space used by all database objects. Listing tables, columns, and datatypes Catalog stored procedures retrieve information from the system tables in tabular form. You can supply wildcard characters for some parameters. sp_tables lists all user tables in a database when used in the following format: Getting information about databases and tables 310 Adaptive Server Enterprise sp_tables @table_type = "’TABLE’" sp_columns returns the datatype of any or all columns in one or more tables in a database. You can use wildcard characters to get information about more than one table or column. For example, the following command returns information about all columns that includes the string “id” in all the tables with “sales” in their name: sp_columns "%sales%", null, null, "%id%" table_qualifier table_owner table_name column_name data_type type_name precision length scale radix nullable remarks ss_data_type colid --------------- ----------- ---------- ----------- --------- --------- --------- ------ ----- -- --- -------- ------- ------------ ----- pubs2 dbo sales stor_id 1 char 4 4 NULL NULL 0 NULL 47 1 pubs2 dbo salesdetail stor_id 1 char 4 4 NULL NULL 0 NULL 4 1 pubs dbo salesdetail title_id 12 varchar 6 6 NULL NULL 0 NULL 39 3 (3 rows affected, return status = 0)CHAPTER 8 Creating Databases and Tables Transact-SQL User’s Guide 311 Finding an object name and ID Use object_id() and object_name() to identify the ID and name of an object. For example: select object_id("titles") ---------- 208003772 Object names and IDs are stored in the sysobjects system table.Getting information about databases and tables 312 Adaptive Server EnterpriseTransact-SQL User’s Guide 313 C H A P T E R 9 Adding, Changing, and Deleting Data After you create a database, tables, and indexes, you can put data into the tables and work with it—adding, changing, and deleting data as necessary. This chapter covers the following topics: Introduction The commands you use to add, change, or delete data are called data modification statements. These commands are: • insert – adds new rows to a table. • update – changes existing rows in a table. • writetext – adds or changes text and image data without writing lengthy changes in the system’s transaction log. • delete – removes specific rows from a table. • truncate table – removes all rows from a table. For information about these commands, see the Reference Manual. You can also add data to a table by transferring it from a file using the bulk copy utility program bcp. See the Utility Guide for your platform for more information. Topic Page Introduction 313 Datatype entry rules 316 Adding new data 324 Changing existing data 337 Changing text and image data 342 Deleting data 343 Deleting all rows from a table 346Introduction 314 Adaptive Server Enterprise You can use insert, update, or delete to modify data in one table per statement. A Transact-SQL enhancement to these commands is that you can base modifications on data in other tables, and even other databases. The data modification commands also work on views, with some restrictions. See Chapter 10, “Views: Limiting Access to Data.” Permissions Data modification commands are not necessarily available to everyone. The Database Owner and the owners of database objects can use the grant and revoke commands to specify the users who have data modification functions. Permissions or privileges can be granted to individual users, groups, or the public for any combination of the data modification commands. Permissions are discussed in the System Administration Guide. Referential integrity insert, update, delete, writetext, and truncate table allow you to change data without changing related data in other tables, however, disparities may develop. For example, if you change the au_id entry for Sylvia Panteley in the authors table, you must also change it in the titleauthor table and in any other table in the database that has a column containing that value. If you do not, you cannot find information such as the names of Ms. Panteley’s books, because you cannot make joins on her au_id column. Keeping data modifications consistent throughout all tables in a database is called referential integrity. One way to manage it is to define referential integrity constraints for the table. Another way is to create special procedures called triggers that take effect when you give insert, update, and delete commands for particular tables or columns (the truncate table command is not caught by triggers or referential integrity constraints). See Chapter 17, “Triggers: Enforcing Referential Integrity”; and Chapter 8, “Creating Databases and Tables.” To delete data from referential integrity tables, change the referenced tables first and then the referencing table.CHAPTER 9 Adding, Changing, and Deleting Data Transact-SQL User’s Guide 315 Transactions A copy of the old and new state of each row affected by each data modification statement is written to the transaction log. This means that if you begin a transaction by issuing the begin transaction command, realize you have made a mistake, and roll the transaction back, the database is restored to its previous condition. Note You cannot roll back changes made on a remote Adaptive Server by means of a remote procedure call (RPC). An exception is writetext, when the select/into bulkcopy database option is set to false. The default mode of operation for writetext does not log the transactions. This avoids filling up the transaction log with the extremely long blocks of data that text and image fields may contain. The with log option to the writetext command must be used to log changes made with this command. A more complete discussion of transactions appears in Chapter 19, “Transactions: Maintaining Data Consistency and Recovery.” Using the sample databases If you follow the examples in this chapter, Sybase suggests that you start with a clean copy of the pubs2 or pubs3 database and return it to that state when you are finished. See a System Administrator for help in getting a clean copy of either of these databases. You can prevent any changes you make from becoming permanent by enclosing all the statements you enter inside a transaction, and then aborting the transaction when you are finished with this chapter. For example, start the transaction by typing: begin tran modify_pubs2 This transaction is named modify_pubs2. You can cancel the transaction at any time and return the database to the condition it was in before you began the transaction by typing: rollback tran modify_pubs2Datatype entry rules 316 Adaptive Server Enterprise Datatype entry rules Several of the Adaptive Server-supplied datatypes have special rules for entering and searching for data. For more information on datatypes, see Chapter 8, “Creating Databases and Tables.” char, nchar, unichar, univarchar, varchar, nvarchar, and text All character, text, date and time data must be enclosed in single or double quotes when you enter it as a literal. Use single quotes if the quoted_identifier option of the set command is set on. If you use double quotes, Adaptive Server treats the text as an identifier. Character literals may be any length, whatever the logical page size of the database. If the literal is wider than 16 kilobytes (16384 bytes), Adaptive Server treats it as text data, which has restrictive rules regarding implicit and explicit conversion to other datatypes. See the Reference Manual for a discussion of the different behavior of character and text datatypes. When you insert character data into a char, nchar, unichar, univarchar, varchar, or nvarchar column whose specified length is less than the length of the data, the entry is truncated. Set the string_rtruncation option on to receive a warning message when this occurs. Note This truncation rule applies to all character data, whether it resides in a column, a variable, or a literal string. There are two ways to specify literal quotes within a character entry: • Use two quotes. For example, if you begin a character entry with a single quote and you want to include a single quote as part of the entry, use two single quotes: ’I don’t ’understand.’’ For double quotes: “He said, ““It’s not really confusing.””” • Enclose the quoted material in the opposite kind of quotation mark. In other words, surround an entry containing a double quote with single quotes, or vice versa. For example: ’George said, “There must be a better way.” ’ To enter a character string that is longer than the width of your screen, enter a backslash (\) before going to the next line. CHAPTER 9 Adding, Changing, and Deleting Data Transact-SQL User’s Guide 317 Use the like keyword and wildcard characters described in Chapter 2, “Queries: Selecting Data from a Table,” to search for character, text, and datetime data. See the Reference Manual for details on inserting text data and information about trailing blanks in character data. date and time data types Adaptive Server allows datatypes datetime, smalldatetime, date and time. Display and entry formats for datetime data provide a wide range of date output formats, and recognize a variety of input formats. The display and entry formats are controlled separately. The default display format provides output that looks like “Apr 15 1997 10:23PM”. The convert command provides options to display seconds and milliseconds and to display the date with other date-part ordering. See Chapter 11, “Using the Built-In Functions in Queries,” for more information on displaying date values. Adaptive Server recognizes a wide variety of data entry formats for dates. Case is always ignored, and spaces can occur anywhere between date parts. When you enter datetime and smalldatetime values, always enclose them in single or double quotes. Use single quotes if the quoted_identifier option is on; if you use double quotes, Adaptive Server treats the entry as an identifier. Adaptive Server recognizes the two date and time portions of the data separately, so the time can precede or follow the date. Either portion can be omitted, in which case Adaptive Server uses the default. The default date and time is January 1, 1900, 12:00:00:000AM. For datetime, the earliest date you can use is January 1, 1753; the latest is December 31, 9999. For smalldatetime, the earliest date you can use is January 1, 1900; the latest is June 6, 2079. Dates earlier or later than these dates must be entered, stored, and manipulated as char, or unichar; or varchar or univarchar values. Adaptive Server rejects all values it cannot recognize as dates between those ranges. For date, the earliest date you can use is Januarry 1, 0001 through December 31, 9999. Dates earlier or later than these dates must be entered, stored, and manipulated as char, or unichar; or varchar or univarchar values. Adaptive Server rejects all values it cannot recognize as dates between those ranges. For time, the earliest time is 12:00AM through 11:59:59:999.Datatype entry rules 318 Adaptive Server Enterprise Entering times The order of time components is significant for the time portion of the data. First, enter the hours; then minutes; then seconds; then milliseconds; then AM (or am) or PM (pm). 12AM is midnight; 12PM is noon. To be recognized as time, a value must contain either a colon or an AM or PM signifier. smalldatetime is accurate only to the minute. time is accurate to the millesecond. Milliseconds can be preceded by either a colon or a period. If preceded by a colon, the number means thousandths of a second. If preceded by a period, a single digit means tenths of a second, two digits mean hundredths of a second, and three digits mean thousandths of a second. For example, “12:30:20:1” means 20 and one-thousandth of a second past 12:30; “12:30:20.1” means 20 and one-tenth of a second past 12:30. Among the acceptable formats for time data are: 14:30 14:30[:20:999] 14:30[:20.9] 4am 4 PM [0]4[:30:20:500]AM Entering dates The set dateformat command specifies the order of the date parts (month, day, and year) when dates are entered as strings of numbers with separators. set language can also affect the format for dates, depending on the default date format for the language you specify. The default language is us_english, and the default date format is mdy. See the set command in the Reference Manual for more information. Note dateformat affects only the dates entered as numbers with separators, such as “4/15/90” or “20.05.88”. It does not affect dates where the month is provided in alphabetic format, such as “April 15, 1990” or where there are no separators, such as “19890415”. Date formats Adaptive Server recognizes three basic date formats, as described below. Each format must be enclosed in quotes and can be preceded or followed by a time specification, as described under “Entering times” on page 318. CHAPTER 9 Adding, Changing, and Deleting Data Transact-SQL User’s Guide 319 • The month is entered in alphabetic format. • Valid formats for specifying the date alphabetically are: Apr[il] [15][,] 1997 Apr[il] 15[,] [19]97 Apr[il] 1997 [15] [15] Apr[il][,] 1997 15 Apr[il][,] [19]97 15 [19]97 apr[il] [15] 1997 apr[il] 1997 APR[IL] [15] 1997 [15] APR[IL] • Month can be a three-character abbreviation, or the full month name, as given in the specification for the current language. • Commas are optional. • Case is ignored. • If you specify only the last two digits of the year, values of less than 50 are interpreted as “20yy”, and values of 50 or more are interpreted as “19yy”. • Type the century only when the day is omitted or when you need a century other than the default. • If the day is missing, Adaptive Server defaults to the first day of the month. • When you specify the month in alphabetic format, the dateformat setting is ignored (see the set command in the Reference Manual). • The month is entered in numeric format, in a string with a slash (/), hyphen (-), or period (.) separator. • The month, day, and year must be specified. • The strings must be in the form: [