Transact-SQLฎ Users 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 Users 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 Users 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 Users 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 columns 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 Users 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 views 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 Users 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 Users 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 Users 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 Users 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 Users Guide xix
About This Book
This manual, the Transact-SQL Users Guide, documents TransactSQLฎ, an enhanced version of the SQL relational database language. The
Transact-SQL Users 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 29 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 1018. 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 1018 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 Users 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.
Whats 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 Users 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 Users 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 Users 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 Users Guide xxi
Full-Text Search Specialty Data Store Users 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 Users 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 Users 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 Programmers Guide describes how to write
Monitor Client Library applications that access Adaptive Server
performance data.
Monitor Server Users 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 Users Guide documents Transact-SQL, Sybases
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 Sybases 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 Users 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 Users 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
Variablesor words that stand for values that you fill
inwhen 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 Users 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 Servers 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 Users 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 IBMs 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, Sybases 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 Users 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 dataa
person, a company, a sale, or some other thing. Each column, or field, describes
one characteristic of the dataa persons name or address, a companys 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 (authors last name). A second table contains title
information about books, including a column that gives the ID number of the
books 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 rowcontaining columns from both tablesis 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 Users 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 Users 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
Servers 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
AZ, az, 09, 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 Users 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 ab into col1, use:
insert "1one"(col1) values(ab)
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 owners 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 Users 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 owners 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 Users 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 Servers 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
parenthesesthe 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 Users 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 Users Guide 17
Table 1-5: Comparison operators
In comparing character data, < means closer to the beginning of the servers
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 dont 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, ""Its 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."
"Isnt there a better way?" CHAPTER 1 SQL Building Blocks
Transact-SQL Users Guide 19
George asked, "Isnt 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-SQLs 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 Users 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 Users 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 integrityenforcing 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 tables 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 Users 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 Users 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 Users 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 Users 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 Users 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
Servers 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 Users 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 AZ, az, 09, _, #, valid single-byte or
multibyte alphabetic characters, or accented alphabetic characters.
It begins with a number 09.
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 Users 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 Users 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 Users 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
books 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 Users 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 Users 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 Users 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 Users 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 Users 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 characterseven blanksin 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 "Publishers Name" = pub_name
from publishers
select pub_name "Publishers Name"
from publishers
Publishers 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 stringotherwise, the
apostrophe is interpreted as a single quotation mark.
Here is a query with a character string:
select "The publishers name is", Publisher = pub_name
from publishers
Publisher
------------------------ --------------------
The publishers name is New Age Books
The publishers name is Binnet & Hardley
The publishers 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 Users 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 Users 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 authors 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 Users 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 columns 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 Users 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 Users 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 Users 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 Users 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 Users 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
OLeary 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
OLeary 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 Users 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 [af] 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 [af], 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 af; [^a2bR] means not a, 2, b,
or R.CHAPTER 2 Queries: Selecting Data from a Table
Transact-SQL Users 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 Users 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 servers
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 Users 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 Users 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 Users 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 Users 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 authors last name is Ringer and the authors 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 Users 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 extensionsthe 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 Users 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 onlyint, 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 valuethe one
closest to the beginning of the alphabetin 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 Users 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 Users 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 Users 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 Sybases 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 Users 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 Users 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 aggregatein this
case, avg.CHAPTER 3 Using Aggregates, Grouping, and Sorting
Transact-SQL Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 subquerys 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 Users 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 Executives 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 Users Guide 125
title price
--------------------------------------- -----
The Busy Executives 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 subquerys from clausethat 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 Users 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 Users 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 Executives 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 Users 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 Executives 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 Users 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 Users 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 Users 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 Executives 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 Users 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
OLeary 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 Users 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 Executives 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 Users 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 publishers 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 publishers 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 publishers 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 Users 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 Executives 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 Users 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 Users 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 variableit 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 Sybases 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 Users 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 Executives 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 Users 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 valuesthat 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 Users 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 manipulatedwhen 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 entitya 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 Users 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 operatoroften 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 Users 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 columnsint, smallint, tinyint, decimal, or float, and among any of
the character type and date columnschar, 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 themand 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
Servers actual procedure is more sophisticated.
Conceptually speaking, the first step in processing a join is to form the
Cartesian product of the tablesall 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 databasewhich 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 authors city is not the same as the publishers city:CHAPTER 6 Joins: Retrieving Data from Several Tables
Transact-SQL Users 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 Users 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 books 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 namessuch as au1 and au2in 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 Users 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 Users 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 Users Guide 183
Kitchens
OLeary 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 joinedau_id
and title_idappear 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 Users 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 tables 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 Users 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 tables 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 Users 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 Executives Datab 19.99
409-56-7008 BU1032 The Busy Executives 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 Users 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 Users 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 Users 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 Executives 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 Users 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 Users 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 Users 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 Executives 19.99 Marjorie Green
The Busy Executives 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 tables 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 Users 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 statements
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
statements 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 Users Guide 205
Michael OLeary 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 Executives 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 Users Guide 207
5023 You Can Combat Computer Stress!
5023 Silicon Valley Gastronomic Treats
5023 Emotional Security: A New Algorithm
5023 The Busy Executives 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
publishers 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 Users 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 Users 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 Users 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 138 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 038 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 Users 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 115 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 Users 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 Users 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 Users 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 Users 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 AF. 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 Users 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 Users 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 Users 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 Users 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 Users Guide 229
When you create a column from an IDENTITY type, you can specify either
identity or not nullor neither onein 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 Users 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 Users 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 objectsviews,
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 Users 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 users 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 Users 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 Users 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 Users Guide 241
Maximum number of columns per table
The maximum number of columns in a table depends on many factors,
including, among others, your servers 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 columnthe 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 Jonahs 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 Users 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 Users 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 columns 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 Users 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 Users 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 Users 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 todays 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 Users 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 objectsviews, rules, defaults, stored
procedures, and triggersin 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 Users 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
tables 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 Users 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 tables
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.
Lets 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 tables 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, lets 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 tables 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 Users 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 Users 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 columns 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 tables IDENTITY
column is not used for referential integrity, use the bcp utility to remove the
gaps. See Reaching the IDENTITY columns maximum value on page 333
for more information.CHAPTER 8 Creating Databases and Tables
Transact-SQL Users 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 tables 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 tables 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 Users 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 Users 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 tables 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 Users 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 tables references by using sp_helpconstraint, described under Using
sp_helpconstraint to find a tables 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 Users 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 tables 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 Users 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 tables 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 Users 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 Users 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 statements 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. Heres 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 Users 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 statements column_list: CHAPTER 8 Creating Databases and Tables
Transact-SQL Users 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 columns 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 tables 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 tables 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 Users 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 tables page chains inherits the tables 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 Users 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 Users
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 tables 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 Users 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 tables 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 Users 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 tables constraints, see Using
sp_helpconstraint to find a tables 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 tables 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 columns 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 Users 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 columns 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 columns 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 Users 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 Users 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 tables 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 columns 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
columns 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 Users 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 tables 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 Users 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 datatypes 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 columns 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 Users 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 tables 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 tables 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 objectscolumns, constraints, datatypes,
views, indexes, rules, defaults, procedures, and triggersuse 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
users 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 Users 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 users 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 Users 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 Users 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 tables 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 constraints 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 Users 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 Users 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 Users 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 itadding, 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 systems 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. Panteleys 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 Users 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 dont understand. For double quotes: He said, Its
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 Users 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 Users 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:
[