Database Design Guide

©Copyright 1998 Pervasive Software Inc. All rights reserved worldwide. Reproduction, photocopying, or transmittal of this publication, or portions of this publication, is prohibited without the express prior written consent of the publisher, unless such reproduction, photocopying, or transmittal is part of a Derivative Software Product as defined in the licenses granted in conjunction with the purchase of this publication and associated software. This product includes software developed by Powerdog Industries. © 1994 Powerdog Industries. All rights reserved. Pervasive Software Inc. 8834 Capital of Texas Highway Austin, Texas 78759 USA

disclaimer

PERVASIVE SOFTWARE INC. LICENSES THE SOFTWARE AND DOCUMENTATION PRODUCT TO YOU OR YOUR COMPANY SOLELY ON AN "AS IS" BASIS AND SOLELY IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF THE ACCOMPANYING LICENSE AGREEMENT. PERVASIVE SOFTWARE INC. MAKES NO OTHER WARRANTIES WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE SOFTWARE OR THE CONTENT OF THE DOCUMENTATION; PERVASIVE SOFTWARE INC. HEREBY EXPRESSLY STATES AND YOU OR YOUR COMPANY ACKNOWLEDGES THAT PERVASIVE SOFTWARE INC. DOES NOT MAKE ANY WARRANTIES, INCLUDING, FOR EXAMPLE, WITH RESPECT TO MERCHANTABILITY, TITLE, OR FITNESS FOR ANY PARTICULAR PURPOSE OR ARISING FROM COURSE OF DEALING OR USAGE OF TRADE, AMONG OTHERS. Btrieve and XQL are registered trademarks of Pervasive Software Inc. Built on Btrieve, Built on Scalable SQL, Client/Server in a Box, DDF Ease InstallScout, MicroKernel Database Engine, MicroKernel Database Architecture, Navigational Client/Server, Pervasive.SQL, Scalable SQL, Smart Components, Smart Component Management, Smart Naming, SmartScout, and Xtrieve PLUS are trademarks of Pervasive Software Inc. Microsoft, MS-DOS, Windows, Windows NT, Win32, Win32s, and Visual Basic are registered trademarks of Microsoft Corporation. Windows 95 is a trademark of Microsoft Corporation. NetWare and Novell are registered trademarks of Novell, Inc. NetWare Loadable Module, NLM, Novell DOS, Transaction Tracking System, and TTS are trademarks of Novell, Inc. All company and product names are the trademarks or registered trademarks of their respective companies.

trademarks

Database Design Guide

100-003195-004

February 1998

Contents
About This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Who Should Read This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Organization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1

Relational Database Design. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Stages of Design . . . . Conceptual Design Logical Design. . . Physical Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 16 17 21

2

Creating a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Named Databases . . . . . . . Bound Databases . . . . . . . . Creating Database Components Naming Conventions . . . . . . Unique Names . . . . . . Valid Characters. . . . . . Maximum Name Lengths . Case-Sensitivity . . . . . . Creating a Data Dictionary . . . Creating Tables . . . . . . . . . Aliases. . . . . . . . . . . Creating Columns . . . . . . . . Creating Indexes . . . . . . . . Index Segments . . . . . . Index Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 24 25 26 26 27 28 29 30 33 34 36 37 39 41

Database Design Guide

3

Contents

3

Inserting and Deleting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Inserting Values . . . . . . . . . . . . . . Inserting Values from Other Tables . Transaction Processing . . . . . . . . . . Deleting Data . . . . . . . . . . . . . . . Dropping Indexes . . . . . . . . . . . . . Dropping Columns . . . . . . . . . . . . Dropping Tables. . . . . . . . . . . . . . Dropping an Entire Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 45 46 47 48 48 49 50

4

Modifying Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Modifying Tables . . . . . . . . . . . . Setting Column Attributes . . . . . . . . Setting Default Values. . . . . . . Setting Valid Values . . . . . . . . Setting Null Values . . . . . . . . Specifying Edit Masks . . . . . . . Permanent and Temporary Masks String Masks . . . . . . . . . . . Number Masks . . . . . . . . . . Hexadecimal Masks . . . . . . . . Date Masks . . . . . . . . . . . . Time Masks . . . . . . . . . . . . Timestamp Masks . . . . . . . . . Boolean Masks . . . . . . . . . . Using UPDATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 53 53 54 55 57 63 63 64 68 69 74 76 77 81

5

Retrieving Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Views . . . . . . . . . . . . . . . Features of Views . . . . . . Temporary and Stored Views Read-Only Tables in Views . . . . . . . . . . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 83 84 86 Contents

Database Design Guide

Mergeable Views . . . . . . . . . Selection Lists. . . . . . . . . . . . . . Sorted and Grouped Rows . . . . . . . Joins. . . . . . . . . . . . . . . . . . . Joining Tables with Other Tables . Joining Views with Tables . . . . . Types of Joins . . . . . . . . . . . Subqueries . . . . . . . . . . . . . . . Subquery Limitations . . . . . . . Correlated Subqueries . . . . . . Restriction Clauses . . . . . . . . . . . Restriction Clause Operators . . . Restriction Clause Examples . . . Expressions . . . . . . . . . . . . Functions . . . . . . . . . . . . . . . . Aggregate Functions . . . . . . . Arguments to Aggregate Functions Aggregate Function Rules. . . . . Scalar Functions . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. 88 . 90 . 92 . 93 . 95 . 96 . 96 . 100 . 101 . 101 . 103 . 104 . 107 . 111 . 126 . 126 . 127 . 128 . 129

6

Storing Logic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Stored Procedures . . . . . . . . . Declaring Stored Procedures . Invoking Stored Procedures . . Deleting Stored Procedures . . SQL Variable Statements . . . . . . Declaring SQL Variables . . . Substitution Variables . . . . . Assignment Statement . . . . SQL Cursor-Based Statements . . . SQL Cursor Declaration . . . . Open Cursor Statement . . . . FETCH Statement . . . . . . . Positioned DELETE Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 . 160 . 160 . 161 . 162 . 162 . 163 . 165 . 166 . 167 . 168 . 169 . 169 Contents

Database Design Guide

Positioned UPDATE Statement . . . . SQL Control Statements . . . . . . . . . . Compound Statement . . . . . . . . . IF Statement. . . . . . . . . . . . . . LEAVE Statement . . . . . . . . . . . LOOP Statement . . . . . . . . . . . WHILE Statement . . . . . . . . . . . Retrieving Status Information . . . . . . . . SQLSTATE System Variable . . . . . Exception and Completion Conditions SQL Triggers . . . . . . . . . . . . . . . . Timing and Ordering of Triggers . . . Defining the Trigger Action . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. 170 . 171 . 171 . 172 . 172 . 173 . 174 . 175 . 175 . 176 . 179 . 180 . 182

7

Managing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Defining Relationships Among Tables . . . . . . . . . . . . Referential Integrity Definitions . . . . . . . . . . . . . Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Primary Keys . . . . . . . . . . . . . . . . . . . . . . Foreign Keys . . . . . . . . . . . . . . . . . . . . . . Referential Constraints . . . . . . . . . . . . . . . . . . . . Referential Integrity Rules . . . . . . . . . . . . . . . . RI in the University Database . . . . . . . . . . . . . . . . . Creating the Course Table . . . . . . . . . . . . . . . Adding a Primary Key to Course . . . . . . . . . . . . Creating the Student Table with Referential Constraints Administering Database Security . . . . . . . . . . . . . . . Understanding Database Rights . . . . . . . . . . . . Establishing Database Security . . . . . . . . . . . . . Enabling Security . . . . . . . . . . . . . . . . . . . . Creating User Groups and Users . . . . . . . . . . . . Granting Rights . . . . . . . . . . . . . . . . . . . . . Dropping Users and User Groups . . . . . . . . . . . . Revoking Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 . 186 . 188 . 188 . 190 . 193 . 194 . 204 . 204 . 204 . 205 . 207 . 208 . 211 . 213 . 213 . 215 . 217 . 218 Contents

Database Design Guide

6

Disabling Security . . . . . . . . . . . . . . . . Specifying Data File Owner Names . . . . . . . Retrieving Information about Database Security Concurrency Controls . . . . . . . . . . . . . . . . . Transaction Processing . . . . . . . . . . . . . Starting and Ending Transactions . . . . . . . . Using Savepoints to Nest Transactions . . . . . Special Considerations . . . . . . . . . . . . . Isolation Levels . . . . . . . . . . . . . . . . . Explicit Locks . . . . . . . . . . . . . . . . . . Passive Control . . . . . . . . . . . . . . . . . Atomicity in Scalable SQL Databases . . . . . . . . Transaction Control in Procedures . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. 218 . 219 . 220 . 221 . 221 . 223 . 223 . 227 . 228 . 234 . 239 . 240 . 241

A

University Database Tables and Referential Integrity. . . . . . . . . . . . 242
Structure of the University Database . . . . . . Assumptions. . . . . . . . . . . . . . . . Entity Relationships . . . . . . . . . . . . Referential Integrity in the University Database. Table Design . . . . . . . . . . . . . . . . . . BILLING Table . . . . . . . . . . . . . . CLASS Table . . . . . . . . . . . . . . . COURSE Table . . . . . . . . . . . . . . DEPARTMENT Table . . . . . . . . . . . ENROLLS Table . . . . . . . . . . . . . FACULTY Table . . . . . . . . . . . . . . PERSON Table . . . . . . . . . . . . . . ROOM Table . . . . . . . . . . . . . . . STUDENT Table . . . . . . . . . . . . . TUITION Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 . 243 . 244 . 246 . 248 . 248 . 249 . 249 . 250 . 250 . 251 . 251 . 253 . 253 . 254

Database Design Guide

7

Contents

Figures
5-1 7-1 7-2 7-3 7-4 7-5 7-6 7-7 7-8 A-1 A-2 Example Restriction Clause .................................................................................... 104 Unsuccessful Insert Operation ................................................................................ 196 Unsuccessful Delete Operation............................................................................... 199 Anomaly on Self-Referencing Tables...................................................................... 200 Anomaly on Delete-Connected Cycle ..................................................................... 201 Prevention of a Delete-Connected Cycle ................................................................ 202 Multiple Paths Anomaly........................................................................................... 203 Foreign Key References ......................................................................................... 206 Relationships Among Rights ................................................................................... 209 Entity Relationships................................................................................................. 245 RI Structure in the University Database .................................................................. 246

Database Design Guide

8

Figures

Tables
2-1 2-2 2-3 4-1 4-2 4-3 4-4 4-5 4-6 5-1 5-2 5-3 5-4 5-5 5-6 5-7 5-8 5-9 5-10 5-11 5-12 Database Component Name Lengths ........................................................................28 Scalable SQL System Tables ....................................................................................30 Maximum Number of Index Segments per Data File .................................................40 Mask Characters and Special Literals for String Data Types.....................................58 Mask Characters and Special Literals for NUMERIC Data Types .............................59 Mask Characters and Special Literals for TIME and TIMESTAMP Data Types.........60 Mask Characters and Special Literals for DATE Data Type ......................................61 Mask Characters and Special Literals for Boolean Data Types .................................62 Examples of Special Literals in Number Masks .........................................................67 Boolean Operators ...................................................................................................104 Relational Condition Operators ................................................................................105 Range Condition Operators .....................................................................................105 Numeric Computations.............................................................................................113 Data Type Categories ..............................................................................................114 Integral Promotions Between Integral Operands .....................................................116 Arithmetic Operators ................................................................................................118 String Operators .......................................................................................................119 Conditional Computed Column Operators ...............................................................120 Date Computations ..................................................................................................121 Time Computations ..................................................................................................123 Aggregate Functions ................................................................................................126 9 Tables

Database Design Guide

5-13 5-14 5-15 5-16 5-17 5-18 7-1 7-2 7-3 A-1

String Scalar Functions ............................................................................................130 Numeric Scalar Functions ........................................................................................131 Date Scalar Functions ..............................................................................................143 Time Scalar Functions .............................................................................................145 CAST Function Data Type Conversions ..................................................................149 Masks and the CAST Function ................................................................................150 Database Rights.......................................................................................................208 Granting Rights ........................................................................................................209 Revoking Rights .......................................................................................................210 Tables and Columns Involved with RI ......................................................................247

Database Design Guide

10

Tables

About This Manual
This manual contains information about using the Scalable SQL relational data access system to design, create, and use databases. If you are new to our products or to databases in general, read the Pervasive Products and Services manual first. Pervasive Software would appreciate your comments and suggestions about this manual. As a user of our documentation, you are in a unique position to provide ideas that can have a direct impact on future releases of this and other manuals. Please complete the User Comments form that appears at the end of this manual, and fax or mail it to Pervasive Software, or send e-mail to docs@pervasive.com.

Who Should Read This Manual
This manual is targeted to developers who are designing a SQL database or planning to execute SQL statements.

Database Design Guide

11

About This Manual

Organization
The following list briefly describes each chapter in the manual:

‹

Chapter 1—“Relational Database Design” This chapter introduces the fundamental principles of relational database design. A thorough database design throughout the development process is critical to successful database functionality and performance.

‹ ‹

Chapter 2—“Creating a Database” This chapter explains how to create a database by creating the data dictionary and creating the database’s tables, columns, and indexes. Chapter 3—“Inserting and Deleting Data” This chapter explains how to add data to a database using either Scalable SQL applications or SQL statements. It also explains how to drop (delete) rows, indexes, columns, or tables from your database or drop an entire database when you no longer need it.

‹

Chapter 4—“Modifying Data” This chapter explains how to modify table definitions, column attributes, and data. You can perform these tasks by entering SQL statements using an interactive application.

‹

Chapter 5—“Retrieving Data” This chapter discusses how you can use SELECT statements to retrieve data.

Database Design Guide

12

About This Manual

‹ ‹

Chapter 6—“Storing Logic” This chapter explains how to store SQL procedures for future use and how to create SQL triggers. Chapter 7—“Managing Data” This chapter discusses defining relationships among tables, administering database security, and controlling concurrency with transactions. This chapter also discusses atomicity in Scalable SQL databases.

‹

Appendix A—“University Database Tables and Referential Integrity” This appendix describes the design of the tables in the university sample database.

This manual also includes an Index.

Database Design Guide

13

About This Manual

Conventions
Unless otherwise noted, command syntax, code, and code examples use the following conventions: Case Commands and reserved words typically appear in uppercase letters. Unless the manual states otherwise, you can enter these items using uppercase, lowercase, or both. For example, you can type MYPROG, myprog, or MYprog. Square brackets enclose optional information, as in [log_name]. If information is not enclosed in square brackets, it is required. A vertical bar indicates a choice of information to enter, as in [file name | @file name]. Angle brackets enclose multiple choices for a required item, as in /D = <5|6|7>. Words appearing in italics are variables that you must replace with appropriate values, as in file name. An ellipsis following information indicates you can repeat the information more than one time, as in [parameter ...]. The symbol ::= means one item is defined in terms of another. For example, a::=b means the item a is defined in terms of b.

[ ] | < >

variable
... ::=

Database Design Guide

14

About This Manual

chapter

1

Relational Database Design

This chapter introduces the fundamental principles of relational database design. A thorough database design throughout the development process is critical to successful database functionality and performance. The Pervasive Software University sample database is provided as part of Pervasive.SQL 7.0 and is frequently used in the documentation to illustrate database concepts and techniques. For an overview of the structure and components of a relational database, refer to the Pervasive Products and Services manual. For definitions of basic relational database concepts, such as table, row, and column, refer to the glossary provided in the Pervasive.SQL User’s Guide.

Database Design Guide

15

Relational Database Design

Stages of Design
Once you understand the basic structure of a relational database, you can begin the database design process. Designing a database is a process that involves developing and refining a database structure based on the requirements of your business. Database design includes the following three stages: 1. Conceptual Database Design 2. Logical Database Design 3. Physical Database Design

Conceptual Design
The first step in the database design cycle is to define the data requirements for your business. Answering these types of questions helps you define the conceptual design:

‹ ‹ ‹ ‹ ‹ ‹ ‹

What types of information does my business currently use? What types of information does my business need? What kind of information do I want from this system? What are the assumptions on which my business runs? What are the restrictions of my business? What kind of reports do I need to generate? What will I do with this information?

Database Design Guide

16

Relational Database Design

‹ ‹

What kind of security does this system require? What kinds of information are likely to expand?

Identifying the goals of your business and gathering information from the different sources who will use the database is an essential process. With this information you can effectively define your tables and columns.

Logical Design
Logical database design helps you further define and assess your business’s information requirements. Logical database design involves describing each piece of information you need to track and the relationships among those pieces of information. Once you create a logical design, you can verify with the users of the database that the design is complete and accurate. They can determine if the design contains all of the information that must be tracked and that it reflects the relationships necessary to comply with the rules of your business. Creating a logical database design includes the following steps: 1. Define the tables you need based on the information your business requires (as determined in the conceptual design). 2. Determine the relationships between the tables. (See the section “Table Relationships” for more information.) 3. Determine the contents (columns) of each table. 4. Normalize the tables to at least the third normal form. (See the section “Normalization” for more information.) 5. Determine the primary keys. (See the “Keys” section for more information.) 6. Determine the values for each column.
Database Design Guide 17 Relational Database Design

Table Relationships
In a relational database, tables relate to one another by sharing a common column. This column, existing in two or more tables, allows you to join the tables. There are three types of table relationships: one-to-one, one-to-many, and many-to-many. A one-to-one relationship exists when each row in one table has only one related row in a second table. For example, the Pervasive Software University may decide to assign one faculty member to one room. Thus, one room can only have one instructor assigned to it at a given time. The university may also decide that a department can only have one Dean. Thus, only one individual can be the head of a department. A one-to-many relationship exists when each row in one table has many related rows in another table. For example, one instructor can teach in many classes. A many-to-many relationship exists when a row in one table has many related rows in a second table. Likewise, those related rows have many rows in the first table. A student can enroll in many courses, and courses can contain many students.

Normalization
Normalization is a process that reduces redundancy and increases stability in your database. Normalization involves determining in which table a particular piece of data belongs and its relationship to other data. Your database design results in a data-driven, rather than process or application-driven, design which provides a more stable database implementation. When you normalize your database, you eliminate the following columns:

‹ ‹

Columns that contain more than one non-atomic value. Columns that duplicate or repeat.
18 Relational Database Design

Database Design Guide

‹ ‹ ‹

Columns that do not describe the table. Columns that contain redundant data. Columns that can be derived from other columns.

First Normal Form
Columns in the first normal form have the following characteristics:

‹ ‹

They contain only one atomic value. They do not repeat.

The first rule of normalization is that you must remove duplicate columns or columns that contain more than one value to a new table. Tables normalized to the first normal form have several advantages. For example, in the Billing table of the sample database, first normal form does the following:

‹ ‹ ‹

Allows you to create any number of transactions for each student without having to add new columns. Allows you to query and sort data for transactions quickly because you search only one column (transaction number). Uses disk space more efficiently because no empty columns are stored.

Second Normal Form
A table is in the second normal form when it is in the first normal form and only contains columns that provide information about the key of the table.

Database Design Guide

19

Relational Database Design

In order to enforce the second rule of normalization, you must move those columns that do not depend on the primary key of the current table to a new table. A table violates second normal form if it contains redundant data. This may result in inconsistent data which causes your database to lack integrity. For example, if a student changes her address, you must then update all existing rows to reflect the new address. Any rows with the old address result in inconsistent data. To resolve these differences, identify data that remains the same when you add a transaction. Columns like Student Name or Street do not pertain to the transaction and do not depend on the primary key, Student ID. Therefore, store this information in the Student table, not in the transaction table. Tables normalized to the second normal form also have several advantages. For example, in the Billing table of the sample database, second normal form allows you to do the following:

‹ ‹ ‹

Update student information in just one row. Delete student transactions without eliminating necessary student information. Use disk space more efficiently since no repeating or redundant data is stored.

Third Normal Form
A table is in the third normal form when it contains only independent columns. The third rule of normalization is that you must remove columns that can be derived from existing columns. For example, for a student, you do not have to include an Age column if you already have a Date of Birth column, because you can calculate age from a date of birth.

Database Design Guide

20

Relational Database Design

A table that is in third normal form contains only the necessary columns, so it uses disk space more efficiently since no unnecessary data is stored. In summary, the rules for the first, second, and third normal forms state that each column value must be a fact about the primary key in its entirety, and nothing else.

Keys
A Scalable SQL key is a column or group of columns on which a table’s referential integrity (RI) constraints are defined. In other words, a key or combination of keys acts as an identifier for the data in a row. For more information about referential integrity and keys, refer to Chapter 7, “Managing Data.”

Physical Design
The physical database design is a refinement of the logical design; it maps the logical design to a relational database management system. In this phase, you examine how the user accesses the database. This step of the database design cycle involves determining the following types of information:

‹ ‹ ‹ ‹

Data you will commonly use. Columns requiring indexes for data access. Areas needing flexibility or room for growth. Whether denormalizing the database will improve performance. (To denormalize your database, you reintroduce redundancy to meet performance.) For more information about normalization, refer to the section “Normalization” earlier in this chapter.
21 Relational Database Design

Database Design Guide

chapter

2

Creating a Database

A Scalable SQL database consists of two basic parts:

‹ ‹

A data dictionary that describes the data. Data files that physically contain your data.

This chapter explains named databases, bound databases, and how to create a database by creating the data dictionary and creating the database’s tables, columns, and indexes in the following sections:

‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹

“Named Databases” “Bound Databases” “Creating Database Components” “Naming Conventions” “Creating a Data Dictionary” “Creating Tables” “Creating Columns” “Creating Indexes”

Database Design Guide

22

Creating a Database

Named Databases
A named database has a logical name that allows users to identify it without knowing its actual location. When you name a database, you associate that name with a particular dictionary directory path and one or more data file paths. When you log in to Scalable SQL using a database name, Scalable SQL uses the name to find the database’s dictionary and data files. Unless your database is named, you cannot do the following:

‹ ‹ ‹ ‹

Define triggers Define primary and foreign keys Bind a database Suspend a database’s integrity constraints

You use the Setup utility to name existing, unbound databases and to create new, bound databases. Refer to the Pervasive.SQL User’s Guide for more information.

Database Design Guide

23

Creating a Database

Bound Databases
Binding a database ensures that the MicroKernel enforces the database’s defined security, referential integrity (RI), and triggers, regardless of the method you use to access the data. The MicroKernel enforces these integrity controls as follows:

‹ ‹ ‹

When you define security on a bound database, Btrieve users cannot access it. When you define security on an unbound database, Btrieve users can access it. When no security is defined on a bound database, Btrieve users can access the data files as follows: Bound File’s Constraint
RI constraints defined INSERT triggers defined UPDATE triggers defined DELETE triggers defined

Level of Access Using Btrieve
User can access and do anything within RI constraints Read-only, update, and delete access Read-only, insert, and delete access Read-only, insert, and update access

If more than one constraint exists on the bound file, the access level follows the most restrictive constraint. For example, if a file has both INSERT and UPDATE triggers defined, then you have read-only and delete access.
Note

Even if you do not bind your database, Scalable SQL automatically stamps a data file as bound if it has a trigger, has a foreign key, or has a primary key that is referenced by a foreign key. Thus, a data file may be part of an unbound database, but be bound. In such cases, the MicroKernel enforces integrity constraints on the file as if it were part of a bound database.

Database Design Guide

24

Creating a Database

The dictionary and data files in a bound database cannot be referenced by other named databases. Also, bound data files cannot be referenced by other tables in the database. When you create a bound database or bind an existing database, Scalable SQL stamps every dictionary and data file with the name of the bound database. Also, Scalable SQL stamps every data file with the name of the table associated with that data file. In addition, when you add new tables or dictionary files to the database, Scalable SQL automatically binds them.

Creating Database Components
To create a new database with Scalable SQL, you first create the dictionary (using the CREATE DICTIONARY statement), and then issue CREATE TABLE statements for each table you want to create. When you issue a CREATE TABLE statement, you must include commands that define columns. In addition, you can include commands that define indexes or referential integrity (RI) constraints. You can also use DDF Ease to create dictionaries and database. Refer to the DDF Ease on-line help for complete instructions on using this utility or refer to the Pervasive.SQL User’s Guide.

Database Design Guide

25

Creating a Database

Naming Conventions
When you create a database, Scalable SQL allows you to assign a descriptive name to each database component. Users and applications refer to the components of the database using these names. This section outlines the conventions to which you must adhere when naming database components.

Unique Names
The following database components must have unique names within a dictionary:

‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹

Tables Views Indexes Keys User names Group names Stored procedures Triggers Column names within a single table

Database Design Guide

26

Creating a Database

Names for parameters and substitution variables must be unique within a SQL statement. Because Scalable SQL keywords are reserved words, you cannot use them for naming database components or in parameter names and substitution variables. See the SQL Language Reference for a list of reserved keywords. When a column name is repeated in different tables, you can qualify it in each table by preceding it with the relevant table name or alias name. For example, you can refer to the ID column in the Student table as Student.ID. This is a fully qualified column name, and the table name (Student) is the column qualifier.

Valid Characters
Following are the valid characters for the names of database components at the SQL level, and for substitution variables and parameter names:

‹ ‹ ‹ ‹ ‹ ‹ ‹

a through z A through Z 0 through 9 _ (underscore) ^ (caret) ~ (tilde) $ (dollar sign)

Database Design Guide

27

Creating a Database

Note

The name of a database component must begin with a letter. If you specify the name of a database component or a parameter name that does not follow these conventions, specify the name in double quotes (such as “name”).

Maximum Name Lengths
Scalable SQL restricts the maximum length of database component names in a dictionary. Table 2-1 lists the maximum name lengths for each type of database component.

Table 2-1
Type of Name
Table View Column Index Foreign key User or group

Database Component Name Lengths
Maximum Length
20 20 20 20 20 30

Type of Name
Password Database Stored Procedure Trigger Substitution variable Data file pathname

Maximum Length
8 20 30 30 None 641

1 The maximum length of the data file pathname is a combination of the Xf$Loc path and the data file path.

Database Design Guide

28

Creating a Database

Case-Sensitivity
Scalable SQL is case-sensitive when you are defining database component names. If you create a table named TaBLe1, Scalable SQL stores the table name in the dictionary as TaBLe1. With the exception of user names, user group names, and passwords, Scalable SQL is case-insensitive after you define the component name. After defining the table TaBLe1, you can refer to it as table1. User names, user group names, and passwords are case-sensitive in Scalable SQL. For example, when you log in as the master user, you must specify the user name as Master. When retrieving data, Scalable SQL displays names for tables, views, aliases, and columns based on the way you specify the name in the query. If you use * to specify column names, Scalable SQL returns the names in all uppercase: SELECT * FROM Course; Scalable SQL returns the column names as follows: NAME, DESCRIPTION, CREDIT_HOURS, DEPT_NAME

Database Design Guide

29

Creating a Database

Creating a Data Dictionary
Scalable SQL uses the dictionary to store information about the database. The dictionary consists of several system tables that describe the tables and views of your database. The system tables contain several types of database information, including table and index definitions, column characteristics, and integrity and security information. Table 2-2 describes the system tables Scalable SQL creates.

Table 2-2
Operation

Scalable SQL System Tables
Resulting Table
X$File, X$Field, X$Index X$Attrib X$Proc X$User, X$Rights X$Relate X$View X$Trigger, X$Depend

Create a data dictionary Specify column attributes Create stored SQL procedures Define database security Define referential constraints Define views Define triggers

Because the system tables are part of the database, you can query them to determine their contents. If you have the appropriate rights, you can also create system tables or change their contents.

Database Design Guide

30

Creating a Database

Note

Scalable SQL does not display some data in the system tables. For example, information about stored views and procedures, other than their names, is available only to Scalable SQL. In addition, some data (such as user passwords) displays in encrypted form.

For a complete reference to the contents of each system table, refer to the SQL Language Reference. Once you have created a dictionary, you can add tables, columns, and indexes to your database.

®

To create a named database, perform the following steps.
Note

You must have named databases in order to use some features, such as referential integrity and triggers. 1. Create a directory in which to store the new dictionary tables. 2. Use the Setup utility to add a Named Database. Refer to the Pervasive.SQL User’s Guide for more information.

®

To create a dictionary for an unnamed database, perform the following steps: 1. Create a directory in which to store the new dictionary tables. 2. Log in to an existing database (for example, the sample university database included with Scalable SQL) using an application that supports Scalable SQL, such as SQLScope.

Database Design Guide

31

Creating a Database

3. Issue a CREATE DICTIONARY statement, specifying the directory you created in Step 1 (such as F:\DemoDict). CREATE DICTIONARY USING ‘f:\DemoDict\; or CREATE DICTIONARY USING ‘\\MyServer\Sys:DemoDict’; or CREATE DICTIONARY USING ‘\\MyServer\Vol1\DemoDict’; Scalable SQL creates dictionary tables to store the X$File, X$Field, and X$Index system tables in the directory you specify. 4. Log out of the database.

Database Design Guide

32

Creating a Database

Creating Tables
When you create a table, you must name it. Each table name must be unique within a database and cannot exceed 20 characters. For more information about rules for naming tables, refer to the section "Naming Conventions." When you are deciding which tables to create in your database, consider that different users can look at data in different combinations using views. A view looks like a table and can be treated as a table for most purposes (such as retrieving, updating, and deleting data). However, a view is not necessarily associated with a single table; it can combine information from multiple tables. For more information, refer to "Views." To create a table, issue a CREATE TABLE statement, as in the following example: CREATE TABLE Department USING 'dept.mkd' (Name CHAR(10), Phone_Number NUMERIC(10), Building_Name CHAR(8), Room_Number FLOAT(4), Head_of_Department NUMERIC(9)); In this example, Department is the table name, and DEPT.MKD is the data file name. This example does not create indexes or define referential constraints. You can add additional columns, indexes, and RI constraints to the table later. The next section, “Creating Columns” provides more information about creating columns. In addition, this example explicitly specifies the name of the data file to create. The data file name stored in the dictionary cannot exceed 64 characters. Also, the combination of the data file name and the directory path for the data file cannot exceed 80 characters. You specify the directory path when logging in with pathnames or when setting up a

Database Design Guide

33

Creating a Database

database name with the Setup utility. For more information about data file pathnames, refer to the SQL Language Reference. You can omit the filename if you want Scalable SQL to create it for you. If Scalable SQL creates the data file name, it generates a unique filename with a .MKD extension.

Aliases
You can assign aliases (also called alias names) to table names in the following elements of statements:

‹ ‹ ‹

FROM clause of a SELECT or DELETE statement. INTO clause of an INSERT statement. List of tables in an UPDATE statement.
Note

Aliases apply only to the statement in which you use them. Scalable SQL does not store them in the data dictionary.

An alias can be any combination of up to 20 characters. Always separate the table name from the alias with a blank. Separate the alias and the column name with a period (.). Once you specify an alias for a particular table, you can use it elsewhere in the statement to qualify column names from that table. The following example specifies the alias name s for the table Student and e for the table Enrolls. SELECT s.ID, e.Grade FROM Student s, Enrolls e WHERE s.ID = e.Student_ID;

Database Design Guide

34

Creating a Database

You can use an alias to do the following:

‹

Replace long table names. When you are working interactively, using aliases can save typing time, especially when you need to qualify column names. For example, the following statement assigns s as the alias for the Student table, e for the Enrolls table, and c1 for the Class table. This example uses aliases to distinguish the source of each column in the selection list and in the WHERE conditions. SELECT s.ID, e.Grade, c1.ID FROM Student s, Enrolls e, Class c1 WHERE (s.ID = e.Student_ID) AND (e.Class_ID = c1.ID);

‹ ‹

Make a statement more readable. Even in statements with only a single table name, an alias can make the statement easier to read. Use the table in the outer query in a correlated subquery. SELECT s.ID, e.Grade, c1.ID FROM Student s, Enrolls e, Class c1 WHERE (s.ID = e.Student_ID) AND (e.Class_ID = c1.ID) AND e.Grade >= (SELECT MAX (e2.Grade) FROM Enrolls e2 WHERE e2.Class_ID = e.Class_ID);

Database Design Guide

35

Creating a Database

Creating Columns
You create columns when you create a table using a CREATE TABLE statement, or you can add columns to an existing table using an ALTER TABLE statement. In either case, you must specify the following characteristics:

‹

Column name—identifies the column. Each column name must be unique within a table and the column name cannot exceed 20 characters. Scalable SQL is case-sensitive when defining database column names, but case-insensitive after you define the column name. For example, if you create a column named ColuMN1, the name is stored in the dictionary as ColuMN1; subsequently, you can refer to it as column1. For more information about rules for naming columns, refer to the section "Naming Conventions." Data type—identifies the kind of data to expect, such as a string of characters or a number, and how much disk storage space to allocate. Length—indicates how much disk storage space to allocate. For some numeric data types, you must also specify the number of decimal places. All the Scalable SQL data types are fixed-length except NOTE and LVAR, which are variable length. For instance, the maximum column length for LVAR is 32,761 bytes.

‹ ‹

For more information about data types, see the SQL Language Reference.

Database Design Guide

36

Creating a Database

Creating Indexes
Indexes optimize operations that either search for or order by specific values. Define indexes for any columns on which you frequently perform either of these operations. Indexes provide a fast retrieval method for a specific row or group of rows in query optimization. Scalable SQL also uses indexes with referential integrity (RI). Indexes improve performance on joins and help to optimize queries. For more information about RI, see Chapter 7, “Managing Data.” In Scalable SQL databases, the MicroKernel creates and maintains indexes as part of the physical file for which they are defined. The MicroKernel performs all maintenance for Insert, Update, or Delete operations. These activities are transparent to any Scalable SQL or Btrieve application. To create an index when you create a table, use the WITH INDEX clause of the CREATE TABLE statement. This method creates an unnamed index. You cannot delete unnamed indexes after you create them. To create an index after you create the table, use a CREATE INDEX statement. This method creates a named index. You can delete named indexes after you create them. For more information about dropping indexes, refer to Chapter 3, “Inserting and Deleting Data.” While indexes allow you to sort rows and retrieve individual rows quickly, they increase the disk storage requirements for a database and decrease performance somewhat on Insert, Update, and Delete operations. You should consider these trade-offs when defining indexes.

Database Design Guide

37

Creating a Database

The following example instructs Scalable SQL to create an index when creating the Course table: CREATE TABLE Course USING 'course.mkd' (Name CHAR(7) CASE, Description CHAR(50) CASE, Credit_Hours UNSIGNED(2), Dept_Name CHAR(20)) WITH INDEX (Name UNIQUE CASE, Dept_Name CASE MOD); The next example uses a CREATE INDEX statement to add an index to a table that already exists: CREATE INDEX DeptHours ON Course (Dept_Name CASE MOD SEG, Credit_Hours MOD);
Note

Be aware that if you use the CREATE INDEX statement on files that contain a lot of data, execution could take some time to complete, and other users may not be able to access data in that file in the meantime.

For detailed information about the CREATE TABLE and CREATE INDEX statements, refer to the SQL Language Reference.

Database Design Guide

38

Creating a Database

Index Segments
You can create an index on any single column or group of columns in the same table. An index that includes more than one column is called a segmented index, in which each column is called an index segment.
Note

You cannot define an index on a column of type BIT, LVAR, or NOTE. For more information about segmented indexes and AUTOINC, refer to the SQL Language Reference.

For example, the Person table in the sample database has the following three indexes:

‹ ‹ ‹

A segmented index consisting of the Last Name column and the First Name column. The Perm_State+Perm_City column. The ID column.

By default, Scalable SQL can create 119 key segments. The number is affected by the MicroKernel Database Engine page size of the data file. See the SQL Language Reference for more information on how to use the PAGESIZE keyword. The maximum number of indexes you can create for a table depends on the page size of its data file and the number of segments in each index. As Table 2-3 shows, data files with page sizes smaller than 4096 bytes cannot contain as many index segments as a data file with a page size of 4096.

Database Design Guide

39

Creating a Database

Table 2-3
Page Size
512 1024 1536 2048 2560 3072 3584 4096

Maximum Number of Index Segments per Data File
Maximum Number of Index Segments
8 23 24 54 54 54 54 119

Using the page size and fixed record length, you can calculate the efficiency with which data is being stored (such as the number of wasted bytes per page). By having fewer records per page, you can improve concurrency where page-level locking is concerned. By default, Scalable SQL creates all tables with a page size of 4096 bytes. However, you can specify a smaller page size using the PAGESIZE keyword in a CREATE TABLE statement, or you can create a table using the MicroKernel Database Engine and specify a smaller page size for that table. When calculating the total number of index segments defined for a table, a nonsegmented index counts as one index segment. For example, if your table has three indexes defined, one of which has two segments, the total number of index segments is four.
Database Design Guide 40 Creating a Database

You can use the SQLScope utility to display the number of defined index segments and the page size of a data file. For information about this utility, see the Pervasive.SQL User’s Guide.

Index Attributes
When you create an index, you can assign to it a set of qualities, or attributes. Index attributes determine the modifiability of the index and how Scalable SQL sorts the indexes you define for a table. You can include parameters specifying index attributes anytime you create or alter an index definition. Indexes can have the following attributes: Case-sensitivity Determines how Scalable SQL evaluates uppercase and lowercase letters during sorting. By default, Scalable SQL creates casesensitive indexes. To create a case-insensitive index, specify the CASE keyword when you create the index. Determines how Scalable SQL sorts index column values. By default, Scalable SQL sorts index column values in ascending order (from smallest to largest). To create an index that sorts in descending order, specify the DESC keyword when you create the index. Determines whether Scalable SQL allows multiple rows to have the same index column value. By default, Scalable SQL creates nonunique indexes. To create an index that requires unique values, specify the UNIQUE keyword when you create the index. Determines whether you can modify index column values after Scalable SQL stores the corresponding row. By default, Scalable SQL does not allow changes to index column values once Scalable SQL stores the row. To create a modifiable index, specify the MOD keyword when you create the index.
41 Creating a Database

Sort order

Uniqueness

Modifiability

Database Design Guide

Null value indexing Determines whether Scalable SQL includes columns that contain the predefined null value in the index structure. By default, Scalable SQL includes null values in the index structure. To create an index so that Scalable SQL does not include null values, specify the NULL keyword when you create the index. Segmentation Indicates whether the index is segmented (whether it consists of a group of columns combined into a single index). By default, Scalable SQL creates indexes that are not segmented. To create a segmented index using the CREATE TABLE statement, specify the SEG keyword for each index segment you create, except the last segment in the index. (The SEG keyword indicates that the next column specified is a segment of the index you are creating.) Because you can create only one index at a time with the CREATE INDEX command, you do not need to use the SEG keyword to specify a segmented index. If you specify more than one column, Scalable SQL creates a segmented index using the columns in the order in which you specify them. Uniqueness and modifiability apply only to entire indexes. You cannot apply uniqueness or modifiability to a single index segment without applying it to the entire index. For example, if you create a segmented index and specify the MOD keyword for one of the index segments, you must specify the MOD keyword for every segment. In contrast, you can apply case-sensitivity, sort order, null value indexing, and segmentation to individual index segments without affecting the entire index. For example, you can create a case-insensitive index segment in an otherwise case-sensitive index.

Database Design Guide

42

Creating a Database

chapter

3

Inserting and Deleting Data

After creating a data dictionary, tables, and columns, you can add data to the database using either Scalable SQL applications or SQL statements. SQL statements allow you to do the following:

‹ ‹

Specify literal values to insert. Select data from other tables and insert the resulting values into entire rows or specified columns.

When you insert a literal value, it must conform to the specified column’s data type, length, and edit mask. You can drop (delete) rows, indexes, columns, or tables from your database. In addition, you can drop an entire database when you no longer need it. This chapter includes the following sections:

‹ ‹ ‹ ‹ ‹ ‹ ‹

“Inserting Values” “Transaction Processing” “Deleting Data” “Dropping Indexes” “Dropping Columns” “Dropping Tables” “Dropping an Entire Database”

Database Design Guide

43

Inserting and Deleting Data

Inserting Values
You can use a VALUES clause in an INSERT statement to specify literal values to insert into a table. The following example inserts a new row into the Course table of the sample database: INSERT INTO Course VALUES ('ART 103', 'Principles of Color', 3, 'Art'); In this example, listing the columns Name, Description, Credit_Hours, and Dept_Name is optional because the statement inserts a value for each column in the table, in order. However, a column list is required if the statement inserted data only into selected columns instead of the entire row, or if the statement inserted data into the columns in a different order than is defined in the table.
Note

If you do not specify a value for a column of DATE, TIME, or TIMESTAMP, Scalable SQL does not insert the current date or time by default. To insert the current date or time, use the CURDATE and CURTIME variables as values.

You can insert a constant into a column by placing it in the VALUES clause of an INSERT statement. If the data type of the column into which you are inserting is DATE, TIME, or TIMESTAMP, then this constant must conform to the mask defined on the column into which you are inserting the data. For all other data types, the constant must conform either to the defined mask on the column or the default mask for the data type of the column. For more information about the role of data types and defined or default masks, or about using the INSERT statement, refer to the SQL Language Reference.

Database Design Guide

44

Inserting and Deleting Data

Inserting Values from Other Tables
You can use a SELECT clause in an INSERT statement to select values from one table and insert them into another table. The following example populates a new table, InactiveStudents, with data selected from the sample database tables Student and Tuition. CREATE TABLE InactiveStudents USING 'Inact.mkd' (Student_ID UNSIGNED(8), Major CHAR(20) CASE, Degree LSTRING(5)); INSERT INTO InactiveStudents (Student_ID, Major, Degree) SELECT ID, Major, Degree FROM Student s, Tuition t WHERE s.tuition_id = t.id AND s.id NOT IN (SELECT Student_ID FROM Enrolls); In this example, Scalable SQL selects the values for the Student_ID, Major, and Degree columns based on restriction criteria that utilizes the Enrolls table. Scalable SQL then inserts these values into the corresponding fields of the new table, InactiveStudents. When inserting rows that are the result of a SELECT statement, the data types of the columns in the view defined by the SELECT statement must be compatible with the data types of the columns into which you are inserting the data. For more information, refer to the SQL Language Reference.

Database Design Guide

45

Inserting and Deleting Data

Transaction Processing
When you attempt to insert data into a table, Scalable SQL returns an error if the data is invalid. Any data inserted before the error occurred is rolled back. This enables your database to remain in a consistent state. You can use transaction processing in a Scalable SQL database to group a set of logically related statements together. Within a transaction, you can use savepoints to effectively nest transactions; if a statement in a nesting level fails, then the set of statements in that nesting level is rolled back to the savepoint. Refer to Chapter 7, “Managing Data,” for information about transaction processing and savepoints.

Database Design Guide

46

Inserting and Deleting Data

Deleting Data
There are two types of DELETE statements: positioned and searched. You can use a DELETE statement to delete one or more rows from a table or an updatable view. To specify specific rows for Scalable SQL to delete, use a WHERE clause in a DELETE statement. DELETE FROM Class WHERE ID = '005'; The Positioned DELETE statement deletes the current row of a view associated with an open SQL cursor. DELETE WHERE CURRENT OF mycursor; For more information about SQL cursors, refer to "SQL Cursor-Based Statements." For more information about the syntax of these statements, refer to the SQL Language Reference.

Database Design Guide

47

Inserting and Deleting Data

Dropping Indexes
If you find that you no longer need a named index, use a DROP INDEX statement to drop it. DROP INDEX DeptHours; You cannot drop unnamed indexes (those you created using a WITH INDEX clause in a CREATE TABLE statement).

Dropping Columns
To drop a column from a table, use an ALTER TABLE statement. ALTER TABLE Faculty DROP Rsch_Grant_Amount; This example drops the Rsch_Grant_Amount column from the Faculty table and deletes the column definition from the data dictionary.
Note

Be aware that if you use the ALTER TABLE statement on files that contain a lot of data, execution could take some time to complete, and other users may not be able to access data in that file in the meantime.

Database Design Guide

48

Inserting and Deleting Data

Dropping Tables
To drop a table from the database, use a DROP TABLE statement. DROP TABLE InactiveStudents; This example drops the InactiveStudents table definition from the data dictionary and deletes its corresponding data file (INACT.MKD).
Note

You cannot drop any system tables. Refer to the SQL Language Reference for a complete listing of system tables.

Database Design Guide

49

Inserting and Deleting Data

Dropping an Entire Database
When you no longer need a particular database, you can drop it using a DROP DICTIONARY statement, which deletes all the data dictionary and data files for the database. You cannot be logged in to the database you are attempting to drop, but you must be logged in to another database. The following example deletes the sample database: DROP DICTIONARY USING 'f:\demodict';
Note

You cannot drop bound databases.

If the database you drop is unbound but named, delete the database name; otherwise, users may try to log in to a database that no longer exists. You can use the Setup utility to delete a database name. For more information, refer to the Pervasive.SQL User’s Guide.

Database Design Guide

50

Inserting and Deleting Data

chapter

4

Modifying Data

After creating a database, you can modify it as follows:

‹ ‹ ‹

After creating tables, you can modify the table definitions. After creating columns, you can set optional column attributes. After adding data to the database, you can modify the data.

You can perform these tasks using either SQL statements or a Scalable SQL application. For information about interactive applications, refer to the Pervasive.SQL User’s Guide. For more information about SQL statements, refer to the SQL Language Reference. This chapter contains the following sections:

‹ ‹ ‹

Modifying Tables Setting Column Attributes Using UPDATE

Database Design Guide

51

Modifying Data

Modifying Tables
You can use an ALTER TABLE statement to modify a table definition after creating the table. ALTER TABLE statements allow you to add, modify, or drop columns; add or drop primary and foreign keys; and change the pathname of a table’s data file. The following example adds a 1-byte logical column called Residency to the Tuition table in the sample database. ALTER TABLE Tuition ADD Residency LOGICAL(1); The following example changes the data file name of the Person table in the sample database. ALTER TABLE Person IN DICTIONARY USING 'person.mkd';
Note

This example changes only the data dictionary. It does not rename the data file. To rename the data file, use operating system commands. For more information about columns, refer to Chapter 2, “Creating a Database.” For more information about primary and foreign keys, refer to Chapter 7, “Managing Data.”

Database Design Guide

52

Modifying Data

Setting Column Attributes
You can set the following optional column attributes for a column using a SET DEFAULT, SET VALUES, SET RANGE, SET CHAR, or SET MASK statement.

‹ ‹ ‹ ‹

Default value—A value that Scalable SQL stores in the column if you do not specify a value. Valid values—Specifies the values Scalable SQL allows you to store in the column. Null value—Specifies the value you can use to indicate that the information that is normally stored in the column is unavailable or irrelevant. Edit mask —Indicates how Scalable SQL displays the column. Some edit masks actually determine the value you specified; others just describe the format.

If you specify attributes on existing data, Scalable SQL does not detect values that are already outside these ranges. The values in SET DEFAULT, SET VALUES, and SET RANGE statements must match either the column’s user-defined edit mask or the column’s data type default mask, except in the case of types DATE, TIME, and TIMESTAMP. The values must match the column’s user-defined edit mask for columns of type DATE, TIME, and TIMESTAMP; if the column has no user-defined edit mask, then the values must match the column’s data type default mask.

Setting Default Values
Scalable SQL inserts a default value if you insert a row but do not provide a value for that column. Default values ensure that each row contains a valid value for the column.

Database Design Guide

53

Modifying Data

In the Person table of the sample database, all students live in a state. Setting a default value such as TX for the State column ensures that the most probable value is always entered for that column. To set a default value for a column, use a SET DEFAULT statement: SET DEFAULT State = 'TX';

Setting Valid Values
Scalable SQL lets you limit the type of information you can insert into a column. Once you set these limits, Scalable SQL validates the data when you attempt to insert or update a row and returns an error if the data conflicts with these limits. Scalable SQL allows you to set the following types of limits:

‹ ‹ ‹
Ranges

Ranges Character lists Value lists

You can specify the minimum and maximum values that a column can accept. You can also set multiple ranges of values for a column. For example, you can specify that a column named Grade accepts values only from 0.0 through 4.0. When you insert a new row or update an existing row, Scalable SQL returns an error if the new column value is not within the specified range. To set a data range for a column, use a SET RANGE statement, as in the following example: SET RANGE Grade = 0.0 - 4.0;

Database Design Guide

54

Modifying Data

Character Lists
A character list allows you to specify individual characters and ranges of characters as valid input for a string column. If you set a character list, Scalable SQL allows you to insert or update data only if each character in the column value is included in the character list. To set a character list for a column, use a SET CHAR statement. SET CHAR Person.Zip = '0'-'9','-';

Value Lists
A value list allows you to specify all acceptable values for a column. For example, a value list for the column recording faculty designations includes PROF, ASST PROF, and ASSOC PROF. To set a value list for a column, use a SET VALUES statement. SET VALUES Designation = 'PROF','ASST PROF','ASSOC PROF';

Setting Null Values
A null value in a column indicates that the corresponding data is unavailable or does not exist. For example, assume the Minor column of a Student row contains a null value. Most likely, either the student’s minor was inadvertently omitted from the database, or the student has not declared a minor. Scalable SQL allows you to set a null value for a particular group of data types. You cannot set a null value for a specific column, only for all columns of a certain group of data types. Also, Scalable SQL does not store the setting in the dictionary; the null value you specify is in effect only for the current login session. When you set a null value for a data type, Scalable SQL inserts that null value into any column that has neither a default value nor a value that the application assigned.
Database Design Guide 55 Modifying Data

Scalable SQL provides predefined null values for each data type. This null value is used as a fill byte for any value in its category. However, it is usually preferable to set a default value for a data type rather than use a null value, because a default value is meaningful and maintains the logical integrity of your database. Depending on the keyword you use with the SET statement, Scalable SQL sets the null value as follows:

‹ ‹ ‹

SET STRINGNULL sets a null value for all columns of data type CHARACTER. SET DECIMALNULL sets a null value for all columns of data type CURRENCY, DECIMAL, MONEY, NUMERIC, NUMERICSA, and NUMERICSTS. SET BINARYNULL sets a null value for all columns of type AUTOINC, BFLOAT, DATE, INTEGER, FLOAT, LOGICAL, LSTRING, TIME, TIMESTAMP, UNSIGNED, and ZSTRING.

You cannot set a null value for LVAR or NOTE columns.
Note

Each session must specify these null values to indicate how Scalable SQL should interpret data values. Otherwise, the session may misinterpret the null value of the data in the database.

The following example instructs Scalable SQL to insert an asterisk into all bytes of a character column if the column has no default value and you do not specify a value. SET STRINGNULL = '*';

Database Design Guide

56

Modifying Data

Specifying Edit Masks
An edit mask specifies the way Scalable SQL displays specific columns when you retrieve them (in some cases, edit masks determine how you insert values into columns). For example, you can choose to separate groups of three digits with a comma or display negative numbers inside parentheses. You can also use edit masks to specify the display length for CHARACTER, LSTRING, and ZSTRING columns. In addition to using edit masks to format displays, you can use masks to format input values when inserting data for the AUTOINC, BFLOAT, BIT, CURRENCY, DATE, DECIMAL, FLOAT, INTEGER, LOGICAL, MONEY, NUMERIC, NUMERICSA, NUMERICSTS, TIME, TIMESTAMP, and UNSIGNED data types. You specify an edit mask using the SET MASK or SELECT statements. Masks do not describe the internal format for data types. Scalable SQL sets the internal format, as explained in the SQL Language Reference. You can specify an edit mask for a column of any data type except LVAR or NOTE. The rules for edit masks vary depending on a column’s data type. Each type uses reserved characters that affect a column’s appearance. Masks cannot exceed 30 characters. Scalable SQL determines the displayable format for a column in one of the following ways:

‹ ‹ ‹

If you defined a temporary edit mask in a SELECT statement, Scalable SQL uses that mask. To define a temporary mask for any column (including a computed column) in a SELECT statement, place the mask in square brackets directly following the column. If you have not specified an edit mask in the SELECT statement, Scalable SQL uses the format specified in the dictionary. You can specify a mask for a column in the dictionary using a SET MASK statement. If you did not specify an edit mask with one of the previous methods, Scalable SQL uses a default mask, which depends on the data type of the column. The SQL Language Reference describes the default mask for each data type.
57 Modifying Data

Database Design Guide

Edit Mask Literals
You can also embed edit mask literals before, after, or within the data positions. An edit mask literal is any character in the mask that does not represent data and is not a special literal. It appears in your formatted data exactly as it appears in the mask. For example, the following mask uses backward slashes (/) to separate day, month, and year values in a DATE column. mm/dd/yy Each mask character you specify correlates to a single character or digit in a column value. Each special literal affects the display of a column value or portion of a column value. The following tables list the edit mask characters and special literals you can use with each Scalable SQL data type and summarizes their effect on displayed data. Table 4-1 lists the mask characters, special literals, and usage rules for string data types. These types include CHARACTER, LSTRING, and ZSTRING data types. (You cannot specify masks for LVAR and NOTE columns.) For more information about these masks, refer to the section "String Masks."

Table 4-1

Mask Characters and Special Literals for String Data Types
Special Literals Char
nnn

Mask Characters Char Effect on Data
x Characters

Effect on Data
Numerals indicate number of characters displayed.

Rules
Mask must be xnnn. You must precede length numerals (nnn) with a lowercase x. Maximum length (nnn) is 255 characters.

Database Design Guide

58

Modifying Data

Table 4-2 lists the mask characters, special literals, and usage rules for numeric data types. These types include the following: AUTOINC DECIMAL MONEY NUMERICSTS BFLOAT FLOAT NUMERIC UNSIGNED CURRENCY INTEGER NUMERICSA

For more information about these masks, refer to the section "Number Masks."

Table 4-2

Mask Characters and Special Literals for NUMERIC Data Types
Special Literals Char
+ –

Mask Characters Char
Z

Effect on Data
Deletes blank characters or displays zeros, depending on context. Displays 0 for each zero value.

Effect on Data
Displays leading or trailing +/–. Displays leading or trailing +/–. Displays negative inside parentheses. Scales integers; displays in actual position for others. Suppresses display of negative values.

Rules
See the section “Special Literals in Number Masks” for the rules for using these literals.

9

() .

{}

Database Design Guide

59

Modifying Data

Table 4-2

Mask Characters and Special Literals for NUMERIC Data Types continued
Special Literals Char
H

Mask Characters Char Effect on Data

Effect on Data
Displays value in hexadecimal format (INTEGER, AUTOINC, and UNSIGNED data types only). Displays values in scientific notation. Positive or negative sign may appear before the exponent.

Rules
Hexadecimal masks must end with H.

E

Table 4-3 lists the mask characters, special literals, and usage rules for TIME and TIMESTAMP data types. For more information about these masks, refer to the section "Time Masks."

Table 4-3

Mask Characters and Special Literals for TIME and TIMESTAMP Data Types
Special Literals Char1 Effect on Data
B b: d: Forces or deletes a blank space. Displays all blanks if column value is 0. Displays current time if column value is 0. Displays all zeros if column value is 0.

Mask Characters Char
hh mm tt f

Effect on Data
Hour digits Minute digits (in TIME) Minute digits (in TIMESTAMP)

Fraction of seconds (in TIMESTAMP) z:

Database Design Guide

60

Modifying Data

Table 4-3

Mask Characters and Special Literals for TIME and TIMESTAMP Data Types
Special Literals Char1 Effect on Data
ap: Indicates a.m./p.m.

Mask Characters Char
ss uu B

Effect on Data
Second digits Hundredth of a second digits Blank

1 Rules: If you do not specify b: or d:, Scalable SQL uses z:. b:, d:, or z: literals must be the first characters of the edit mask. The ap: can appear at the beginning or end of the mask.

Table 4-4 lists the mask characters, special literals, and usage rules for the DATE data type. For more information about these masks, refer to the section "Date Masks."

Table 4-4

Mask Characters and Special Literals for DATE Data Type
Special Literals Char1 Effect on Data
B b: d: Forces a blank space. Displays all blanks if column value is 0. Displays current date if column value is 0.

Mask Characters Char
mm mmm... MMM...

Effect on Data
Month digits Month characters, minimum of 3 (trailing blanks) Month characters, minimum of 3 (no trailing blanks)

Database Design Guide

61

Modifying Data

Table 4-4

Mask Characters and Special Literals for DATE Data Type continued
Special Literals Char1 Effect on Data
z: Displays all zeros if column value is 0.

Mask Characters Char
dd www... WWW... yy yyyy

Effect on Data
Day digits Day characters (trailing blanks) Day characters (no trailing blanks) Last two digits of year Entire year

1 Rules: If you do not specify b: or d:, Scalable SQL uses z:. b:, d:, or z: literals must be the first characters of the edit mask.

Table 4-5 lists the mask characters, special literals, and usage rules for Boolean data types. These types include LOGICAL and BIT. For more information about these masks, refer to the section "Boolean Masks."

Table 4-5

Mask Characters and Special Literals for Boolean Data Types
Special Literals Char

Mask Characters Char
<true> <false>

Effect on Data

Effect on Data

Rules

Separates true For details about specifying Boolean and false values. masks, see the section “Boolean Masks”

Database Design Guide

62

Modifying Data

Permanent and Temporary Masks
Permanent masks are stored in the data dictionary and become part of the column’s data definition. You can use a SET MASK statement to set a permanent mask. Temporary masks are used in a single data retrieval operation. You can use a temporary mask either to set the display format for a column that does not have a mask or to override a permanent mask specified for a column. To set a temporary mask, specify the mask after the column name in a SELECT statement, and enclose the mask in square brackets ([ ]).

String Masks
String masks specify only the display length for CHARACTER, LSTRING, and ZSTRING columns; you cannot embed characters like you can with number masks. You cannot specify masks for LVAR and NOTE columns. You can specify the display length for CHARACTER, LSTRING, and ZSTRING columns by defining the mask as follows: xnnn In this format, nnn specifies how many characters you want the column values to contain. Always precede the length numerals with a lowercase x. The maximum length you can specify after the x is 255. The following string-length mask specifies a display length of 121 bytes. x121 If the mask is longer than the defined length of the string data, Scalable SQL blank-pads the data up to nnn bytes before it returns the data to the application.

Database Design Guide

63

Modifying Data

If you attempt to insert data into a string column that has a defined mask shorter than the actual column length (using a SQL INSERT statement), Scalable SQL inserts the data according to the mask, truncating your data as necessary. The following example sets a permanent edit mask to limit the display length of the City column to 10 characters in the Person table of the sample database. SET MASK Person.City = 'x10'; If a value in the City column is longer than 10 characters, Scalable SQL truncates the column from the right. For example, the column value Philadelphia is displayed as Philadelph. To set the same mask as a temporary mask, you could issue the following SELECT statement: SELECT City [x10] FROM Person;

Number Masks
Number masks specify the display format for AUTOINC, BFLOAT, CURRENCY, DECIMAL, FLOAT, INTEGER, MONEY, NUMERIC, NUMERICSA, NUMERICSTS, and UNSIGNED columns. The following example sets a permanent mask for the Scholarship Amount column (a DECIMAL column) in the Student table of the sample database. SET MASK Student.Scholarship_Amount = '$Z,ZZZ.99'; This mask inserts a dollar sign ($) at the beginning of the column value, inserts a comma between the hundreds and thousands places, and adds a decimal point and zeros. For example, the column value 1095 is displayed as $1,095.00. To set the same mask as a temporary mask, you could issue the following SELECT statement. SELECT Scholarship_Amount [$Z,ZZZ.99] FROM Student;
Database Design Guide 64 Modifying Data

Data Digits in Number Masks
When you define a mask for any of the numeric data types, you can use either Z or 9 to represent the data digits. Each leading zero digit defined by a 9 in the mask appears in the displayed column as a zero. For example, if the number you enter is 45.50 and you defined the mask as 99999.99, the number appears as 00045.50. Scalable SQL handles the Z (zero-suppression) mask character, depending on the context in which it appears. Scalable SQL deletes any Zs preceding the first significant digit of the value to which the mask applies. Scalable SQL displays any Zs to the right of the last significant digit as zeros. Type
INTEGER

Value
4958

Mask
ZZZZ.ZZ

Representation
49.58

Special Literals in Number Masks
You can use the following special literals in number masks: + If a plus sign (+) appears as the first or last character in a mask, Scalable SQL displays a leading or trailing minus sign for negative values, and a leading or trailing plus sign for positive values. A plus sign anywhere else in the mask always appears at that position in the column, regardless of the value. If a minus sign (–) appears as the first or last character in a mask, either a leading or trailing minus sign appears with negative values. The minus sign does not appear in the column for positive values and for the UNSIGNED data type.

Database Design Guide

65

Modifying Data

()

If the first character in your mask is an open parenthesis [(] and the last character is a close parenthesis [)], Scalable SQL encloses negative column values in parentheses. The parentheses do not appear for positive values. Open or close parentheses elsewhere in the mask always appear at that position, regardless of the value. The effect of a decimal point in the mask depends on the specific data type. For all data types except INTEGER, Scalable SQL positions the decimal according to the defined value of the column. For INTEGER columns, a decimal in the mask adjusts the displayed value of the column according to the position of the decimal. In this case, only the displayed value is adjusted; Scalable SQL uses the integer value, not the masked value, in comparisons and computations. If you specify too few digits to the right or left of the decimal in your mask, Scalable SQL displays asterisks (*) instead of the data.

.

{}

If the first character in your mask is an open brace [{] and the last character is a close brace [ }], Scalable SQL displays only positive values. If the value in the column is negative, Scalable SQL suppresses it. If the last character in your number mask is an H, Scalable SQL displays values in hexadecimal format. (You can use this literal with INTEGER, UNSIGNED, and AUTOINC data types only.) The letter E is a special literal that indicates a number is in scientific notation. A plus or minus sign may appear in front of the exponent to indicate its sign. If the mask has a minus sign (–) in front of the exponent, a minus sign appears for negative exponents, and no sign appears in the column for positive exponents. If the mask has a plus sign (+) in front of the exponent, a minus sign appears for negative exponents and a plus sign appears for positive exponents.

H

E

Database Design Guide

66

Modifying Data

Table 4-6 lists examples of the special literals you can use in number masks.

Table 4-6
Type
FLOAT FLOAT FLOAT MONEY MONEY MONEY DECIMAL NUMERIC INTEGER INTEGER INTEGER INTEGER FLOAT(4) FLOAT(4) FLOAT(8) FLOAT(8)

Examples of Special Literals in Number Masks
Value
244.4 –244.4 –244.4 –6577.89 577.89 598.21 56784.50 5125551234 63 – 63 578293 578293 7.87989 7.87989E+2 7.87989 –7.87989E+111

Mask
–ZZZZZ.99 –ZZZZZ.ZZ ZZZZZ.ZZ– (ZZ,ZZZ.99) +Z,ZZZ.99 ($ZZ,ZZZ.99) Z,ZZZ.99 (999)999–9999 {ZZZ} {ZZZ} ZZZZZZ ZZZZ.99 –Z.ZZZZZZE+ZZ –Z.ZZZZZZE+ZZ –Z.ZZZZZE+ZZZ –Z.ZZZZZE+ZZZ

Representation
244.40 –244.40 244.40– (6,577.89) +577.89 $598.21 6,784.50 (512)555-1234 63

578293 5782.93 7.879890E+00 7.879890E+02 7.87989E+000 –7.87989E+111

Database Design Guide

67

Modifying Data

Other Characters in Number Masks
A mask character that is neither data nor a special literal appears in the column as follows:

‹ ‹

Only if other data appears to the left of that character. If no data appears in the column and you place the character in the leftmost position in the mask.

For example, you can place commas so that they appear between sets of three digits. Scalable SQL does not include the comma if no digits are to the left of the comma. The following examples illustrate the use of commas and other literals in masks: Type
NUMERIC NUMERIC NUMERIC

Value
473553291 678950 784.50

Mask
999–99–9999 ZZZ,ZZZ.ZZ ZZZ,ZZZ.ZZ

Representation
473–55–3291 678,950.00 784.50

Hexadecimal Masks
Hexadecimal masks specify the hexadecimal display format for INTEGER, UNSIGNED, and AUTOINC columns. The following example sets a permanent mask for a 1-byte INTEGER column called ID in the Class table. SET MASK Class.ID = 'ZZZ9H'; All hexadecimal masks must end with H. The example mask includes 9 as the last digit in the mask value; therefore, if the column value is zero, Scalable SQL displays it as 0H. To set the same mask as a temporary mask, you could issue the following SELECT statement: SELECT ID [Z9H] FROM Class;
Database Design Guide 68 Modifying Data

When you define a mask for columns of type INTEGER, UNSIGNED, or AUTOINC, you can use the number mask characters Z and 9 followed by an H, to represent a hexadecimal value. If you use 9s in the mask, Scalable SQL displays a zero for each leading zero digit you defined. For example, if the number you enter is 15 and you defined the mask as 999H, Scalable SQL formats the value as 00FH. If you use Zs in the mask, leading zero digits defined in the mask do not appear in the data. For example, if the number you enter is 15 and you defined the mask as ZZZH, the value appears as FH. The following examples illustrate the effects of hexadecimal masks. Type
INTEGER INTEGER INTEGER INTEGER

Value
244 63782 –63782 10

Mask
ZZZ9H ZZZZZZZ9H ZZZZZZZ9H 9999H

Representation
F4H F926H FFFF06DAH 000AH

Date Masks
To permit applications to use a variety of date formats, Scalable SQL uses a date mask to evaluate input and output values. For this reason, ASCII date value formats must conform to the currently defined mask (or to the default mask, if you have not defined another mask). Date masks allow you to set both the input format for column values and the display, or output format for DATE values. By default, Scalable SQL requires that you enter date values using the mask mm/dd/yy. However, you can change the default by setting a different permanent mask.

Database Design Guide

69

Modifying Data

In restriction clauses and computed columns, you must specify date values according to the default mask. For example, even if you set a permanent date mask as mm-dd-yy, you must specify dates as mm/dd/yy in restriction clauses and computed columns. In INSERT statements, you must specify date values according to the permanent mask, or the default mask if you do not have a permanent mask. The following example sets a permanent date mask for the Date of Birth column in the sample database: SET MASK Person.Date_of_Birth = 'mm-dd-yy'; This mask changes both the input and display formats for the Date of Birth column from the default mm/dd/yy to mm-dd-yy. To set the same mask as a temporary mask, you could issue the following SELECT statement: SELECT Date_of_Birth [mm-dd-yy] FROM Person; A column of data type DATE contains three elements: month, day, and year. These elements are represented as follows: Mask Character
mm dd yy yyyy

Meaning
Month Day Last two digits of year length Full year

You can use a mask to specify names for the month and day. Any other characters you include in the mask appear unchanged in the displayed value of the column. You can insert blanks in the column using the B literal.
Database Design Guide 70 Modifying Data

You can set the default values for the date mask by placing the following characters at the beginning of the mask. Mask Character Result
b: d: z: Displays all blanks when the input value is all zeros (month, day, and year). Uses the system date when the date is not specified (input value is all blanks); has no effect on output. Uses all zeros when the date is not specified (input value is all blanks); has no effect on output.

If you do not precede the mask with either b: or d:, Scalable SQL uses z: at the beginning of the mask. The following examples illustrate the effects of using masks. Value
05/09/56 05/09/56 04/01/85 05/28/85 06/30/86 03/15/86 00/00/00 00/00/00

Mask
mm–dd–yy mm/dd/yyyy mm/yy dd.mm.yyyy b:mm/dd/yy z:mm/dd/yy b:mm/dd/yy z:mm/dd/yy

Representation
05–09–56 05/09/1956 04/85 28.05.1985 06/30/86 03/15/86 [blank] 00/00/00

Database Design Guide

71

Modifying Data

Scalable SQL provides mask characters that allow you to specify the name of the day or the month when the date is displayed. Mask Character Meaning
M Displays the month name, up to the number of M characters you include in the mask, and strips any trailing blanks. The minimum number of M characters you can include is three. If you specify only two characters (MM), Scalable SQL displays the month as an integer. Displays the month name, up to the number of m characters you include in the mask, including trailing blanks. The minimum number of m characters you can include is three. If you specify only two characters (mm), Scalable SQL displays the month as an integer. Displays the name of the day of the week, up to the number of W characters you include in the mask, and strips any trailing blanks. Displays the name of the day of the week, up to the number of w characters you include in the mask, including trailing blanks.

m

W w

The following examples show different date masks and their results. This example strips any trailing blanks. MMMMMMMMMBdd,Byyyy December 12, 1992 April 06, 1992 September 30, 1992 May 23, 1992

Database Design Guide

72

Modifying Data

This example includes trailing blanks. mmmmmmmmmBdd,Byyyy December 12, 1992 April 06, 1992 September 30, 1992 May 23, 1992 mmmmmMMMMBdd,Byyyy December 12, 1992 April 06, 1992 September 30, 1992 May 23, 1992 The following examples show different day masks and their results. wwwwwwwwwBmmmBdd Tuesday Dec 01 Wednesday May 10 wwwWWWWWWBmmmBdd Tuesday Dec 01 Wednesday May 10 WWWWWWWWW, BMMMMMMMMMBdd Tuesday , December 01 Wednesday, May 10

Database Design Guide

73

Modifying Data

Time Masks
To permit users and applications to use a variety of time formats, Scalable SQL uses a time mask to evaluate input and output values. For this reason, ASCII time value formats must conform to the currently defined mask (or to the default mask if you have not defined another mask). Time masks allow you to set both the input format for column values and the display, or output format for TIME values. By default, Scalable SQL requires that you enter time values using the mask hh:mm:ss. However, you can change the default by setting a different permanent mask. In restriction clauses and computed columns, you must specify time values according to the default mask. For example, even if you set a permanent time mask as hh:mm, you must specify times as hh:mm:ss in restriction clauses and computed columns. In INSERT statements, you must specify time values according to the permanent mask, or the default mask if you do not specify another mask. The following example sets a permanent time mask for the Start Time and Finish Time columns for a class in the sample database. SET MASK Class.Start_Time = 'hh:mm'; SET MASK Class.Finish_Time = 'hh:mm'; This mask changes both the input and display formats for the Start Time and Finish Time columns from the default hh:mm:ss to hh:mm. To set the same mask as a temporary mask, you could issue the following SELECT statement: SELECT Start_Time [hh:mm], Finish_Time [hh:mm] FROM Class;

Database Design Guide

74

Modifying Data

Columns of data type TIME contain four elements: hours, minutes, seconds, and hundredths of a second. Each element is represented as follows. Mask Character
hh mm ss uu

Meaning
Hours Minutes Seconds Hundredths of a second

Any other characters you include in the mask appear unchanged in the displayed value of the column. You can insert blanks in the column using the B literal. If you use the B literal, you cannot insert data into the space in which you placed the literal. You can set the default values for the time mask using the following characters. Mask Character Meaning
b: d: z: ap Displays all blanks when the input value is all zeros. Uses the system time when the time is not specified (input value is all blanks); has no effect on output. Uses all zeros when the time is not specified (input value is all blanks); has no effect on output. Displays am or pm after the time. Used to interpret input and output value.

You must place the b:, d:, and z: characters in front of the mask. The ap: characters can appear either in front of the mask or after it.

Database Design Guide

75

Modifying Data

If you do not precede the mask with either b: or d:, Scalable SQL uses z: at the beginning of the mask. The following examples illustrate some time masks. Value
06:15:32:99 00:02:10:54 08:15:00:00 00:00:00:00 08:15:00:00 00:00:00:00 08:20:00:00

Mask
hh:mm:ss mm:Bss:uu b:hh:mm:ss b:hh:mm:ss z:hh:mm:ss z:hh:mm:ss z:hh:mm:ss ap

Representation
06:15:32 02: 10:54 08:15:00 [blank] 08:15:00 00:00:00 08:20:00 am

Timestamp Masks
To permit applications to use a variety of date and time formats, Scalable SQL uses a timestamp mask to evaluate input and output values. For this reason, ASCII date and time value formats must conform to the currently defined mask (or to the default mask, if you have not defined another mask). Timestamp masks allow you to set both the input format for column values and the display or output format for TIMESTAMP values. By default, Scalable SQL requires that you enter date values using the mask YYYY-mm-ddBhh:tt:ss.fffffff (where f is equal to the precision, which is optional). You can change the default by setting a different permanent mask. In restriction clauses and computed columns, you must specify TIMESTAMP values according to the default mask. In INSERT statements, you must specify TIMESTAMP values according to the permanent mask, or the default mask if you do not specify another mask.

Database Design Guide

76

Modifying Data

You can also set the following default values: Mask Character Description
b z Displays blanks when you do not specify the TIMESTAMP value. Displays zeros when you do not specify the TIMESTAMP value.

You must use at least one separator character (b or any character that is not used as a mask character) between the date and time of the mask.

Boolean Masks
Boolean masks set the display format for BIT and LOGICAL columns. By default, Scalable SQL displays true or false in Boolean columns. Although Scalable SQL stores values in a Boolean column as true or false, you can use a Boolean data type for any column that can have only two values. By specifying an edit mask, you can cause Scalable SQL to display the two actual values and accept them as input. In restriction clauses and computed columns, you must specify Boolean values according to the default mask. For example, even if you set a permanent logical mask as yes-no, you must specify logical values as true-false in restriction clauses and computed columns. In INSERT statements, you must specify Boolean values according to the permanent mask, or the default mask if you do not specify another mask. The following example sets a permanent yes-no mask for a BIT column called Married in the Person table. SET MASK Person.Married = 'yes-no';

Database Design Guide

77

Modifying Data

This mask changes the display for the Married column from the default true-false to yesno. For example, the column value True is displayed as yes. To set the same mask as a temporary mask, you could issue the following SELECT statement: SELECT Married [yes-no] FROM Person; You can specify the word that represents the true condition without specifying a word that represents the false condition. If the value is true, Scalable SQL displays your true mask; otherwise, it displays blanks for the false value. You can also specify the word that represents the false condition without specifying a word for the true condition, but in this case, a dash must precede the word. If you set a Boolean column’s mask to yes – no, you must enter yes to input true values and no to input false values. However, if you set the mask to true – , you must still enter the word false when you enter false values, even though the current dictionary mask causes Scalable SQL to display false values as blanks. Scalable SQL also uses Boolean masks to interpret ASCII Boolean input values. For INSERT statements, you must specify Boolean values using either the current dictionary mask or the default mask if you have not defined another mask, or a 0 to represent false and a 1 to represent true. Additionally, in restriction clauses and computed columns, you must either specify Boolean values according to the default mask, or specify a 0 to represent false and a 1 to represent true. Following are some examples of Boolean masks. Internal Value
true false true false

Mask
‘yes – no’ ‘yes – no’ ‘ON – OFF’ ‘T – F’

Representation
yes no ON F

Database Design Guide

78

Modifying Data

Internal Value
false true false false true true false true false

Mask
‘T –’ ‘YES –’ ‘YES –’ ‘–NO’ ‘– NO’ ‘available –’ ‘available–’ ‘2 dr. – 4 dr.’ ‘2 dr. – 4 dr.’

Representation
YES NO available 2 dr. 4 dr.

The following table shows the appropriate values for input when each mask is in effect. Input Values Mask
‘yes – no’ ‘ON – OFF’ ‘T – F’ ‘T–’ ‘YES –’ ‘– NO’ ‘available –’ ‘2 dr.’–‘4 dr.’

True
yes ON T T YES true available 2 dr.

False
no OFF F false false NO false 4 dr.

Database Design Guide

79

Modifying Data

Masks Specified on Multiple Columns
You can specify temporary masks for multiple columns within the same SELECT statement. Use a comma to separate each column and its mask definition from the next column. SELECT Name, Phone_Number [(999) 999-9999], Room_Number [ZZZ] FROM Department WHERE Name = 'English'; Issuing this SQL statement on the sample database produces the following results: Name
English

Phone_Number
(512) 694-1900

Room_Number
307

Database Design Guide

80

Modifying Data

Using UPDATE
You can use an UPDATE statement to change the data in a row that is already in a table. UPDATE statements let you modify specific columns in a row. Also, you can use a WHERE clause in an UPDATE statement to specify which rows for Scalable SQL to change. This is referred to as a searched update. Using SQL declared cursors and the Positioned UPDATE statement, you can update the current row of a declared cursor from which you are fetching data. UPDATE Course SET Credit_Hours = 4 WHERE Course.Name = 'Math'; This example instructs Scalable SQL to find the row that contains the course name Math and change the Credit Hours column value to 4. As shown in the previous example, you can use a constant to update a column by placing it on the right hand side of a SET clause in an UPDATE statement. If the data type of the column you are updating is DATE, TIME, or TIMESTAMP, then this constant must conform to the column’s user-defined edit mask, if present; otherwise, it must match the default mask for the data type. For all other data types, the constant must conform either to the mask defined on the column or the default mask for the data type of the column. For more information about the role of data types and defined or default masks, refer to the SQL Language Reference.

Database Design Guide

81

Modifying Data

chapter

5

Retrieving Data

Once your database contains data, you can retrieve and view that data using a SELECT statement. Scalable SQL returns the data you request in a result table. Using SQL statements, you can do the following:

‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹

Create temporary views or permanent (stored) views. Specify a selection list that lists the columns to retrieve from one or more tables in your database. Specify how to sort the rows. Specify criteria by which to group the rows into subsets. Assign a temporary name (alias) to a table. Retrieve data from one or more tables and present the data in a single result table (a join). Specify a subquery within a SELECT statement. Specify a restriction clause to restrict the rows Scalable SQL selects.

The remainder of this chapter discusses how you can use SELECT statements to accomplish these tasks in the following sections: Views Selection Lists Sorted and Grouped Rows Joins Subqueries Restriction Clauses Functions
82 Retrieving Data

Database Design Guide

Views
A view is the mechanism for examining the data in your database. A view can combine data from multiple tables or can include only certain columns from a single table. Although a view looks like a table, it consists of a selected set of columns or calculations based on those columns from tables in your database. Thus, a view may contain data from columns in more than one table or data that is not actually in any table at all (for example, SELECT COUNT (*) FROM Person).

Features of Views
Following are some of the features of views:

‹ ‹ ‹ ‹

You can arrange the columns of a view in any order except that the variablelength column must be last. You can specify only one variable-length column. You can use a restriction clause to specify the set of rows that Scalable SQL returns in a view. The restriction clause lists criteria that the data must satisfy to be included in the view. For more information, see the section "Restriction Clauses." You can specify a sort order for the view. When Scalable SQL returns the data to your application, the rows are returned in the view according to the sort order you designate. If you do not specify a sort order, the order of the returned rows is undefined. You can design and customize views for each user and application that accesses the database. You can store these view definitions within the data dictionary for later recall.

Database Design Guide

83

Retrieving Data

‹ ‹

You can include any number of stored view names in a table list when retrieving, updating, or deleting data unless the view is a read-only view. In a read-only view, you can only retrieve data. In a stored view, you must provide headings for the view’s computed columns and constants and use those names in a list of column names when you retrieve data from the view.

Temporary and Stored Views
You can use SELECT statements to create temporary views or stored views. You use a temporary view only once and then release it. Scalable SQL places the definition of a stored view in the data dictionary so you can recall the view later. You use CREATE VIEW statements to create and name stored views. Each view name must be unique within a database and cannot exceed 20 characters. For more information about rules for naming views, refer to Chapter 2, “Creating a Database.” Scalable SQL is case-sensitive when defining database element names. If you create a stored view named PhoNE, Scalable SQL stores the view name in the dictionary as PhoNE. Scalable SQL is case-insensitive after you define the view name. After defining the stored view PhoNE, you can refer to it as phone. Using stored views provides the following features:

‹

You can store frequently executed queries and name them for later use. The following example creates a stored view named Phones based on the Department table. CREATE VIEW Phones (PName, PPhone) AS SELECT Name, Phone_Number FROM Department;

Database Design Guide

84

Retrieving Data

‹

You can specify the name of the stored view in table lists when retrieving, updating, and deleting data. The stored view behaves as though it is a table in the database, but it is actually reconstructed internally by the Scalable SQL engine each time it is used. The following example updates the phone number for the History Department in the Department table by referring to the stored view Phones. UPDATE Phones SET PPhone = '5125552426' WHERE PName = 'History';

‹

You can specify headings. A heading specifies a column name that is different from the name you defined for the column in the dictionary. The following example specifies the headings Department and Telephone for the stored view Phones. CREATE VIEW Dept_Phones (Department, Telephone) AS SELECT Name, Phone_Number FROM Department; You can use the headings in subsequent queries on the view, as in the following example. SELECT Telephone FROM Dept_Phones; If the selection list contains simple column names and you do not provide headings, Scalable SQL uses the column name as the column heading. You must use headings to name constants and computed columns that you include in the view. If you do not provide a heading for a computed column, Scalable SQL returns Status Code 845; you need headings for computed columns in order to reference them explicitly. The following example creates the headings Student and Total. CREATE VIEW Accounts (Student, Total) AS SELECT Student_ID, SUM (Amount_Paid)

Database Design Guide

85

Retrieving Data

FROM Billing GROUP BY Student_ID; You must also use headings if you specify SELECT * from multiple tables that have any duplicate column names. If you do not specify a heading, Scalable SQL returns Status Code 533.

‹

You can create customized views for each user or application that accesses the database. You can store these view definitions within the data dictionary for later recall.

Read-Only Tables in Views
You cannot insert, update, or delete rows from views that contain read-only tables. (Here the term update refers to insert, update, and delete; if a table is read-only, you cannot update it.) Some tables are read-only whether or not they are in views that are specified as such; such tables are intrinsically read-only, and you cannot update them. A table is read-only if it meets one of the following criteria:

‹ ‹ ‹

The database has security enabled, and the current user or user group has only SELECT rights defined for the database or the table. The data files have been flagged read-only at the physical file level (for example, using the FLAG command in NetWare or the ATTRIB command in DOS). You execute a SELECT clause that creates a view and contains any of the following items:
Š An aggregate function in the selection list. Š A GROUP BY or HAVING clause. Š A UNION. Š The DISTINCT keyword.

Database Design Guide

86

Retrieving Data

‹

You execute a SELECT statement that creates a view, and the table contains any of the following characteristics:
Š It appears in a non-mergeable view that is in the SELECT statement’s FROM clause. Š It is a system table. System tables are always opened as read-only in a view, even if this overrides the view’s open mode. Š A column from the table appears in a computed column or a scalar function in the selection list. Š The table appears in the FROM clause of a subquery that is not correlated to the outermost query. A subquery can be directly or indirectly correlated to the outermost query. A subquery is directly correlated with the outermost query if it contains a reference to a column from a table and its specific occurrence in the outermost query’s FROM clause. A subquery is indirectly correlated to the outermost query if it is correlated to a subquery that is in turn directly or indirectly correlated to the outermost query. Š The open mode is read-only. You can set the open mode using the SET OPENMODE statement.
Note

You cannot set the open mode on a table by table basis; the SET OPENMODE statement causes all tables to be opened in the indicated mode.
Š You execute a Positioned UPDATE statement with any of the following keywords, without specifying FOR UPDATE:
ORDER BY SCROLL

Database Design Guide

87

Retrieving Data

Mergeable Views
A view is mergeable if you can rewrite the SELECT statement using only base tables and columns. For example, if you want to know how many students are in a class, you can define a view to calculate that. The view NumberPerClass is defined as follows: CREATE VIEW NumberPerClass (Class_Name, Number_of_Students) AS SELECT Name, COUNT(Last_Name) FROM Person, Class, Enrolls WHERE Person.ID = Enrolls.Student_ID AND Class.ID = Enrolls.Class_ID GROUP BY Name; The view NumberPerClass is defined as follows: SELECT * FROM NumberPerClass; The view NumberPerClass is then mergeable because we can rewrite the SELECT statement as follows: SELECT Name, COUNT(Last_Name) FROM Person, Class, Enrolls WHERE Person.ID = Enrolls.Student_ID AND Class.ID = Enrolls.Class_ID GROUP BY Name; The view NumberPerClass is non-mergeable if you want to write a SELECT statement such as the following: SELECT COUNT(Name) FROM NumberPerClass WHERE Number_of_Students > 50; This statement is invalid for the view NumberPerClass. You cannot rewrite it using only base tables and base columns.
Database Design Guide 88 Retrieving Data

A view is mergeable if it does not contain any of the following characteristics:

‹ ‹ ‹ ‹

It refers to a non-mergeable view. It has an aggregate function in its selection list or a DISTINCT keyword, and it appears in the FROM clause of a SELECT statement that has an aggregate in its selection list. It has a DISTINCT keyword and appears in the FROM clause of a SELECT statement that has more than one item in its FROM clause, does not have an aggregate in its selection list, and does not have a DISTINCT keyword. It has an aggregate in its selection list and appears in the FROM clause of a SELECT statement that either has more than one item in its FROM clause or a WHERE clause restriction.

Database Design Guide

89

Retrieving Data

Selection Lists
When you use a SELECT statement to retrieve data, you specify a list of columns (a selection list) to include in the result table. To retrieve all the columns in a table or tables, you can use an asterisk (*) instead of a list of columns.
Note

Avoid using * in place of the list. Using * can expose an application to potential problems if the number of columns or column sizes in a table changes. Also, it typically returns unnecessary data.

The following example selects three columns from the Class table. SELECT Name, Section, Max_Size FROM Class; The following example selects all columns from the Class table. SELECT * FROM Class; When retrieving data, Scalable SQL displays column names based on how you specify the names in the query.

‹

If you explicitly specify a column name, Scalable SQL returns it as you entered it. The following example specifies column names in all lowercase. SELECT name, section, max_size FROM Class; Scalable SQL returns the column names as follows: name, section, max_size These column names are headings for the returned data; they are not data themselves.

Database Design Guide

90

Retrieving Data

The following example defines aliases for the tables Department and Faculty. SELECT d.Name, f.ID FROM Department d, Faculty f; Scalable SQL returns the column names as follows: d.Name, f.ID

‹

If you use * to specify column names, they appear in all uppercase, as in the following example. SELECT * FROM Department; Scalable SQL returns the column names as follows: NAME, PHONE_NUMBER, BUILDING_NAME, ROOM_NUMBER, HEAD_OF_DEPARTMENT The following example defines aliases for the tables Department and Faculty. SELECT * FROM Department d, Faculty f; Scalable SQL returns the column names as follows: D.NAME D.PHONE_NUMBER D.BUILDING_NAME D.ROOM_NUMBER D.HEAD_OF_DEPT F.ID F.DEPT_NAME F.DESIGNATION F.SALARY F.BUILDING_NAME F.ROOM_NUMBER F.RSCH_GRANT_AMOUNT

Database Design Guide

91

Retrieving Data

Sorted and Grouped Rows
Once you have decided what data to include in your result table, you can specify how to order the data. You can use the ORDER BY clause to sort the data, or you can use a GROUP BY clause to group rows by a certain column. When you group the data, you can also use aggregate functions to summarize data by group. For more information about aggregate functions, refer to the section "Aggregate Functions." The following example orders all rows by last name in the Person table of the sample database. SELECT * FROM Person ORDER BY Last_Name; The following example groups the results by the Building Name column in the Room table. This example also uses two aggregate functions, COUNT and SUM. SELECT Building_Name, COUNT(Number), SUM(Capacity) FROM Room GROUP BY Building_Name;

Database Design Guide

92

Retrieving Data

Joins
A join results from a statement that combines columns from two or more tables into a single view. From this view, you can retrieve, insert, update, or delete data, provided it is not read-only.
Note

This section primarily discusses joining tables using SELECT statements. However, you can also create joins with INSERT, UPDATE, and DELETE statements by applying a single statement to more than one table. The SQL Language Reference describes these SQL statements and how to optimize joined views.

You can retrieve data from tables by listing each table or view name in a FROM clause. Use a WHERE clause to specify one or more join conditions. A join condition compares an expression that references a column value from one table to an expression that references a column value from another table. When data is properly normalized, most joins associate values based on some specified key value. This allows you to extract data in terms of referential integrity relationships. For example, if you want to know which professor teaches each class, you can create a join based on the Faculty ID, which is a foreign key in the Class table and a primary key in the Person table: SELECT DISTINCT Class.Name, Person.Last_Name FROM Class, Person, Faculty WHERE Class.Faculty_ID = Person.ID AND Class.Faculty_ID = Faculty.ID; This example joins two tables on the basis of common values in a common column: Faculty ID.

Database Design Guide

93

Retrieving Data

You can also join tables by making numeric comparisons between columns of like data types. For example, you can compare columns using <, >, or =. The following self-join on the Faculty table identifies all faculty members whose salary was higher than each faculty member (this would produce considerably more records than the faculty table contains): SELECT A.ID, A.Salary, B.ID, B.Salary FROM Faculty A, Faculty B WHERE B.Salary > A.Salary; Similar comparisons of dates, times, etc. can produce many useful and meaningful results. When joining columns, choose columns that are of the same data type when possible. For example, comparing two NUMERICSTS columns is more efficient than comparing a NUMERICSTS column with an INTEGER column. If the columns are not of the same data type but are both numeric or strings, Scalable SQL scans both the tables and applies the join condition as a restriction to the results. However, if you attempt to compare a string type column (such as a ZSTRING column) to a numeric type column (such as a DECIMAL column), Scalable SQL returns Status Code 223, and does not complete the query. When you use string type columns in a WHERE clause, one column in the join condition can be a computed string column. This allows you to concatenate two or more strings and use a join condition to compare them to a single string from another table. The way in which Scalable SQL handles a join depends on whether the join condition contains an index column.

‹ ‹

If the join condition contains a column that is defined as an index, performance improves. Using the index to sort rows in the corresponding table, Scalable SQL selects only rows that meet the restriction clause condition. If the join condition does not contain a column that is defined as an index, performance is less efficient. Scalable SQL reads each row in each table to

Database Design Guide

94

Retrieving Data

select rows that meet the restriction clause condition. To enhance performance, you can create an index in one of the tables before executing the join. This is especially helpful if the query is one that you perform often.

Joining Tables with Other Tables
To specify a join using a SELECT statement, use a FROM clause to list the relevant tables and a WHERE clause to specify the join condition and the restriction. The following example also uses aliases to simplify the statement. SELECT Student_ID, Class_ID, Name FROM Enrolls e, Class cl WHERE e.Class_ID = cl.ID; The next example joins three tables: SELECT p.ID, Last_Name, Name FROM Person p, Enrolls e, Class cl WHERE p.ID = e.Student_ID AND e.Class_ID = cl.ID; The next example retrieves a list of students who received a grade lower than a 3.0 in English. SELECT First_Name, p.Last_Name FROM Person p, Student s, Enrolls e, Class cl WHERE s.ID = e.Student_ID AND e.Class_ID = cl.ID AND s.ID = p.ID AND cl.Name = 'ACC 101' AND e.Grade < 3.0; In this example, the first three conditions in the WHERE clause specify the join between the four tables. The next two conditions are restriction clauses connected by the Boolean operator AND.

Database Design Guide

95

Retrieving Data

Joining Views with Tables
To join a view with one or more tables, include a view name in the FROM clause. The view you specify can include columns from a single table or from several joined tables.

Types of Joins
Scalable SQL supports equal joins, nonequal joins, null joins, Cartesian product joins, and self joins.

Equal Joins
An equal join occurs when you define the two join columns as equal. The following statement defines an equal join. SELECT First_Name * Last_Name, Degree, Residency FROM Person p, Student s, Tuition t WHERE p.ID = s.ID AND s.Tuition_ID = t.ID;

Nonequal Joins
You can join tables based on a comparison operation. You can use the following operators in nonequal joins:
< > <= >= Less than Greater than Less than or equal Greater than or equal

Database Design Guide

96

Retrieving Data

The following WHERE clause illustrates a join that uses a greater than or equal operator. SELECT Name, Section, Max_Size, Capacity, r.Building_Name, Number, FROM Class cl, Room r WHERE Capacity >= Max_Size;

Null Joins
A null join allows you to retrieve each row from one table, regardless of whether there is a corresponding row in the table to which you are joining. The join returns rows from the leftmost table in the join condition, even if the rightmost table does not contain data that satisfies the restriction. For these rows, Scalable SQL returns null values for all the columns in the rightmost table. To specify a null join, insert a plus sign in parentheses after the rightmost column in a WHERE clause. The following example performs a null join on the Person and Class tables from the sample database and returns a row for each student enrolled in a class. If a student is enrolled, the corresponding course names return; otherwise, a null returns if the student is not enrolled. SELECT First_Name * Last_Name, cl.Name FROM Person, Enrolls, Class cl WHERE ID = Student_ID (+) AND Class_ID = cl.ID (+); Null joins often behave similarly to left outer joins, unless you specify additional conditions or restrictions. You can only specify a null join condition in a SELECT statement; do not specify a null join in an UPDATE or DELETE statement.

Database Design Guide

97

Retrieving Data

Cartesian Product Joins
A Cartesian product join associates each row in one table with each row in another table. Scalable SQL reads every row in one table once for each row in the other table. On large tables, a Cartesian product join can take a significant amount of time to complete since Scalable SQL must read the following number of rows to complete this type of join: (# of rows in one table) * (# of rows in another table) For example, if one table contains 600 rows and the other contains 30, Scalable SQL reads 18,000 rows to create the Cartesian product join of the tables. The following statement produces a Cartesian product join on the Person and Course tables in the sample database: SELECT s.ID, Major, t.ID, Degree, Residency, Cost_Per_Credit FROM Student s, Tuition t;

Database Design Guide

98

Retrieving Data

Self Joins
In a self join, you can specify a table name in the FROM clause more than once. When you specify a self join, you must assign aliases to each instance of the table name so that Scalable SQL can distinguish between each occurrence of the table in the join. The following example lists all the people who have a permanent address in the same state as the person named Jason Knibb. The query returns the ID, first name, last name, current phone number, and e-mail address. SELECT p2.ID, p2.First_Name, p2.Last_Name, p2.Phone, p2.EMail_Address FROM Person p1, Person p2 WHERE p1.First_Name = 'Jason' AND p1.Last_Name = 'Knibb' and p1.Perm_State = p2.Perm_State

Database Design Guide

99

Retrieving Data

Subqueries
A subquery (also known as a nested query) is a SELECT statement contained within one of the following:

‹ ‹

The WHERE clause or HAVING clause of another SELECT statement. The WHERE clause of an UPDATE or DELETE statement.

A subquery allows you to base the result of a SELECT, UPDATE, or DELETE statement on the output of the nested SELECT statement. Except in correlated subqueries, when you issue a subquery Scalable SQL parses the entire statement and executes the innermost subquery first. It uses the result of the innermost subquery as input for the next level subquery, and so forth. The following statement returns the names of students who are enrolled in Math: SELECT First_Name * Last_Name FROM Person p, Enrolls e WHERE p.ID = e.Student_ID AND e.Class_ID IN (SELECT ID FROM Class WHERE Name BEGINS WITH 'MAT'); Scalable SQL first evaluates the subquery to retrieve the class ID from the Class table. It then performs the outer query, restricting the results to only those students who have enrolled in the class. For more information about expressions you can use with subqueries, refer to "Expression Rules."

Database Design Guide

100

Retrieving Data

Subquery Limitations
A subquery in a WHERE clause becomes part of the search criteria. The following limits apply to using subqueries in SELECT, UPDATE, and DELETE statements:

‹ ‹ ‹

You must enclose the subquery in parentheses. The subquery cannot contain a UNION clause. Unless you use an ANY, ALL, EXISTS, or NOT EXISTS keyword in the WHERE clause of the outer query, the selection list of the subquery can contain only one column name expression.

You can nest several levels of subqueries in a statement. The number of subqueries you can nest is determined by the amount of memory available to Scalable SQL.

Correlated Subqueries
A correlated subquery contains a WHERE or HAVING clause that references a column from a table in the outer query’s FROM clause; this column is called a correlated column. To test the results from a subquery against the results from the outer query, or to test for a particular value in a query, you must use a correlated subquery. Since the correlated column comes from the outer query, its value changes each time a row in the outer query is fetched. Scalable SQL then evaluates the expressions in the inner query based on this changing value. The following example shows the names of courses that provide more credit hours than time actually spent in the class room. SELECT Name, Credit_Hours FROM Course c WHERE Name IN
Database Design Guide 101 Retrieving Data

(SELECT Name FROM Class cl WHERE c.Name = cl.Name AND c.Credit_Hours > (HOUR (Finish_Time - Start_Time) + 1)); To improve performance, you could rephrase the previous statement as a simple query. SELECT Name, Credit_Hours FROM Class, Course WHERE Course.Name = Class.Name AND Credit_Hours > (HOUR (Finish_Time - Start_Time) + 1);

Database Design Guide

102

Retrieving Data

Restriction Clauses
A restriction clause is an ASCII text string of operators and expressions. A restriction clause specifies selection criteria for the values in the columns of a view, limiting the number of rows the view contains. The syntax of certain clauses (such as WHERE or HAVING) requires using a restriction clause. A restriction clause can specify these conditions:

‹ ‹

Restriction condition—Compares an expression that references a column value to either a constant or another expression that references a column value in the same table. Join condition—Compares an expression that references a column value from one table to an expression that references a column value from another table.

A restriction clause can contain multiple conditions. It can also contain a SELECT subquery that bases search criteria on the contents of other tables in the database. The condition containing the subquery can contain the EXISTS, NOT EXISTS, ALL, ANY, and SOME keywords, or the IN range operator. You can specify a restriction clause using a WHERE or HAVING clause in a SELECT, UPDATE, or DELETE statement. Figure 5-1 provides an example restriction clause and illustrates restriction clause elements.

Database Design Guide

103

Retrieving Data

Figure 5-1

Example Restriction Clause
where table1.field1 > 5 and table1.field2 = table1.field1 * 10 and table1.field1 = table2.field1
Boolean Operators Condition Operators Restriction Clause Expression Operator

Restriction Clause Operators
Restriction clauses can use three types of operators:

‹ ‹ ‹

Boolean operators — Connect conditions in a restriction clause. Condition operators — Connect expressions to form a condition. A condition operator can be a relational or a range operator. Expression operators — Connect two expressions to form another expression. An expression operator can be an arithmetic or string operator.

Boolean Operators
Boolean operators specify logical conditions.

Table 5-1
Operator
AND OR NOT

Boolean Operators
Description
If all search conditions connected with AND are true, the restriction passes. If at least one of the conditions connected by OR is true, the restriction passes. If the condition is true, the restriction passes.

Database Design Guide

104

Retrieving Data

Condition Operators
A condition operator can be a relational or a range operator.

‹ ‹

Relational operator—Compares a column value with either another column value or a constant. If the value of the column is true, Scalable SQL selects the row. Range operator—Compares a column value with a specified range of values for the column. If the value of the column is true, the restriction passes, and Scalable SQL selects the row.

Table 5-2 lists the relational operators.

Table 5-2
Operator
< > = <=

Relational Condition Operators
Description
Less than Greater than Equal to Less than or equal to

Operator
>= != <>

Description
Greater than or equal to Not equal to Not equal to

Table 5-3 lists the Condition operators.

Table 5-3
Operator
IN NOT IN BETWEEN

Range Condition Operators
Description
Value exists in specified list. Value does not exist in specified list. Value exists within specified range.

Database Design Guide

105

Retrieving Data

Table 5-3

Range Condition Operators continued

NOT BETWEEN Value does not exist within specified range. BEGINS WITH CONTAINS NOT CONTAINS IS NULL IS NOT NULL LIKE Value begins with specified string. Value contains specified string. Value does not contain specified string. Value is the defined NULL value for the column. Value is not the defined NULL value for the column. Value matches specified string. You can substitute two wildcard characters for actual characters. The percent sign (%) represents any sequence of n characters (where n can be zero). The underscore ( _ ) represents a single character. Value does not match specified string.

NOT LIKE

With the IN and NOT IN operators, the second expression can be a subquery instead of a column name or constant.
Note

Do not confuse using range operators with using the RANGE keyword in SET statements. For more information about the RANGE keyword, refer to the discussion of the SET statement in the SQL Language Reference.

Expression Operators
Expression operators allow you to create expressions for computed columns using arithmetic or string operators. For more information, refer to "Expressions."

Database Design Guide

106

Retrieving Data

Restriction Clause Examples
The following examples demonstrate some of the restriction clause operators.

OR and Equal To (=)
The following example uses the relational EQUAL TO and boolean OR operators. It selects all rows in which the value of the State column is Texas or New Mexico. SELECT Last_Name, First_Name, State FROM Person WHERE State = 'TX' OR State = 'NM';

IN
The following example uses the IN operator. It selects all rows in which the value of the Date of Birth column contains the date 10/01/65, 12/06/67, 01/19/70, 11/13/77, or 08/02/79. SELECT ID, Last_Name, First_Name, Date_Of_Birth FROM Person WHERE Date_Of_Birth IN (10/01/65, 12/06/67, 01/19/70, 11/13/77, 08/02/79); Following is the result table: ID (9 bytes)
101-13-5758 103-65-7107 267-11-2927 267-33-3252 314-57-7429

Last Name (26 bytes)
Badad Bald Gabbard Now Iofin

First Name (16 bytes)
Ismail Elaine Arnold Brad Lev

Date of Birth (4 bytes)
08/02/79 11/13/77 01/19/70 11/13/77 01/19/70

Database Design Guide

107

Retrieving Data

BEGINS WITH
The following example uses the BEGINS WITH operator: SELECT ID, Last_Name, City, State, Zip FROM Person WHERE Last_Name BEGINS WITH 'Ab'; Following is the result table: ID (9 bytes)
175-05-3812 177-56-5161 717-61-2272 241-11-1587 605-82-2311 631-03-5801 243-62-1722 246-14-1857

Last_Name (26 bytes)
Abad Abaecherli Abebe Abel Abgoon Abken Abu Abuali

City (31 bytes)
Austin Austin Austin Austin Austin Austin Austin Austin

State Zip (3 bytes) (11 bytes)
TX TX TX TX TX TX TX TX 78722-1307 78749-1225 78701 78705 78704-2353 78704-2834 78701 78757-2021

CONTAINS
The following example uses the CONTAINS operator: SELECT First_Name FROM Person WHERE First_Name CONTAINS 'nd';

Database Design Guide

108

Retrieving Data

Following is a portion of the result table: First Name (16 bytes)
Randy Cindy Linda Randy Andrew

LIKE
The following example uses the LIKE operator: SELECT ID, First_Name, Last_Name FROM Person WHERE Zip LIKE '787__-____'; Following is a portion of the result table: ID (9 bytes)
101-13-5758 103-65-7107 106-16-8457 108-68-9806 111-19-1115

First_Name (16 bytes)
Ismail Elaine Richard Randy Anthony

Last_Name (26 bytes)
Badad Bald Baldwin Beavis Beer

Database Design Guide

109

Retrieving Data

The next example retrieves all person rows in which the character string ll is part of the person’s last name: SELECT ID, First_Name, Last_Name FROM Person WHERE Last_Name LIKE '%ll%'; In the preceding example, the percent signs are wildcards. If a percent sign or underscore is part of the string for which you are searching with a LIKE condition, precede the character with a backslash (\). The backslash indicates that Scalable SQL should treat the character as a regular character, not a wildcard. For example, to determine if any course names include an underscore character, enter the following statement: SELECT Name, Dept_Name, Description FROM Course WHERE Name LIKE '%\_%'; To include a backslash in the search string, precede it with another backslash (\\).

NOT LIKE
The following example uses the NOT LIKE operator: SELECT Zip, Last_Name FROM Person WHERE Zip NOT LIKE '78759%';

Database Design Guide

110

Retrieving Data

Following is a portion of the result table: Zip
78758-6394 78722-2012 78703-5504 78731-3202 78748-1846

Last Name
Badad Bald Baldwin Beavis Beer

Expressions
An expression is an element of a condition in a restriction clause, an element in a selection list, or an element on the right hand side of a SET statement. Expressions consist of operands and can also include an expression operator. See the section “Expression Operators” for more information. When you call any string scalar function (except for LENGTH) with a fixed-length string data type, the result is the same data type as the argument. Any string function (except for LENGTH) called with a variable-length string data type returns the result as a ZSTRING. The following syntax describes the parts of an expression: expression ::= < constant | column_ref | scalar_function > [expression_operator < constant | column_ref | scalar_function >...] column_ref ::= [ column_qualifier. ] < column_name > column_qualifier ::= < alias | table_name | view_name >
Database Design Guide 111 Retrieving Data

Expression Rules
The following rules apply to Scalable SQL expressions:

‹

You must enclose character string constants in single quotation marks. Using the Course table as an example, Name is a column reference, ART101 is a constant expression, and = is an expression operator. These can be used to form the following expression: Name = 'ART101'

‹ ‹ ‹ ‹

String constants cannot exceed 255 bytes in length. You must enter all values as character values. The maximum length of a Scalable SQL expression is limited only by available memory. The rightmost expression of the following expression operators must be a subquery, list of columns, or a constant value:
< > = <= >= <> != IN NOT IN NOT =ANY !=ANY =ALL !=ALL The right side can be an expression or a subquery.

The right side must be a subquery.

Database Design Guide

112

Retrieving Data

EXISTS NOT EXISTS CONTAINS NOT CONTAINS LIKE NOT LIKE BETWEEN NOT BETWEEN BEGINS WITH

There is no left side; the right side is a subquery. The right side may not be a subquery.

‹

You must specify constant values using the data type’s default mask when comparing the constant to a column value, or when the constant is used as a column’s data value.

Expression Operators
An expression operator is an element of a condition that connects two expressions to form another expression. An expression operator can be an arithmetic operator or a string operator. Scalable SQL allows you to use arithmetic and string operators to create computed columns.

Numeric Computations
The following table lists the data types of the value Scalable SQL generates based on the data types of the columns (as operands) in the computation. The terms Decimal, Float, and Integer refer to the categories of data types listed in the following table.

Table 5-4
Computation

Numeric Computations
Resulting Data Type
Same as data type and size used in FLOAT.

float operator [decimal or integer]

Database Design Guide

113

Retrieving Data

Table 5-4
Computation

Numeric Computations continued
Resulting Data Type
Same as data type and size used in FLOAT. If both types are BFLOAT or one is BFLOAT size 8 and the other is FLOAT size 4, the result is BFLOAT. In all other cases, the result is FLOAT. Size is always the largest size.

[decimal or integer] operator float float operator float

decimal operator integer decimal operator decimal integer operator decimal integer operator integer

Determined by precision and scale rules. Decimal category. Data type determined by precision and scale rules. Determined by precision and scale rules. Integer category. Determined by integral promotion. Refer to the “Integral Promotion” section for more information.

When you specify an expression based on numeric data types, the data type of the result depends on the data types of the operands in the expression. The following table lists the categories of data types that are used in the computations in Table 5-4.

Table 5-5
Category
Decimal Float Integer

Data Type Categories
Data Types
CURRENCY, DECIMAL, MONEY, NUMERIC, NUMERICSA, NUMERICSTS BFLOAT, FLOAT AUTOINC, INTEGER, UNSIGNED

Database Design Guide

114

Retrieving Data

Precision and Scale Rules
The precision of the result of an expression is the total number of digits. The scale of the result of an expression is the number of digits to the right of the decimal point. Both are determined according to the following equation. Result Scale = max (S1, S2) Result Precision = max [(P1 — S1), (P2 — S2)] + Result Scale where P1 P2 S1 S2 = = = = Precision of operand 1 Precision of operand 2 Scale of operand 1 Scale of operand 2

As you can see from these rules, the data type of the expression’s result is one that can hold the largest value, with no loss of precision or scale from either operand. If no data type is large enough to prevent loss of precision or scale, the data type that loses the least amount of precision and scale is the resulting data type. The data type must be from either the category of the left or right operand. If the result precision is greater than the maximum precision for the result data type, you can determine the result by reducing the result precision and result scale equally until the result precision is less than or equal to the maximum precision for the result data type.

Integral Promotion
Integral promotion is the process of promoting a value from one integral data type into a value in another integral data type of an equal or greater capacity.

Database Design Guide

115

Retrieving Data

Integral promotion occurs when the two operands are of different types, different sizes, or when promotion could prevent data loss. The following table shows the integral promotions that occur between two integral operands. In all cases, the promotions never promote to 8 bytes unless at least one of the operands has a size of 8 bytes.

Table 5-6
Operand 1 Type
UNSIGNED INTEGER UNSIGNED INTEGER UNSIGNED INTEGER UNSIGNED INTEGER UNSIGNED INTEGER AUTOINC INTEGER AUTOINC INTEGER AUTOINC INTEGER AUTOINC INTEGER UNSIGNED

Integral Promotions Between Integral Operands
Operand 2 Size
1 1 1 1 1 2, 4, 8 2, 4 2, 4, 8 8 2, 4

Result Size
1 2 4, 8 2 4, 8 1 2, 4 8 2, 4 2, 4

Type
UNSIGNED INTEGER UNSIGNED UNSIGNED AUTOINC INTEGER AUTOINC INTEGER UNSIGNED INTEGER UNSIGNED UNSIGNED UNSIGNED AUTOINC INTEGER

Type
INTEGER INTEGER UNSIGNED INTEGER INTEGER INTEGER INTEGER INTEGER INTEGER INTEGER

Size
2 4 Size of operand 2 4 Size of operand 2 Size of operand 1 4 8 8 4

Database Design Guide

116

Retrieving Data

Table 5-6
Operand 1 Type
UNSIGNED UNSIGNED UNSIGNED UNSIGNED UNSIGNED UNSIGNED UNSIGNED AUTOINC INTEGER AUTOINC INTEGER AUTOINC INTEGER

Integral Promotions Between Integral Operands continued
Operand 2 Size
2, 4 8 2 2, 4 4 2, 4, 8 8 2, 4 2, 4, 8 8

Result Size
8 2, 4, 8 2 4 2, 4 8 2, 4 2, 4 8 2, 4

Type
AUTOINC INTEGER AUTOINC INTEGER UNSIGNED UNSIGNED UNSIGNED UNSIGNED UNSIGNED AUTOINC INTEGER AUTOINC INTEGER AUTOINC INTEGER

Type
INTEGER INTEGER INTEGER UNSIGNED UNSIGNED UNSIGNED UNSIGNED INTEGER INTEGER INTEGER

Size
8 8 4 4 4 8 8 4 8 8

Arithmetic Operators
You can use arithmetic operators in computed column expressions that contain columns of data types INTEGER, UNSIGNED, CURRENCY, FLOAT, BFLOAT, NUMERIC, NUMERICSA, NUMERICSTS, AUTOINC, DECIMAL, or MONEY. Table 5-7 lists the arithmetic operators.

Database Design Guide

117

Retrieving Data

Table 5-7

Arithmetic Operators

Operator Description
+ – * / // % Adds two expressions. Subtracts the first expression from the second. Multiplies two expressions. Divides the first expression by the second, returning the quotient and remainder. Divides the first expression by the second, returning only the integer quotient. Calculates the modulus or MOD, returning only the remainder.

For example, a table might include one column that contains a student’s credit hours and another that contains the cost per credit. For Scalable SQL to calculate a computed column, such as tuition, specify an expression to multiply the two column values. CREATE VIEW Credit (CurStudent, Credits) AS SELECT Student_ID, SUM(Credit_Hours) FROM Enrolls e, Class cl, Course c WHERE e.Class_ID = cl.ID AND cl.Name = c.Name GROUP BY Student_ID; SELECT CurStudent, Credits, (Credits * Cost_Per_Credit) [$ZZ,ZZZ.99] FROM Credit, Student s, Tuition t WHERE CurStudent = s.ID AND s.Tuition_ID = t.ID; DROP VIEW Credit;
Note

If you use the / or // operators to divide by 0, you receive Status Code 346.

Database Design Guide

118

Retrieving Data

String Operators
Scalable SQL provides three operators that allow you to specify expressions for fixedlength string operands (columns).

Table 5-8

String Operators

Operator Description
* + ++ Concatenates columns while separating them with a blank. Concatenates string columns and strips all trailing blanks from the first column in the expression. Concatenates string columns but leaves trailing blanks in the first column of the expression intact.

When you specify an expression based on different string data types (such as LSTRING and CHARACTER), the resulting data type is ZSTRING. You can use LVAR or NOTE as one of the different types, but the size of the resulting ZSTRING is limited to the maximum for ZSTRING (255). For LSTRING columns, the length byte determines the length of the value. For ZSTRING columns, the null terminator determines the length of the value. For both of these data types, Scalable SQL considers any blanks at the end of the data to be significant and does not strip them for the * and + operators. In effect, the ++ operator is significant only for CHARACTER columns, since the result when using the + and ++ operators is the same for LSTRING and ZSTRING columns. The following example uses the + and * operators: SELECT Last_Name + ',' * First_Name FROM Person;

Database Design Guide

119

Retrieving Data

Scalable SQL concatenates the string columns while deleting blanks between the columns, producing results such as the following: Baldwin, Richard

Conditional Expression Operators
Scalable SQL provides two operators that allow you to specify conditions with expression operations.

Table 5-9
Operator
?? ::

Conditional Computed Column Operators
Description
This operator means Then. This operator means Else.

You can use these operators in SELECT statements to manipulate values based on criteria. The following example selects the class name, room number, room capacity, and maximum class size from the sample database. If the capacity of a room is greater than the maximum class size, then the ClassCanExpand field is TRUE; otherwise, the field is FALSE. select class.name, room.number, room.capacity, class.max_size, class.max_size < room.capacity ?? TRUE :: FALSE AS ClassCanExpand from class, room where class.room_number = room.number
Note

The ?? and :: operators are not supported in the Delphi development environment.

Database Design Guide

120

Retrieving Data

Date and Time Arithmetic
Scalable SQL supports date and time arithmetic in expressions. The date or time you specify can be either a constant or a column value. You can also use the SQL functions CURDATE, CURTIME, and CURRENT_TIMESTAMP to specify the current system date, current system time, and current system timestamp. When you use a statement for date or time arithmetic, the data type of the result is fixed. For example, a date subtracted from another date always results in an integer value representing the number of days.

Date Arithmetic
Scalable SQL uses days as the basis for date arithmetic. All date computations are based on the difference in days between two dates. Valid expressions for date arithmetic include the following:

‹ ‹ ‹ ‹

A constant that corresponds to the default date mask. A date value from a column. The CURDATE function (the current system date). An integer value that represents a number of days.

Table 5-10 lists some valid date computations.

Table 5-10
Computations
date – date

Date Computations
Result
number of days date date

date + number of days date – number of days

Database Design Guide

121

Retrieving Data

Table 5-10
Computations

Date Computations continued
Result
number of days date date

CURDATE – date CURDATE + number of days CURDATE – number of days

The following example retrieves all classes scheduled to begin in the next two days: SELECT ID, Name, Section FROM Class WHERE (Start_Date - CURDATE) <= 2 AND (Start_Date - CURDATE) >= 0;

Time Arithmetic
Scalable SQL uses hundredths of a second as the basis for time computations. All times are based on a 24-hour clock. Valid expressions for time arithmetic include the following:

‹ ‹ ‹ ‹

A constant that corresponds to the default time mask. A time value from a column. The CURTIME function (the current system time). An integer value that represents a time of day or elapsed time expressed in hundredths of a second.

Database Design Guide

122

Retrieving Data

Table 5-11 lists some valid time computations.

Table 5-11
Computations
time – time time + time

Time Computations
Result
time time time time time time time time

time + hundredths of a second time – hundredths of a second CURTIME – time CURTIME + time CURTIME + hundredths of a second CURTIME – hundredths of a second

The following example lists all classes that begin today before noon. SELECT ID, Name, Section FROM Class WHERE Start_Time <= 12:00:00;

Expression Examples
This section provides examples of Scalable SQL expressions.

Database Design Guide

123

Retrieving Data

Append (*)
In this example, the * operator appends three string columns (from the Course table) and inserts blanks between the columns: SELECT Dept_Name * Name * Description FROM Course; The result of this operation on a particular row might be the following: Accounting ACC 203 Intermediate Accounting I

Concatenate with Blanks (++)
In the following example, the ++ operator concatenates two string columns without deleting blanks between them. SELECT Dept_Name ++ Name FROM Course; The result of this operation on some particular rows might be the following: Accounting ACC 101 Anthropology ANT 405

Concatenate without Blanks (+), LENGTH, and RTRIM
The following example removes the trailing blanks from the string in the Dept_Name column, then concatenates the Name column without leaving any blanks between them and determines the length of the new string. SELECT Dept_Name, Name, LENGTH(RTRIM(Dept_Name) + Name) FROM Course;

Database Design Guide

124

Retrieving Data

This operation yields results similar to the following: Anthropology ANT 405 19 Art ART 101 10 Modifying the previous example shows how you can apply arithmetic operators to the results of scalar functions. Suppose you need to calculate the number of characters for signs for each building. The signs will say “Pervasive University [Building Name],” and you have to allow for twice the number of characters needed. (There are 20 characters in “Pervasive University.”) SELECT (20 + LENGTH(RTRIM(Building_Name))) * 2 FROM Room; Once Scalable SQL determines the number of letters in a building name, it adds 18 to this number and then multiplies the result by 2.

Database Design Guide

125

Retrieving Data

Functions
Once your database contains data, you can use functions on the data to return a result for a set of column values (using aggregate functions) or accept one or more parameters as input and return a single value (using scalar functions).

Aggregate Functions
An aggregate function is a function that returns a single result for a given set of column values. Scalable SQL supports the aggregate functions shown in Table 5-12.

Table 5-12
Function
AVG

Aggregate Functions
Description
Determines the average of a group of values. If the operand is not a DECIMAL, then AVG returns an 8-byte FLOAT. If the operand is a DECIMAL, AVG returns a 10-byte DECIMAL. Counts the number of rows in a specified group. COUNT always returns a 4-byte INTEGER. Returns the maximum value of a group of values. MAX returns the same data type and size as the operand. Returns the minimum value of a group of values. MIN returns the same data type and size as the operand. Determines the sum of a group of values. If the operand is not a DECIMAL, then SUM returns an 8-byte FLOAT. If the operand is a DECIMAL, SUM returns a 10-byte DECIMAL.

COUNT MAX MIN SUM

For more information about each of these functions, refer to the SQL Language Reference.
Database Design Guide 126 Retrieving Data

Arguments to Aggregate Functions
For AVG and SUM functions, the argument to the function must be the name of a numeric column. The COUNT, MIN, and MAX functions can provide results on numeric or nonnumeric columns. You cannot nest aggregate function references. For example, the following reference is not valid: SUM(AVG(Cost_Per_Credit)) You can use aggregate functions in an expression, as in the following example: AVG(Cost_Per_Credit) + 20 You can also use an expression as an argument to a group aggregate function. For example, the following expression is valid: AVG(Cost_Per_Credit + 20) The aggregate functions treat null column values as significant. For example, on a table that contains 40 rows of data and 5 rows of null values, the COUNT function returns 45. You can use the DISTINCT keyword to force Scalable SQL to treat all null column values as a single value. The following example calculates the average column value in the Grade column: AVG(DISTINCT Grade) The DISTINCT keyword affects the AVG, COUNT, and SUM functions. It has no effect on the MIN and MAX functions.

Database Design Guide

127

Retrieving Data

Aggregate Function Rules
You can use aggregate functions in a SELECT statement as follows:

‹ ‹

As items in the selection list. In a HAVING clause.

Generally, you use aggregate functions in a SELECT statement that contains a GROUP BY clause to determine aggregate values for certain groups of rows. However, if the SELECT statement does not contain a GROUP BY clause and you want to use aggregate functions in it, all the items in the selection list must be aggregate functions. If the SELECT statement does contain a GROUP BY clause, the column or columns specified in the GROUP BY clause must be select terms that are single columns, not aggregate functions. All the select terms that are not also listed in the GROUP BY clause, however, must be aggregate functions. The following example returns a result table that allows you to determine the amount each student has paid. SELECT Student_ID, SUM(Amount_Paid) FROM Billing GROUP BY Student_ID; You can also include aggregate functions in HAVING clauses used with a GROUP BY clause. Using the HAVING clause with a GROUP BY clause restricts the groups of rows Scalable SQL returns. Scalable SQL performs the aggregate function on the column of each group of rows specified in the GROUP BY clause, and returns a single result for each set of rows that has the same value for the grouping column.

Database Design Guide

128

Retrieving Data

In the following example, Scalable SQL returns row groups only for students currently enrolled with more than 15 credit hours: SELECT Student_ID, SUM(Credit_Hours) FROM Enrolls e, Class cl, Course c WHERE e.Class_ID = cl.ID AND cl.Name = c.Name GROUP BY Student_ID HAVING SUM(Credit_Hours) > 15; When you use a HAVING clause without a GROUP BY clause, Scalable SQL does not divide the rows of the table into multiple groups. Instead, Scalable SQL treats the rows of the entire table as one large group when it applies the aggregate function, as in the following example: SELECT SUM(Amount_Owed) FROM Billing HAVING COUNT(*) > 200; Using the Billing table as an example, this statement returns the sum of the amount owed only if there are more than 200 rows in the table.

Scalar Functions
Scalar functions—STRING, NUMERIC, DATE, TIME, and CAST—accept one or more parameters as input and return a single value. For example, the LENGTH function returns the length of a string column value. You can use scalar functions in Scalable SQL statements that allow computed columns in expressions. The type of expression operator you can use depends on the type of result the function returns. For example, if the function returns a numeric value, you can use arithmetic operators. If the function returns a string value, you can use string operators.

Database Design Guide

129

Retrieving Data

You can nest scalar functions, but each nested function must return a result that is an appropriate parameter to the next level scalar function, as in the following example: SELECT RIGHT (LEFT (Last_Name, 3), 1) FROM Person; Scalable SQL executes the LEFT function first. If the value in the Last Name column is Baldwin, the string resulting from the LEFT function is Bal. This string is the parameter of the RIGHT function, which returns ‘l’ as the rightmost character of the string. You can use scalar functions that return a numeric result within a computed column that calculates a numeric value. You can also use scalar functions that return a string value as an expression to another string function, but the total length of the string result cannot exceed 255 bytes.

String and Numeric Functions
For each of the string scalar functions, the function’s parameter may be a character string, the name of a column that is specified as a fixed-length or variable-length string type, or an expression that evaluates to a string. Table 5-13 lists the string scalar functions.

Table 5-13
Function
LEFT LENGTH LOWER

String Scalar Functions
Description
Returns a specified number of characters from a string, beginning with the leftmost character. Returns the length of a string in bytes. Converts all characters to lowercase.

Database Design Guide

130

Retrieving Data

Table 5-13
Function
LTRIM RIGHT RTRIM SUBSTRIN G UPPER

String Scalar Functions continued
Description
Removes leading spaces. Returns a specified number of characters from a string, beginning with the rightmost character. Removes trailing spaces. Returns a portion of a string specified by a start position and a length parameter. Converts all characters to uppercase.

The LENGTH and SUBSTRING functions can also accept numeric data types as parameters. Table 5-14 shows the numeric scalar functions.

Table 5-14
Function
LENGTH ROUND SUBSTRIN G TRUNC

Numeric Scalar Functions
Description
When used with a column value or a constant that is not a string, returns the internal storage length of the column value or constant. Performs arithmetic rounding to the specified number of places. When used with a BIT, INTEGER, or AUTOINC column, returns a packed set of bit columns (4-byte INTEGER value) based on the parameters you specify. Truncates the numeric value to the specified number of places.

Database Design Guide

131

Retrieving Data

String Functions
For most of the string functions, the function’s first parameter may be a string or any expression that evaluates to a string (including the name of a column defined as a fixedlength or variable-length string type). The exceptions to this rule are the LENGTH and SUBSTRING functions; these functions can accept parameters that reference non-string data types. Refer to “LENGTH” and “SUBSTRING” for more information.
Note

String functions called with a fixed-length string data type return the result as the same data type. String functions called with a variable-length data type return the result as a character. The only exception to this rule is the LENGTH function, which returns the INTEGER data type.

You can use string functions that return a numeric result (as numeric operands within expressions). You can use string functions that return a character value as operands to other string functions as long as the total length of the result does not exceed 255 bytes. Scalable SQL considers trailing blanks in a character value to be significant for comparisons in restriction clauses and when you use the LENGTH function to return the length of a string column. (A character value is any expression that includes only character column values or constant values.) Use the LTRIM, RTRIM, or SUBSTRING functions described in this section to ensure that the lengths of string columns you compare are the same.

LEFT
The scalar function LEFT returns a specified number of characters from the string parameter, starting with the first character on the left. If the length you specify is longer

Database Design Guide

132

Retrieving Data

than the string from which you are extracting the returned string, Scalable SQL pads the returned string with spaces on the right to achieve the designated length. Example
left(Last_Name, 3)

Result
Bal

This example shows how the LEFT function works on the Person table, using the Last Name column value Baldwin.

LENGTH
Unlike most other string functions, the LENGTH function can accept parameters that reference non-string data types:

‹ ‹ ‹

If the parameter is a column name, the column does not have to be a string data type. If the parameter is an expression, the expression does not have to evaluate to a string data type. If the parameter is a constant, the constant does not have to be a string.

In these cases, the LENGTH function returns the internal storage length of the column, expression result, or constant, respectively. The value the LENGTH function returns is a 4-byte integer.

Database Design Guide

133

Retrieving Data

With a parameter that does reference a string data type, the function returns the length of the string or column in bytes. Scalable SQL determines the length for string types as follows: Data Type
CHARACTE R LSTRING LVAR NOTE ZSTRING

Length Returned
Length of the character string, including trailing spaces. Value of the length byte at the beginning of the data. Length of the data, including length words. Length of the data, including the delimiter. Length of the data, up to binary 0 (not including the binary 0 terminator).

The following examples show how the LENGTH function works. In the following example, the parameter is a string. Example 1
LENGTH(’abcdef’)

Result
6

In Example 2, the parameter is a column of data type DATE. Example 2
LENGTH(Person.Date_of_Birth)

Result
4

Database Design Guide

134

Retrieving Data

In Example 3, the parameter is an integer constant, and Scalable SQL returns the internal size of a 4-byte integer. Example 3
LENGTH(10)

Result
4

LOWER
The LOWER function converts all characters in the specified string to lowercase. This example shows how the LOWER function works on the Person table, using the Last Name column value Baldwin. Example
LOWER(Last_Name)

Result
baldwin

LTRIM
The LTRIM function removes leading spaces from the specified string parameter. This example shows how the LTRIM function works on the column value “ abc” in a column named String. Example
LTRIM(string)

Result
abc

Database Design Guide

135

Retrieving Data

RIGHT
The RIGHT function extracts the last n characters from any expression that evaluates to a string, where n is the number of characters to extract. Example 1 shows how the RIGHT function works on the Person table, using the Last Name column value Baldwin. Example 1
RIGHT(Last_Name, 2)

Result
in

Example 2 shows how the RIGHT function works on the Person table, using the Last Name column values Turnipseed, Tuten, Tuyahov, Tuyes, Twelvetrees, and Twentyman. In this example, n is longer than the sizes of the strings extracted. Consequently, Scalable SQL pads each string with spaces on the left until the string is n characters long. You can use this feature to right justify character strings. Example 2
SELECT RIGHT (RTRIM (Last_Name), 15) FROM Person WHERE Last_Name > 'Turn' AND Last_Name < 'Twitch' ORDER BY Last_Name;

Result
Turnipseed Tuten Tuyahov Tuyes Twelvetrees Twentyman

Note

Since the RIGHT function retains trailing blanks in CHARACTER, ZSTRING, LSTRING, NOTE, and LVAR data, the resulting data may not appear right justified. In this case, you must use the RTRIM function to remove trailing blanks.

Database Design Guide

136

Retrieving Data

RTRIM
The RTRIM function removes trailing blanks from the specified string. This example shows how the LTRIM function works on the column value “abc ” in a column named String. Example
rtrim(string)

Result
abc

SUBSTRING
You can specify SUBSTRING using its shortened form, SUBSTR. The parameters for the SUBSTRING function are as follows (in order):

‹ ‹ ‹

An expression. The start position (relative to 1). The length of the portion of the data value to be returned.

The length parameter is optional; if you omit it, Scalable SQL calculates the length of the substring as: LENGTH(data) – start position + 1 The smallest length SUBSTRING can return is one byte. SUBSTRING can return two different types of information, depending on the value you specify in the expression parameter:

‹

If the expression parameter is a string value or evaluates to a string, the function returns the portion of the string that the start position and the length parameter

Database Design Guide

137

Retrieving Data

specify. Examples 1, 2, and 3 show how the SUBSTRING function works on the sample database table Room, using the Building Name column. Example 1
SELECT DISTINCT Building_Name, SUBSTRING(Building_Name, 1, 5) FROM Room WHERE Building_Name BEGINS WITH 'K';

Result
Kimball Building Kimba Klinetob Building Kline

Example 2
SELECT DISTINCT Building_Name, SUBSTRING(Building_Name, 6) FROM Room WHERE Building_Name BEGINS WITH 'K';

Result
Kimball Building ll Building Klinetob Building tob Building

Example 3
SELECT DISTINCT Building_Name, SUBSTRING(Building_Name, 1, 5) + SUBSTRING(Building_Name, 6) FROM Room WHERE Building_Name BEGINS WITH 'K';

Result
Kimball Building Kimball Building Klinetob Building Klinetob Building

Database Design Guide

138

Retrieving Data

‹

If the expression you specify evaluates to a BIT, INTEGER, or AUTOINC value, the SUBSTRING function returns a 4-byte integer value. In this case, SUBSTRING functions according to the following rules:
Š SUBSTRING ignores the specified start position. (You must still set this parameter to 1, since SUBSTRING evaluates it as a value of 1.) Š The length specifies the number of contiguous bits to return, beginning with the loworder bit of the specified column.
If the number of bit positions specified is less than 32 (4 bytes), then the extra bit positions are zero-filled in the returned data.

Example 4
SELECT Capacity, SUBSTRING(Capacity, 1, 4) FROM Room WHERE Building_Name BEGINS WITH 'Faske';

Result
2 2 40 60 50 1 2 2 8 12 2 1

The following chart shows the binary values for the Capacity column and the rightmost 4 bits, as well as the decimal value of the rightmost 4 bits: Capacity
2 40 60 50 1

Binary
10 101000 111100 110010 1

Rightmost Four
0010 1000 1100 0010 0001

Decimal Value
2 8 12 2 1

Database Design Guide

139

Retrieving Data

Example 4 shows the SUBSTRING function returning a 4-byte integer value. The expression is the name of a 2-byte INTEGER column (Intcolumn). If the value in Intcolumn is decimal 35, SUBSTRING returns the integer value for the rightmost 4 bits of the binary value of 35, which is 00100011. The rightmost 4 bits are 0011.

UPPER
The UPPER function converts characters from lowercase to uppercase. You may specify this parameter as either a string value or a column name. This example shows how the UPPER function works on the sample database table Person, using the Building Name column value Young Building. Example Result

SELECT UPPER(Building_Name) YOUNG BUILDING FROM Room WHERE Building_Name BEGINS WITH 'Young';

Numeric Functions
You can use the numeric scalar functions to correct rounding errors that may occur as a result of floating-point math operations. Scalable SQL supports the ROUND and TRUNC functions for all numeric data types.
Note

ASCII decimal values stored as FLOAT or BFLOAT values are subject to the normal approximation that floating point normalization requires. The ROUND and TRUNC functions do not correct inaccuracies that result from this approximation.

Database Design Guide

140

Retrieving Data

ROUND
Following the evaluation of an expression, the ROUND function performs arithmetic rounding to n spaces, where n represents the number of places to round. The syntax of the function is as follows: ROUND (expression, n) You can apply the ROUND function to either a numeric constant or an arithmetic expression. With an arithmetic expression, Scalable SQL applies ROUND to the resulting value. The result of the ROUND function is a value with the same data type and length as the expression. If the specified number of places to round is positive, Scalable SQL rounds the designated number of places to the right of the decimal point. If the specified number is negative, Scalable SQL rounds the designated number of places to the left of the decimal point. Example 1 specifies rounding the expression to the decimal point; both 0 and -0 round to the decimal point. Example 1
SELECT Cumulative_GPA, ROUND(Cumulative_GPA, -0) FROM Student;

Result
4.000 1.231 2.636 2.239 4.000 1.000 3.000 2.000

Example 2 specifies rounding the expression two places to the right of the first positive digit. Example 2
SELECT Cumulative_GPA, ROUND(Cumulative_GPA, 2) FROM Student;

Result
4.000 1.231 2.636 2.239 141 4.000 1.230 2.640 2.240 Retrieving Data

Database Design Guide

TRUNC
Following the evaluation of an expression, the TRUNC function truncates a numeric value to n spaces, where n represents the number of places to truncate. The syntax of the function is as follows: TRUNC (expression, n) You can apply the TRUNC function to either a numeric constant or an arithmetic expression. With an arithmetic expression, Scalable SQL applies TRUNC to the resulting value. The result of the TRUNC function is a value with the same data type and length as the expression. If the specified number of places to truncate is positive, Scalable SQL truncates the designated number of places to the right of the decimal point. If the specified number is negative, Scalable SQL truncates the designated number of places to the left of the decimal point. The following example specifies truncating the expression to the decimal point; both 0 and -0 round to the decimal point. Example 1
SELECT Cumulative_GPA, TRUNC(Cumulative_GPA, 0) FROM Student;

Result
4.000 1.231 2.636 2.239 4.000 1.000 2.000 2.000

The following example specifies truncating the expression two places to the left of the decimal point. Example 2
SELECT Cumulative_GPA, TRUNC(Cumulative_GPA, 1) FROM Student;

Result
4.000 1.231 2.636 2.239 4.000 1.200 2.600 2.200 142 Retrieving Data

Database Design Guide

Date Functions
You can use the date scalar functions to manipulate DATE column values. The result is always a 4-byte INTEGER value. Only DATE columns are valid for the date functions.

Table 5-15
Function
DAY MONTH

Date Scalar Functions
Description
Returns the day value. Returns the month value.

WEEKDAY Returns the day of the week value, where Sunday is 0 and Saturday is 6. For example, if the day is Thursday, the WEEKDAY function returns 4. YEAR Note Returns the year value.

The examples in this section assume that the value for the start date column is 01/04/96.

DAY
This function returns the day value for a DATE column. Example
DAY(Start_Date)

Result
4

Database Design Guide

143

Retrieving Data

MONTH
This function returns the month value for a DATE column. Example
MONTH(Start_Date)

Result
1

WEEKDAY
This function returns the day of the week value for a DATE column. The returned values correspond to the days of the week, as follows:
Sunday Monday Tuesday Wednesday Thursday Friday Saturday 0 1 2 3 4 5 6

In the following example, the weekday that corresponds to the start date of a class is Wednesday. Example
WEEKDAY(Start_Date)

Result
3

Database Design Guide

144

Retrieving Data

YEAR
This function returns the year value for a DATE column. Example
YEAR(Start_Date)

Result
1996

Time Functions
You can use the time scalar functions to manipulate TIME column values. The result is always a 4-byte INTEGER value. Only TIME columns are valid for the time functions.

Table 5-16
Function
HOUR MILLISECOND MINUTE SECOND Note

Time Scalar Functions
Description
Returns the hour value. Returns the millisecond value. Returns the minute value. Returns the second value.

The examples in this section assume that the value for the start date column is 01/04/96 and the start time is 08:00:37:26.

Database Design Guide

145

Retrieving Data

HOUR
This function returns the hour value for a TIME column. Example
HOUR(Start_Time)

Result
8

MILLISECOND
This function returns the millisecond value for a TIME column. Example
MILLISECOND(Start_Time)

Result
260

MINUTE
This function returns the minute value for a TIME column. Example
MINUTE(Start_Time)

Result
0

Database Design Guide

146

Retrieving Data

SECOND
This function returns the second value for a TIME column. Example
SECOND(Start_Time)

Result
37

Date and Time Function Example
This example illustrates the date and time functions. It returns all Accounting classes that start on Monday morning. SELECT Name, Section, MONTH(Start_Date), DAY(Start_Date), YEAR(Start_Date), HOUR(Start_Time), MINUTE(Start_Time) FROM Class WHERE Name BEGINS WITH 'ACC' AND WEEKDAY(Start_Date) = 1 AND Start_Time < 12:00:00; This example might yield the following results: Name
ACC 101 ACC 102 ACC 203 ACC 204

Section
001 003 001 001

Month
6 6 6 6

Day
5 5 5 5

Year
1995 1995 1995 1995

Hour
8 8 11 11

Minute
0 0 0 0

Database Design Guide

147

Retrieving Data

CAST Function
The CAST function converts an expression to a specific data type. The CAST function can be used in any expression to connect a constant value to a different data type or different mask format. You can specify a mask to apply to the expression when converting to the specified data type. The syntax of the function is as follows: CAST (expression AS < data_type | [ TYPE [ OF ] ] column_reference > [ < [ MASK ] edit_mask | [ MASK [ OF ] ] column_reference | [ MASK ] DEFAULT > ] ) ) data_type ::= < AUTOINC | BFLOAT | BIT | CHAR | CHARACTER | CURRENCY | DATE | DEC | DECIMAL | FLOAT | INT | INTEGER | LOGICAL | LSTRING | LVAR | MONEY | NOTE | NUMERIC | NUMERICSA | NUMERICSTS | TIME | TIMESTAMP | UNSIGNED |

ZSTRING >
column_reference ::= [ column_qualifier. ] column_name

Database Design Guide

148

Retrieving Data

Table 5-17 shows the valid conversions.

Table 5-17

CAST Function Data Type Conversions
Target Data Type Numeric
Valid

String
Valid Valid Valid Valid Valid Valid

Boolean
Not Valid
except INTEGER

Date
Valid Valid Not valid Valid Not valid Valid

Time
Valid Valid Not valid Not valid Valid Valid

Timestamp
Valid Valid Not valid Valid Valid Valid

Numeric Original Data Type String Boolean Date Time
Valid Not Valid Valid Valid

Valid Valid Not valid Not valid Not valid

Timestamp Valid

Note

When using the CAST function, Scalable SQL assumes the default data type unless you specify the size of the CAST data type equal to the data type on which the CAST is being performed. If you do not specify the size, you may receive a Status Code 349, “The length exceeds the column length.” The first example returns Status Code 349. The second example specifies the data type size. Incorrect Example: SELECT CAST(SUBSTR(TEST, 1, 255) AS CHAR) Correct Example: SELECT CAST(SUBSTR(TEST, 1, 255) AS CHAR(255))

Database Design Guide

149

Retrieving Data

If you do not specify a mask, Scalable SQL uses the default input format or default displayable mask for the data type size and scale specified. Table 5-18 describes how Scalable SQL uses masks in various data type combinations.

Table 5-18

Masks and the CAST Function
Comments
Scalable SQL applies the mask to the expression before determining the result. Because string masks specify the number of characters in the result data value, some data may be truncated during the cast. Scalable SQL uses the mask to assist in correctly interpreting the expression. For example, if the expression is ‘12345-6789’ and the mask is ‘999-99-9999’ and the target data type is INTEGER(4), then the result value is 123456789.

Original Data Type Target Data Type Mask Used
CHARACTER LSTRING ZSTRING NOTE LVAR CHARACTER LSTRING ZSTRING NOTE LVAR CHARACTER LSTRING ZSTRING NOTE LVAR INTEGER UNSIGNED AUTOINC CURRENCY MONEY DECIMAL NUMERIC NUMERICSTS NUMERICSA FLOAT BFLOAT LOGICAL BIT String

Number

CHARACTER LSTRING ZSTRING NOTE LVAR INTEGER

Logical

Scalable SQL uses the mask to assist in correctly interpreting the expression. For example, if the expression is ‘YES’ and the mask is ‘YES-NO’, then the result value is TRUE (stored as a nonzero value). If the value of the expression is not zero, the result value is TRUE. Otherwise, it is FALSE.

LOGICAL BIT

Database Design Guide

150

Retrieving Data

Table 5-18

Masks and the CAST Function continued
Comments
Scalable SQL uses the mask to assist in correctly interpreting the expression. For example, if the expression is ‘12/11/ 1996’ and the mask is ‘dd/mm/yy’, then the result value is November 12, 1996. Scalable SQL uses the mask to assist in correctly interpreting the expression. For example, if the expression is ‘12:10’ and the mask is ‘hh:mm’, then the result value is 12:10:00:00 (that is, 12:10 in the afternoon, 0 seconds, 0 hundredths of seconds). Scalable SQL uses the mask to assist in correctly interpreting the expression. For example, if the expression is ‘12/11/ 1996 12:10’ and the mask is ‘dd/mm/ yyyy hh:tt’, then the result value is November 12, 1996, at 12:10:00:00 in the afternoon (local time zone). Scalable SQL uses the mask to assist in formatting the expression in the target data type. For example, if the expression is an INTEGER(4) with a value of 1234567 and the mask is ‘ZZZ,ZZZ,ZZZ’ and the target data type is CHARACTER(11), then the result is ‘ 1,234,567’ (two leading blanks included).

Original Data Type Target Data Type Mask Used
CHARACTER LSTRING ZSTRING NOTE LVAR CHARACTER LSTRING ZSTRING NOTE LVAR DATE Date

TIME

Time

CHARACTER LSTRING ZSTRING NOTE LVAR

TIMESTAMP

Timestamp

INTEGER UNSIGNED AUTOINC CURRENCY MONEY DECIMAL NUMERIC NUMERICSTS NUMERICSA FLOAT BFLOAT

CHARACTER LSTRING ZSTRING NOTE LVAR

Number

Database Design Guide

151

Retrieving Data

Table 5-18

Masks and the CAST Function continued
Comments
Scalable SQL uses the mask to assist in formatting the expression in the target data type. For example, if the expression is a LOGICAL with a value of True and the mask is ‘UP-DOWN’ and the target data type is CHARACTER(4), then the result is ‘UP ’ (two trailing blanks included). Scalable SQL uses the mask to assist in formatting the expression in the target data type. For example, if the expression has a value of November 12, 1996 and the mask is ‘MMM dd, yyy’ and the target data type is CHARACTER(12), then the result is ‘Nov 12, 1996’. Scalable SQL uses the mask to assist in formatting the expression in the target data type. For example, if the expression has a value of 12:10 in the afternoon and the mask is ‘hh:mm:ss’ and the target data type is CHARACTER(8), then the result is ‘12:10:00’.

Original Data Type Target Data Type Mask Used
LOGICAL BIT CHARACTER LSTRING ZSTRING NOTE LVAR Logical

DATE

CHARACTER LSTRING ZSTRING NOTE LVAR

Date

TIME

CHARACTER LSTRING ZSTRING NOTE LVAR

Time

Database Design Guide

152

Retrieving Data

Table 5-18

Masks and the CAST Function continued
Comments
Scalable SQL uses the mask to assist in formatting the expression in the target data type. For example, if the expression has a value of November 12, 1996, at 12:10 in the afternoon (local time) and the mask is ‘yyyy-mmdd hh:tt:ss.fff’ and the target data type is CHARACTER(23), then the result is ‘1996-11-12 12:10:00.000’. Scalable SQL uses the mask to round the expression before converting it to the target data type. If the expression is an INTEGER, the mask scales the value rather than rounding the value.

Original Data Type Target Data Type Mask Used
TIMESTAMP CHARACTER LSTRING ZSTRING NOTE LVAR Timestamp

INTEGER UNSIGNED AUTOINC CURRENCY MONEY DECIMAL NUMERIC NUMERICSTS NUMERICSA FLOAT BFLOAT LOGICAL BIT DATE TIMESTAMP

INTEGER UNSIGNED AUTOINC CURRENCY MONEY DECIMAL NUMERIC NUMERICSTS NUMERICSA FLOAT BFLOAT LOGICAL BIT DATE

Number

Logical Date

The mask is not useful to Scalable SQL in this situation. Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression is a DATE with a value of November 12, 1920 and the mask is ‘mm/dd’ and the current year is 1996, then the result is November 12, 1996.

Database Design Guide

153

Retrieving Data

Table 5-18

Masks and the CAST Function continued
Comments
Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression has a value of 12:10:06:03 in the afternoon and the mask is ‘hh:mm’, then the result is 12:10:00:00 in the afternoon. Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression has a value of November 12, 1996 at 12:10:06:03.3456 in the afternoon and the mask is ‘hh:mm:ss’, then the result value is 12:10:06 in the afternoon. Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression has a value of November 12, 1920 and the mask is ‘mm/dd’ and the current year is 1996, then the result value is November 12, 1996 at the current local time.

Original Data Type Target Data Type Mask Used
TIME TIME Time

TIMESTAMP

TIME

Timestamp without a date component

DATE

TIMESTAMP

Date

Database Design Guide

154

Retrieving Data

Table 5-18

Masks and the CAST Function continued
Comments
Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression has a value of 12:10:06:11 in the afternoon and the mask is ‘hh:mm:ss’ and the current day is November 12, 1996, then the result value is November 12, 1996 at 12:10:06 in the afternoon. Scalable SQL uses the mask to set certain components of the expression to the default value in the result value. For example, if the expression has a value of November 12, 1920 at 12:10:06:3456 in the afternoon and the mask is ‘mm/dd hh:tt:ss.fffffff’ and the current year is 1996, then the result value is November 12, 1996 at 12:10:06:3456 in the afternoon.

Original Data Type Target Data Type Mask Used
TIME TIMESTAMP Time

TIMESTAMP

TIMESTAMP

Timestamp

Database Design Guide

155

Retrieving Data

When you convert expressions to string data types, the size of the mask determines the number of characters in the result data. Consider the following examples, in which B is a blank: Value Type
INTEGER INTEGER DATE

Value
1 1 May 25, 1992

Mask
ZZZ ZZZ mm/dd/yy

Result Type
CHARACTER(7) ZSTRING(7) CHARACTER(12)

Result Value
‘BB1BBBB’ ‘BB1’ ‘05/25/92BBBB’

To remove leading blanks in the result value, you can use the LTRIM function. Using the previous examples, the result values would be ‘1BBBB’, ‘1’, and ‘05/25/92BBBB’, respectively. You may want to compare a string value with trailing blanks (such as ‘1BBBB’) to a constant value (such as ‘1’); however, the two values do not compare as equal, because the constant value lacks trailing blanks. To avoid this situation, you can do any one of the following:

‹ ‹ ‹

Specify the size of the CHARACTER result value to be the same as the size of the mask. For example, if the mask is ZZZ, then the result would be CHARACTER(3). Use a result type of ZSTRING or LSTRING and specify the size of the result to be at least 1 more than the size of the mask. For example, if the mask is ZZZ, then the result would be ZSTRING(4). Combine RTRIM functions on the result of the CAST function to remove trailing blanks.

Database Design Guide

156

Retrieving Data

Examples
Use the TYPE OF clause to convert an expression to a specific column’s data type. The referenced column must be from a table referenced in the statement. The following example converts a string value to a FLOAT value: CAST ( ‘3.2’ AS TYPE OF Enrolls.Grade ) Use the MASK clause to convert an expression using a mask. The following example converts a string to a DATE value. The mask ensures that the value is interpreted as November 10, 1992: CAST ( ‘10/11/92’ AS DATE MASK [dd/mm/yy] ) The following example presents the expression as a non-string constant. Note that even though the statement includes a mask, Scalable SQL interprets the value as October 11, 1992, because Scalable SQL applies the mask only after first interpreting the constant value, for which mm/dd/yy is the default mask. CAST ( 10/11/92 AS DATE MASK [dd/mm/yy] )

Database Design Guide

157

Retrieving Data

chapter

6

Storing Logic

This chapter explains how to store SQL procedures for future use and how to create triggers. For information about stored views, see Chapter 5, “Retrieving Data.” This chapter includes the following sections:

‹ ‹ ‹ ‹ ‹ ‹

“Stored Procedures” “SQL Variable Statements” “SQL Cursor-Based Statements” “SQL Control Statements” “Retrieving Status Information” “SQL Triggers”

Database Design Guide

158

Storing Logic

Stored Procedures
Using stored procedures, you can group logically associated programming steps into a general process and then invoke that process with one statement. You can also execute this process using different values by passing parameters. Once invoked, SQL stored procedures are executed in their entirety without internal communication between a host language program and the SQL engine. You can invoke them independently, and they can be invoked as part of the body of other procedures or triggers. For more information about triggers, refer to the section "SQL Triggers." You can use SQL variable statements within stored procedures to store values internally from statement to statement. See the section “SQL Variable Statements” for more information about these statements. You can use SQL cursor-based statements in row-based data manipulation statements within stored procedures. For details about these statements, see the section "SQL Cursor-Based Statements." You can use SQL control statements in stored procedures to control the execution flow of the procedure. For more information about these statements, refer to the section “SQL Control Statements” later in this chapter.

Database Design Guide

159

Storing Logic

Declaring Stored Procedures
To define a stored procedure, use the CREATE PROCEDURE statement. CREATE PROCEDURE EnrollStudent (Stud_id INT (4), Class_Id INT (4)); BEGIN INSERT INTO Enrolls VALUES (Stud_id, Class_Id, 0.0); END The maximum size for a stored procedure name is 30 characters. Parentheses are required around the parameter list, and the parameter name may be any valid SQL identifier. Stored procedures must have unique names in the dictionary. When a declaration of a stored procedure is passed to the Scalable SQL engine and a previous stored procedure declaration with the same name exists, Scalable SQL returns Status Code 366. For information about the syntax of the CREATE PROCEDURE statement, refer to the SQL Language Reference.

Invoking Stored Procedures
To invoke a stored procedure, use the CALL statement. CALL EnrollStudent (274410958, 50); You must define a value for every parameter. You can assign a value to a parameter using the associated argument in the CALL statement or with the associated default clause in the CREATE PROCEDURE statement. An argument value for a parameter in a CALL statement overrides any associated default value.

Database Design Guide

160

Storing Logic

You can specify calling values in a CALL statement using either of the following two ways:

‹ ‹

Positional arguments—Allow you to specify parameter values implicitly based on the ordinal position of the parameters in the list when the procedure was created. Keyword arguments—Allow you to specify parameter values explicitly by using the name of the parameter whose value is being assigned.

You cannot assign a parameter value twice in the argument list (either positional or keyword). If you use both positional arguments and keyword arguments in the same call, the keyword arguments must not refer to a parameter that receives its value through the positional arguments; if they do, Scalable SQL returns Status Code 864. When using keyword arguments, the same parameter name must not occur twice; if it does, Scalable SQL returns Status Code 897. For more information about the syntax of the CALL statement, refer to the SQL Language Reference.

Deleting Stored Procedures
To delete a stored procedure, use the DROP PROCEDURE statement. DROP PROCEDURE EnrollStudent; For more information about the syntax of this statement, refer to the SQL Language Reference.

Database Design Guide

161

Storing Logic

SQL Variable Statements
SQL variable statements provide a means to store values internally from statement to statement. SQL variable statements include the following two statements:

‹ ‹

SQL variable declaration Assignment statement

You can use these statements either inside stored procedures or outside stored procedures as independent, single SQL statements.

Declaring SQL Variables
A SQL variable declaration defines a SQL variable. DECLARE CourseName CHAR(7); You can use SQL variables in the following ways:

‹ ‹ ‹ ‹ ‹ ‹

As FETCH statement target values. In SELECT list expressions. In WHERE clauses. In UPDATE expressions. As INSERT values. In an expression used to assign values to the same or other variables.

For more information about the syntax of this statement, refer to the SQL Language Reference.
Database Design Guide 162 Storing Logic

Substitution Variables
Substitution variables allow you to create a Scalable SQL statement without supplying specific values for all the options; you specify the values when you execute the statement. Because standard SQL syntax does not provide a way to replace substitution variables with values, you can use substitution variables only with applications that allow you to define values interactively or in batch processing. The following statement allows you to insert data into the Course table by providing the course name, description, and credit hours.

INSERT INTO Course (name, description, credit_hours) VALUES (@vName, @vDescription, @vCreditHours);
The identifiers @vName, @vDescription, and @vCreditHours are substitution variables. Before you can execute the statement, you must define values for these variables to Scalable SQL. You can use substitution variables in place of character strings or numeric constants in the following types of clauses:

‹ ‹ ‹ ‹

WHERE HAVING VALUES (in an INSERT statement) SET (in an UPDATE statement)
Note

You cannot use substitution variables in place of column names or table names.

Database Design Guide

163

Storing Logic

The following rules apply to the names of substitution variables:

‹ ‹ ‹ ‹ ‹ ‹ ‹

a through z A through Z 0 through 9 _ (underscore) ^ (caret) ~ (tilde) $ (dollar sign)

The syntax description for each type of statement that allows substitution variables includes details about how to specify the variables. Refer to the SQL Language Reference for the syntax description of each SQL statement.

Procedure-Owned Variables
A SQL variable you define inside a stored procedure is a procedure-owned variable. Its scope is that procedure in which it is declared; you can only refer to it within that procedure. If a procedure calls another procedure, the procedure-owned variable of the calling procedure cannot be directly used in the called procedure; instead, it must be passed in a parameter. You cannot declare a procedure-owned variable more than once in the same stored procedure; if you do, Scalable SQL returns Status Code 807. If a compound statement is the body of a stored procedure, then no SQL variable name declared in that procedure can be identical to a parameter name in the parameter list of that procedure. For more information about compound statements, refer to "Compound Statement."

Database Design Guide

164

Storing Logic

Session Variables
A SQL variable you define outside of any stored procedure is a session variable. Its scope is the user’s login session, and you can refer to it anywhere inside or outside of procedures. Once you have declared a session variable, it remains for the duration of that session. You cannot declare a session variable more than once during the same user’s login session; if you do, Scalable SQL returns Status Code 807. You must declare the SQL variable before any reference to the SQL variable name. However, you can declare the same SQL variable name in different procedures as well as declaring that name as a session variable. If the same SQL variable name appears in a procedure and as a session variable, then a reference to the variable name within that procedure references the procedure-owned variable.

Assignment Statement
The assignment statement initializes or changes the values of SQL variables. The value expression may be a computed expression involving constants, operators, and this or other SQL variables. SET CourseName = 'HIS305'; The value expression may also be a SELECT statement. SET MaxEnrollment = (SELECT Max_Size FROM Class WHERE ID = classId); For more information about the syntax of this statement, refer to the SQL Language Reference.

Database Design Guide

165

Storing Logic

SQL Cursor-Based Statements
You use SQL cursor-based statements in row-based data manipulation statements. You can use these statements either inside or outside stored procedures as independent, single SQL statements. The cursor-based statements consist of the following:

‹ ‹ ‹ ‹ ‹ ‹

SQL Cursor Declaration Open Cursor Fetch Positioned Delete Positioned Update Close Cursor
Note

Developers: Cursors declared with a SQL cursor declaration statement are not the same as the cursor ID allocated as a result of the SQL-level function call, XQLCursor. For more information about these cursors, see the Scalable SQL Programmer’s Guide.

A cursor is in a closed state at the point you declare it, or following a CLOSE statement. You must first open a closed cursor using the OPEN statement before you can use it in any row-based data manipulation statement. Data manipulation statements are based on the current position of the cursor. The current position during the open state of the cursor is either before the first row, on a row, or after the last row. When you initially open a cursor, the position of the cursor is before the first row. If a cursor is on a row, that row is the current row of the cursor. A cursor may be before the first row of a table or after the last row of a table even though the table is empty.

Database Design Guide

166

Storing Logic

A cursor can only move forward through the query results unless you specify the SCROLL option when declaring the cursor. A scroll cursor allows you to move backward as well as forward, or to the first row, the last row, or to a relative row. When declaring a cursor, you can specify whether or not that cursor is read-only or updatable. If you specify FOR UPDATE for the cursor, then the view defined by the query expression must be updatable. In a scroll cursor, the updatability clause is READ ONLY by default. You use the FETCH statement to position an open cursor on a specified row and to retrieve the values of the columns of that row. If you specify any positioning option other than NEXT, then the cursor must be a scroll cursor. To delete the current row of the cursor, use a Positioned DELETE statement. To update the current row of the cursor, use a Positioned UPDATE statement. You must execute a FETCH statement on the cursor before you can issue a Positioned UPDATE or Positioned DELETE statement. To close a cursor, issue a CLOSE statement. Once you close a cursor, you can reopen it with an OPEN statement, which re-establishes the cursor before the first row. For more information about these statements and their syntax, refer to the SQL Language Reference.

SQL Cursor Declaration
A DECLARE CURSOR statement defines a SQL cursor. A declared cursor logically ties a SELECT statement to a cursor name. DECLARE cursor1 CURSOR FOR SELECT Name FROM Course WHERE Name = CourseName; The maximum length for a cursor name is 255 characters.
Database Design Guide 167 Storing Logic

For more information about the syntax of the DECLARE CURSOR statement, refer to the SQL Language Reference.

Procedure-Owned Cursors
A SQL cursor defined inside a stored procedure is a procedure-owned cursor. Its scope is the procedure itself; therefore, you can refer to it only within the procedure.

Session Cursors
A SQL cursor you define outside of a procedure is a session cursor. You can reference a session cursor inside a stored procedure. Its scope is the user’s login session. You must declare a SQL cursor before any reference to the cursor name. However, you can declare the same SQL cursor name in one or more procedures as well as declaring that name as a session cursor. If the same SQL cursor name appears in a procedure and as a session cursor, then a reference to the cursor name within that procedure references the procedure-owned cursor.

Open Cursor Statement
An OPEN CURSOR statement opens a cursor. OPEN cursor1; The cursor specified by cursor name must not be open when you issue the OPEN statement. The current position of the cursor is before the first row of the table. For more information about the syntax of the OPEN cursor statement, refer to the SQL Language Reference.
Database Design Guide 168 Storing Logic

FETCH Statement
A FETCH statement positions a SQL cursor on a specified row of a table and retrieves values from that row. The specified cursor name must be open. FETCH NEXT FROM cursor1 INTO CourseName; If you do not specify the fetch orientation, NEXT is the default. If the cursor is not a scroll cursor, then the fetch orientation must be NEXT. For more information about the syntax of the FETCH statement, refer to the SQL Language Reference.

Positioned DELETE Statement
A Positioned DELETE statement deletes the current row of a table associated with a SQL cursor. DELETE WHERE CURRENT OF cursor1; The referenced cursor name must be open, and it must be positioned on a row, not before the first row or after the last row. For more information about the syntax of the Positioned DELETE statement, refer to the SQL Language Reference.

Database Design Guide

169

Storing Logic

Positioned UPDATE Statement
A Positioned UPDATE statement updates the current row of a table associated with a SQL cursor. The cursor must be open and updatable, and it must be positioned on a row, not before the first row or after the last row. The Positioned UPDATE statement in the following example updates the course description “Modern European History” to “Ancient European History.” DECLARE CourseDescription CHAR(50) = 'Modern European History'; DECLARE OldDescription CHAR(50); DECLARE cursor1 CURSOR FOR SELECT Description FROM Course WHERE Description = CourseDescription; OPEN cursor1; FETCH NEXT FROM cursor1 INTO OldDescription; UPDATE SET Description = 'Ancient European History' WHERE CURRENT OF cursor1; In order to use the Positioned UPDATE statement, you must also use DECLARE CURSOR, OPEN CURSOR, and FETCH FROM cursorname statements. For more information about the syntax of the Positioned UPDATE statement, refer to the SQL Language Reference.

Database Design Guide

170

Storing Logic

SQL Control Statements
You can only use control statements in the body of a stored procedure. These statements control the execution of the procedure. The control statements include the following:

‹ ‹ ‹ ‹

Compound statement (BEGIN...END) IF statement (IF...THEN...ELSE) LEAVE statement Loop statements (LOOP and WHILE)

Compound Statement
A compound statement groups other statements together. BEGIN DECLARE NumEnrolled INT(4); DECLARE MaxEnrollment INT(4); DECLARE failEnrollment CONDITION FOR SQLSTATE '09000'; SET NumEnrolled = (SELECT COUNT (*) FROM Enrolls WHERE Class_ID = classId); SET MaxEnrollment = (SELECT Max_Size FROM Class WHERE ID = classId); IF (NumEnrolled >= MaxEnrollment) THEN SIGNAL failEnrollment ELSE SET NumEnrolled = NumEnrolled + 1; END IF; END
Database Design Guide 171 Storing Logic

You can use a compound statement in the body of a stored procedure or a trigger. For more information about triggers, see the section "SQL Triggers." Although you can nest compound statements within other compound statements, only the outermost compound statement can contain DECLARE statements. For more information about the syntax of compound statements, refer to the SQL Language Reference.

IF Statement
An IF statement provides conditional execution based on the truth value of a condition. IF (SQLSTATE = '02000' OR counter = NumRooms) THEN LEAVE Fetch_Loop; END IF; For more information about the syntax of the IF statement, refer to the SQL Language Reference.

LEAVE Statement
A LEAVE statement continues execution by leaving a compound statement or loop statement. LEAVE Fetch_Loop A LEAVE statement must appear inside a labeled compound statement or a labeled loop statement. The statement label from the LEAVE statement must be identical to the label of a labeled statement containing LEAVE. This label is called the corresponding label.

Database Design Guide

172

Storing Logic

Note

A compound statement can contain a loop statement; therefore, since you can embed loop statements, the statement label in a LEAVE statement can match the label of any of the embedded loops or the label of the body of the stored procedure.

For more information about the syntax of the LEAVE statement, refer to the SQL Language Reference.

LOOP Statement
A LOOP statement repeats the execution of a block of statements. FETCH_LOOP: LOOP FETCH NEXT cRooms INTO CurrentCapacity; IF (SQLSTATE = '02000' OR counter = NumRooms) THEN LEAVE FETCH_LOOP; END IF; SET counter = counter + 1; SET TotalCapacity = TotalCapacity + CurrentCapacity; END LOOP; If each statement in the SQL statement list executes without error and Scalable SQL does not encounter a LEAVE statement or invoke a handler, then execution of the LOOP statement repeats. A LOOP statement is similar to a WHILE statement in that execution continues while a given condition is true. If a LOOP statement has a beginning label, it is called a labeled LOOP statement. If you specify the ending label, then it must be identical to the beginning label.
Database Design Guide 173 Storing Logic

For more information about the syntax of the LOOP statement, refer to the SQL Language Reference.

WHILE Statement
A WHILE statement repeats the execution of a block of statements while a specified condition is true. FETCH_LOOP: WHILE (counter < NumRooms) DO FETCH NEXT cRooms INTO CurrentCapacity; IF (SQLSTATE = '02000') THEN LEAVE FETCH_LOOP; END IF; SET counter = counter + 1; SET TotalCapacity = TotalCapacity + CurrentCapacity; END WHILE; Scalable SQL evaluates the Boolean value expression. If it is true, then Scalable SQL executes the SQL statement list. If each statement in the SQL statement list executes without error and no LEAVE statement is encountered, then execution of the loop statement repeats. If the Boolean value expression is false or unknown, Scalable SQL terminates execution of the loop statement. If a WHILE statement has a beginning label, it is called a labeled WHILE statement. If you specify an ending label, it must be identical to the beginning label. For more information about the syntax of the WHILE statement, refer to the SQL Language Reference.

Database Design Guide

174

Storing Logic

Retrieving Status Information
During execution of a stored procedure, you may need information about the last completed statement. The control flow of your procedure may depend on the completion status of the previous operation. For example, you may retrieve data row by row with a FETCH statement inside a loop in a stored procedure, but you need to know whether or not the FETCH statement returned any data. If it has, the loop can continue; if it has not, the loop should terminate. If the status information shows that an error occurred during the execution of a stored procedure, you may need to take some special steps to resolve the error. You do this through condition handling. The SQLSTATE system variable provides the means for you to check the status of an operation.

SQLSTATE System Variable
Whenever Scalable SQL executes a SQL statement (including the call of a stored procedure), a status value is placed in the SQLSTATE system variable. This value indicates either that the statement completed or that an exception was raised during the execution of the statement. SQLSTATE is defined as a string of 5 characters, where the first 2 characters form a class value and the last 3 characters form a subclass value.

Database Design Guide

175

Storing Logic

There are two basic categories of conditions: completion conditions and exception conditions. The following three classes indicate completion conditions:

‹ ‹ ‹

Successful completion: class ‘00’, subclass ‘000’ Completion with warning: class ‘01’, subclass ‘000’ Completion with no data: class ‘02’, subclass ‘000’

All other classes indicate exception conditions. By default, the system continues execution beyond completion conditions, but halts execution when it encounters an exception condition. You can only change this default behavior using condition handlers. For more information about the SQLSTATE values and their meanings, refer to SQL Language Reference.

Exception and Completion Conditions
When a statement in a stored procedure returns an exception condition or a completion condition other than a successful completion, Scalable SQL checks to see if the procedure has a declared HANDLER associated with that condition. If it does, then the corresponding handler is invoked. Statements that you can use to handle exception and completion conditions include the following:

‹ ‹ ‹ ‹

DECLARE CONDITION statement DECLARE HANDLER statement SIGNAL statement RESIGNAL statement

Database Design Guide

176

Storing Logic

DECLARE CONDITION Statement
A DECLARE CONDITION statement declares a condition and an associated SQLSTATE value. DECLARE endData CONDITION FOR SQLSTATE '02000'; For more information about the syntax of the DECLARE CONDITION statement, refer to the SQL Language Reference.

DECLARE HANDLER Statement
A DECLARE HANDLER statement provides handlers for exception or completion conditions in a compound statement. DECLARE EXIT HANDLER FOR endData BEGIN SET TotalCapacity = tempCapacity; END; For more information about the syntax of the DECLARE HANDLER statement, refer to the SQL Language Reference.

Database Design Guide

177

Storing Logic

SIGNAL Statement
A SIGNAL statement explicitly sets the SQLSTATE system variable to a specified value. The following example signals the value of the SQLSTATE variable associated with the endData declared condition. IF (counter = NumRooms) THEN SIGNAL endData; END IF; For more information about the syntax of the SIGNAL statement, refer to the SQL Language Reference.

RESIGNAL Statement
You can use the RESIGNAL statement in a handler if you want to leave the SQLSTATE variable set to the value it had when the handler was invoked, and you do not know what that value was. Any successful statement sets SQLSTATE back to the success value. The purpose of the RESIGNAL statement is to preserve an original SQLSTATE value after an attempt to handle the condition has changed the SQLSTATE value, either by failing or succeeding. DECLARE EXIT HANDLER FOR endData BEGIN SET TotalCapacity = tempCapacity; RESIGNAL; END; A RESIGNAL statement can occur only in a handler action or in a procedure invoked by a handler. For more information about the syntax of the RESIGNAL statement, refer to the SQL Language Reference.
Database Design Guide 178 Storing Logic

SQL Triggers
Triggers are actions defined on a table that you can use to enforce consistency rules for a database. They are dictionary objects that identify the appropriate action for the DBMS to perform when a user executes a SQL data modification statement on that table. To declare a trigger, use the CREATE TRIGGER statement. CREATE TRIGGER CheckCourseLimit; The maximum size for a trigger name is 30 characters. To delete a trigger, use the DROP TRIGGER statement. DROP TRIGGER CheckCourseLimit; You cannot invoke a trigger directly; they are invoked as a consequence of an INSERT, UPDATE, or DELETE action on a table with an associated trigger. For more information about the syntax of these statements, refer to the SQL Language Reference.
Note

In order to prevent circumvention of triggers, Scalable SQL stamps the data file containing a trigger as a bound data file; this restricts access to Btrieve users and prevents the Btrieve user from performing an action that would fire the trigger in a Scalable SQL database. For more information, refer to "Understanding Database Rights."

Database Design Guide

179

Storing Logic

Timing and Ordering of Triggers
Since triggers execute automatically for a given event, it is important to be able to specify when and in what order the trigger or triggers should execute. You specify time and order when you create the trigger.

Specifying the Triggered Action Time
When an event that is associated with a trigger occurs, the trigger must execute either before the event or after the event. For example, if an INSERT statement invokes a trigger, the trigger must execute either before the INSERT statement executes or after the INSERT statement executes. CREATE TRIGGER CheckCourseLimit BEFORE INSERT ON Enrolls You must specify either BEFORE or AFTER as the triggered action time. The triggered action executes once for each row. If you specify BEFORE, the trigger executes before the row operation; if you specify AFTER, the trigger executes after the row operation.
Note

Scalable SQL does not invoke a trigger by enforcing an RI constraint. Also, a table may not have a DELETE trigger defined if an RI constraint may also cause the system to perform cascaded deletes on that table.

Database Design Guide

180

Storing Logic

Specifying Trigger Order
You may have situations in which an event invokes more than one trigger for the same specified time. For example, an INSERT statement may invoke two or more triggers that are defined to execute after the INSERT statement executes. Since these triggers cannot execute simultaneously, you must specify an order of execution for them. Since the following CREATE TRIGGER statement specifies an order of 1, any subsequent BEFORE INSERT triggers that you define for the table must have a unique order number greater than 1. CREATE TRIGGER CheckCourseLimit BEFORE INSERT ON Enrolls ORDER 1 You designate the order value with an unsigned integer, which must be unique for that table, time, and event. If you specify a duplicate order for the same time and event as other triggers defined for that table, Scalable SQL returns Status Code 365. If you anticipate inserting new triggers within the current order, leave gaps in the numbering to accommodate this. If you do not designate an order for a trigger, then the trigger is created with a unique order value that is higher than that of any trigger currently defined for that table, time, and event.

Database Design Guide

181

Storing Logic

Defining the Trigger Action
The trigger action executes once for each row. The syntax for the trigger action is as follows: CREATE TRIGGER CheckCourseLimit BEFORE INSERT ON Enrolls ORDER 1 REFERENCING NEW AS N FOR EACH ROW BEGIN CALL CheckMax (N.Class_ID); END; If the triggered action contains a WHEN clause, then the triggered SQL statement executes if the Boolean expression is true. If the expression is not true, then the triggered SQL statement does not execute. If no WHEN clause is present, then the triggered SQL statement executes unconditionally. The triggered SQL statement can be either a single SQL statement, including a stored procedure call (CALL procedure_name), or a compound statement (BEGIN...END).
Note

The triggered action must not change the subject table of the trigger; if you attempt to declare a trigger that contains an action on the subject table, Scalable SQL returns Status Code 903.

When you need to reference a column of the old row image (in the case of DELETE or UPDATE) or a column of the new row image (in the case of INSERT or UPDATE) in the

Database Design Guide

182

Storing Logic

triggered action, you must add a REFERENCING clause to the trigger declaration, as follows: REFERENCING NEW AS N The REFERENCING clause allows you to maintain information about the data that the trigger modifies.

Database Design Guide

183

Storing Logic

chapter

7

Managing Data

This chapter discusses the following topics:

‹ ‹ ‹ ‹

Defining relationships among tables Administering database security Controlling concurrency Atomicity in Scalable SQL databases

In most cases, you can use SQL statements to perform these database management tasks. You can also enter the SQL statements using an interactive application. For more information about using interactive applications, refer to the Pervasive.SQL User’s Guide. This chapter includes the following sections:

‹ ‹ ‹ ‹ ‹ ‹ ‹

Defining Relationships Among Tables Keys Referential Constraints RI in the University Database Administering Database Security Concurrency Controls Atomicity in Scalable SQL Databases

Database Design Guide

184

Managing Data

Defining Relationships Among Tables
You can use referential integrity (RI) with Scalable SQL to define how each table is related to other tables in the database. RI assures that when a column (or group of columns) in one table refers to a column (or group of columns) in another table, changes to those columns are synchronized. RI provides a set of rules that define the relationships between tables. These rules are known as referential constraints. (Referential constraints are also informally referred to as relationships.) When you define referential constraints for tables in a database, the MicroKernel Database Engine enforces the constraints across all applications that access those tables. This frees the applications from checking table references independently each time an application changes a table. You must name your database in order to use RI. Once you have defined referential constraints, each affected data file contains the database name. When someone attempts to update a file, the MicroKernel uses the database name to locate the data dictionary containing the applicable RI definitions and checks the update against those RI constraints. This prevents both Scalable SQL and Btrieve applications from compromising RI, since the MicroKernel blocks updates that do not meet referential constraints. To define referential constraints on the tables in a database, use CREATE TABLE and ALTER TABLE statements. Refer to the SQL Language Reference for the syntax of these statements.

Database Design Guide

185

Managing Data

Referential Integrity Definitions
The following definitions are useful in understanding referential integrity.

‹ ‹ ‹

A parent table is a table that contains a primary key referenced by a foreign key. A parent row is a row in a parent table whose primary key value matches a foreign key value. A delete-connected table occurs if your deletion of rows in one table causes the deletion of rows in a second table. The following conditions determine whether tables are delete-connected:
Š A self-referencing table is delete-connected to itself. Š Dependent tables are always delete-connected to their parents, regardless of the delete rule. Š A table is delete-connected to its grandparents when the delete rules between the parent and grandparents is CASCADE.

‹ A dependent table is a table that contains one or more foreign keys. Each of

these foreign keys can reference a primary key in either the same or a different table. A dependent table can contain multiple foreign keys. Every foreign key value in a dependent table must have a matching primary key value in the associated parent table. In other words, if a foreign key contains a particular value, the primary key of one of the rows in the foreign key’s parent table must also contain that value. Attempting to insert a row into a dependent table fails if the parent table for each referential constraint does not have a matching primary key value for the foreign key value in the dependent table row being inserted. Attempting to delete a row in a parent table to which foreign keys currently refer either fails or causes the dependent rows to be deleted as well, depending on how you have defined the referential constraints.
Database Design Guide 186 Managing Data

‹ ‹ ‹ ‹ ‹ ‹ ‹

A dependent row is a row in a dependent table; its foreign key value depends on a matching primary key value in the associated parent row. An orphan row is a row in a dependent table that has a foreign key value that does not exist in the index corresponding to the parent table’s primary key. The dependent key value does not have a corresponding parent key value. A reference is a foreign key that refers to a primary key. A reference path is a particular set of references between dependent and parent tables. A descendant is a dependent table on a reference path. It may be one or more references removed from the path’s original parent table. A self-referencing table is a table that is its own parent table; the table contains a foreign key that references its primary key. A cycle is a reference path in which the parent table is its own descendant.

Database Design Guide

187

Managing Data

Keys
To use RI, you must define keys. There are two types of keys: primary and foreign. A primary key is a column or group of columns whose value uniquely identifies each row in a table. Because the key value is always unique, you can use it to detect and prevent duplicate rows. A foreign key is a column or set of columns that is common to the dependent and parent tables in a table relationship. The parent table must have a matching column or set of columns that is defined as the primary key. Foreign keys reference primary keys in a parent table. It is this relationship of a column in one table to a column in another table that provides the MicroKernel with its ability to enforce referential constraints.

Primary Keys
A good primary key has these characteristics:

‹ ‹

It is mandatory; it must store non-null values. It is unique. For example, the ID column in a Student or Faculty table is a good key because it uniquely identifies each individual. It is less practical to use a person’s name because more than one person might have the same name. Also, databases do not detect variations in names as duplicates (for example, Andy for Andrew or Jen for Jennifer). It is stable. The ID of a student is a good key not only because it uniquely identifies each individual, but it is also unlikely to change, while a person’s name might change. It is short; it has few characters. Smaller columns occupy less storage space, database searches are faster, and entries are less prone to mistakes. For example, an ID column of 9 digits is easier to access than a name column of 30 characters.
188 Managing Data

‹ ‹

Database Design Guide

Creating Primary Keys
You create a referential constraint by creating a foreign key on a table. However, before creating the foreign key, you must create a primary key on the parent table to which the foreign key refers. A table can have only one primary key. You can create a primary key using either of the following:

‹ ‹

A PRIMARY KEY clause in a CREATE TABLE statement. An ADD PRIMARY KEY clause in an ALTER TABLE statement.

The following example creates the primary key ID on the Person table in the sample database: ALTER TABLE Person ADD PRIMARY KEY (ID); When creating a primary key, remember that Scalable SQL implements the primary key on the table using a unique, non-null, non-modifiable index. If one does not exist for the specified columns, then Scalable SQL adds a non-named index with these attributes containing the columns specified in the primary key definition.

Dropping Primary Keys
You can delete a primary key only after you have dropped all foreign keys that depend on it. To drop a primary key from a table, use a DROP PRIMARY KEY clause in an ALTER TABLE statement. Since a table can have only one primary key, you do not have to specify the column name when you drop the primary key, as the following example illustrates: ALTER TABLE Person DROP PRIMARY KEY;
Database Design Guide 189 Managing Data

Changing Primary Keys
To change a table’s primary key, follow these steps: 1. Drop the existing primary key using a DROP PRIMARY KEY clause in an ALTER TABLE statement.
Note

Doing so does not remove the column, or the index used by the primary key; it only removes the primary key definition. To remove the primary key, there must be no foreign key referencing the primary key. 2. Create a new primary key using an ADD PRIMARY KEY clause in an ALTER TABLE statement.

Foreign Keys
A foreign key is a column or set of columns that is common to the dependent and parent tables in a table relationship. The parent table must have a matching column or set of columns that is defined as the primary key. When you create a foreign key, you are creating a referential constraint, or a data link, between a dependent table and its parent table. This referential constraint can include rules for deleting or updating dependent rows in the parent table. The foreign key name is optional. If you do not specify a foreign key name, Scalable SQL tries to create a foreign key using the name of the first column in the foreign key definition. For more information about naming conventions for foreign keys and other database elements, refer to "Naming Conventions." Because Scalable SQL keywords are reserved words, you cannot use them in naming database elements. For a list of the Scalable SQL keywords, refer to the SQL Language Reference.
Database Design Guide 190 Managing Data

Creating Foreign Keys in Existing Tables
To create a foreign key in an existing table, follow these steps: 1. Ensure that a primary key exists in the parent table you are referencing. All columns in the primary and foreign key must be of the same data type and length, and the set of columns must be in the same order in both definitions. 2. Scalable SQL creates a non-null index for the column or group of columns specified in the foreign key definition. If the table definition already has such an index, Scalable SQL uses that index; otherwise, Scalable SQL creates a nonnamed index with the non-null, non-unique, and modifiable index attributes. 3. Create the foreign key using an ADD FOREIGN KEY clause in an ALTER TABLE statement. For example, the following statement creates a foreign key called Faculty_Dept on the column Dept_Name in the Faculty table of the sample database. The foreign key references the primary key created in the Department table and specifies the delete restrict rule. ALTER TABLE Faculty ADD FOREIGN KEY Faculty_Dept (Dept_Name) REFERENCES Department ON DELETE RESTRICT;

Creating Foreign Keys When Creating a Table
To create a foreign key when creating the table, follow these steps: 1. Ensure that a primary key exists in the parent table you are referencing. All columns in the primary and foreign key must be of the same data type and length, and the set of columns must be in the same order in both definitions.

Database Design Guide

191

Managing Data

2. Scalable SQL creates a non-null index for the column or group of columns specified in the foreign key definition. If the table definition already has such an index, Scalable SQL uses that index; otherwise, Scalable SQL creates a nonnamed index with the non-null, non-unique, and modifiable index attributes. 3. Create the table using a CREATE TABLE statement and include a FOREIGN KEY clause. For example, the following statement creates a foreign key called Course_in_Dept on the column Dept_Name in a table called Course. CREATE TABLE Course USING 'course.mkd' (FOREIGN KEY Course_in_Dept (Dept_Name) REFERENCES Department ON DELETE RESTRICT, Name CHAR(7) CASE, Description CHAR(50) CASE, Credit_Hours UNSIGNED(2), Dept_Name CHAR(20) CASE) WITH INDEX (Name UNIQUE CASE, Dept_Name CASE MOD);

Dropping Foreign Keys
To delete a foreign key from a table, use a DROP FOREIGN KEY clause in an ALTER TABLE statement. You must specify the foreign key name since a table can have more than one foreign key. ALTER TABLE Course DROP FOREIGN KEY Course_in_Dept;

Database Design Guide

192

Managing Data

Referential Constraints
Databases on which you define referential constraints must meet the following requirements:

‹ ‹ ‹

The database must have a database name. The database must reside on a single workstation drive or a single mapped network drive. The data files must be in 6.x or later MicroKernel format. For information about converting 5.x or later data files to 6.x or 7.x format, refer to the Pervasive.SQL User’s Guide.

In order for a database to support referential integrity it must also support the concept of foreign keys. A foreign key is a column or set of columns in one table (called the dependent table) that is used to reference a primary key in another table (called the parent table). The RI rule requires all foreign keys’ values to reference valid primary key values. For example, a student cannot enroll in a nonexistent course. You can use a CREATE TABLE or ALTER TABLE statement to define keys on a table in a named database. The following sections explain how to create and modify keys. These sections also provide examples of referential constraints. After you define referential constraints on a database, applications that do not perform data updates according to referential rules may fail. For example, if an application tries to insert a row into a dependent table before inserting the corresponding parent row into the parent table, the insertion fails. Refer to the section “Referential Integrity Rules” for more information.

Database Design Guide

193

Managing Data

Note

If a file has referential constraints defined, it is a bound data file. If a user tries to access it with Btrieve, then the Btrieve user can access the file, but can only perform actions within RI constraints. For more information about bound data files, refer to the section "Understanding Database Rights."

Referential Integrity Rules
Certain rules apply to inserting and updating rows in dependent tables and updating and deleting rows in parent tables when you define referential constraints on database tables. Scalable SQL supports the restrict and cascade rules as follows:

‹ ‹ ‹ ‹

Insert into dependent table — The parent table for each foreign key definition must have a corresponding primary key value for the foreign key value being inserted. If any parent table does not have a corresponding value, then the Insert operation fails. Update in the dependent table — The parent table for each foreign key definition must have a corresponding primary key value for the foreign key value (the new value for the foreign key). If any parent table does not have a corresponding value, then the Update operation fails. Update in the parent table — This is not allowed. You cannot update primary key values. To perform a similar operation, delete the row you want to update, then insert the same row with the new primary key value. Delete in the parent table — You can specify either the cascade or restrict rule for this operation. Cascade means that if a dependent table contains a foreign key value that matches the primary key value being deleted, then all rows containing that matching value are deleted from the dependent table also. Restrict means that if a dependent table contains a foreign key value that
194 Managing Data

Database Design Guide

matches the primary key value being deleted, then the Delete operation on the parent table fails. The cascade operation is recursive; if the dependent table has a primary key that is the parent table of a cascade foreign key, then the process is repeated for that set of data.

Insert Rule
The insert rule is a restrict rule. For each foreign key in the row being inserted, the foreign key value must be equivalent to a primary key value in the parent table. The parent table must contain a parent row for the foreign key in the row you are inserting; otherwise, the insertion fails. Scalable SQL causes the MicroKernel to automatically enforce the insert rule on dependent tables. Figure 7-1 shows an attempted insert into the Course table. Since the parent table, Department, does not contain the Government Department, Scalable SQL does not insert the row in the Course table.

Database Design Guide

195

Managing Data

Figure 7-1

Unsuccessful Insert Operation

Department Table Primary Key: Department.Name Name French German History Phone_Number Building_Name 5125558909 5125558569 5125558120 Bartold Building Boerner Building McAnally Building Room_Number Head_of_Department 307 206 104 123771790 126281925 128802059

Foreign Key Reference Course Table Foreign Key: Course.Dept_Name (references Department.Name) Name GER204 GER305 GER406 GOV101 Description German IV Studies in German Literature Advanced German Literature Introduction to Government Credit Hours 3 3 3 3 Dept_Name German German German Government

INSERT operation fails

Update Rule
The update rule is restrict. A foreign key value must be updated to an equivalent primary key value in the parent table. If the parent table does not contain a parent row for the foreign key value, the update fails. You can explicitly specify the update rule as restrict when you define a foreign key on a table; however, Scalable SQL causes the MicroKernel to enforce the rule by default if you do not specify it.

Database Design Guide

196

Managing Data

Delete Rule
You can explicitly specify the delete rule as either restrict or cascade when you define a foreign key. If you do not specify the delete rule explicitly, Scalable SQL assumes a default of restrict for the delete rule.

‹

If you specify restrict as the delete rule, Scalable SQL causes the MicroKernel to check each row you attempt to delete from a parent table to see if that row is a parent row for a foreign key in another table. If it is a parent row, Scalable SQL returns a status code and does not delete the row. You must first delete all corresponding rows in the referenced table or tables before you can delete the parent row. If you specify cascade as the delete rule, Scalable SQL causes the MicroKernel to check each row you attempt to delete from a parent table to see if that row is a parent row for a foreign key in another table. The MicroKernel then checks the delete rule for each descendant of that table. If any descendant has restrict as the delete rule, the attempted deletion fails. If all descendants have cascade as the delete rule, Scalable SQL deletes all dependent rows on the reference path to the original parent table.

‹

The following guidelines govern the delete rule for foreign keys:

‹ ‹ ‹ ‹ ‹

The delete rule for a self-referencing table must not be restrict. A cycle with two or more tables cannot be delete-connected to itself. Consequently, the delete rule for at least two of the dependent tables in the cycle must not be cascade. The last delete rule in all paths from one table to another must be the same. If the delete rule for the foreign key is cascade, then the table containing the foreign key may not have a delete trigger defined on it. If the table containing the foreign key has a delete trigger defined on it, then the delete rule must be restrict.
197 Managing Data

Database Design Guide

Scalable SQL enforces these guidelines on databases that have referential constraints defined. If you attempt to declare delete rules that violate these guidelines, Scalable SQL returns a status code to indicate an error occurred. Following are some common status codes you might receive: Status Code
882 883 884 885

Description
The delete rule for self-referencing tables must not be restrict. The delete rule for at least two of the foreign key connections in the cycle must not be cascade. The delete rules for multiple paths to the same parent table must match. Scalable SQL allows a maximum of 16 adjacent delete cascade rules in a reference path.

Figure 7-2 represents an attempt to delete the row that contains the primary key value Young Building, 200 from the Room table. However, this row is a parent row for one of the rows in the Department table. (One of the rows in Department has a foreign key value of Young Building, 200.) The delete rule defined for the foreign key is restrict; therefore, Scalable SQL does not delete the row.

Database Design Guide

198

Managing Data

Figure 7-2

Unsuccessful Delete Operation

Room Table Primary Key: Room.Building_Name, Room.Room_Number Building_Name Currah Building Faske Building Young Building Room_Number 318 101 200 Capacity 1 1 1 Type Office Office Office

Delete Operation Fails

Foreign Key Reference Department Table Foreign Key: Department.Building_Name, Department.Room_Number Name Phone_Number Building_Name Currah Building Faske Building Young Building Room_Number Head_of_Department 318 101 200 113711250 116221385 118741520

5125558345 Communication Computer Science 5125558123 5125558823 Economics

Scalable SQL enforces the delete rule guidelines to avoid certain anomalies that might otherwise occur when you delete dependent rows from tables. Following are examples of anomalies that might occur without these guidelines.

Anomaly on Self-Referencing Tables
The delete rule for a self-referencing table must be cascade. As Figure 7-3 and the accompanying example show, the results of delete operations can be inconsistent without this rule.

Database Design Guide

199

Managing Data

Figure 7-3 shows a subset of a table named Faculty_Head.

Figure 7-3

Anomaly on Self-Referencing Tables
Faculty_Head Table Primary Key: Faculty_Head.ID Foreign Key: Faculty_Head.Head_of_Dept ID 180086510 176188111 125861123 Dept_Name English English Computer Science Head_of_Dept 180086510 180086510 175053812

Restrict

The following statement deletes all faculty in the English Department. DELETE FROM Faculty_Head WHERE Dept_Name = 'English'; This statement succeeds if Scalable SQL deletes the rows in the following order: 1. The row in which the primary key value equals 176188111. 2. The row in which the primary key value equals 180086510. However, if Scalable SQL attempts to delete the rows in any other order, the delete operation fails. To avoid such inconsistencies, specify the delete rule for Head_of_Dept as cascade. This guideline ensures that all rows that subsequently reference the initially deleted row are also deleted. When deleting rows from a self-referencing table, be sure that your statement does not inadvertently delete all or most of the rows in the table.
Database Design Guide 200 Managing Data

Anomaly on Delete-Connected Cycles
A cycle with two or more tables cannot be delete-connected to itself. Consequently, the delete rule for at least two of the dependent tables in the cycle must be restrict. Figure 7-4 shows an anomaly that might occur without this guideline.

Figure 7-4

Anomaly on Delete-Connected Cycle
Faculty Table ID Dept_Name Department Table Name Head_of_Department

181831941 Mathematics 179321806 Mathematics 310082269 Sociology

Mathematics 181831941 Sociology 310082269

Restrict

Cascade

Assume you want to execute the following statement. DELETE FROM Faculty Because of the relationships between the Faculty and Department tables, deleting a row from Faculty first deletes a row from Faculty, then from Department, where the cascaded delete stops because of the restrict rule on the name of the department. The results could be inconsistent, depending on the order in which Scalable SQL deletes rows from the Faculty table. If it attempts to delete the row in which the ID is 181831941, the delete operation fails. The restrict rule on the Department name prevents Scalable SQL from deleting the first row in the department table in which the primary key value
Database Design Guide 201 Managing Data

equals Mathematics, since the second row in Faculty continues to reference this row’s primary key. If instead, Scalable SQL deletes the Faculty rows in which the primary keys equal 179321805 and 310082269 first (in either order), all the rows in Faculty and Department are deleted. Figure 7-5 shows how you can avoid this anomaly by specifying the two delete rules as restrict.

Figure 7-5

Prevention of a Delete-Connected Cycle
Faculty Table ID Dept_Name Department Table Name Head_of_Department

181831941 Mathematics 179321806 Mathematics 310082269 Sociology

Mathematics 181831941 Sociology 310082269

Restrict

Restrict

Since the result of the example DELETE statement is consistent, no rows are deleted.

Anomaly on Multiple Paths
Delete rules from multiple delete-connected paths must be the same. Figure 7-6 shows an example of one anomaly that might occur without this guideline. In the figure, the arrows point to the dependent tables.
Database Design Guide 202 Managing Data

Figure 7-6

Multiple Paths Anomaly
Room Restrict Cascade

Faculty

Cascade

Department

Faculty is delete-connected to Room through multiple delete-connected paths with different delete rules. Assume you want to execute the following statement. DELETE FROM Room WHERE Building_Name = 'Bhargava Building' AND Number = 302; The success of the operation depends on the order in which Scalable SQL accesses Faculty and Department to enforce their delete rules.

‹ ‹

If it accesses Faculty first, the delete operation fails because the delete rule for the relationship between Room and Faculty is restrict. If it accesses Department first, the delete operation succeeds, cascading to both Department and Faculty.

To avoid problems, Scalable SQL insures that the delete rules for both paths that lead to Faculty are the same.

Database Design Guide

203

Managing Data

RI in the University Database
This section demonstrates the table and referential constraint definitions on the sample database.

Creating the Course Table
The following statement creates the Course table. CREATE TABLE Course USING 'course.mkd' (Name CHAR(7) CASE, Description CHAR(50) CASE, Credit_Hours UNSIGNED(2), Dept_Name CHAR(20)) WITH INDEX (Name UNIQUE CASE, Dept_Name CASE MOD);

Adding a Primary Key to Course
The following statement adds a primary key (Name) to the Course table. ALTER TABLE Course ADD PRIMARY KEY (Name);

Database Design Guide

204

Managing Data

Creating the Student Table with Referential Constraints
The following statement creates the Student table and defines its referential constraints. CREATE TABLE Student USING 'Student.mkd' (PRIMARY KEY (ID), FOREIGN KEY S_Tuition (Tuition_ID) REFERENCES Tuition, FOREIGN KEY S_Major (Major) REFERENCES Department, FOREIGN KEY S_Minor (Minor) REFERENCES Department, ID UNSIGNED(8), Cumulative_GPA NUMERICSTS(5,3), Tuition_ID INTEGER(4), Transfer_Credits NUMERICSA(4,0), Major CHAR(20) CASE, Minor CHAR(20) CASE, Scholarship_Amount DECIMAL(10,2), Cumulative_Hours INTEGER(2)) WITH INDEX (ID UNIQUE, Tuition_ID); Figure 7-7 shows the foreign key references on the Student, Tuition, and Department tables and includes sample rows from each table.

Database Design Guide

205

Managing Data

Figure 7-7

Foreign Key References
Foreign Key: Tuition_ID (references Tuition.ID) Foreign Key: Major (references Department.Name) Foreign Key: Minor (references Department.Name) Cumulative_GPA Tuition_ID 8 8 Transfer_Credits Major 0 0 Accounting Accounting Minor Chemistry Theatre

Student Table

ID

4.000 158974022 3.633 219333635 Foreign Key Reference

Foreign Key Reference Foreign Key Reference Department Table Name Tuition Table Primary Key: ID ID 3 8 Degree BBA NONE Phone_Number Primary Key: Name Building_Name Bhargava Building Currah Building Room_Number 302 318

Accounting 5126941000 Chemistry 5126941500 Cost_Per_Credit 1.250000E+02 2.500000E+02

Residency True False

Comments 1 Bachelor of Business... # no degree program ...

Database Design Guide

206

Managing Data

Administering Database Security
The Scalable SQL security option allows you to protect your data by limiting operations on some data columns to particular users. These limits may range from allowing a user to see only certain columns in a table, to allowing them to see all the columns in a table, but not update them. Scalable SQL makes no assumptions about database authorization based on the operating system’s file and directory rights. By default, all users accessing a database through Scalable SQL have complete read-write access to the data. You must enable and define database security to limit this access and protect the database from unauthorized update or access through Scalable SQL. Scalable SQL security statements allow you to perform the following actions to limit access to your database:

‹ ‹ ‹ ‹ ‹ ‹ ‹

Enable security for the database. Identify users and groups of users and assign passwords to them. Grant rights to users and user groups. Revoke rights from users and user groups. Disable security for the database. Specify data file owner names. Retrieve information about security defined for a database.

Database Design Guide

207

Managing Data

Understanding Database Rights
Table 7-1 shows the rights you can grant to users and user groups.

Table 7-1
Right
Login

Database Rights
Description
Allows a user to log in to a database. You assign this right when you create a user and a password. The Login right does not give users access to data, however. You must assign other rights to users before they can access data. You cannot assign the Login right to a user group.

Create Table Enables a user to create new table definitions. The user automatically has full access rights to the tables he or she creates at the time of creation, but the Master User can later revoke read, write, and alter rights for the table. The Create Table right is also referred to as a global right, because it applies to the entire data dictionary. Select Update Insert Delete Alter References All Allows a user to query tables for information. You can grant the Select right for specific columns or for a whole table. Gives a user the right to update information in specified columns or tables. You can grant the Update right for specific columns or for a whole table. Allows a user to add new rows to tables. You can grant the Insert right only at the table level. Allows a user to delete information from tables. You can grant the Delete right only at the table level. Allows a user to change the definition of a table. You can grant the Alter right only at the table level. Allows a user to create foreign key references that refer to a table. The References right is necessary for defining referential constraints. Includes Select, Update, Insert, Delete, Alter, and References rights.

Database Design Guide

208

Managing Data

Many rights automatically imply other rights. When you grant or revoke certain rights, you implicitly grant or revoke additional rights. Figure 7-8 shows the relationships among rights.

Figure 7-8

Relationships Among Rights

References

Alter

Login Delete

Update

Insert

Select All

Table 7-2 lists the implied rights granted for each Scalable SQL right you grant.

Table 7-2

Granting Rights
Implicitly Grants These Rights
None None Select, Insert, Update, Delete, and Alter None

Explicitly Granting This Right
Select Create Table References Login

Database Design Guide

209

Managing Data

Table 7-2

Granting Rights continued
Implicitly Grants These Rights
Select Select, Insert, Delete Select, Update, Delete Select, Update, Insert Select, Update, Insert, Delete Select, Update, Insert, Delete, Alter, References

Explicitly Granting This Right
Update (columns) Update (tables) Insert Delete Alter All

Table 7-3 lists the implied rights revoked for each Scalable SQL right you revoke.

Table 7-3
Select

Revoking Rights
Implicitly Revokes These Rights
Update, Insert, Delete, Alter, References Insert, Delete, Update (columns), Alter None None None Insert, Delete, Alter, References Update, Delete, Alter, References Update, Insert, Alter, References References Select, Update, Insert, Delete, Alter, References

Explicitly Revoking This Right
Select (columns) References Login Update (columns) Update (tables) Insert Delete Alter All

Database Design Guide

210

Managing Data

When you grant or revoke one of the following table rights for a user, Scalable SQL also grants and revokes the other two rights at the table level, as well as the user’s Alter rights. This does not apply to column-specific Update rights.

‹ ‹ ‹

Delete Insert Update

You can assign certain types of rights over the whole database or for a particular database element. For example, when you assign the Update right to a user or user group, you can limit it to certain tables or to certain columns in tables. In contrast, when you assign the Create Table right to a user or user group, that user or user group has the Create Table right for the entire database. You cannot apply the Create Table right to a single table or column. While the Create Table and Login rights apply to the entire database, all other rights apply to tables. In addition, you can apply Select and Update rights to individual columns in tables.

Establishing Database Security
The following steps describe the general procedure for establishing security for a database. 1. Log in to the database for which you want to establish security. For more information about logging in to a database, refer to the Pervasive.SQL User’s Guide for your platform. 2. Enable security for the database by creating the master user and specifying the master password with the SET SECURITY statement.

Database Design Guide

211

Managing Data

After you have enabled security, the name of the master user is Master (casesensitive), and the password you specified when you enabled security becomes the master password (also case-sensitive). For more information, refer to "Enabling Security." 3. Log out of the database and log back in as the master user. 4. Optional: Define a minimal set of rights for the PUBLIC group. All users automatically belong to the PUBLIC group. For more information, refer to "Granting Rights to the PUBLIC Group." 5. Optional: Create user groups with the CREATE GROUP statement. You can create as many groups as you need for your system. However, a user can belong to only one group other than PUBLIC. For more information, refer to "Creating User Groups." 6. Optional: Grant rights to each user group with the GRANT CREATETAB and GRANT (access rights) statements. For more information, refer to "Granting Rights to User Groups." 7. Grant login privileges to users by specifying the users’ names and passwords with the GRANT LOGIN statement, and if you choose, assign each user to a user group. For more information, refer to "Creating Users." 8. Grant rights to the users you have created who are not members of a user group using the GRANT CREATETAB and GRANT (access rights) statements. For more information, refer to "Granting Rights to Users." 9. Optional: To protect your files from unauthorized Btrieve access, assign file owner names when you create tables using the CREATE TABLE statement.

Database Design Guide

212

Managing Data

If you assign owner names, users may execute the SET OWNER statement to allow access to the data files during a login session. Another way to protect your files from Btrieve access is to make the database a bound database. For more information about bound databases, refer to "Understanding Database Rights."

Enabling Security
You can use a SET SECURITY statement to enable security. In response, Scalable SQL creates the master user, who has complete read-write access to the database. The password you specify with a SET SECURITY statement becomes the master password for the database. The following example enables security for a database and specifies the password for the master user as Secure: SET SECURITY = Secure; Passwords are case-sensitive. When you enable security, Scalable SQL creates the system tables X$User and X$Rights. Enabling security excludes all users except the master user from accessing the database until you explicitly create other users and grant them login rights.

Creating User Groups and Users
After you enable security, your database has one user (Master) and one user group (PUBLIC). To provide other users access to the database, log in to the database as the master user and create users by name and password. You can also organize the users in user groups. User names are case-sensitive in Scalable SQL. Therefore, when you log in as the master user, you must specify the user name as Master.
Database Design Guide 213 Managing Data

Creating User Groups
To simplify security administration, you can organize users in user groups. You can create as many user groups as you need for your system. A user, however, can belong to only one group in addition to PUBLIC. Once the user is in an additional group, the user inherits the rights of that group, and you cannot grant individual rights to that user. The rights of a user in a group cannot differ from the rights defined for the entire group. To give a user unique rights, create a special group just for that user. To create a user group, use a CREATE GROUP statement. CREATE GROUP Accounting; You can also create multiple user groups at once. CREATE GROUP Accounting, Registrar, Payroll; User group names are case-sensitive, cannot exceed 30 characters, and must be unique to the database. For more information about rules for naming user groups, refer to the SQL Language Reference.

Creating Users
When you create a user for a database, Scalable SQL enters the corresponding user name and password into the database’s security tables. To create a user, use a GRANT LOGIN TO statement. The following example creates the user Cathy and assigns Passwd as her password. GRANT LOGIN TO Cathy : Passwd;
Note

Scalable SQL stores passwords in encrypted form. Therefore, you cannot query the X$User table to view user passwords.

Database Design Guide

214

Managing Data

You can also assign a user to a user group when you create the user. For example, to assign the user Cathy to the Accounting group, use the following statement: GRANT LOGIN TO Cathy : Passwd IN GROUP Accounting; User names and passwords are case-sensitive. User names cannot exceed 30 characters and must be unique to the database. Passwords cannot exceed 8 characters, and passwords do not have to be unique to the database. For more information about rules for user names and passwords, refer to the SQL Language Reference.

Granting Rights
This section explains how to grant rights to user groups and individual users.

Granting Rights to the PUBLIC Group
All users automatically belong to the PUBLIC group, a special user group used to define the minimum set of rights for all users of a particular database. No user can have fewer rights than those assigned to the PUBLIC group. You cannot drop a user from the PUBLIC group, and you cannot revoke rights from a user if those rights are granted to the PUBLIC group. By default, the PUBLIC group has no rights. To change the rights of the PUBLIC group, use a GRANT (access rights) statement. For example, the following statement allows all users of the sample database to query the Department, Course, and Class tables in the database: GRANT SELECT ON Department, Course, Class TO PUBLIC;

Database Design Guide

215

Managing Data

After granting rights to the PUBLIC group, you can create other groups to define higher levels of access. You can also give individual users additional rights that differ from any other user or group, provided the user is not part of a group.

Granting Rights to User Groups
You can assign rights to a user group and add user names and passwords to the group. Doing so eliminates assigning each user’s rights individually. Also, security is easier to maintain if you assign security rights to groups, since you can change the rights of many users by granting new rights or revoking existing rights for an entire group at once. To grant rights to a user group, use a GRANT (access rights) statement. For example, the following statement allows all users in the Accounting group to alter the Billing table definition in the sample database. GRANT ALTER ON Billing TO Accounting;
Note

Remember that granting the Alter right implicitly grants the rights Select, Update, Insert, and Delete.

Granting Rights to Users
After you create a user, that user can log in to the database. However, the user cannot access data until you either place the user in a user group with rights or grant rights to the user. To grant rights to a user, use a GRANT (access rights) statement. The following example allows the user John to insert rows into the billing table in the sample database. GRANT INSERT ON Billing TO John;
Database Design Guide 216 Managing Data

Note

Granting the Insert right implicitly grants the rights Select, Update, and Delete.

Dropping Users and User Groups
To drop (delete) a user, use a REVOKE LOGIN statement. REVOKE LOGIN FROM Bill; This statement removes the user Bill from the data dictionary. After you drop a user, the user cannot access any tables in the database unless you disable security for the database. You can also drop multiple users at once, as in the following example. REVOKE LOGIN FROM Bill, Cathy, Susan; To drop a user group, follow these steps: 1. Drop all users from the group, as in the following example: REVOKE LOGIN FROM Cathy, John, Susan; 2. Use a DROP GROUP statement to drop the group. The following example drops the Accounting group: DROP GROUP Accounting;

Database Design Guide

217

Managing Data

Revoking Rights
Revoking certain rights automatically revokes other rights. For example, if a user has the Insert right to a table and you revoke that right, you automatically revoke the user’s Delete, Update, Alter, and References rights to that table. For more information about revoking rights, refer to Table 7-3. To revoke a user’s rights, use the REVOKE statement. The following example revokes the user Ron’s Select, Update, Insert, Delete, and Alter rights from the Billing table of the sample database. REVOKE SELECT ON Billing FROM Ron;

Disabling Security
To disable security for a database, follow these steps: 1. Log in to the database as the master user. 2. Issue a SET SECURITY statement, specifying the NULL keyword, as follows: SET SECURITY = NULL; When you disable security for a database, Scalable SQL removes the X$User and X$Rights system tables from the database and deletes the associated .DDF files.
Note

You cannot disable security simply by deleting the USER.DDF and RIGHTS.DDF data dictionary files. If you delete these and try to access the database, Scalable SQL returns an error and denies access to the database.

Database Design Guide

218

Managing Data

Specifying Data File Owner Names
One way to protect the data files associated with your tables from unauthorized access by Btrieve applications is to specify data file owner names when you create the tables. (Another way is to use a bound database; for more information about bound databases, refer to "Understanding Database Rights.") A file owner name works like a password: a user must provide the owner name before the MicroKernel allows that user to access the corresponding data file. You can assign a file owner name to a table when you create the table using a CREATE TABLE statement. CREATE TABLE Tuition USING 'Tuition.mkd' OWNER 'Doris' (ID AUTOINC(4), Degree LSTRING(5) CASE, Residency LOGICAL(1), Cost_Per_Credit FLOAT(4), Comments LVAR(200)) WITH INDEX (ID UNIQUE, Degree CASE MOD, Residency MOD);
Note

Owner names are case-sensitive. Therefore, when you specify the owner name as Doris and a user sets the owner name as DORIS (using a SET OWNER statement), Scalable SQL denies the user access to the file.

You can also specify owner access restriction levels (0 through 3) on a file that has an owner name. These levels allow read access to users who do not set the owner name, and they allow you to specify data encryption. For more information, refer to the SQL Language Reference.

Database Design Guide

219

Managing Data

Once you specify an owner name for a file, users must use a SET OWNER statement to set the owner name at the beginning of each Scalable SQL session. If a user wants to access multiple data files that have different owner names, the user can set multiple owner names upon starting the Scalable SQL session. For example, the following statement sets three owner names: SET OWNER = Sally, Thomas, Doris;

Retrieving Information about Database Security
When you set up database security, Scalable SQL creates the system tables X$User and X$Rights. Because the system tables are part of the database, you can query them if you have the appropriate rights. For a complete reference to the contents of each system table, refer to the SQL Language Reference.

Database Design Guide

220

Managing Data

Concurrency Controls
The MicroKernel and its automatic recovery functions handle the physical integrity of your database. Scalable SQL provides logical data integrity using the transaction and recordlocking capabilities of the MicroKernel. Scalable SQL, in conjunction with the MicroKernel, provides the following types of concurrency controls:

‹ ‹ ‹

Isolation levels for transactions Record locks Passive control

Transaction Processing
When you attempt to insert data into a table, Scalable SQL returns an error if the data is invalid. However, if you are using the xInsert, xUpdate, or xRemove APIs, any data inserted before the error occurred remains in the database. For example, if you insert three rows into a table and the third row is invalid, the first two rows remain in the table. To avoid this type of inconsistency, you can use transaction processing.
Note

This inconsistency does not occur when using INSERT, UPDATE, and DELETE SQL statements.

Transaction processing lets you identify a set of logically related database modifications, either within a single table or across multiple tables, and require them to be completed as a unit. Transaction processing involves two important concepts:

‹

A logical unit of work, or transaction, is a set of discrete operations that must be treated as a single operation to ensure database integrity. If you make a mistake

Database Design Guide

221

Managing Data

or encounter a problem during a transaction, you can issue a ROLLBACK WORK statement to undo the changes you have already made. For example, the Registrar might credit a student account with an amount paid in one operation, then update the amount owed in a second operation. By grouping these operations together you ensure the student’s finances are accurate.

‹

A locking unit is the amount of data from which other tasks are blocked until your transaction is complete. (A task is a Scalable SQL session.) Locking prevents other tasks from changing the data you are trying to change. If other tasks can also change the data, Scalable SQL cannot roll back work to a previously consistent state. Thus, within a transaction, only one task may access a given locking unit at a time. However, multiple cursors that belong to the same task can access the locking unit at the same time.

On the SQL level, the START TRANSACTION statement begins a transaction. When you have issued all the statements you want to complete during the transaction, issue a COMMIT WORK statement to end the transaction. The COMMIT WORK statement saves all your changes, making them permanent. If an error occurs in one of the operations, you can roll back the transaction and then retry it again after correcting the error. For example, if you need to make related updates to several tables, but one of the updates is unsuccessful, you can roll back the updates you have already made so the data is not inconsistent. Scalable SQL automatically performs a rollback operation if a task issues an XQLLogout or XQLStop call at any time before the current transaction completes. Scalable SQL also performs the rollback operation if two tasks are sharing a login session and the task that originated the session logs out before the second task completes its transition.

Database Design Guide

222

Managing Data

Starting and Ending Transactions
To begin a transaction, issue a START TRANSACTION statement. After issuing all the statements you want to complete during the transaction, issue a COMMIT WORK statement to save all your changes and end the transaction. START TRANSACTION; UPDATE Billing B SET Amount_Owed = Amount_Owed - Amount_Paid WHERE Student_ID EXISTS (SELECT E.Student_ID FROM Enrolls E WHERE E.Student_ID = B.Student_ID); COMMIT WORK; For more information about the START TRANSACTION statement, refer to the SQL Language Reference.

Using Savepoints to Nest Transactions
In a SQL transaction, you can define additional markers called savepoints. Using savepoints, you can undo changes after a savepoint in a transaction and continue with additional changes before requesting the final commit or abort of the entire transaction. To begin a transaction, use the START TRANSACTION statement. The transaction remains active until you issue a ROLLBACK or COMMIT WORK statement. To establish a savepoint, use the SAVEPOINT statement. SAVEPOINT SP1;

Database Design Guide

223

Managing Data

To rollback to a savepoint, use the ROLLBACK TO SAVEPOINT statement. ROLLBACK TO SAVEPOINT SP1; The savepoint name must specify a currently active savepoint in the current SQL transaction. Any changes made after establishing this savepoint are cancelled. To delete a savepoint, use the RELEASE SAVEPOINT statement. RELEASE SAVEPOINT SP1; You can only use this statement if a SQL transaction is active. If you issue a COMMIT WORK statement, all savepoints defined by the current SQL transaction are destroyed, and your transaction is committed.
Note

Do not confuse ROLLBACK TO SAVEPOINT with ROLLBACK WORK. The former cancels work only to the indicated savepoint, while the latter cancels the entire outermost transaction and all savepoints established within it.

Savepoints provide a way to nest your transactions, thereby allowing the application to preserve the previous work in the transaction while it waits for a sequence of statements to complete successfully. As an example, you can use a WHILE loop for this purpose. You can set a savepoint before beginning a sequence of statements that may fail on the first attempt. Before your transaction can proceed, this sub-transaction must complete successfully. If it fails, the sub-transaction rolls back to the savepoint, where it can start again. When the sub-transaction succeeds, the rest of the transaction can continue. A SQL transaction must be active when you issue a SAVEPOINT statement.

Database Design Guide

224

Managing Data

Note

The MicroKernel allows each transaction a total of 255 internal nesting levels. However, Scalable SQL uses some of these levels internally to enforce atomicity on INSERT, UPDATE, and DELETE statements. Therefore, a session can effectively define no more than 253 savepoints to be active at one time. This limit may be further reduced by triggers that contain additional INSERT, UPDATE, or DELETE statements. If your operation reaches this limit, you must reduce the number of savepoints or the number of atomic statements contained within it.

Work that is rolled back within a savepoint cannot be committed even if the outer transaction(s) completes successfully. However, work that is completed within a savepoint must be committed by the outermost transaction before it is physically committed to the database. For example, in the university database you might start a transaction to register a student for several classes. You may successfully enroll the student in the first two classes, but this may fail on the third class because it is full or it conflicts with another class for which the student has enrolled. Even though you failed to enroll the student in this class, you don’t want to undo the student’s enrollment for the previous two classes. The following stored procedure enrolls a student into a class by first establishing a savepoint, SP1, then inserting a record into the Enrolls table. It then determines the current enrollment for the class and compares this to the maximum size for the class. If the comparison fails, it rolls back to SP1; if it succeeds, it releases savepoint SP1. CREATE PROCEDURE Enroll_Student (student UNSIGNED(8), classNum INT(4)); BEGIN DECLARE currentEnrollment INT(4); DECLARE maxEnrollment INT(4); SAVEPOINT SP1;
Database Design Guide 225 Managing Data

INSERT INTO Enrolls VALUES (student, classNum); SET currentEnrollment = (SELECT COUNT (*) FROM Enrolls WHERE class_id = classNum); SET maxEnrollment = (SELECT Max_Size FROM Class WHERE ID = classNum); IF (currentEnrollment >= maxEnrollment) THEN ROLLBACK TO SAVEPOINT SP1; ELSE RELEASE SAVEPOINT SP1; END IF; END A calling program or procedure must issue a START TRANSACTION before invoking this procedure, because savepoints are only permitted within a transaction. By the same token, the caller may issue a COMMIT WORK statement, regardless of the outcome of this procedure, because no class is allowed to exceed its enrollment limit. For more information about the syntax of any of these statements, refer to the entries for these statements in the SQL Language Reference.

Database Design Guide

226

Managing Data

Special Considerations
Transactions do not affect the following operations:

‹ ‹ ‹

Operations that create or change dictionary definitions. Therefore, you cannot roll back the results of the following statements: ALTER TABLE, CREATE DICTIONARY, CREATE GROUP, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, CREATE TRIGGER, and CREATE VIEW. Operations that remove dictionary definitions. Therefore, you cannot roll back the results of the following statements: DROP DICTIONARY, DROP GROUP, DROP INDEX, DROP PROCEDURE, DROP TABLE, DROP TRIGGER, and DROP VIEW. Operations that grant or revoke security rights. Therefore, you cannot roll back the results of the following statements: CREATE GROUP, DROP GROUP, GRANT (access rights), GRANT CREATETAB, GRANT LOGIN, REVOKE (access rights), REVOKE CREATETAB, and REVOKE LOGIN.

If you attempt any of these operations within a transaction and Scalable SQL completes the statement, then you cannot roll back the results. You cannot alter or drop a table (in other words, change its dictionary definition) during a transaction if you have previously referred to that table during the transaction. For example, if you start a transaction, insert a record into the Student table, and then try to alter the Student table, the ALTER statement fails. You must commit the work from this transaction, and then alter the table.

Database Design Guide

227

Managing Data

Isolation Levels
An isolation level determines the scope of a transaction locking unit by allowing you to define the extent to which a transaction is isolated from other users, who may also be in a transaction. When you use isolation levels, Scalable SQL automatically locks pages or tables according to the isolation level you specify. These automatic locks, which Scalable SQL controls internally, are called implicit locks, or transaction locks. Locks that an application specifies explicitly are called explicit locks, formerly record locks. For more information, refer to "Explicit Locks." Scalable SQL offers two isolation levels for your transactions:

‹ ‹

Exclusive (locks the entire data file you are accessing). Cursor stability (locks either the row or page you are accessing).

The system’s default isolation level is set when you load Scalable SQL. You can use the default isolation level or specify an isolation level for the current session using a SET ISOLATION statement. SET ISOLATION = < EX | CS > The value EX specifies the exclusive isolation level; the value CS specifies the cursor stability isolation level. The session’s isolation level determines the isolation level of the next transaction the session starts; if you change the isolation level within a transaction, the change does not take effect until the next transaction begins. For information about specifying a default isolation level when you load Scalable SQL, see the Pervasive.SQL User’s Guide. For information about setting the isolation level after startup, refer to the discussions of the SET ISOLATION statement in the SQL Language Reference.

Database Design Guide

228

Managing Data

Exclusive Isolation Level
When you use the exclusive isolation level, the locking unit is an entire data file. Once you access a file or files within an exclusive transaction, those files are locked from any similar access by any other user in a transaction. This type of locking is most effective when few applications attempt to access the same tables at the same time, or when large parts of the file must be locked in the course of a transaction. Scalable SQL releases the lock on the file or files when you end the transaction. When you access a table during an exclusive transaction, the following conditions take effect:

‹ ‹ ‹

Other tasks that are in a transaction cannot read, update, delete, or insert rows in that table until you end the transaction. Other tasks that are not in a transaction can read rows in the table, but they cannot update, delete, or insert rows. Multiple cursors within the same task can read any row in the table. However, when you perform an update, delete, or insert operation with a particular cursor, Scalable SQL locks the entire data file for that cursor.

When you access tables through a joined view using the exclusive isolation level, Scalable SQL locks all the accessed data files in the view.

Cursor Stability Isolation Level
The MicroKernel maintains data files as a set of data pages and index pages. When you use the cursor stability isolation level, the locking unit is a data page or index page instead of a data file. When you read records within a cursor stability transaction, Scalable SQL locks the data pages that contain those records for possible update, but allows concurrent access to a table by multiple tasks within transactions. These read locks are

Database Design Guide

229

Managing Data

released only when you read another set of records. Scalable SQL supports set level cursor stability since it allows an application to fetch multiple records at a time. In addition, any data modifications you make to the data or index pages cause those records to remain locked for the duration of the transaction, even if you issue subsequent reads. Other users in a transaction cannot access these locked records until you commit or roll back your work. However, other applications can lock other pages from the same files within their own transactions. When you access a file during a cursor stability transaction, Scalable SQL locks data and index pages as follows:

‹ ‹ ‹

You read a row, but you do not update it or delete it. Scalable SQL locks the data page for that row until your next read operation or until you end the transaction. You update a non-index column in a row, delete a row from a table that does not contain indexes, or insert a new row into a table that does not contain indexes. Scalable SQL locks the data page for that row for the remainder of the transaction, regardless of subsequent read operations. You update an indexed column in a row, delete a row from a table that contains indexes, or insert a new row into a table that contains indexes. Scalable SQL locks the affected index page(s), as well as the data page, for the remainder of the transaction, regardless of subsequent read operations.

Cursor stability ensures that the data you read remains stable, while still allowing other users access to other data pages within the same data files. Within the cursor stability isolation level, you can generally achieve greater concurrency for all tasks by limiting the number of rows you read at one time, thereby locking fewer data pages at a time. This allows other network users access to more pages of the data file, since you do not have them locked.

Database Design Guide

230

Managing Data

However, if your application is scanning or updating large numbers of rows, you increase the possibility of completely locking other users out of the affected tables. Therefore, it is best to use cursor stability for reading, writing, and committing small transactions. Cursor stability does not lock records within a subquery. Cursor stability does not guarantee that the conditions under which a row is returned do not change, only that the actual row returned does not change.

Transactions and Isolation Levels
Whenever you access data within a transaction, Scalable SQL locks the accessed pages or files for that application. No other application can write to the locked data pages or files until the locks are released. Using the cursor stability isolation level, when you access tables through a joined view, Scalable SQL locks all the accessed pages for all the tables in the view. Using the exclusive isolation level, when you access tables through a joined view, Scalable SQL locks all the accessed tables in the view. Scalable SQL performs no-wait transactions. If you try to access a record that another task has locked within a transaction, Scalable SQL informs you that the page or table is locked or that a deadlock has been detected. In either case, roll back your transaction and begin again. Scalable SQL allows multiple cursors in the same application to access the same data file.

Database Design Guide

231

Managing Data

The following steps illustrate how two applications interact while accessing the same tables within a transaction. The steps are numbered to indicate the order in which they occur. Task 1
1. Activate the view. 2. Activate the view. 3. Begin a transaction. 4. Begin a transaction. 5. Fetch records. 6. Attempt to fetch records from the same data files. 7. Receive Status Code 84 (Record or Page Locked) if both tasks are using cursor stability and Task 2 attempts to fetch the same records that Task 1 has already locked, or receive 85 (File Locked) if one of the tasks is using an exclusive transaction. 8. Retry the fetch if needed. 9. Update the records. 10. End the transaction. 11. The fetch is successful. 12. Update the records. 13. End the transaction.

Task 2

Since a transaction temporarily locks records, pages, or tables against other applications’ updates, an application should not pause for operator input during a transaction. This is because no other application can update the records, pages, or tables accessed in the transaction until the operator responds and the transaction is terminated.

Database Design Guide

232

Managing Data

Note

Reading records within a cursor stability transaction does not guarantee that a subsequent update succeeds without conflict. This is because another application may have already locked the index page that Scalable SQL needs to complete the update.

Avoiding Deadlock Conditions
A deadlock condition occurs when two applications are retrying operations on tables, data pages, index pages, or records that the other one has already locked. To minimize the occurrence of deadlock situations, have your application commit its transactions frequently. Do not attempt to retry the operation from your application; Scalable SQL attempts a reasonable number of retries before returning an error.

Deadlock Conditions under Exclusive Isolation Level
When you use the exclusive isolation level, Scalable SQL locks the entire data file against updates by other applications; thus, it is possible for a deadlock to occur if your applications do not access data files in the same order, as shown in the following table. Task 1
1. Begin a transaction. 2. Begin a transaction. 3. Fetch from File 1. 4. Fetch from File 2. 5. Fetch from File 2. 6. Receive lock status.

Task 2

Database Design Guide

233

Managing Data

7. Retry Step 5. 8. Fetch from File 1. 9. Receive lock status. 10. Retry Step 8.

Deadlock Conditions under Cursor Stability Isolation Level
When you use the cursor stability isolation level, other applications can read and update records or pages in the file you are accessing (records or pages that your application has not locked).

Explicit Locks
Whenever your application fetches data through Scalable SQL using the Scalable SQL APIs, it can specify that it wants to lock the physical records that contain the data using explicit record locks. These locks are called explicit locks because the task is responsible for setting the locks. Explicit locks lock the rows for update and delete operations but do not allow you to roll back the operations. You can only use explicit locks outside of a transaction. After an application locks a record, other applications can read the same records, but they cannot lock the records or update them. Only the application holding the lock can update or remove the record. An application can lock multiple records in a file at the same time. A single application cannot issue both implicit locks (transaction locks) and explicit locks (record locks). However, multiple applications may use different types of locks, even when accessing the same file (provided the entire file is not locked.)

Database Design Guide

234

Managing Data

For example, Application 1, under the cursor stability isolation level, accesses File 1 to read a record. Application 2, without starting a transaction, accesses File 1, requesting an explicit lock on a record. As long as they are not trying to lock the same record, both applications can obtain the data they need. (However, if Application 1 were running under the exclusive isolation level, Application 2 would not be able to access File 1 since Application 1 would already have the entire file locked.) By using explicit locks with the XQLFetch or xFetch APIs, you can lock the physical records that contain the data you are fetching instead of using transactions; however, you do not have the commit or rollback capabilities that a transaction provides if you use this method. Within the same session, multiple cursors can lock the same rows on a read operation. However, only one cursor can update or delete the locked rows. For example, you might use one cursor to read rows and a second cursor to update rows (the second cursor must also read the row before it can perform the update operation.) The first cursor maintains the position within the view because an update operation on a cursor requires the task to re-establish position if the operation is unsuccessful. Scalable SQL provides two types of explicit record locks: wait and no-wait. Regardless of which one you use, Scalable SQL locks all the records it returns on a fetch.You specify the type of lock on the XQLFetch or xFetch call when fetching the data. On read operations, the locks have the following effects on other tasks (or other cursors of the same task) that try to access the same files:

‹ ‹

If the second task is in a transaction, it cannot read the record. By default, Scalable SQL locks a record on a read operation if a task is in a transaction. A second task that is also in a transaction cannot read and lock a record that is already locked by the first task. However, the second task can lock other records on the same page.

Database Design Guide

235

Managing Data

‹ ‹

If the second task is not in a transaction (and is not using XQLFetch or xFetch with explicit locks), it can read the record. In this case, Scalable SQL reads the record without trying to lock it. If a single task uses multiple cursors to access the same files, other cursors can lock the same record that the first cursor locked.

On Update, Delete, and Insert operations, the locks have the following effects on other tasks (or other cursors of the same task) that try to access the same files:

‹ ‹

If the first task locks a data page, other tasks (or other cursors of the same task) cannot update or delete any of the records on the locked data page. Also, these tasks (or cursors) cannot insert a record on the locked data page. The tasks that are not in transactions (and are not using XQLFetch or xFetch with explicit record locks) can still read records on the locked data page, as can multiple cursors of the same task. Other tasks that are in transactions cannot read the records. However, any task, whether it is in a transaction or not, can lock other data pages in the same files, as can multiple cursors of the same task. If the first task also locks an index page, other tasks (or other cursors of the same task) cannot perform an update, delete, or insert operation on any record on any data page if the operation involves an index and the index field value of that record is listed on the locked index page. When you access files through a joined view using the cursor stability isolation level, Scalable SQL locks the appropriate records, data pages, or index pages for all the files in the view.

‹ ‹

Database Design Guide

236

Managing Data

Wait Locks
When you fetch records with a wait lock, Scalable SQL does not return control to your application until it has obtained the lock on every record you requested. If another application has locked one of the records you requested, Scalable SQL waits indefinitely until that application releases the record before proceeding to lock the rest of the records you requested.
Note

The Scalable SQL for Windows local engine does not support wait locks. The MicroKernel maps wait locks to no-wait locks.

No-Wait Locks
When you fetch records with a no-wait lock, Scalable SQL returns control to your application if it cannot lock the record for any reason (for example, because another application has already locked that record). Scalable SQL immediately returns a non-zero status to your application and unlocks any records it has already locked during the fetch request. A read with no-wait locks may return one of the following results:

‹ ‹ ‹

Record in use (Status Code 84) File in use (Status Code 85) Deadlock (Status Code 78)

Outside a transaction, you can retry if you receive Status Code 84 or Status Code 85. If you receive Status Code 78, you must release all locked resources. Inside a transaction, you must rollback when you receive any lock error, in order to reduce the contention for

Database Design Guide

237

Managing Data

resources. Refer to the Status Codes and Messages manual for details about these status conditions.

Releasing Locks
You can release record locks in two ways: implicitly and explicitly. If you choose the implicit release, Scalable SQL automatically unlocks all locked records when you perform any of the following operations:

‹ ‹ ‹ ‹ ‹ ‹ ‹

Update or delete the locked records. Fetch another set of records. Release the cursor ID associated with the locked records. Log out.

If you choose the explicit release, Scalable SQL unlocks records only if you perform one of these operations: Issue an explicit unlock operation. Release the cursor ID associated with the locked records. Log out.

Database Design Guide

238

Managing Data

Passive Control
If your application performs single record fetch and update sequences that are not logically connected, you can use Scalable SQL’s passive method of concurrency. Using this method, you can fetch and update (or delete) records without performing transactions or record locks. These operations are referred to as optimistic updates and deletes. By default, if your task does not use transactions or explicit record locks to complete update and delete operations, your task cannot overwrite another task’s changes. The feature that ensures this data integrity is passive control, sometimes referred to as optimistic concurrency control. With passive control, your task does not perform any type of locking. If another task modifies a record after you originally fetched it, you must fetch the record again before you can perform an update or delete operation. Under passive control, if another application updates or deletes a record between the time you fetch it and the time you issue an update or remove operation, your application receives a conflict status. This indicates that another application has modified the data since you originally fetched it. When you receive a conflict status, you must fetch the record again before you can perform the update or remove operation. Passive control allows an application that was designed for a single-user system to run on a network without implementing lock calls. However, passive control is effective only when an application is operating in a lightly used network environment or on files in which the data is fairly static. In a heavily used environment or on files that contain volatile data, passive control may be ineffective.

Database Design Guide

239

Managing Data

Atomicity in Scalable SQL Databases
The principle of atomicity states that if a given statement does not execute to completion, then it should not leave partial or ambiguous effects in the database. For example, if a statement fails after it has inserted three out of five records but does not undo that insert, then the database is not in a consistent state when you retry the operation. If the statement is atomic and it fails to complete execution, then all changes are rolled back, so that the database is in a consistent state. In this example, if all five records are not successfully inserted, then none of them are inserted. The atomicity rule is especially significant for statements that modify multiple records and/or tables. It also makes retrying failed operations simpler, because any previous attempt is guaranteed not to have left any partial effects. Scalable SQL enforces atomicity in two ways: 1. Any UPDATE, INSERT, or DELETE statement is defined to be atomic. Scalable SQL guarantees that, if a multi-record and/or multi-table modification operation fails, none of the effects of that modification remain in the database. This is true for Update, Insert, or Delete operations whether or not they are performed inside or outside of procedures. 2. You may specify stored procedures as ATOMIC when you create them. Such procedures apply the rule of atomicity to their entire execution. Therefore, not only do UPDATE, INSERT, or DELETE statements within an ATOMIC procedure execute atomically, but if any other statements within that procedure fail, all effects of the procedure’s execution thus far are rolled back.

Database Design Guide

240

Managing Data

Transaction Control in Procedures
Because triggers are always initiated by an external data change statement (INSERT, DELETE, or UPDATE), and all data change statements are defined to be atomic, the following statement are not allowed in triggers or in any procedures invoked by triggers:

‹ ‹ ‹

START TRANSACTION COMMIT WORK ROLLBACK WORK (including RELEASE SAVEPOINT and ROLLBACK TO SAVEPOINT)

In other words, triggers follow the same rules as ATOMIC compound statements. No user-initiated COMMIT WORK, ROLLBACK WORK, RELEASE SAVEPOINT, or ROLLBACK TO SAVEPOINT statement can cause a system-begun transaction (for purposes of atomicity) to end. If you attempt to use these statements in a trigger, Scalable SQL returns Status Code 501.

Database Design Guide

241

Managing Data

appendix

A

University Database Tables and Referential Integrity

The Pervasive University sample database is provided as part of the Scalable SQL product and is frequently used in the documentation to illustrate database concepts and techniques. Even if you are already familiar with Pervasive Software’s products, you may want to review the information in this appendix in order to become acquainted with the new sample database. Even though you may not be working in an academic environment, you can use the sample database examples both as a template and a reference to help you design and develop your own customized information systems. You can use the sample queries and other aspects included in our example, since it reflects a real-life scenario. This appendix includes the following sections:

‹ ‹ ‹

Structure of the University Database Referential Integrity in the University Database Table Design

Database Design Guide

242

University Database Tables and Referential Integrity

Structure of the University Database
The physical structure of the database consists of the elements of a relational database: tables, columns, rows, keys, and indexes. The database contains 10 tables with various relationships between them. It contains data on students, faculty, classes, registration, etc.

Assumptions
Following are some assumptions around which the database was built:

‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹

The scope of the database is one semester. A student cannot take the same course more than once. For example, a student cannot enroll in Algebra I, Sections 1 and 2. A faculty member can be a student, but a faculty member cannot teach and enroll in the same class. Any course is offered by only one department. In order for a student to receive a grade, they must be enrolled in a class, and a faculty member must be assigned to teach the class. Faculty members belong to a single department, but they can teach for many departments. All students have a Student ID that is based on the US standard of a social security number. All faculty members have a Faculty ID that is based on the US standard of a social security number.
243 University Database Tables and Referential Integrity

Database Design Guide

‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹

All other persons have a Person ID that is based on the US standard of a social security number. Rooms are unique within the same building. Two classes cannot be taught in the same room at the same time. A faculty member can only be teaching one class at a given time. Prerequisites are not required for enrollment in a class. Departments imply majors. A course can only be taught by one faculty member throughout the semester. A telephone number or zip code does not correlate to a state. A registrar cannot be a faculty member or student. When a person is entered into the database, they can complete a survey of which they must answer all the questions or none of the questions. Credit hours for a course are not necessarily equal to the number of hours that a class convenes. An e-mail address does not have to be unique.

Entity Relationships
Entities are objects that describe primary components in the database. When designing a database, it is important to define the entities and their relationships to one another before proceeding further. In the university database, CLASSES, STUDENTS, FACULTY, GRADES, etc., are entities. The entities and their relationships to one another are outlined in Figure A-1.

Database Design Guide

244

University Database Tables and Referential Integrity

Figure A-1 Entity Relationships
is head of PERSON is a FACULTY belongs to

has many registrars from

GRADE

teaches

has an office

is a

enrolls for

CLASS

is taught in

ROOM

STUDENT

has sections for

COURSE

offers

has an office

BILLING

pays fees to

DEPARTMENT

majors in

TUITION

has a

minors in

LEGEND
many to many
ENTITY WEAK ENTITY relationship

one to many one to one

This diagram does not show any attributes.

GRADES is a weak entity. It is dependent upon a student taking a class, so its existence is dependent upon the validity of other entities. The STUDENT and FACULTY tables create common information, since a student could be a faculty member and vice versa. The common information is in the PERSON table.

Database Design Guide

245

University Database Tables and Referential Integrity

Referential Integrity in the University Database
This section describes the referential integrity (RI) design in the university database. Figure A-2 depicts the referential constraints that exist among the various tables in the university database. The boxes represent tables. The unidirectional-directional arrow implies a referential constraint from the parent table to the referencing table. For example, in constraint number 16 a foreign key exists in the Class table that references a primary key in its parent table, Course.

Figure A-2 RI Structure in the University Database

BILLING
1 13 2 8 3 4

TUITION STUDENT
10 11 9 14

ENROLLS
17 6 5 16

PERSON

DEPARTMENT
12

FACULTY

ROOM
7

COURSE
15

CLASS

Note

Figure A-2 also serves as a dependency graph. It tells you what tables must be populated before others when doing the physical design.
Database Design Guide 246 University Database Tables and Referential Integrity

The tables, columns, and keys participating in RI are defined as follows:

Table A-1

Tables and Columns Involved with RI
Foreign Key
Registrar_ID ID ID Tuition_ID Building_Name, Room_Number Building_Name, Room_Number Building_Name, Room_Number Dept_Name Head_Of_Dept Major Minor Dept_Name Student_ID Student_ID Faculty_ID Course_Name Class_ID

Constraint Referencing Table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 BILLING STUDENT FACULTY STUDENT FACULTY DEPARTMENT CLASS FACULTY DEPARTMENT STUDENT STUDENT COURSE BILLING ENROLLS CLASS CLASS ENROLLS

Referenced Table Primary Key
PERSON PERSON PERSON TUITION ROOM ROOM ROOM DEPARTMENT FACULTY DEPARTMENT DEPARTMENT DEPARTMENT STUDENT STUDENT FACULTY COURSE CLASS ID ID ID ID Building_Name, Number Building_Name, Number Building_Name, Number Name ID Name Name Name ID ID ID Name ID

Database Design Guide

247

University Database Tables and Referential Integrity

Table Design
Following is a guide to the tables in the university database. This information is included with each table:

‹ ‹ ‹ ‹ ‹

Columns in the table Data types for each column Size, or length, of the column in bytes Keys (blank if the column is not a key) Indexes (blank if the column does not have an index)

BILLING Table
Column
Student_ID Transaction_Number Log Amount_Owed Amount_Paid Registrar_ID Comments

Data Type
UNSIGNED UNSIGNED TIMESTAMP MONEY MONEY NUMERIC NOTE

Size
8 2 8 6 6 8 200

Keys
PRIMARY, FOREIGN PRIMARY

FOREIGN

Database Design Guide

248

University Database Tables and Referential Integrity

CLASS Table
Column
ID Name Section Max_Size Start_Date Start_Time Finish_Time Building_Name Room_Number Faculty_ID

Data Type
AUTOINC CHARACTER CHARACTER INTEGER DATE TIME TIME CHARACTER UNSIGNED UNSIGNED

Size
4 7 3 2 4 4 4 25 4 8

Keys
PRIMARY FOREIGN

FOREIGN FOREIGN FOREIGN

COURSE Table
Column
Name Description Credit_Hours Dept_Name

Data Type
CHARACTER CHARACTER UNSIGNED CHARACTER

Size
7 50 2 20

Keys
PRIMARY

FOREIGN

Database Design Guide

249

University Database Tables and Referential Integrity

DEPARTMENT Table
Column
Name Phone_Number Building_Name Room_Number Head_of_Dept

Data Type
CHARACTER NUMERIC CHARACTER UNSIGNED UNSIGNED

Size
20 10.0 25 4 8

Keys
PRIMARY

FOREIGN FOREIGN FOREIGN

ENROLLS Table
Column
Student_ID Class_ID Grade

Data Type
UNSIGNED INTEGER FLOAT

Size
8 4 4

Keys
PRIMARY, FOREIGN PRIMARY, FOREIGN

Database Design Guide

250

University Database Tables and Referential Integrity

FACULTY Table
Column
ID Dept_Name Designation Salary Building_Name Room_Number Rsch_Grant_Money

Data Type
UNSIGNED CHARACTER CHARACTER CURRENCY CHARACTER UNSIGNED BFLOAT

Size
8 20 10 8 25 4 8

Keys
PRIMARY, FOREIGN FOREIGN

FOREIGN FOREIGN

PERSON Table
Column
ID First_Name Last_Name Perm_Street Perm_City Perm_State Perm_Zip Perm_Country Database Design Guide

Data Type
UNSIGNED ZSTRING ZSTRING ZSTRING ZSTRING ZSTRING ZSTRING ZSTRING

Size
8 16 26 31 31 3 11 21 251

Keys
PRIMARY

University Database Tables and Referential Integrity

Column
Street City State Zip Phone Emergency_Phone Unlisted Date_Of_Birth Email_Address Sex Citizenship Survey Smoker Married Children Disability Scholarship Comments

Data Type
ZSTRING ZSTRING ZSTRING ZSTRING NUMERIC CHARACTER BIT DATE ZSTRING LOGICAL ZSTRING BIT BIT BIT BIT BIT BIT NOTE

Size
31 31 3 11 10.0 20 1 4 31 1 21 1 1 1 1 1 1 200

Keys

Database Design Guide

252

University Database Tables and Referential Integrity

ROOM Table
Column
Building_Name Number Capacity Type

Data Type
CHARACTER UNSIGNED INTEGER CHARACTER

Size
25 4 2 20

Keys
PRIMARY PRIMARY

STUDENT Table
Column
ID Cumulative_GPA Tuition_ID Transfer_Credits Major Minor Scholarship_Money Cumulative_Hours

Data Type
UNSIGNED NUMERICSTS INTEGER NUMERICSA CHARACTER CHARACTER DECIMAL INTEGER

Size
8 5.3 4 4 20 20 10.2 2

Keys
PRIMARY, FOREIGN

FOREIGN

FOREIGN FOREIGN

Database Design Guide

253

University Database Tables and Referential Integrity

TUITION Table
Column
ID Degree Residency Cost_Per_Credit Comments

Data Type
AUTOINC LSTRING LOGICAL FLOAT LVAR

Size
4 5 1 4 200

Keys
PRIMARY

Database Design Guide

254

University Database Tables and Referential Integrity

Index A
Access rights. See Security; Rights ADD FOREIGN KEY clause 191 ADD keyword, with ALTER TABLE statement 52 ADD PRIMARY KEY clause 189 Administering database security Aggregate functions. See Group aggregate functions Alias names for tables 34 All right about 208 granting 210 revoking 210 Allocating disk storage space 36 Alter right description 208 granting 210 revoking 210 ALTER TABLE statement defining referential constraints 185 dropping columns with 48 with ADD FOREIGN KEY clause 191 with ADD keyword 52 with ADD PRIMARY KEY clause 189 with DROP FOREIGN KEY clause 192 Database Design Guide 255 with DROP keyword 48 with DROP PRIMARY KEY clause 190 with USING clause 52 AND boolean operator 104 Anomalies on delete-connected cycles 201 on multiple paths 202 on self-referencing tables 199 Appending string columns, example of 124 Arithmetic operators in expressions 117 Ascending sort order in indexes 41 ATOMIC keyword, with compound statement 171 Atomicity overview 240 transaction processing and 46 Attributes, index 41 AVG function 126

B
BEGIN...END statement 171 BEGINS WITH operator 106 BETWEEN operator 105 Boolean expressions in triggers 182 masks 77 Index

operators, in restriction clauses 104 Bound databases 24

C
CALL (procedure) statement 160 Cartesian product joins 98 Cascaded deletes 197 Case-sensitivity column names and 36 index column values and 41 stored view names and 84 table names and 29 CAST function 148 Changing primary keys 190 rows 81 Character lists 55 Clauses, restriction 103 Columns attributes of 53 character lists, specifying 55 computed 94 creating 36 data types for 36 default values, specifying 53 dropping 48 headings in views 85 masks for 57 naming 26 naming, case-sensitivity and 36 null values in 55

qualified names of 27 ranges, specifying 54 removing 48 selecting 90 value lists, specifying 55 COMMIT WORK statement 222 Completion conditions 176 Compound statements 171 Computed columns conditional operators for 120 in joins 94 Concatenating strings 119, 124 Concurrency controls 221 data file locks 229 explicit locks 234 passive control 239 transaction processing 221 Condition operators 105 Conditional execution of SQL statements 172 Conditions completion 176 declaring 177 exception 176 handling 177 resignalling 178 signalling 178 CONTAINS operator 106 Correlated subqueries 101 COUNT function 92, 126 CREATE GROUP statement 214 INDEX statement 38 PROCEDURE statement 160 256 Index

Database Design Guide

TABLE statement defining referential constraints 185 granting right to use 208 with FOREIGN KEY clause 192 with OWNER clause 219 with PRIMARY KEY clause 189 with USING clause 38 with WITH INDEX clause 37 TRIGGER statement 179 VIEW statement, with SELECT clause 84, 85 Create Table right about 208 granting 209 Creating columns 36 data dictionaries 30 databases 25 foreign keys 190 indexes 37 primary keys 189 stored procedures 160 tables 33 user groups 213 users 214 views 83 CURDATE function 121 Cursor stability isolation level 229 Cursor-based statements, SQL cursor declaration 167 FETCH statement 169 overview 166 Positioned DELETE statement 169 Database Design Guide 257

Positioned UPDATE statement 170 Cursors cursor-based statements 166 declaring 167 opening 168 procedure-owned 168 scroll cursors 167 session 168 CURTIME function 122 Cycle defined 187 delete-connected 201

D
Data dictionaries contents 30 creating 30 deleting 50 path limit 33 querying 30 Data files as locking units 229 index segments, maximum number of 41 owner names, specifying 219 path limit 33 Data security. See Security Data types and joins 94 computations with numeric 113 for columns 36 Database element names

Index

about 26 duplicate 26 maximum lengths for 28 unique 26 valid characters for 27 Databases adding rows to 44 bound 24 creating 25 defining referential constraints for 193 deleting 50 deleting rows from 47 design of conceptual 16 logical 17 physical 21 named 23 normalization of 18 retrieving rows from 82, 126 rights 208 security 207 transactions in 221 updating 81 using transactions in 46 Date arithmetic in expressions 121 in scalar functions 143 Date masks 69 DAY function 143 Deadlock condition with cursor stability isolation level 234 with exclusive isolation level 233 Deadlock conditions, avoiding 233 Database Design Guide 258

DECLARE CONDITION statement 177 cursor statement 167 HANDLER statement 177 Default column values 53 Defining stored procedures 160 Delete right description 208 granting 210 revoking 210 Delete rule about 197 anomalies, for foreign keys 197 DELETE statement deleting rows with 47 invoking triggers with 179 Delete-connected table 186 Deleting columns 48 current row with Positioned DELETE statement 169 databases 50 foreign keys 192 indexes 48 primary keys 189 rows 47 savepoints 224 stored procedures 161 tables 49 triggers 179 users and user groups 217 Dependent rows 187 Index

tables 186 Descendants 187 Descending sort order in indexes 41 Dictionaries.See Data dictionaries Disabling security 218 Disk storage space, allocation of 36 Display masks. See Masks DROP DICTIONARY statement 50 FOREIGN KEY clause 192 INDEX statement 48 PRIMARY KEY clause 190 PROCEDURE statement 161 TABLE statement 49 TRIGGER statement 179 Dropping columns 48 indexes 48 tables 49 Duplicatability in indexes 41

Explicit locks 228, 234 Expressions about 111 arithmetic operators in 117 date arithmetic 121 examples of 123 integral promotion 115 numeric computations in 113 operators in 113 precision rules 115 rules for 112 scalar functions in 129 scale rules 115 syntax in 111 time arithmetic 122

F
FETCH statement 169 First normal form 19 Foreign keys about 190 creating 191 defined 187, 188 deleting 192 Functions aggregate 126 arguments for 127 AVG 126 COUNT 126 MAX 126 MIN 126

E
Edit masks. See Masks Enabling security 213 Ending transactions 223 Entities defined 244 weak entities 245 Equal joins 96 Exception conditions 176 Exclusive isolation level 229

Database Design Guide

259

Index

SUM 126 with the DISTINCT keyword 127 CURDATE 121 CURTIME 122 scalar DAY 143 HOUR 145 LEFT 130, 132 LENGTH 124, 130, 131, 133 LOWER 130, 135 LTRIM 131, 135 MILLISECOND 145 MINUTE 145 MONTH 143 overview 129 RIGHT 130, 131, 136 ROUND 131, 141 RTRIM 131, 137 SECOND 145 SUBSTRING 131, 137 TRUNC 131, 142 UPPER 131, 140 WEEKDAY 143 YEAR 143

G
Glossary. See Pervasive.SQL User’s Guide GRANT access rights statement 215 LOGIN statement 214 Granting rights 209 Group aggregate functions about 126 arguments for 127 GROUP BY clause, with SELECT statement 92, 128 Grouping rows 92 Groups. See User groups

H
HAVING clause, with SELECT statement 128 Headings 85 Hexadecimal masks 68 HOUR function 145, 146

Database Design Guide

260

Index

I
IF statement 172 Implicit locks 228 IN operator 105 Indexes attributes 41 creating 37 dropping 48 duplicatability in 41 join conditions and 94 maximum number of 39 modifiability 41 named 26 null values in 42 removing 48 segmented 39, 42 sorting ascending order 41 case-sensitivity and 41 descending order 41 Insert right description 208 granting 210 revoking 210 rule 195 INSERT statement invoking triggers with 179 with VALUES clause 44 Inserting rows 44

values from other tables 45 Integral promotion in expressions 115 Integrity of updates 46, 221 IS NOT NULL operator 106 IS NULL operator 106 Isolation levels cursor stability deadlock condition 234 overview 229 exclusive deadlock condition 233 overview 229 overview 228

J
Joins about 93 cartesian product 98 computed columns in 94 data types and 94 equal 96 indexes and 94 nonequal 96 null 97 self 99 specifying 95 using views and tables in 96

Database Design Guide

261

Index

K
Keys about 21, 188 foreign defined 188, 190 deleting 192 naming 26 primary changing 190 characteristics of 188 creating 189 defined 188 deleting 189

granting 209 revoking 210 LOOP statement 173 Loops about 173 and the WHILE statement 174 exiting from 172 LOWER function 130, 135 LTRIM function 131, 135

M
Many-to-many relationship 18 Masks boolean 77 date 69 hexadecimal 68 literals 58 number data digits in 65 overview 64 special literals in 65 permanent and temporary 63 specifying 57 string length 63 temporary, for multiple columns 80 time 74 timestamp 76 Master user 213 MAX function 126 MILLISECOND function 145, 146 MIN function 126

L
LEAVE statement 172 LEFT function 130, 132 LENGTH function 124, 130, 131, 133 LIKE operator 106 Locking units 222 Locks about 228 data files 229 deadlock condition 233 explicit 234 implicit 228 transaction 228 wait 237 Login right description 208 Database Design Guide 262

Index

MINUTE function 145, 146 Modifiability in indexes 41 Modifying data 51 tables 52 MONTH function 143, 144

N
Named databases about 23 removing names of 50 Naming conventions columns 26 database elements 26 group names 26 indexes 26 keys 26 stored procedures 26 tables 26 triggers 26 usernames 26 views 26 Nested queries. See Subqueries Nonequal joins 96 Normalization of databases first normal form 19 overview 18 second normal form 19 third normal form 20 NOT BETWEEN operator 106 NOT CONTAINS operator 106

NOT IN operator 105 NOT LIKE operator 106, 110 Null joins 97 Null values in indexes 42 setting 55 Number masks 64 Numeric computations 113 scalar functions. See Scalar functions

O
One-to-many relationship 18 One-to-one relationship 18 OPEN (cursor) statement 168 Operators arithmetic 117 BEGINS WITH 106 BETWEEN 105 boolean AND 104 OR 104 condition range 105 relational 105 CONTAINS 106 expression 113 for conditional computed columns 120 IN 105 IS NOT NULL 106 IS NULL 106

Database Design Guide

263

Index

LIKE 106 NOT BETWEEN 106 NOT CONTAINS 106 NOT IN 105 NOT LIKE 106, 110 string 119 OR boolean operator 104 ORDER BY clause, with SELECT statement 92 Orphan rows 187 Owner names for data files, specifying 219

defined 188 deleting 189 Procedure-owned cursors 168 variables 164 Procedures, stored 159 Processing transactions 46 PUBLIC group 212, 215

Q
Qualified column names 27 Querying, data dictionaries 30 Quotes, using with string constants 112

P
Page size, maximum index segments and 39 Parent rows 186 tables 186 Passive control 239 Passwords about 213 case-sensitivity and 29 storing 214 Paths, limit when stored in dictionary 33 Positioned DELETE statement 169 Positioned UPDATE statement 170 Precision rules in expressions 115 PRIMARY KEY clause 189 Primary keys changing 190 characteristics of 188 creating 189

R
Range operators in restriction clauses 105 Ranges, specifying in columns 54 Read-only tables in views 86 Record locks about 228 wait locks 237 References defined 187 paths cycle 187 defined 187 right 208 granting 209 revoking 210 Referential constraints

Database Design Guide

264

Index

creating foreign keys with 190 creating primary keys with 189 defining 193 deleting foreign keys 192 primary keys 189 examples of 204 overview 185 Referential integrity anomalies about 197 and delete-connected cycles 201 and multiple, delete-connected paths 202 and self-referencing tables 199 and the delete rule for foreign keys 197 definitions 186 delete rule 197 insert rule 195 overview 185 self-referencing tables and 187 update rule 196 Relational operators 105 Relationships many-to-many 18 one-to-many 18 one-to-one 18 RELEASE SAVEPOINT statement 224 RESIGNAL statement 178 Restriction clauses about 103 examples 107 operators 104 Database Design Guide 265

Retrieving data 82, 126 REVOKE access rights statement 218 LOGIN statement 217 Revoking rights 210, 217 RI. See Referential integrity; Referential constraints RIGHT function 130, 131, 136 Rights all 208 alter 208 create table 208 delete 208 granting 208, 209 insert 208 login 208 overview 208 references, about 208 revoking 210, 218 select 208 update 208 ROLLBACK with TO SAVEPOINT clause 224 WORK statement 221 Rolling back to a savepoint 224 transactions 221 ROUND function 131, 141 Rows deleting 47 dependent 187 inserting 44 orphan 187 Index

parent 186 sorting and grouping 92 updating 81 RTRIM function 124, 131, 137

S
Sample database. See University database. SAVEPOINT statement 223 Savepoints creating 223 deleting 224 overview 223 rolling back to 224 Scalar functions CAST 148 date DAY 143 MONTH 144 overview 143 WEEKDAY 144 YEAR 145 numeric overview 140 ROUND 141 TRUNC 142 overview 129 string LEFT 132 LENGTH 133 LOWER 135 LTRIM 135

overview 130, 132 RIGHT 136 RTRIM 124, 137 SUBSTRING 137 UPPER 140 time HOUR 146 MILLISECOND 146 MINUTE 146 overview 145 SECOND 147 Scale rules in expressions 115 Scroll cursors 167 SECOND function 145, 147 Second normal form 19 Security creating user groups and 214 creating users and 214 disabling 218 enabling 213 groups, naming 26 master user and 213 overview 207 owner names for data files 219 passwords about 213 case-sensitivity and 29 PUBLIC group and 215 rights about 208 granting 209 revoking 210 setting up 211 266 Index

Database Design Guide

system tables 220 users, naming 26 Segmentation in indexes 39, 42 Select right description 208 granting 209 revoking 210 SELECT statement as nested query 100 lists, specifying 90 with FROM clause 64 with GROUP BY clause 92, 128 with HAVING clause 128 with ORDER BY clause 92 with WHERE clause 95 Selecting, columns 90 Selection lists 90 Self joins 99 Self-referencing tables 187 Session cursors 168 Session variables 165 SET BINARYNULL statement 56 CHAR statement 55 DECIMALNULL statement 56 DEFAULT statement 54 ISOLATION statement 228 MASK statement 63 OWNER statement 220 RANGE statement 54 SECURITY statement about 211 with NULL keyword 218 Database Design Guide 267

SQL variable statement 165 STRINGNULL statement 56 Setting column attributes 53 null values 55 security 211 SIGNAL statement 178 Sorting indexes 41 rows 92 Special literals in masks 57 Specifying character lists 55 column default values 53 column ranges 54 edit masks joins 95 list of columns 90 owner names 219 trigger order 181 triggers 180 value lists 55 SQL control statements compound statements 171 IF statement 172 LEAVE statement 172 LOOP statement 173 overview 171 WHILE statement 174 SQL cursor-based statements cursor declaration 167 FETCH statement 169 overview 166 Index

Positioned DELETE statement 169 Positioned UPDATE statement 170 SQL variable statements assigning 165 declaring SQL variables 162 overview 162 procedure-owned variables 164 session variables 165 substitution variables 163 SQLSTATE system variable 175 START TRANSACTION statement 222 Starting transactions 223 Stored procedures as triggers 179 creating 160 defining 160 deleting 161 invoking 160 naming 26 overview 159 Stored statements. See Stored procedures Stored views 84 Storing, passwords 214 String concatenating 119, 124 functions. See Scalar functions length masks 63 operators in expressions 119 Subqueries about 100 correlated 101 limitations 101 Substitution variable statements 163 Database Design Guide 268

Substitution variables 163 SUBSTRING function 131, 137 SUM function 92, 126 System tables 30

T
Tables aliases for, assigning 34 creating 33 defining relationships with referential integrity 185 defining views as an alternative 33 delete-connected 186 deleting 49 dependent defined 186 descendant 187 dropping 49 joining with other tables 95 with views 96 modifying definitions of 52 naming about 26 case-sensitivity and 29 parent 186 primary keys, changing 190 read-only in views 86 relationships many-to-many 18 one-to-many 18

Index

one-to-one 18 overview 18 self-referencing anomalies 199 defined 187 system 30 Temporary views 84 Third normal form 20 Time arithmetic, in expressions 122 arithmetic, in scalar functions 145 masks 74 Timestamp masks 76 Transaction locks 228 Transactions ending 223 locking units in 222 nesting, with savepoints 223 overview of 46 processing 46, 221 rolling back 221 special considerations for 227 starting 223 Triggers creating 179 defining trigger action 182 deleting 179 invoking 179 naming 26 overview 179 specifying execution time 180 specifying order of execution 181 TRUNC function 131, 142 Database Design Guide 269

U
Unique indexes 41 University database and referential integrity 204 entity relationships 244 overview 242 referential integrity 246 structure 243 table design 248 tables Billing 248 Class 249 Course 249 Department 250 Enrolls 250 Faculty 251 Person 251 Room 253 Student 253 Tuition 254 Update anomalies, avoiding 197 right description 208 granting 210 revoking 210 rule 196 UPDATE statement invoking triggers with 179 overview 81 with SET clause 85

Index

with WHERE clause 81, 85 Updating rows 81 UPPER function 131, 140 User groups creating 213 deleting 217 granting rights to 216 PUBLIC 215 Users creating 213 deleting 217 granting rights to 216 USING clause with ALTER TABLE statement 52 with CREATE TABLE statement 38

creating 83 features of 83 joining, with tables 96 naming 26 stored 84 temporary 84 with read-only tables 86

W
Wait locks 237 Weak entities 245 WEEKDAY function 143, 144 WHEN clause, in triggers 182 WHERE clause, with SELECT statement 95 WHILE statement 174 WITH INDEX clause, with CREATE TABLE statement 37

V
Value lists 55 VALUES clause, with INSERT statement 44 Variable statements. See SQL variable statements Variables SQL assigning 165 declaring 162 procedure-owned 164 session 165 substitution 163 system, SQLSTATE 175 Views column headings in 85

Y
YEAR function 143, 145

Database Design Guide

270

Index

User Comments
Pervasive Software would like to hear your comments and suggestions about our manuals. Please write your comments below and send them to us at:

Pervasive Software Inc. Documentation 8834 Capital of Texas Highway Austin, Texas 78759 USA Telephone: 1-800-287-4383 Fax: 512-794-1778 Email: docs@pervasive.com
Your name and title: Company: Address:

Database Design Guide 100-003195-004 February 1998

Phone number:

Fax:

You may reproduce these comment pages as needed so that others can send in comments also.

I use this manual as:

‰ an overview
Excellent

‰ a tutorial
Good

‰ a reference
Fair

‰ a guide
Poor

Completeness Readability (style) Organization/Format Accuracy Examples Illustrations Usefulness

‰ ‰ ‰ ‰ ‰ ‰ ‰

‰ ‰ ‰ ‰ ‰ ‰ ‰

‰ ‰ ‰ ‰ ‰ ‰ ‰

‰ ‰ ‰ ‰ ‰ ‰ ‰

Please explain any of your above ratings:

In what ways can this manual be improved?

You may reproduce these comment pages as needed so that others can send in comments also.

Sign up to vote on this title
UsefulNot useful