Sie sind auf Seite 1von 124

Chapter 1

Overview of SQL Server

Starting Microsoft SQL Server


A database is a collection of information destined to make that information easy to view and exploit.
To use our lessons, you must have access to a Microsoft SQL Server computer. There are different
ways this is taken care of but we cannot cover such details here. If you are a network administrator
with an account on the SQL Server, you are in luck. If you are not a network administrator, you will
have to convince your boss or the server folks that you are learning database administration and you
need an account that allows you to create databases on the server (you will need more than luck).

Practical Learning: Launching SQL Server

1. Log on to your Windows NT or 2000 Server.To start Microsoft SQL Server 2000, on the task
bar, click Start -> Programs -> Microsoft SQL Server -> Enterprise Manager
2. On the left frame of MMC (the type of window you are working on is called a Microsoft
Management Console or MMC), click the + sign of the Microsoft SQL Servers folder to expand it.
3. Click the + sign on the SQL Server Group folder to expand it.
4. Click the + sign of the server name you want to use
5. Click the + sign of the Databases folder to expand it.

Creating a Database in the Console Manager


There are three main ways you can create a database in MS SQL Server 2000, one of which consists
of using the Database Properties dialog box. There are various ways you can launch the Database
Properties:
In the Microsoft Management Console window, you can right-click the server, position your mouse
on New, and click Database.
In the left frame of MMC, you can also right-click the Databases folder and click New Database
When the server name is selected in the left frame, on the toolbar of the MMC window, click Action,
position your mouse on New, and click Database...

1
When the server name is selected in the left frame, right-click an empty area in the right frame,
position your mouse on New, and click Database...
When the Databases folder is selected in the left frame, on the toolbar, click Action and click New
Database...
When the Databases folder is selected in the left frame, right-click an empty area in the right frame
and click New Database...
Practical Learning: Creating a database Using the MMC

1. To create a database in the MMC, right-click the Databases node and click New Database...

2. On the Database Properties dialog box, in the General property sheet, click the Name text
box and type BookCollection

2
3. Click OK
Creating a Database Using the Database Wizard
Another technique you can use to create a database is by using the Database Wizard. There are two
main ways you can launch the Database Wizard. In the left frame, when the server node or the
Databases folder is selected, on the toolbar, you can click the Tools button and click Wizards. In the
Select Wizard dialog box, expand the Database node, click Create Database Wizard and click OK.
Practical Learning: Creating a database Using the Wizard
1. In the left frame, click Databases to make sure it is selected.
On the toolbar, click Tools and click Wizards...
2. In the Select Wizard dialog box, click the + sign on Database to expand. Then click Create
Database Wizard

3. Click OK
4. In the first page of the Create Database Wizard dialog box, read the whole text and click Next

3
5. In the Database Name text box change the name to PublicRecords

6. Click Next
7. Accept the default database size in the third page of the wizard and click Next
8. In the fourth page, accept all suggested defaults values of the database and click Next
9. Accept the suggested size of the log file and click Next
10. Accept the defaults values suggested and click Next

11. Once the Database Wizard has gathered all necessary information, click Finish.
12. You will receive a message box stating that the database was successfully created. Click OK.
13. When asked whether you want to create a maintenance plan for the database, click No.

4
Deleting a Database
If you have created a database by mistake or simply don't need a particular database anymore, you
can get rid of it. Make sure you never delete the databases that were installed along with Microsoft
SQL server.
To delete a database in the MMC window, if the Databases folder is expanded in the left frame, you
can right-click the undesired database and click Delete. In the right frame, you can also right-click the
undesired database and click Delete.
Practical Learning: Deleting a Database
1. In the MMC window, in the left frame, make sure the Databases folder is expanded.
In the left frame, right-click PublicRecords and click Delete

2. When a message box asks you to confirm, click Yes.


3. Still in the MMC window, while the Databases folder is selected, in the right frame, right-
click BookCollection and click Delete (if you don't see BookCollection, right-click in the right frame
and click Refresh).
4. On the Delete Database confirmation dialog box, click Yes

5
Chapter 2
The Structured Query Language

Introduction
Computer science is filled with various languages, for different purposes. The database industry is
just one field of the computer world. As such, it enjoys its share of issues, such as what could be the
best approach to create, use, and manage a database. A big issue of the database environment is how
different database environments can communicate. Although this problem has not been completely
solved, at least most database systems use a common language.
The Structured Query Language, known as SQL, is a universal language used on various computer
systems for database purposes. The SQL is a standard language. This means that not a single
company owns it or its copyright. Like other non-platform specific languages such as C/C++,
Pascal, or Java, the SQL you learn can be applied to various database systems. As it happens with
many computer languages (human languages too), when a company adopts a language to develop its
system, the company adds and sometimes subtracts some parts even if they would be conform to the
standard.
Transact-SQL is Microsoft's implementation of SQL. Transact-SQL is the language used internally
by Microsoft SQL Server. Although SQL Server highly adheres to the SQL standards, it has some
internal details that might not be applied to other database systems like MySQL, Oracle, or even
Microsoft Access, etc; although they too fairly conform to the standard.
The SQL we will learn and use here is Transact-SQL. In other words, we will assume that you are
using Microsoft SQL Server as your platform for learning about databases. Nevertheless, we have
tutorials on the SQL and Microsoft Access. Therefore, unless specified otherwise, most of the time,
on this site, the word SQL refers to Transact-SQL or the way the language is implemented in
Microsoft SQL Server.
The SQL Query Analyzer
Microsoft SQL Server ships with a highly effective utility (or program or application, whatever you
want to call it) called SQL Query Analyzer. Although the SQL Query Analyzer is not a particularly
visual development environment, it provides all the tools you need to make good use of your
database platform. It allows you to create, use, and manage your databases. You can interchangeably
use the Enterprise Manager and the Query Analyzer. Whatever you do in one can be understood by
the other.
There are two main ways you can start the Query Analyzer:
• If the Enterprise Manager is already opened, in the left frame, you can click the server or any
node under the server to select it. Then, on the toolbar of the MMC, click Tools -> SQL Query
Analyzer. In this case, the Query Analyzer would open directly.
• If the Enterprise Manager is not opened, on the taskbar, you can click Start -> Programs ->
Microsoft SQL Server -> Query Analyzer. If the Enterprise Manager is opened but the server or
none of its nodes is selected, on the toolbar of the MMC, you can click Tools -> SQL Query
Manager. In both cases you would be asked to log in. You will need to provide two pieces of
information. You must have/know the server you want to connect to. In the SQL Server combo
box, you can select the server you want to connect to or select (local)(you can also click the Browse
button to locate your server). To login to that server, you have two main options, you can log in
using the SQL Server Authentication, in which case you would need to have an account:

6
Alternatively, you can log in using the Windows NT authentication, in which case you would click
the Windows Authentication radio button:

Once you click OK, the server will need to analyze your credentials. If everything is alright, the SQL
Query Analyzer would display:

7
Practical Learning: Opening the Query Analyzer
As you will find out, there are many things you can do with the SQL Query Analyzer. There are even
various ways you can create a database using the SQL Query Analyzer. To use the Query Analyzer,
you must know and type the code for any task you want to perform.
Like every computer language, using SQL consists of giving (sometimes small) instructions to the
computer. The computer analyzes each instruction and interprets it. If the instruction is
"understandable", the computer produces a result. If the instruction contains an unallowable mistake
or the computer cannot figure out what the instruction means, it would throw (display or show) an
error. In reality, the scenario I have just described doesn't have much to do with the computer. The
SQL implementation you are using is equipped with an engine that receives your instructions,
analyzes, and interprets them.
The first instruction we will learn in SQL is to create a database. This is done with the CREATE
instruction using the following syntax:
CREATE DATABASE DatabaseName
SQL is not case-sensitive. This means that CREATE, create, and Create mean the same thing. It is a
tradition to write SQL's own words in uppercase. This helps to distinguish SQL instructions with the
words you use for your database.

Practical Learning: Creating a Database Using the


Query Analyzer
1. In the SQL Query Analyzer window, type CREATE DATABASE POMPEI

8
2. To create the database, on the toolbar, click the Execute Query button
Once the database has been created, a message will let you know by splitting the child window in
two:

3. To give another instruction, delete the content of the top section of the window and type:

CREATE DATABASE PublicRecords


4. Press F5 to create the database

9
From now on, unless directed otherwise, whenever you are given new instructions to type, you must
delete the content of the top section of the window. We will assume that you have deleted the top
section once the previous instruction has been executed.

Deleting a Database in the Console Manager


If you have created a database but don't need it anymore, you can delete it. To delete a database using
SQL, you use the DROP DATABASE instruction followed by the name of the database. The
syntax used is:
DROP DATABASE DatabaseName
Before deleting a database in SQL, you must make sure the database is not being used or accessed.
On this tutorial, we assume that you are only learning, which means you can control whether your
database is being accessed or who is accessing your database.
To make sure your database is not busy, you can check the Enterprise Manage and make sure the
database you want to delete is not selected.

Practical Learning: Deleting a Database Using the Query Analyzer

1. In the top section of the window, type DROP DATABASE PublicRecords

2. To delete the database, press F5 (or click the Execute Query button )
After the database has been deleted, two lines will give you a confirmation.

10
3. Close the SQL Query Analyzer window by clicking its Close button
4. When asked whether you want to save the text, click No.
5. Back in the MMC window, press F5 to refresh.
Accessories for Code Writing
The Current Database
While writing code in the Query Window, you should always know what database you are working
on, otherwise you might create things in the wrong database. To programmatically specify the current
database, type the USE keyword followed by the name of the database. Here is an example:
USE Northwind

The End of a Statement


In SQL, after writing a statement, you can end it with a semi-colon. In fact, many SQL environments
require the semi-colon. If you want to execute many statements in SQL Server, you can write them
once. Here is an example:
CREATE DATABASE CountriesStatistics
Comments
A comment is text that the SQL engine would not consider as code. As such, a comment is written
any way you like. What ever it is made of would not be read.
Transact-SQL supports two types of comments. The C++ style of comment that starts with /* and
ends with */ can be used in SQL. To apply it, start a line with /*, include any kind of text you like,
on as many lines as you want. To close the commented section, type */. Here is an example of a line
of comment:
/* This line will not be read */
A comment can also spread on more than one line, like a paragraph. Here is an example:
/*
The following database allows the whole
company to manage its resources.
*/

CREATE DATABASE Friendship

11
/*
The following table is mainly used by the Accounting department
for payroll and other emplpoyees-related issues.
This table should not be accessed just by anybody. Only
authorized staff members will be allowed to view its data.
*/
Transact-SQL also supports the double dash comment. This comment applies to only one line of
text. To use it, start the line with --. Anything on the right side of -- is part of a comment and would
not be considered as code. Here is an example:
-- Creating a database to keep records of US senators

CREATE DATABASE Senate

-- Another database
-- This one will be used for members of the Chamber of Representatives

USE CountriesStatistics
In this case, you are asking SQL Server to create a database and then to make it the current database.
This statement will not work:

The problem here is that, when the interpreter encounters these two lines, it would execute all of
them at once and in fact would treat both lines as one expression. When the statements are executed,
some must come after others. To separate statements, that is, to indicate when a statement ends, you
can/must use the GO keyword. Therefore, the above two statements can be performed separately
but with one execution as follows:
CREATE DATABASE CountriesStatistics
GO
USE CountriesStatistics
GO
This time, when you execute the code, it would work fine:

12
Comments
A comment is text that the SQL engine would not consider as code. As such, a comment is written
any way you like. What ever it is made of would not be read.
Transact-SQL supports two types of comments. The C++ style of comment that starts with /* and
ends with */ can be used in SQL. To apply it, start a line with /*, include any kind of text you like,
on as many lines as you want. To close the commented section, type */. Here is an example of a line
of comment:
/* This line will not be read */
A comment can also spread on more than one line, like a paragraph. Here is an example:
/*
The following database allows the whole
company to manage its resources.
*/

CREATE DATABASE Friendship

/*
The following table is mainly used by the Accounting department
for payroll and other emplpoyees-related issues.
This table should not be accessed just by anybody. Only
authorized staff members will be allowed to view its data.
*/
Transact-SQL also supports the double dash comment. This comment applies to only one line of
text. To use it, start the line with --. Anything on the right side of -- is part of a comment and would
not be considered as code. Here is an example:
-- Creating a database to keep records of US senators

CREATE DATABASE Senate


-- Another database
-- This one will be used for members of the Chamber of Representatives

13
Chapter 3
Fundamental SQL Operators

Introduction
An operation is an action performed on one or more values either to modify the value held by one or
both of the variables or to produce a new value by combining variables. Therefore, an operation is
performed using at least one symbol and one value. The symbol used in an operation is called an
operator. A value involved in an operation is called an operand.
A unary operator is an operator that performs its operation on only one operand.
An operator is referred to as binary if it operates on two operands.

Practical Learning: Starting a Database


1. Open the SQL Query Analyzer
2. To create a new database, in the Query Window, type CREATE DATABASE Operations
3. Press F5 to execute the above statement
4. To set this new database as default, delete the above statement and replace it with
USE Operations
5. Press F5 to execute the above statement

PRINT Something
The Query Window is divided in two main sections. The top part allows you to type statements. The
lower part is used to display a result, depending on the expression. You can also use these parts to
perform a test. For example, you can enter a test statement in the upper section and execute it to
have the result displayed in the lower part.
Like every language, SQL ships with some words used to carry its various operations. If you want to
display something in plain text as a result of a statement, in the upper section, type PRINT followed
by what to display. Therefore, PRINT uses the following syntax:
PRINT WhatToPrint
The item to display can be anything that is allowed and it is provided on the right side of PRINT. If
it is a normal (called a constant) number, simply type it on the right side of PRINT. Here is an
example:

14
The item to display can also be an operation or the result of an operation as we will learn in this
lesson. If you want to display a character, a word, or a sentence, include it between single-quotes.
You can also display an expression as a combination of number(s) and sentences as we will learn
later.
After creating an expression, to execute it, you can press F5.

Practical Learning: Printing Something


1. To use PRINT, change the statement with PRINT 'Welcome to the wonderful world of
MS SQL Server
2. Execute the statement

15
SELECT, Anything
The SELECT keyword, the most widely used word of databases, can be used, among other things,
to display a value. The SELECT keyword uses the following syntax:
SELECT What
Based on this, to use it, where it is needed, type SELECT followed by a number, a word, a string, or
an expression. The item to display follows the same rules as PRINT. Here is an example:
SELECT 402

Practical Learning: Selecting a Value


1. To use the SELECT keyword, change the statement with SELECT 'Transact-SQL is the
SQL implemented in MS SQL Server'
2. Execute the statement

SELECT This AS That


In the above introductions, we used either PRINT or SELECT to display something in the Query
Window. One of their differences is that PRINT is primarily used to display a simple result in the
lower section. As we will learn in other lessons, SELECT is used to select one or more values
and/or perform other, more elaborate, operations. One of the characteristics of SELECT is that it
can segment its result in different sections. Each section is represented separately. To create various
sections using SELECT, separate them with a comma. Here is an example:

16
SELECT represents each value in a section called a column. Each column is represented with a
name also called a caption. By default, the caption displays as "(No column name)". If you want to
use your own caption, on the right side of an expression, type the AS keyword followed by the
desired caption in single quotes. Here is an example:
SELECT 26 As 'Age'
If you create different sections, separated by a comma, you can followed each with AS and a caption.

Practical Learning: Setting Captions


1. To set some captions for columns, change the statement as follows: SELECT 'James
Knight' As FullName, 20.48 AS Salary
2. Execute the statement

Unary Operators
The Positive Operator +
Algebra uses a type of ruler to classify numbers. This ruler has a middle position of zero. The
numbers on the left side of the 0 are referred to as negative while the numbers on the right side of
the rulers are considered positive:
-∞ -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 +∞

17
0
-∞ -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 +∞
A value on the right side of 0 is considered positive. To express that a number is positive, you can
write a + sign on its left. Examples are +4, +228, +90335. In this case the + symbol is called a unary
operator because it acts on only one operand.
The positive unary operator, when used, must be positioned on the left side of its operand, never on
the right side.
As a mathematical convention, when a value is positive, you do not need to express it with the +
operator. Just writing the number without any symbol signifies that the number is positive.
Therefore, the numbers +4, +228, and +90335 can be, and are better, expressed as 4, 228, 90335.
Because the value does not display a sign, it is referred as unsigned as we learned in the previous
lesson.
To express a variable as positive or unsigned, you can just type it. here is an example:
PRINT +1250
The Negative Operator -
As you can see on the above ruler, in order to express any number on the left side of 0, it must be
appended with a sign, namely the - symbol. Examples are -12, -448, -32706. A value accompanied by
- is referred to as negative.

The - sign must be typed on the left side of the number it is used to negate.

Remember that if a number does not have a sign, it is considered positive. Therefore, whenever a
number is negative, it MUST have a - sign. In the same way, if you want to change a value from
positive to negative, you can just add a - sign to its left.

Here is an example that uses two variables. One has a positive value while the other has a negative
value: SELECT -1250

Here is an example with various uses of the sizeof operator


This would produce:
Binary Operators

The Addition
The addition, also called the sum, is an operation used to add one item to another. The addition is
performed using the + sign. To get the addition of two values, you type + between them, as in
Value1 to Value2. After the addition has been performed, you get a new value that you can make
available or display to the user. You can perform the addition on two numbers. Here is an example:
PRINT 125 + 4088
In Transact-SQL, you can also perform the addition on text. Here is an example:
PRINT 'Henry ' + 'Kono'
You can also add more than two values, like a + b + c. The order you use to add two or more values
doesn't matter. This means Value1 + Value2 is the same as Value2 + Value1. In the same way a + b
+ c is the same as a + c + b the same as b + a + c and the same as c + b + a. This means that the
addition is associative as illustrated in the following statement:

18
The Subtraction
The subtraction operation, sometimes called the difference, is used to take out or subtract one value
from another value. It is essentially the opposite of the addition. The subtraction is performed with
the - sign. Here is an example:
PRINT 1240 - 608
Unlike the addition, the subtraction operation is not associative. This means that a - b - c is not
necessarily equal to c - b - a. This is illustrated in the following statements:
PRINT 128 - 42 - 5
PRINT 5 - 42 - 128
This would produce: 81,-165
Notice that both operations of the addition convey the same result. In the subtraction section, the
numbers follow the same order but a different operation; and the last two operations render different
results.
The Multiplication
The multiplication allows adding one value to itself a certain number of times, set by a second value.
As an example, instead of adding a value to itself in this manner: a + a + a + a, since the variable a is
repeated over and over again, you could simply find out how many times a is added to itself, then
multiply a by that number which, is this case, is 4. This would mean adding a to itself 4 times, and
you would get the same result.

The multiplication is performed with the * sign. Just like the addition, the multiplication is
associative: a * b * c = c * b * a. Here is an example:
PRINT 128 * 42
This would produce 5376
The Division
The division operation is similar to cutting an item in pieces or fractions of a set value. Therefore, the
division is used to get the fraction of one number in terms of another. The division is performed
with the forward slash /. Here is an example:
PRINT 128 / 42
This would produce 3
When performing the division, be aware of its many rules. Never divide by zero (0). Make sure that
you know the relationship(s) between the numbers involved in the operation.

19
The Modulo
In the above division, 128/42, the result is 3. When you multiply 42 by 3, as in 42*3, you get 126. In
some cases, you may be interested in knowing the amount that was left out after the operation. The
modulo operation is used to get the remainder of a division as a natural number. The remainder
operation is performed with the percent sign (%). Here is an example:
PRINT 128 % 42
This would produce 2

Additional SQL Operators


Parentheses
Like most computer languages, Transact-SQL uses parentheses to isolate a group of items that must
be considered as belonging to one entity. For example, as we will learn soon, parentheses allow a
function to delimit the list of its arguments. Parentheses can also be used to isolate an operation or
an expression with regards to another operation or expression. For example, when studying the
algebraic operations, we saw that the subtraction is not associative and can lead to unpredictable
results. In the same way, if your operation involves various operators such as a mix of addition(s) and
subtraction(s), you can use parentheses to specify how to proceed with the operations, that is, what
operation should (must) be performed first. Here is an example:
PRINT (154 - 12) + 8
PRINT 154 - (12 + 8)
This would produce:
150
134
As you can see, using the parentheses controls how the whole operation would proceed. This
difference can be even more accentuated if your operation includes 3 or more operators and 4 or
more operands.

Bit Manipulations
Introduction
When you use a value in your database or application, the value must be stored somewhere in the
computer memory using a certain amount of space. As we review in our study of bytes and words, a
value occupies space that resembles a group of small boxes. In our human understanding, it is not
always easy to figure out how a letter such as as B is stored in 7 seven small boxes when we know
that B is only one letter.

Bit manipulation or a bit related operation allows you to control how values are stored in bits. This is
not an operation you will need to perform very often, especially not in the early stages of your
database. Nevertheless, bit operations (and related overloaded operators) are present in all or most
programming environments, so much that you should be aware of what they do or what they offer.
Bits Operators: The Bitwise NOT Operator ~
One of the operations you can perform on a bit consists of reversing its value. That is, if a bit holds a
value of 1, you may want to change it to 0 and vice-versa. This operation can be taken care of by the
bitwise NOT operator that is represented with the tilde symbol ~
The bitwise NOT is a unary operator that must be placed on the left side of its operand as in
~Value

20
Here is an example:
PRINT ~158
To perform this operation, the Transact-SQL interpreter considers each bit that is part of the
operand and inverts the value of each bit from 1 to 0 or from 0 to 1 depending on the value the bit is
holding. This operation can be resumed in the following table:
Bit ~Bit
1 0
0 1
Consider a number with a byte value such as 248. In our study of numeric systems, we define how
to convert numbers from one system to another. Based on this, the binary value of decimal 248 is
1111 1000 (and its hexadecimal value is 0xF8). If you apply the bitwise NOT operator on it to
reverse the values of its bits, you would get the following result:
Value 1 1 1 1 1 0 0 0
~Value 0 0 0 0 0 1 1 1
Bits Comparison: The Bitwise AND Operator &
The bitwise & is a binary operator that uses the following syntax
Operand1 & Operand2
This operator considers two values and compares the bit of each with the corresponding bit of the
other value. If both corresponding bits are 1, the comparison produces 1. Otherwise, that is, if either
bit is 0, the comparison produces 0. This comparison is resumed as follows:
Bit1 Bit2 Bit1 & Bit2
0 0 0
1 0 0
0 1 0
1 1 1
Imagine you have two byte values represented as 187 and 242. Based on our study of numeric
systems, the binary value of decimal 187 is 1011 1011 (and its hexadecimal value is 0xBB). The
binary value of decimal 242 is 1111 0010 (and its hexadecimal value is 0xF2). Let’s compare these
two values bit by bit, using the bitwise AND operator:
Binary Decimal
N1 1 0 1 1 1 0 1 1 187
N2 1 1 1 1 0 0 1 0 242
N1 & N2 1 0 1 1 0 0 1 0 178
Most of the times, you will want the interpreter to perform this operation and use the result in your
program. This means that you can get the result of this operation and possibly display it to the user.
The above operation can be performed by the following program:

PRINT 187 & 242


This would produce 178
Bits Comparison: The Bitwise OR Operator |
You can perform another type of comparison on bits using the bitwise OR operator that is
represented by |. Its syntax is:
Value1 | Value2

21
Once again, the interpreter compares the corresponding bits of each operand. If at least one of the
equivalent bits is 1, the comparison produces 1. The comparison produces 0 only if both bits are 0.
This operation is resumed as follows:
Bit1 Bit2 Bit1 | Bit2
0 0 0
1 0 1
0 1 1
1 1 1
Once again, let’s consider decimals 187 and 242. Their bitwise OR comparison would render the
following result:
Binary Decimal
N1 1 0 1 1 1 0 1 1 187
N2 1 1 1 1 0 0 1 0 242
N1 | N2 1 1 1 1 1 0 1 1 251
You can also let the compiler perform the operation and produce a result. Here is an example:
PRINT 187 | 242
This would produce 251
Bits Comparison: The Bitwise-Exclusive XOR Operator ^
Like the previous two operators, the bitwise-exclusive OR operator performs a bit comparison of
two values. It syntax is:
Value1 ^ Value2
The compiler compares the bit of one value to the corresponding bit of the other value. If one of the
bits is 0 and the other is 1, the comparison produces 1. In the other two cases, that is, if both bits
have the same value, the comparison produces 0. This operation is resumed as follows:
Bit1 Bit2 Bit1 ^ Bit2
0 0 0
1 0 1
0 1 1
1 1 0
We will again consider decimals 187 and 242. Their bitwise-exclusive XOR comparison would render
the following result:

Binary Decimal
N1 1 0 1 1 1 0 1 1 187
N2 1 1 1 1 0 0 1 0 242
N1 ^ N2 0 1 0 0 1 0 0 1 73
If the interpreter performs this operation, it can produce a result as in the following example:
PRINT 187 ^ 242;
This would produce 73

22
Chapter 4
Variables Fundamentals

Introduction
The values we have used so far are referred to as constant because we certainly knew them in
advance and didn't change them in our statements. If you intend to use a certain category of number
over and over again, you can reserve a section of memory. This allows you to put a number in that
area of memory, easily change the number with another, over an over. For example, you can store
the names of employees one after another in the same area of memory as needed. To manage this
exchange of memory, Transact-SQL uses an internal program called an interpreter.
To use the same area of memory to store and remove values as needed, the interpreter needs two
primary pieces of information: a name and the desired amount of space in memory capable of storing
the value.

Practical Learning: Introducing Variables


1. Open the SQL Query Analyzer with its default blank window
2. To create a new database, type and execute the following statement:

CREATE DATABASE Variables1


Declaring Variables
A variable is an area of memory used to store values that can be used in a program. Before using a
variable, you must inform the interpreter. This is also referred to as declaring a variable. To declare a
variable, use the DECLARE keyword using the following formula:
DECLARE Options
The DECLARE keyword lets the interpreter know that you are making a declaration. The
DECLARE keyword is followed by a name for the variable. In Transact-SQL, the name of a
variable starts with the @ sign. The name of a variable allows you to identify the area of memory
where the value of the variable is stored. While other languages like C/C++, Pascal, Java, C#, etc
impose strict rules to names, Transact-SQL is extremely flexible. A name can be made of digits only.
Here is an example:
DECLARE @264
Such a name made of digits can create some confusion with a normal number. A name can also be
made of one or more words.
Objects Names
To avoid confusion, here are the rules we will use on this site:
• A name will start with either an underscore or a letter. Examples are @_n, @act, or
@Second
• After the first character as an underscore or a letter, the name will have combinations of
underscores, letters, and digits. Examples are @_n24, @act_52_t
• A name will not include special characters such as !, @, #, $, %, ^, &, or *
• We will avoid using spaces in a name, with few exceptions
• If the name is a combination of words, each word will start in uppercase. Examples are
@DateHired, @_RealSport, or @DriversLicenseNumber
To declare a variable, as we will see in the next section, after giving a name to a variable, you must
also specify the amount of memory that the variable would need. The amount of memory is also
called a data type. Therefore, the declaration of a variable uses the following formula:
DECLARE @Variable DataType

23
You can also declare more than one variable. To do that, separate them with a comma. The formula
would be:
DECLARE @Variable1 DataType, @Variable2 DataType, @Variable1 DataType
Unlike most other languages like C/C++ or Pascal, if you declare many variables that use the same
data type, the name of each variable must be followed by its own data type.

Initializing a Variable
After declaring a variable, the interpreter reserves a space in memory for it but the space doesn't
necessarily hold a recognizable value. This means that, at this time, the variable is null. One way you
can change this is to give a value to the variable. This is referred as initializing the variable.
Remember that a variable's name starts with @ and whenever you need to refer to the variable, you
must make sure you include the @ sign. To initialize a variable, in the necessary section, type the
SELECT or the SET keyword followed by the name of the variable, followed by the = sign,
followed by an appropriate value. The formula used is:
SELECT @VariableName = DesiredValue
or
SET @VariableName = DesiredValue
Once a variable has been initialized, you can make its value available or display it to the user. This
time, you can type the name of the variable to the right side of PRINT or SELECT.

Data Types
Introduction
After setting the name of a variable, you must specify the amount of memory that the variable will
need to store its value. Since there are various kinds of information a database can deal with, SQL
Server provides a set of categories called data types. Therefore, you must specify the data type that is
necessary for a particular column.
A database deals with various types of data, appropriate or not for certain fields. This means that you
should take care of jobs behind the scenes as much as you can. One way you can do this is by
controlling the amount of information that can be entered in a particular field. As various columns
can hold different types of data, so can the same data type control its own mechanism of internal
data entry. The length of data means different things to different fields. Columns that carry the same
data type can have different lengths.
Boolean Variables
A Boolean value is a piece of information stated as being true or false, On or Off, Yes or No, 1 or 0.
To declare a variable that holds a Boolean value, you can use the BIT or bit keyword.
After declaring a Boolean variable, you can initialize it with 0 or another value. If the variable is
initialized with 0, it receives the Boolean value of False. If it is initialized with any other number, it
receives a True value. Here is an example of a Boolean variable:

24
Practical Learning: Using Boolean Variables
1. Replace the statement with the following:

USE Variables1
DECLARE @IsMarried bit
SET @IsMarried = 1
SELECT @IsMarried AS [Is Married?]
2. Execute the statement

Integer Variables
An integer, also called a natural number, or a whole number, is a number that can start with a + or a
- sign and is made of digits. Between the digits, no character other than a digit is allowed. When the
number starts with +, such as +44 or +8025, such a number is referred to as positive and you should
omit the starting + sign. This means that the number should be written as 44 or 8025. Any number
that starts with + or simply a digit is considered as greater than 0 or positive. A positive integer is
also referred to (in the programming world) as unsigned. On the other hand, a number that starts with
a - symbol is referred to as negative.
If a variable would hold natural numbers in the range of -2,147,483,648 to 2,147,483,647, you can
declare it with the int keyword as data type. Here is an example:
DECLARE @Category int
SET @Category = 208
PRINT @Category
The length of an integer is the number of bytes its field can hold. For an int type, that would be 4
bytes.
If you except to use very small numbers such as student's ages, or the number of pages of a brochure
or newspaper, apply the tinyint data type to such a field. A variable with the tinyint data type can
hold positive numbers that range from 0 to 255.
The smallint data type follows the same rules and principles as the int data type except that it is used
to store smaller numbers that would range between -32,768 and 32,767.

25
The bigint data type follows the same rules and principles as the int data type except that its field
can hold numbers from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
The binary data type is used for a variable that would hold hexadecimal numbers. Examples of
hexadecimal numbers are 0x7238, 0xFA36, or 0xAA48D. Use the binary data type if all values of the
variable would have the exact same length (or quantity). If you anticipate that some entries would be
different than others, then use the alternative varbinary data type. The varbinary type also is used
for hexadecimal numbers but allows dissimilar entries, as long as all entries are hexadecimals.
Practical Learning: Using Integer Variables
1. Change the statement as follows:

DECLARE @IsMarried bit, @EmplStatus int


SET @IsMarried = 1
SET @EmplStatus = 2
SELECT @IsMarried AS [Is Married?],
@EmplStatus AS [Employment Status]
2. Execute the statement:

Decimal Variables
A decimal number is a number that can have a period (or the character used as the decimal separator
as set in the Control Panel) between the digits. An example would be 12.125 or 44.80. Like an
integer, a decimal number can start with a + or just a digit, which would make it a positive number. A
decimal number can also start with a - symbol, which would make it a negative number. If the
number represents a fraction, a period between the digits specifies what portion of 1 was cut. If you
anticipate such a number for a field, specify its data type as numeric or decimal (either decimal or
numeric would produce the same effect in SQL Server). Here is an example:

26
A floating-point number is a fractional number, like the decimal type. Floating-point numbers can be
used if you would allow the database engine to apply an approximation to the actual number that a
field is supposed to carry. To declare such a variable, use the float or the real keyword.
A precision is the number of digits used to display a numeric value. For example, the number 42005
has a precision of 5, while 226 has a precision value of 3. If the data type is specified as an integer
(the int and its variants) or a floating-point number (float and real), the precision is fixed by the
database and you can just accept the value set by SQL Server. For a decimal number (decimal or
numeric data types), SQL Server allows you to specify the amount of precision you want. The value
must be an integer between 1 and 38 (28 if you are using SQL Server 7).
A decimal number is a number that has a fractional section. Examples are 12.05 or 1450.4227. The
scale of a number if the number of digits on the right side of the period (or the character set as the
separator for decimal numbers for your language, as specified in Control Panel). The scale is used
only for numbers that have a decimal part, which includes currency (money and smallmoney) and
decimals (numeric and decimal). If a variable is declared with the decimal or numeric data type,
you can specify the amount of scale you want. The value must be an integer between 0 and 18. Here
is an example:

27
Practical Learning: Using Decimal Variables
1. Change the statement as follows:

DECLARE @IsMarried bit,


@EmplStatus int,
@WeeklyHours Decimal(6,2)
SET @IsMarried = 1
SET @EmplStatus = 2
SET @WeeklyHours = 36.50
SELECT @IsMarried AS [Is Married?],
@EmplStatus AS [Employment Status],
@WeeklyHours AS Hours
2. Execute the statement

Currency Variables
If a variable would hold monetary values, you can declare it with the money keyword. A variable
with a money data type can hold positive or negative values from -922,337,203,685,477.5808 to
+922,337,203,685,477.5807. Here is an example:
DECLARE @YearlyIncome Money
SET @YearlyIncome = 20800.12
SELECT @YearlyIncome
While the money data type can be used for a variable that would hold large quantities of currency
values, the smallmoney data type can be applied for a variable whose value cannot be lower than -
214,748.3648 nor higher than 214,748.3647.
The precision and scale of a money or smallmoney variable are fixed by SQL Server. The scale is
fixed to 4.
Practical Learning: Using Currency Variables
1. Change the statement as follows:

DECLARE @EmplStatus int,

28
@IsMarried bit,
@WeeklyHours Decimal(6,2),
@HourlySalary SmallMoney,
@WeeklySalary SmallMoney
SET @IsMarried = 1
SET @EmplStatus = 2
SET @WeeklyHours = 36.50
SET @HourlySalary = 15.72
SET @WeeklySalary = @WeeklyHours * @HourlySalary
SELECT @EmplStatus AS [Empl Status],
@IsMarried AS [Married?],
@WeeklyHours AS Hours,
@HourlySalary AS Hourly,
@WeeklySalary AS Weekly
2. Execute the statement

Date and Time Variables


A datetime data type is used for a column whose data would consist of date and/or time values. The
entries must be valid date or time values but SQL Server allows a lot of flexibility, even to display a
date in a non-traditional format. The date value of a datetime field can be comprised between
January 1st, 1753 and December 31, 9999.
The smalldatetime is an alternative to the datetime data type. It follows the same rules and
principles as the datetime data type except that a date value must be comprised between January 1st,
1900 and June 6, 2079.
To initialize a date or time-based variable, include the desired but recognizable value in single-quotes.
Here is an example:

Practical Learning: Using Date/Time Variables


1. Change the statement as follows:

DECLARE @DateHired DateTime,


@EmplStatus int,

29
@IsMarried bit,
@WeeklyHours Decimal(6,2),
@HourlySalary SmallMoney,
@WeeklySalary SmallMoney
SET @DateHired = '12/05/1998'
SET @IsMarried = 1
SET @EmplStatus = 2
SET @WeeklyHours = 36.50
SET @HourlySalary = 15.72
SET @WeeklySalary = @WeeklyHours * @HourlySalary
SELECT @DateHired AS [Date Hired],
@EmplStatus AS [Empl Status],
@IsMarried AS [Married?],
@WeeklyHours AS Hours,
@HourlySalary AS Hourly,
@WeeklySalary AS Weekly

Execute the statement

Character Variables
A field of characters can consist of any kinds of alphabetical symbols in any combination, readable or
not. If you want a variable to hold a fixed number of characters, such as the book shelf numbers of a
library, declare it with the char data type.
In the computer world, a string is a character or a combination of characters that are considered "as
is" with regards to the scenario in which they are used. If a variable will hold strings of different
lengths, declare it with the varchar data type. The maximum length of text that a field of varchar
type can hold is equivalent to 8 kilobytes.
In some circumstances, you will need to change or specify the number of characters used in a
varchar variable. Although a First Name and a Book Title variables should use the varchar type,
both variables would not have the same length of entries. As it happens, people hardly have a first
name that is beyond 20 characters and many book titles go beyond 32 characters. In this case, both
variables would use the same data type but different lengths. To specify the maximum number of
characters that can be stored in the variable, on the right side of varchar, type an opening and a
closing parentheses. Inside of the parentheses, type the desired number. Here is an example:
DECLARE @Welcome varchar(50)
SET @Welcome = 'Welcome to the world of Transact-SQL'
PRINT @Welcome
The text data type can be applied to a field whose data would consist of ASCII characters. As
opposed to a varchar type of field, a text type of field can hold text that is longer than 8 kilobytes.
The nchar, nvarchar, and ntext types follow the same rules as the char, varchar, and text
respectively, except that they can be applied to variables that would hold international characters, that
is, characters of languages other than US English. This is done following the rules of Unicode
formats.
Practical Learning: Using Character Variables
1. Change the statement as follows:

DECLARE @FirstName varchar(20),


@LastName varchar(20),
@FullName varchar(40),
@DateHired DateTime,
@EmplStatus int,
@IsMarried bit,
@WeeklyHours Decimal(6,2),

30
@HourlySalary SmallMoney,
@WeeklySalary SmallMoney
SET @FirstName = 'Samuel'
SET @LastName = 'Weinberg'
SET @FullName = @LastName + ', ' +@FirstName
SET @DateHired = '12/05/1998'
SET @IsMarried = 1
SET @EmplStatus = 2
SET @WeeklyHours = 36.50
SET @HourlySalary = 15.72
SET @WeeklySalary = @WeeklyHours * @HourlySalary
SELECT @FullName As [Full Name],
@DateHired AS [Date Hired],
@EmplStatus AS [Empl Status],
@IsMarried AS [Married?],
@WeeklyHours AS Hours,
@HourlySalary AS Hourly,
@WeeklySalary AS Weekly
2. Execute the statement

3. Save the file as Variables in your My Documents folder

31
Chapter 5
Functions Fundamentals
Introduction
A function is a relatively small task that should be performed aside but can be accessed any time to
give a result. Unlike most other languages, a function in Transact-SQL is always created publicly
(meaning it is automatically made available to any section of the database) and globally. As such, it is
stored in its own file.
After creating a function in Transact-SQL, it becomes part of the User-Defined Functions node in
the Enterprise Manager. Therefore, to view the structure of an existing function, in Enterprise
Manager, locate the database and expand it. Click the User-Defined Functions node in the left pane
and, in the right pane, double-click the name of the function.
Practical Learning: Introducing Functions
1. Open SQL Query Analyzer
2. To create a new database, in the Query Window, type and execute the following statement:

CREATE DATABASE Functions1


GO
USE Functions1
GO
3.

Function Creation
There are two main ways you can create a function: using Enterprise Manager or SQL Query
Analyzer. In the MMC, to create a function, in the desired database, right-click the User-Defined
Functions node and click New User Defined Function... You would be presented with a dialog box
that displays a formula in which you can make the necessary change.
In Transact-SQL, to create a function, you start with the CREATE FUNCTION expression
followed by a name. To indicate that the name represents that of a function, it must be followed by
parentheses:
CREATE FUNCTION FunctionName()
For a function to be useful, it must produce a result. This is also said that the function returns a
result or a value. When creating a function, you must specify the type of value that the function
would return. To provide this information, after the name of the function, type the RETURNS
keyword followed by a definition for a data type. Here is an example:
CREATE FUNCTION Addition()
RETURNS Decimal(6,3)
After specifying the type of value that the function would return, you can create a body for the
function. The body of a function starts with the BEGIN and ends with the END keywords:
CREATE FUNCTION Addition()
RETURNS Decimal(6,3)
BEGIN

END
Optionally, you can type the AS keyword before the BEGIN keyword:
CREATE FUNCTION Addition()
RETURNS Decimal(6,3)
AS
BEGIN

32
END
Between the BEGIN and END keywords, which is the section that represents the body of the
function, you can define the assignment the function must perform. After performing this
assignment, just before the END keyword, you must specify the value that the function returns. This
is done by typing the RETURN keyword followed by an expression.
CREATE FUNCTION Addition()
RETURNS Decimal(6,3)
AS
BEGIN

RETURN Expression
END

Practical Learning: Creating Functions


1. To create a function, replace the statement with the following:

CREATE FUNCTION CalculateWeeklySalary()


RETURNS Decimal(8,2)
AS
BEGIN
RETURN 880.44
END
2. Execute the function

Function Deletion
If you create a function and at one time decide that you don't need it any more, you can delete it. To
delete a function, in the Enterprise Manager, locate the function in the User-Defined Functions
node. Right-click it and click Delete. To programmatically delete a function, in the Query Window,
type DROP FUNCTION followed by the name of the function.

Function Implementation
Local Variables
As mentioned already, in the body of the function, you define what the function is supposed to take
care of. As a minimum, a function can return a simple number, typed on the right side of the
RETURN keyword. Here is an example:
CREATE FUNCTION Addition()
RETURNS int
BEGIN
RETURN 1
END
You can also declare new variables in the body of the function to help in carrying the assignment. A
variable declared in the body of a function is referred to as a local variable. Once such a variable has
been declared, it can be used like any other variable. Here is an example:
CREATE FUNCTION Addition()
RETURNS int
BEGIN
DECLARE @Number1 int
SET @Number1 = 588
RETURN @Number1 + 1450
END

33
Function Calling
After a function has been created, you can use the value it returns. Using a function is also referred to
as calling it. To call a function, you must specify the database in which it was created and the dbo
factor. The formula to use is:
DatabaseName.dbo.FunctionName()
Because a function returns a value, you can use that value as you see fit. For example, you can use
either PRINT or SELECT to display the function's value in the Query Window. Here is an example
that calls the above Addition() function:
PRINT Variables1.dbo.Addition()

Functions and Arguments


Introduction
In order to carry its assignment, a function can be provided with some values. Put it another way,
when you create a function, instead of, or in addition to, local variable, you may want the code that
will call the function to provide the values needed to perform the assignment. For example, imagine
you want to create a function that would generate employees email addresses when user has entered a
first and last name. At the time you are creating the function, you cannot the names of employees,
including those who have not even been hired yet. In this case, you can write the whole function but
provide one or more placeholders for values that would be supplied when the function is called.
An external value that is provided to a function is called an argument. A function can also take more
than one argument. Therefore, when you create a function, you also decide whether your function
would take one or more arguments and what those arguments, if any would be.
An Argumentative Function
We have already seen that a function's name is also followed by parentheses. If the function doesn't
use an external value, its parentheses can be left empty. If a function will use an external value, when
you create the function, you must specify a name and the type of value of the argument. The name of
the argument is created with the @ sign. Here is an example:
CREATE FUNCTION Addition(@Number1 Decimal(6,2))
When a function takes an argument, in the body of the function, you can use the argument as if you
knew its value, as long as you respect the type of that value. Here is an example:
CREATE FUNCTION Addition(@Number1 Decimal(6,2))
RETURNS Decimal(6,2)
BEGIN
RETURN @Number1 + 1450
END
When you call a function that takes one argument, you must supply a value for that argument. To do
this, type the value of the argument in the parentheses of the function. Here is an example:

34
Instead of only one argument, you can also create a function that takes more than one argument. In
this case, separate the arguments in the parentheses of the function with a comma. Here is an
example:
CREATE FUNCTION Addition(@Number1 Decimal(6,2), @Number2 Decimal(6,2))
Once again, in the body of the function, you can use the arguments as if you already knew their
value. You can also declare local variables and involve them with arguments as you see fit. Here is an
example:
CREATE FUNCTION Addition(@Number1 Decimal(6,2), @Number2 Decimal(6,2))
RETURNS Decimal(6,2)
BEGIN
DECLARE @Result Decimal(6,2)
SET @Result = @Number1 + @Number2
RETURN @Result
END
When calling a function that takes more than one argument, in the parentheses of the function,
provide a value for each argument, in the exact order they appear in the parentheses of the function.
Here is an example:
PRINT Variables1.dbo.Addition(1450, 228)
You can also pass the names of already declared and initialized variables. Here is an example that
calls the above function:
DECLARE @Nbr1 Decimal(8,3),
@Nbr2 Decimal(4,2)
SET @Nbr1 = 4268.55
SET @Nbr2 =26.83
SELECT @Nbr1 As First,
@Nbr2 As Second,
Variables1.dbo.Addition(@Nbr1, @Nbr2) AS Result
This would produce:

35
Practical Learning: Creating Functions With Arguments
1. To create a function that takes arguments, change the statement as follows:

DROP FUNCTION CalculateWeeklySalary


GO
CREATE FUNCTION CalculateWeeklySalary(@Hours Decimal(5,2),
@Salary SmallMoney)
RETURNS Decimal(8,2)
AS
BEGIN
DECLARE @Weekly SmallMoney
SELECT @Weekly = @Hours * @Salary
RETURN @Weekly
END
GO
2. Execute the statement
3. To call the function, replace the statement with the following:

DECLARE @WeeklyHours Decimal(5,2),


@Hourly SmallMoney
SELECT @WeeklyHours = 42.50
SELECT @Hourly = 18.62
SELECT 'Hermine Singh' As [Employee Name],
@WeeklyHours As [Weekly Hours],
@Hourly As [Hourly Salary],
Functions1.dbo.CalculateWeeklySalary(@WeeklyHours,
@Hourly) AS [Weekly Salary]
GO
4. Execute the statement

36
37
Chapter 6
Overview of Table Design
Introduction
The information relevant to a database is stored in tables. This information is organized in columns
and rows. A column holds a category of data that is common to all records. A row is called a record
and holds all information that belongs to an entry of the table. To organize the information that a
column holds, a table needs a series of details about each column. Two aspects are particularly
important: a name and the type of data that a column should/must/can hold.
Practical Learning: Starting a Database
1. Start Microsoft SQL Server. In the MMC window, expand the Databases folder
2. In the left frame, right-click Databases and click New Database...
3. On the Database Properties dialog box, click the General property sheet.
In the Name text box, type BCR

4. Click the Data Files property sheet.

38
5. Click under Initial Size (MB) and type 10 Accept the Filegroup as PRIMARY

6. Click the Transaction Log property sheet


7. Click under Initial Size (MB) and type 2

39
8. Click OK
9. In the left frame, click the + sign of BCR to expand it. In the left frame, right-click Tables
(under BCR) and click New Table...

Columns and Object Names


The name of a column allows the database as a file to identify the column. The name of a column
also will help you, the database developer, to identify that column. There are rules and suggestions
you must or should follow when naming the columns of a table.
The name of a column:
• can start with a letter, a digit, or an underscore
• Can include letters, digits, and spaces in any combination

40
After respecting these rules, you can add your own rules. On this site, we will apply the rules we
defined in for objects names
Practical Learning: Setting Columns Names
• As the cursor is blinking in the first empty field under the Column Name column, type
FirstName

The Types of Data


After deciding on the name of a column, the database needs to know what kind of information the
column would hold. Since there are various kinds of information a database can deal with, SQL
Server provides a set of categories called data types. Therefore, you must specify the data type that is
necessary for a particular column. The data types are those we reviewed when studying variables.

Practical Learning: Setting Data Types


1. Click the empty field under the Data Type column and notice that it is a combo box. Also
notice that the char data type is selected as default
2. Click the arrow of the combo box, scroll down and select varchar from the list

3. Click the first empty field under FirstName and type MI

41
4. Press the down arrow key to position the cursor under MI
5. Type LastName and press the down arrow key
6. Type DateHired
7. Press Tab and type d
8. Notice that the datetime data type is selected.
9. Press Enter three times to position the mouse cursor under DateHired
10. Type EmployeeNumber and press the down arrow key
11. Notice that the char data type was selected by default for the EmployeeNumber field
12. Complete the table as follows:

The Length of Data


A database deals with various types of data, appropriate or not for certain fields. This means that you
should take care of jobs behind the scenes as much as you can. One way you can do this is by
controlling the amount of information that can be entered in a particular field. As various columns
can hold different types of data, so can the same data type control its own mechanism of internal
data entry. The length of data means different things to different fields. Columns that carry the same
data type can have different lengths.
Bit Fields: We saw already that a bit column type is meant for one of two answers. The user is
supposed to simply let the database know that the answer is yes or no, true or false, on or off, 1 or 0.
Therefore, the only length of this field is 1.
Integers: The length of an integer is the number of bytes its field can hold. For an int type, that
would be 4 bytes.
Decimal and Floating-Point Numbers: The Length specifies how many bytes the field can store.
Strings: The Length of a character or string column specifies the maximum number of characters
that the field can hold.
In some circumstances, you will need to change or specify the length as it applies to a particular field.
For example, since you should use the varchar data type for a string field whose content will change
from one record to another, not all varchar columns need to have the same length. Although a First
Name and a Book Title columns should use the varchar type, both columns would not have the
same length of entries. As it happens, people hardly have a first name that is beyond 20 characters
and many book titles go beyond 32 characters. In this case, both fields would use the same data type

42
but different lengths. On the other hand, for columns of datetime and money data types, you
should accept the default length suggested by the database.

Practical Learning: Setting Data Types


1. Double-click the Length field for the EmployeeNumber and type 6
2. Press the down arrow key and type 40 for the Length of the Address field.
3. In the same way, complete the table as follows:

The Nullity of a Field


During data entry, users of your database will face fields that expect data. Sometimes, for one reason
or another, data will not be available for a particular field. An example would be an MI (middle
initial) field: some people have a middle initial, some others either don't have it or would not provide
it to the user. This aspect can occur for any field of your table. Therefore, you should think of a way
to deal with it.
A field is referred to as null when no data entry has been made to it:
• Saying that a field is null doesn't mean that it contains 0 because 0 is a value.
• Saying that a field is null doesn't mean that it is empty. A field being empty could mean that
the user had deleted its content or that the field itself would not accept what the user was trying to
enter into that field, but an empty field can have a value.
A field is referred to as null if there is no way of determining the value of its content (in reality, the
computer, that is, the operating system, has its own internal mechanism of verifying the value of a
field) or its value is simply unknown. As you can see, it is not a good idea to have a null field in your
table. As a database developer, it is your responsibility to always know with certainty the value held
by each field of your table. Remember that even if a field is empty, you should know what value it is
holding because being empty could certainly mean that the field has a value.
To solve the problem of null values, SQL Server proposes one of two options: allow or not allow
null values on a field. For a typical table, there are pieces of information that the user should make
sure to enter; otherwise, her data entry would not be validated. To make sure the user always fills out
a certain field before moving to the next field, you must make sure the field doesn't allow null values;
this will ensure that you know that the field is holding a value and you can find out what that value is.
This is enforced by clearing the Allow Nulls check box for a field. On the other hand, if the value of
a field is not particularly important, for example if you don't intend to involve that value in an
algebraic operation, you can allow the user to leave it null. This is done by checking the Allow Nulls
check box for the field.

43
Practical Learning: Applying Fields Nullity
• To apply the nullity of fields, change the table as follows:

Tables Names
While or after creating a table, you should save it. If you are freshly creating a table and decide to
save it, you would be prompted to name it. The name of a table:
• Can be made of digits only. For example you can have a table called 148
• Can start with a digit, a letter, or an underscore
• Can be made of letters, digits, and spaces
Besides these rules, you can make up yours. On this tutorial, we will use the same rules we defined
for objects names to name our tables.
Practical Learning: Naming a Table
1. To save your table, on the toolbar of the table, click the Save button

2. In the Choose Name dialog box, type Employees and press Enter
3. After saving the table, close it by clicking its system Close button .
Tables, Fields and Their Properties
Introduction
It will not be unusual that, as you learn more or become highly productive, you will be dealing with
various databases, some of which you will create, some others will have been created by someone
else. In all cases, whenever you are performing a database task on an existing database, you should
make sure you know which database you are using at all times.
In SQL, to specify the database you want to use, use the USE keyword followed by the name of the
database you want to use. This is done with the following syntax:

44
USE DatabaseName
The database you want to use must exist in the system and it is specified by its name after he USE
keyword.
Using the SQL Query Analyzer, there is another technique to specify the database you want to work
with. On the toolbar, click the arrow of the combo box and select the database you want to use.
Alternatively, if you don't know for sure what database you want to select or you don't even know
what databases exist on your server, on the main menu, you can click Query -> Change Database...
This would display the Select Database dialog box:

You can click the desired database and click OK.


Whether you use the USE keyword or the combo box, once you have selected your database, unless
specified otherwise, any instruction you give in the Query window would apply to the selected
database.
Practical Learning: Using Multiple Databases
1. Start the SQL Query Analyzer
2. To create a new database, type the following statement:

CREATE DATABASE PublicLibrary;


3. Press F5
4. To create another database, type and execute the following statement:

CREATE DATABASE Countries;


5. Notice the name of the database on the combo box of the toolbar. It should be master.
Now that we have a few databases, let's specify which one to use.
On the main menu, click Query -> Change Database...
6. In the Select Database dialog box, click pubs and click OK. Notice that the database has
changed in the combo box.
7. In the upper section of the window, type and execute the following statement:

USE PublicLibrary;
8. Notice that a message in the bottom frame lets you know that the command completed
successfully.
On the combo box of the toolbar, notice that the name has changed:

45
Creating a Table Using the Query Analyzer
In SQL, to create a table, use the statement
CREATE TABLE TableName
The CREATE and TABLE keywords must be used to let SQL know that you want to create a
table. The TableName factor specifies the name of the new table. The TableName can use the rules
and suggestions we reviewed for the database objects.
After specifying the name of the table, you must list the columns of the table. The list of columns
starts with an opening parenthesis "(". The list ends with a closing parenthesis ")". Each column must
be separated from the next with a comma, except for the last column. You can include all columns
on the same line if possible as follows:
CREATE TABLE Country(Column1, Column2, Column3)
Alternatively, to make your statement easier to read, you should create each column on its own line
as follows:
CREATE TABLE Country(
Column1,
Column2,
Column3);
There are two primary pieces of information you must specify for each column: its name and its type.
Therefore, the syntax of creating a column is:
ColumnName DataType Options
The name of a column should follow the same rules and suggestions we reviewed for the database
objects.
After typing the name of the column, type the desired or appropriate data type for the column. For
this example, use one of the (that is the appropriate) data types we reviewed.
Remember that some of the data types need to have a length. This is certainly true for all string or
text-based columns (char, text, varchar, etc). In the case of text-based columns, when using SQL to

46
create your columns, because it is less visual than the table design of the Enterprise Manager, you
cannot rely on the default length of strings suggested by SQL (in fact, in MySQL, you must specify a
length for varchar). As it happens, SQL Query Analyzer and the New Table window specify
different default values for text-based columns. Therefore, when using SQL to create your columns,
you should (strongly) specify your own default length for text-based columns.
We saw that some fields would allow blank values, called nulls. If you don't want a column to have
empty fields, specify its option as NOT NULL remember that SQL is not a case-sensitive language,
but we type SQL own words in uppercase to make them distinct from our own words). If a field can
afford null values, you do not have to specify that as an option.
Practical Learning: Creating a Table Using the SQL Query
Analyzer
1. Make sure you are using the PublicLibrary database. To create a new table, type the
following:

CREATE TABLE Members


2. Press Enter and continue the table to complete it as follows:

CREATE TABLE Members


(
FirstName VARCHAR(20),
MI CHAR,
LastName VARCHAR(20),
Address VARCHAR(50),
City VARCHAR(40),
State CHAR(2),
MaritalStatus BIT
);

3. Execute the statement (which you can do by pressing F5).


4. To create another table, type and execute the following statement:

CREATE TABLE Books


(
ShelfNbr CHAR(6),
BookTitle VARCHAR(50),
AuthorName VARCHAR(50),
Category INT,
CopyYear INT,
CoverType VARCHAR(18),
Pages SMALLINT,
);

5. To specify a database and create a table in one step, type the following statement:

USE Countries
CREATE TABLE Country
(
CountryName varchar(50) NOT NULL,
Area bigint,
Population BigInt,
Capital VarChar(40) NOT NULL,
InternetCode char(2)
)

47
6. Execute it by pressing F5.
7. Close the SQL Query Analyzer window.
8. When asked whether you want to save the text, click No.
If you are back in the MMC, right-click the right frame and click Refresh.

Introduction to Fields Properties


A column on a table controls what kind of data is appropriate for that particular column. The
characteristics that identify or describe such a table are defined as its properties. As we have seen
previously, three primary properties are particularly important and required for each column: the
name, the data type, and the length. Besides these, some other properties can be used to further
control the behavior of a particular field.
Besides the name, data type and length of a column, you can control the columns of a table using the
Columns property sheet in the lower section of the table in Design View. These properties
sometimes depend on the data type of the column. Therefore, to specify the properties of a column,
you must first select it in the upper section of the table. This selection can be done by just clicking
either the name, the data type, or the length of the column. Then you can either press F6 or click the
first field in the lower section, select the desired property and type the necessary value:

Description: Common and enabled for all fields, the description is used for a sentence that describes
the column. You can type anything on that field.
Default Value: This is used to display a value in case the user would not enter a value in a field that
allows null values.
Precision: A precision is the number of digits used to display a numeric value. For example, the
number 42005 has a precision of 5, while 226 has a precision value of 3. The Precision field is used
for columns that hold numeric values (integers and decimal numbers). If the data type is specified as
an integer (the int and its variants) or a floating-point number (float and real), the precision is fixed
by the database and you can just accept the value set by SQL Server. For a decimal number (decimal
or numeric data types), SQL Server allows you to specify the amount of precision you want. The
value must be an integer between 1 and 38 (28 if you are using SQL Server 7).
Scale: A decimal number is a number that has a fractional section. Examples are 12.05 or 1450.4227.
The scale of a number if the number of digits on the right side of the period (or the character set as
the separator for decimal numbers for your language, as specified in Control Panel). The Scale
property is used only for numbers that have a decimal part, which includes currency (money and
smallmoney) and decimals (numeric and decimal). If the data type is set as money or
smallmoney, the scale is fixed to 4. If the column is of a decimal or numeric data type, you can
specify the amount of scale you want. The value must be an integer between 0 and 18.

48
Identity: If a column is used as an identifier such as a primary key (soon, we will learn what a
primary key is), you can set so using the Identity property. The default value is No, which would
mean that the column is not used as an identifier. If the column is used as an identifier, set its
Identity property to Yes. If the column is used as an identifier except when a replication is adding
data to the table, you can set this property to Yes (Not For Replication).
Identity Seed: If you set the Identity property to Yes, you can specify how the value would change
for the field. For example, if you set the Identity to Yes for a column that is the primary key and the
column's data type is an integer, you can use the Identity Seed property to specify what would be
the first number counted. This can allow you to ask the database to start counting the numbers at a
value other than 1.
Identity Increment: If you specify the Identity property of a column as Yes, you can use the
Identity Increment to specify how the counting would occur. By default, SQL Server would count
numbers in increments of 1. An example would be 15, 16, 17, 18, etc. With a custom Identity
Increment, you can use a number of 5 to increment as 15, 20, 25, 30, etc.
Is RowGuid: This property allows you to specify that a column with the Identity property set to
Yes is used as a ROWGUID column.
Formula: This property is used to specify a formula used for the column. The formula can be an
algebraic expression or any expression, which are things we will learn soon.
Collation: Because different languages use different mechanisms in their alphabetic characters, this
can affect the way some sort algorithms or queries are performed on data, you can ask the database
to apply a certain language mechanism to the field by changing the Collation property. Otherwise,
you should accept the default specified by the table.
Practical Learning: Setting Fields Properties
1. Start SQL Server and expand the Databases folder
2. Create a new database named LiquorStore
3. Create a new table and add the following fields to it EmployeeNo and DataHired
4. Save the table as Employees
5. In the top section of the table, click EmployeeNo to select it and press F6.
6. In the lower section of the table, in the Description field, type
Employee Number set by the Management
7. Complete the table as follows:

49
8. In the top section, click DateHired and press F6. In the Description field, type:
Date the employee was formally hired
9. In the top section, click Country
10. In the lower section for the Country field, click the Default Value field and type USA
11. In the upper section, click MaritalStatus
12. In the lower section for the MaritalStatus field, set the Default Value to 0
13. After using the table, to close it, click its Close button .
14. When asked whether you want to save the changes, click Yes.

50
Chapter 7
Data Navigation With Tables
Table Data Navigation in MMC
Data Navigation consists of displaying and viewing data, for any reason judged necessary. Because
information of a database is stored in tables, your primary means of viewing data consists of opening
a table in a view that displays its information.
In SQL Server, to view data, you open a table in the view that displays the records. To do this, you
can right-click the table -> Open Table -> Return All Rows. If the table contains too much
information, you can specify the maximum number of records you want to see. To do this you would
select Return Top... This would present a dialog box that allows you to type the desired number. The
third option (just like the first two) has to do with queries but we haven't studied them yet.
When a table displays its records, you navigate through its fields using the mouse or the keyboard.
With the mouse, to get to any cell, you can just click it. To navigate through records using the
keyboard, you can press:
• The right arrow key to move to the right cell; if the caret is already in the most right cell, it
would be moved to the first cell of the next record, up to the last empty cell of the first empty record
• The left arrow key to move to the previous cell; if the caret is in, or reaches, the most left cell
of the first record, nothing would happen when you press the the left arrow key
• The down arrow key to move to the cell under the current one; if the caret is already in the
last cell of the current column, nothing would happen
• The up arrow key to move to the cell just above the current one; if the caret is already in the
first cell of the current column, nothing would happen
• The Page Down to move to the next group of cell that would correspond to the next page; if
the number of records is less than a complete page, the caret would move to the last cell of the
current column
• The Page Up to move to the next group of cell that would correspond to the next page; if
the number of records is less than a complete page, the caret would move to the first cell of the
current column

Practical Learning: Navigating Through Records of a Table


1. Start the Enterprise Manager (MMC) of Microsoft SQL Server.
Expand the Microsoft SQL Servers node. Expand the server node. Expand the Databases folder.
2. Expand Northwind (by clicking its + symbol)
3. In the left frame, click Tables
4. In the right-frame, right-click Customers, position the mouse on Open Table and click
Return All Row

51
5. To navigate through records, press the right arrow key twice
6. Press the down arrow key five times
7. Press Ctrl + End to move to the last record
8. Press Page Up
9. Press Ctrl + Home
10. After viewing the records, to close the table, click its system Close button

Data Navigation With a Microsoft Access Table


Besides the MMC, if you have Microsoft Access, you can use it to display data from a SQL Server
table. To use a SQL Server table in Microsoft Access, you must create a project (in Microsoft
Access). This would require you to connect to the database.
Microsoft Access makes it easy to display data from a SQL Server table because it automatically
imports the tables of the database you select.

Practical Learning: Navigating Data With Microsoft Access


1. Start Microsoft Access
2. On the opening Microsoft Access dialog box, click the Access Database Wizards, Pages,
And Projects radio button and click OK
3. In the New dialog box, click the General property page and click the Project (Existing
Database) icon

52
4. Click OK
5. In the File New Database dialog box, specify the name as NWind

6. Click Create
7. In the Data Link Properties dialog box, make sure the Connection property page is selected.
In the first combo box, select the server that holds the database
8. Specify your preferred authentication mode in the 2 section
9. In the second combo box, select Northwind
10. Click Test Connection

53
11. Click OK and OK
12. To display a SQL Server table, in the Tables section of the Database window, double-click
Customers

13. To navigate through records, press the right arrow key twice
14. Press the down arrow key five times
15. Press Ctrl + End to move to the last record
16. Press Page Up
17. Press Ctrl + Home
18. After viewing the data, close the table by clicking its System Close button

54
Chapter 8
Data Entry With Tables
Introduction
As you are probably aware already, columns are used to organize data by categories. Each column
has a series of fields under the column header. One of the actual purposes of a table is to display data
that is available for each field under a particular column. Data entry consists of providing the
necessary values of the fields of a table. Data is entered into a field and every time this is done, the
database creates a row of data. This row is called a record. Therefore, entering data also self-creates
rows. Except for any unknown reason I can't think of, you will never have to create rows of a table.
They are created automatically as the user is entering data.
There are four main ways you can perform data entry for a Microsoft SQL Server table:
• You can use a table from the Enterprise Manager
• You can enter data by typing code in the SQL Query Analyzer
• You can import data from another object or another database
• You can use an external application such as Microsoft Access, Borland C++ Builder,
Microsoft Visual C++, Borland Delphi, Microsoft Visual Basic, etc.
Using the Enterprise Manager
Probably the easiest and fastest way to enter data into a table is by using the Enterprise Manager. Of
course, you must first open the desired table from an available database. In the MMC, after selecting
the database and the Tables node, to open a table for data entry, right-click it, position your mouse
on Open Table, and click Return All Rows. If the table does not contain data, it would appear with
one empty row. If some records were entered already, their rows would show and the table would
provide an empty row at the end, expecting a new record:

To perform data entry on a table, a user would click in a field. Each column has a title, called a
caption, on top. This gray section on top is called a column header. In SQL Server, it displays the
actual name of the column. When using external and friendlier applications, you will find out that the
caption can be different from the actual name of a column.

55
The user refers to the column header to know what kind of data should/must go in a field under a
particular column. This is why you should design your columns meticulously. After identifying a
column, a user can type a value. Except for text-based columns, a field can accept or reject a value if
the value does not conform to the data type that was set for the column. This means that in some
circumstances, you may have to provide some or more explicit information to the user.
While performing data entry, the user may skip some fields if the information is not available. The
user can skip only columns that allow NULL values. If a column was configured as NOT accepting
NULL values, the user must enter something in the field, otherwise he would receive an error and
the table would not allow going further.
Practical Learning: Performing Data Entry on a Table
1. Start the Enterprise Manager of Microsoft SQL Server.
2. Expand the Countries database and the click the Tables node.
3. In the right frame, right-click Country, position the mouse on Open Table and click Return
All rows
4. As the cursor is positioned in the first empty field under CountryName, type Cote d'Ivoire
and press Enter
5. Type 322460 and press Tab
6. Type 16,393,221 and press Enter
7. Notice that you receive an error because the commas are not allowed:

8. Click OK on the error message box.


9. Type 16393221 People and press Tab.
10. Notice that you receive another error because the column is configured for a natural number
and not a string.
11. Click OK on the error message box and delete People
12. Click under InternetCode, type td and press Enter

13. Notice that you receive an error because you left the Capital field empty in the previous
record although the Capital column does NOT allow NULL
14. Click OK on the error message box
15. Click the field under Capital, type Yamoussoukro and press Enter twice
16. Notice that we typed td as the Internet Code for Cote D'Ivoire and the database allowed it.
The Internet Code of Cote d'Ivoire is not td. This was done to illustrate that the database engine
does not perform such validations unless explicitly directed to do so
17. Under InternetCode, double-click td to select the entry, type ci and press Enter
18. Complete the table as follows:

56
19. Close the table

Data Entry With SQL Query Analyzer


In the SQL, data entry is performed using the INSERT combined with the VALUES keywords.
The primary statement uses the following syntax:
INSERT TableName VALUES(Column1, Column2, Column_n)
Alternatively, or to be more precise, you can specify that you are entering data in the table using the
INTO keyword between the INSERT keyword and the TableName factor. This is done with the
following syntax:
INSERT INTO TableName VALUES(Column1, Column2, Column_n)
The TableName factor must be a valid name of an existing table in the database you are using. If the
name is wrong, the SQL would simply consider that the table you are referring to doesn't exist.
Consequently, you would receive an error.
The VALUES keyword indicates that you are ready to list the values of the columns. The values of
the columns must be included in parentheses.
If the column is a BIT data type, you must specify one of its values as 0 or 1.
If the column is a numeric type, you should pay attention to the number you type. If the column was
configured to receive an integer (int, bigint, smallint), you should provide a valid natural number
without the decimal separator.
If the column is for a decimal number (float, real, decimal, numeric), you can type the value with
its character separator (the period for US English).
If the column was created for a date data type, make sure you provide a valid date.
If the data type of a column is a string type, you should include its entry between single quotes. For
example, a shelf number can be specified as 'HHR-604' and a middle initial can be given as 'D'.

In the previous paragraphs, we were stating "you" as if you will be the one performing data entry. In
reality, the user will be performing data entry on your products. Therefore, it is your responsibility to
reduce, as much as possible, the likelihood of mistakes. Of course, there are various ways, through a
"visual" application such as Borland C++ Builder, Microsoft Visual Basic, or Visual C++, etc, that
you can take care of this.

Adjacent Data entry


The most common technique of performing data entry requires that you know the sequence of fields
of the table in which you want to enter data. With this subsequent list in mind, enter the value of
each field in its correct position.

57
During data entry on adjacent fields, if you don't have a value for a numeric field, you should type 0
as its value. For a string field whose data you don't have and cannot provide, type two single-quotes ''
to specify an empty field.
Practical Learning: Performing Adjacent Data Entry
1. Open the SQL Query Analyzer
2. On the toolbar, click the arrow of the combo box and select Countries
3. In the child window, type:

INSERT Country VALUES('Sweden',449964,8875053,'Stockholm','se')

4. Press F5 to execute
5. To perform another entry, type and execute the following statement:

INSERT Country
VALUES
(
'Angola',
1246700,
10593171,
'Luanda',
'ao'
)
6. To perform another entry, type and execute the following statement:

INSERT INTO Country VALUES


(
'Mongolia', 1565000, 2694432, 'Ulaanbaator','mn'
)

58
7. To perform an entry with a NULL and an empty field, type and execute the following
statement:

INSERT INTO Country


VALUES('Trinidad and Tobago', NULL, 1163724, 'Port-of-Spain','')
8. To perform another entry with NULL fields, type and execute the following statement:

INSERT INTO Country VALUES('Spain', NULL, NULL, 'Madrid', '')


9. Close the SQL Query Analyzer. When asked whether you want to save your statement, click
No.
Random Data Entry
The adjacent data entry we have been performing requires that you know the position of each field.
The SQL provides an alternative that allows you to perform data entry using the name of a field
instead of its position. This allows you to provide the values of fields in any order you desire. We
have just seen a few examples where the values of some of the fields are not available during data
entry. Instead of remembering to type 0 or NULL for such fields or leaving empty quotes for a field,
you can use their names to specify the fields whose data you want to provide.
To perform data entry at random, you must provide a list of the fields of the table in the order of
your choice. You can either use all columns or provide a list of the same columns but in your own
order. In the same way, you don't have to provide data for all fields, just those you want, in the order
you want.
Practical Learning: Performing Random Data Entry
1. To perform our first random data entry, type and execute the following statement:

INSERT Country(CountryName, Capital,InternetCode,Population,Area)


VALUES('Taiwan', 'Taipei', 'tw', 22548009, 35980)
2. To perform another random data entry, type and execute the following statement:

INSERT
Country(InternetCode, CountryName, Capital, Area)
VALUES( 'mx', 'Mexico', 'Mexico', 1972550)
3. Type and execute one more statement as follows:

INSERT Country(
Population, CountryName, InternetCode, Capital)
VALUES(
NULL, 'Cape Verde', '', 'Praia')
4. Type and execute this last statement:

INSERT Country(CountryName, Capital)


VALUES('Tunisia', 'Tunis')
5. Close the SQL Query Analyzer. When asked whether you want to save the changes in the
text, click No.
Data Import
Another technique used to perform data entry consists of importing already existing data from
another database or from any other recognizable data file. Microsoft SQL Server provides various
techniques and means of importing data into Microsoft SQL Server.
The easiest type of data that can be imported into SQL Server, and which is available on almost all
database environments is the text file. Almost any database application you can think of can import a
text file but data from that file must be formatted in an acceptable format. For example, the
information stored in the file must define the columns as distinguishable by a character that serves as

59
a separator. This separator can be the single-quote, the double-quote, or any valid character. SQL
Server is able to recognize the double-quote as a valid separator of columns. Data between the
quotes is considered as belonging to a distinct field. Besides this information, the database would
need to separate information from two different columns. Again, a valid character must be used.
Most databases, including SQL Server, recognize the comma as such a character. The last piece of
information the file must provide is to distinguish each record from another. This is easily taken car
of by the end of line of a record. This is also recognized as the carriage return.
These directives can help you manually create a text file that can be imported into SQL Server. In
practicality, if you want to import data that resides on another database, you can ask that application
to create the source of data. Most applications can do that for and format it so another application
can easily use such data. That is the case for the data we will use in the next exercise: it is data that
resided on a Microsoft Access database and was prepared to be imported in SQL Server.
After importing data, you should verify and possibly format it to customize its fields.
Practical Learning: Importing Data From an External Source
1. Download the Students text file and save it to your hard drive.
2. In the Enterprise Manager, right-click the Databases node and click New Database...
3. Type HighSchool and press Enter
4. In the left frame, right-click HighSchool, position the mouse on All Tasks and click Import
Data
5. On the first page of the wizard, click Next
6. On the second page, click the arrow of the Data Source combo box and select Text File:

7. Click the button on the right side of the File Name edit box

60
8. Locate the folder where you saved the Students text file. Select the file and press Enter:

9. Click Next

10. On the third page, make sure the file is type ANSI and the Row Delimiter is the Carriage
Return-Line Feed ({CR}{LF}) and accept all other defaults. Click Next

61
11. On the fourth page, accept all defaults and click Next.
12. On the fifth page, make sure that the Destination is SQL Server and the destination
Database is HighSchool. Then click Next
13. Accept all defaults from the sixth and the seventh pages. Then click Next.
14. On the eighth page, click Finish

62
15. When you receive a confirmation of "Successfully Copied, click OK
16. On the Executing Package page, click Close
17. Back in the MMC, expand the HighSchool node if necessary, and click Tables. in the right
frame, right-click Students and click Design Table.
18. As the first field is selected, type StudentNbr and change its Length to 10
19. Change the other columns as follows:

20. To save the table, click the Save button on the toolbar:

21. When a Validation Warnings dialog box presents a few warnings, click Yes
22. Close the table.
23. To view data stored on the table, right-click Students -> Open Table -> Return All Rows

63
Chapter 9
Data Selection and Analysis
Introduction to Data Analysis
Overview
After creating a table, the next step is probably to see what you can do with data stored in it. One of
the most commonly performed operations by the users on a database is to look for data or to isolate
data that responds to a particular criterion. Looking for data that is conform to a criterion is referred
to as querying.
As a database developer, you perform queries by passing instructions to the database engine. This is
done using some special reserved words.
In SQL Server, data analysis can be performed using Enterprise Manager or the SQL Query
Analyzer. In this lesson, I will perform data analysis using Enterprise Manager and you will do in the
SQL Query Analyzer.
Before performing data analysis in Enterprise Manager, you must first open the table that Returns All
Rows. To actually perform data analysis, on the toolbar, you can click the Show/Hide SQL Pane
button .
Field Selection
The most fundamental keyword used by SQL is SELECT. In order to process a request, you must
specify what to select. Therefore, the SELECT keyword uses the following syntax:
SELECT What FROM WhatObject;

As stated already, SQL is not case-sensitive. That means SELECT, Select, and select represent the
same word.
To select everything from a table, you can use the asterisk as the range of values. For example, to
display all records from a table called Students, you can type
SELECT * FROM Students
After writing the expression, you must execute the query. This can be done by click the Run button

. Alternatively, you can writer click anywhere in the window and click Run:

64
As opposed to viewing all data, you can also select one particular column whose fields you want to
view. To do this, you can replace the What in the syntax with the name of the desired column. For
example, to get a list of last names of students, you can type:
SELECT LastName FROM Students
When you execute the query, it would display only the column that contains the last names.
To consider more than one column in a query, you can list them in the What factor of our syntax,
separating them with a comma except for the last column. The syntax you would use is:
SELECT Column1, Column2, Column_n FROM WhatObject;
For example, to display a list that includes only the names, gender, Email address and home phone of
records from a table called Students, you would type:
SELECT FirstName, LastName, Gender, EmailAddress, HomePhone
FROM Students
When execute, this expression would produce:

65
Practical Learning: Performing Data Analysis
1. Start Microsoft SQL Server Enterprise Manager and switch to SQL Query Analyzer.
2. Enlarge the Query window as much as you can. In the combo box of the toolbar, select
Northwind (if necessary)

66
3. To select everything from the Customers table, in the empty window, type

SELECT * FROM Customers


4. To execute the query, click the Execute Query button to see the result
5. As opposed to viewing all data, you can also select one particular column whose fields you
want to view. For example, to get a list of countries where the Northwind customers reside, change
the statement as follows:

SELECT Country FROM Customers


6. To execute the query, press F5
7. You can also make a list of some specific columns whose data you want to see. For example,
to get information about the companies that Northwind is doing business with, you can list the
company names and their contact information. To get it, change the statement as follows:

SELECT CompanyName, ContactName, ContactTitle FROM Customers


8. Execute it to see the result:

9. It is sometimes a good idea to divide a statement on different lines to make it a little easier to
read.
As an example, change the statement as follows:

SELECT CompanyName, ContactName, ContactTitle


FROM Customers

10. Execute it.

67
Conditions and Data Analysis
List Arrangement
The lists of records we got above with the SELECT statement were presented in the same order
they are presented in the table. SQL allows you to arrange records in alphabetical order, in
chronological order or in numeric incremental order.
After selecting a series of columns, you may want to list the records following an alphabetical order
from one specific field. To get an alphabetical or an incremental order of records, you must let the
database know what field would be used as reference. In SQL, this is done using the ORDER BY
expression. The syntax used would be:
SELECT What FROM WhatObject ORDER BY WhatField;
The column used as the basis must be recognized as part of the selected columns.
To get a list of students in alphabetical order based on the LastName column, you can use the
following statement:

SELECT FirstName, LastName, Gender, EmailAddress


FROM Students
ORDER BY LastName

This would produce:

In the same way, you can get the list of girls followed by the list of boys by ordering the list in
alphabetical order based on the Gender. The statement to produce this ca be written as follows:

SELECT FirstName, LastName, Gender, EmailAddress FROM Students ORDER BY


Gender

To list all students arranged in alphabetical order by their last name, you can change the statement as
follows:
SELECT *
FROM Students
ORDER BY LastName

68
By default, records are ordered in ascending order. Nevertheless, the ascending order is controlled
using the ASC keyword specified after the based field. For example, to sort the last names in
ascending order including the first and last names, you would use a statement as follows:
SELECT *
FROM Students
ORDER BY LastName ASC
On the other hand, if you want to sort records in reverse order, you can use the DESC keywords
instead. It produces the opposite result to the ASC effect. Here is an example:
SELECT LastName, FirstName, Gender, HomePhone, EmailAddress
FROM Students
ORDER BY LastName DESC
This would produce:

On the bottom section of the lower part of the Query window, notice that 164 records were
displayed as specified by 164 rows.

Practical Learning: Ordering Items


1. To get a list of countries of Northwind customers in alphabetical order, the statement such
as:

SELECT Country, CompanyName, ContactName


FROM Students
ORDER BY Country
2. Execute the statement to see the result:

69
3. On the bottom section of the lower part of the Query window, click the Messages tab and
notice that 91 records were displayed.

Introduction to Conditions
Instead of displaying all data as we have done so far using the SELECT keyword, you can present a
condition that the database would follow to isolate specific records.
One of the keywords you can use to formulate conditions is WHERE. Its basic syntax is:
SELECT What FROM WhatObject WHERE Expression;
The expressions used in conditions are built using algebraic, logical, and string operators. The
Expression factor is called a criterion. Although a group of expressions, making it plural is called
criteria, the word criteria is sometimes used for a singular expression also.
The expression is written using the formula:
ColumnName=Value
The ColumnName factor must be an existing column of the table. It is followed by the assignment
operator. The Value factor is the value that would set the condition. If the value is a word or a group
of words (also called a string), you must include it in single-quotes. If it is a number, you can type its
numeric value.
To get a list of students who live in Maryland, you would use a statement as follows:
SELECT *
FROM Students
WHERE State='MD'
To get a list of girls with their names and email addresses, you would execute the following
statement:

SELECT LastName, FirstName, Gender, EmailAddress


FROM Students
WHERE Gender='Female'

Practical Learning: Using the WHERE Condition


1. To get a list of customers who live in Canada, change the statement as follows:

SELECT *
FROM Customers
WHERE Country='Brazil'

70
2. Execute it to see the result

3. Click the Messages tab to see how the number of customers who live in Brazil

4. To get a list of customers who own their company but the list including only necessary
contact information and the list in alphabetical order based on the names of countries, change and
execute the following statement:

SELECT CompanyName, ContactName, ContactTitle, Country


FROM Customers
WHERE ContactTitle='Owner'
ORDER BY Country
5. Execute the statement to see the result

71
6. Since we already know that the list only includes company owners, we don't need to have
that column in the statement. Therefore, to omit the ContactTitle in the list change the statement as
follows:

SELECT CompanyName, ContactName, Country


FROM Customers
WHERE ContactTitle='Owner'
ORDER BY Country
7. Execute the statement to see the result

Operators and Data Analysis


Arithmetic Operations
Using the SELECT keyword, we have learned to create a list of isolated columns. These columns
were rendered separate of each other. Instead of having separate columns, you can combine them to

72
create a string or a value that is in fact an expression. For example, you can combine a first name and
a last name to create a full name.
An expression that combines columns can be performed on text-based columns. such as a first name
being added to a last name to get a full name. Another expression can use a date on the table, add a
number to it to get a data on another day. An expression can also be used to perform a calculation on
two or more columns such as employees weekly hours multiplied by their hourly salary to get their
weekly salary.
The most common operator used is the addition. It can be used to combine two or more strings to
get a new one. Here is an example:

The addition can also be used on numeric values. All other arithmetic operators can be used. For
example, you can multiply a weekly hours value to an hourly salary to get a weekly salary. The
statement of such an expression can be written as follows:
SELECT WeeklyHours * HourlySalary
FROM Payroll

The Assignment Operator


If you just create a regular expression using arithmetic operators as done above, the new column
would not have a name as you can see on the above screenshot. The SQL allows you to specify a
different name for any column during data analysis or a name for an expression. This is dine using
the assignment operator "=".
To change the name of a column during data analysis, on the right side of SELECT, type the desired
name, followed by the assignment operator, followed by the actual name of the column. Here is an
example:

73
Notice that the new name is the one that appears as the column header. In the same way, if you
create an expression, you can assign it to a name of your choice. Here is an example:

Boolean Constants
Introduction
Databases and other programming environments provide operators you can use to perform data
analysis. The operators used are called logical operators because they are used to perform
comparisons that produce a result of true or false (there is no middle result; in other words,
something is not half true or half false or "Don't Know": either it is true or it is false).
The TRUE and FALSE Constants
In Boolean algebra, something is considered TRUE when it holds a value. The value is also
considered as 1 or Yes. By contrast, if something doesn't hold a value, it is considered non-existent
and non-worthy of consideration. Such a thing has a value of FALSE, 0, or No. To retrieve such a
value, you can just find out if the value of a field is existent or not.
The comparison for a True or False value is mostly performed on Boolean fields, such a case is the
SPHome (which specifies whether a student lives in a single parent home) field of the Students table
of the HighSchool database. If a record has a value of 1, the table considers that such a field is True.
If the field has a 0 value, then it holds a FALSE value.
To perform a TRUE or FALSE comparison, you can use the WHERE condition.

74
The NULL Constant
While the True and False constants are used to find out whether a Boolean field has a positive or a
negative value, the database provides another constant used to find out whether a field is empty. This
can be done using the NULL constant.
When a field holds a value, the value would be considered using the comparison operators we will
learn shortly. If the field is empty, it holds a value of NULL.
The NOT Operator
To deny the presence, the availability, or the existence of a value, you can use the NOT operator.
This operator is primarily used to reverse a Boolean value. For example, we have learned that
FALSE is the opposite of TRUE. In the same way, TRUE is the opposite of FALSE. If you want
to compare a value as not being TRUE, the NOT TRUE would produce the same result as the
FALSE value. For the same reason, the expression NOT FALSE is the same as TRUE.
The IS Operator
To validate something as being possible, you can use the IS operator. For example, to acknowledge
that something is NULL, you can use the IS NULL expression. In the same way, to validate that
something is not null, you can use the expression IS NOT NULL.

Neither Microsoft Access nor Microsoft Visual Basic are case-sensitive. Therefore, the words
TRUE, True, and true represent the same word. In the same way, FALSE, False, and false
represent the same word. This also applies to NULL, Null, and null or NOT, Not, and not or IS,
Is, and is.

To get a list of records where the student's email address is not specified, you can use a statement as
follows:
SELECT LastName, FirstName, Gender, EmailAddress
FROM Students
WHERE EmailAddress IS NULL
To see a list of only the students whose records have an email address, you can use a statement as
follows:
SELECT LastName, FirstName, State, EmrgName, EmrgPhone
FROM Students
WHERE EmrgPhone IS NOT NULL

Boolean Operators
Logical Operators: The Equality =
The equality operator is used to compare two values for similarity. The syntax of this operation is:
Value1 = Value2
If Value1 and Value2 hold the same value, the comparison produces a TRUE result. If they hold
different values, the comparison renders a FALSE value.
During data analysis, you can perform the comparison of equality, and the other operation that we
will learn shortly, on a field. This allows you to dismiss Value1 from our syntax.
Logical Operators: The Inequality <>
To find out if two fields hold different values, you can use the inequality operator which is
represented by <>. Its syntax is:
Value1 <> Value2

75
This comparison is performed between Value1 and Value2. If they hold different values, then the
comparison produces a TRUE value. If they hold the same value, the comparison produces FALSE.
This shows you that the equality (=) and the inequality (<>) operators are opposite each other.
Logical Operators: The Less Than <
The "Less Than" operator uses the following syntax:
Value1 < Value2
If Value1 holds a value that is lower than that of Value2, the comparison produces TRUE. If Value1
holds a value that is greater than or similar to that of Value2, the comparison renders FALSE.
Logical Operators: The Comparison for Lower or Similar
Value <=
When comparing two values, you might want to know whether two fields hold the same value or if
one is lower than the other. This comparison can be performed with the "Less Than Or Equal to"
operator. It is represented by <=. Its syntax is:
Value1 <= Value2
If both operands (Value1 and Value2) hold the same value, then the comparison produces a TRUE
result. If Value1 holds a value that is lower than that of Value2, the comparison still produces a
TRUE result. By contrast, if the value of Value1 is higher than that of Value2, the comparison
renders a FALSE result. Notice that the > and the <= operators are opposite each other.
Logical Operators: The Greater Than >
The > operator is used to find out whether one value is "Greater Than" another. Its syntax is:
Value1 > Value2
The operation is performed on the values of Value1 and Value2. If Value1 holds a value greater than
that of Value2, then the comparison produces TRUE. Otherwise, the comparison produces FALSE.
That is, if the value of Value2 is greater than or equal to that of Value1, then the comparison
produces FALSE.
Logical Operators: The Comparison for Greater or Similar
Value >=
If you have two values and want to find out whether they hold similar values or the first is greater
than the second, you can use the >= operator whose syntax is:
Value1 >= Value2
If both Value1 and Value2 hold the same value, then the comparison renders a TRUE result.
Similarly, if the left operand, Value1, holds a value greater than that of the right operand, Value2, the
comparison still produces TRUE. If the value of Value1 is less than the value of Value2, the
comparison produces a FALSE result. Therefore, < and >= are opposite.
Comparison Operators: IN
If you have a series of records and want to find a record or a group of records among them, you can
use the IN operator.
SQL provides many and many other operators that we have not reviewed here.

76
Chapter 10
Stored Procedures
The Fundamentals of Procedures
Introduction
Imagine that your create a database that includes employees. When you want to perform payroll for
each employee, you would need his or her weekly hours and his or her hourly salary. To calculate the
weekly salary, you would write an equation such as:
Weekly Salary = Weekly Hours * Hourly Salary
Since there are various employees in the salary, you would need a a fast means of performing this
kind of assignment, maybe automatically, for each employee. This is the basis of a function.
Referred to as a function or a routine in most other programming languages, a procedure is an (or a
relatively small) assignment that can take care of a task in a database so that you can call it as/when
needed to get its result.
Creating a Procedure
A procedure can be as simple as calculating 124 + 68 or as complex as finding out if a date range
includes a holiday for somebody who is renting a car so the day can be calculated with a different rate
as compared to other dates in the same range. As always, we should start with simple examples. To
create a procedure, you can use either Enterprise Manager or SQL Query Analyzer.
To create a new procedure in Enterprise Manager, after expanding the database, you can right-click
it, position the mouse on New, and click Stored Procedure... You would be presented with a skeleton
syntax that you can complete using the techniques we will learn in this lesson.
To create a new procedure in SQL Query Analyzer, after selecting the database (either from the
combo box on the toolbar or with the USE keyword), you can type code based on the syntaxes we
will learn shortly.
The creation of a procedure starts with the CREATE PROCEDURE expression. You can also use
CREATE PROC. Both expressions produce the same result.
Like everything in your database, you must name your procedure. The name of a procedure can be
any string that follows the rules we reviewed for naming objects. There are some other rules or
suggestions you should or must follow when naming your procedure. For example, refrain from
starting the name of a procedure with sp_ because it would conflict with some of the procedures that
already ship with SQL Server.
After the name of the procedure, type the keyword AS.
The section, group of words, or group of lines after the AS keyword is called the body of the
procedure. It states what you want the procedure to do or what you want it to produce.
Based on this, the simplest syntax of defining a procedure is:
CREATE PROCEDURE ProcedureName
AS
Body of the Procedure
It is important to keep in mind that there are many other issues related to creating a procedure but
for now, let's consider that syntax.
Executing a Procedure
After creating a procedure, to get its result, you would need to execute it (in other programming
languages, we would say that, in order to use a function, you must call it). To execute a procedure,
you use the EXECUTE keyword followed by the name of the procedure. Although there are some

77
other issues related to executing a procedure, for now, we will consider that the simplest syntax to
call a procedure is:
EXECUTE ProcedureName
Alternatively, instead of EXECUTE, you can use the EXEC keyword:
EXEC ProcedureName
After a procedure has been executed, it is saved using its name. Since it becomes stored as an integral
part of the database, a SQL procedure is also called a Stored Procedure.

Exploring Procedures
The Simplest Procedures
Probably the simplest procedure you can write would consist of selecting columns from a table. This
is done with the SELECT keyword and applying the techniques we reviewed for data analysis. For
example, to create a procedure whose job would consist of creating a list of car makes from a table
called Cars, you can write:
CREATE PROCEDURE ListOfMakes
AS
SELECT Make
To execute this procedure, you would type:
EXECUTE ListOfMakes
You can also create a procedure that selects more than one column from a table. As done with the
SELECT keyword in data analysis, you would separate each item of the list with a comma, except
for the last. Here is an example:
CREATE PROCEDURE ListOfCars
AS
SELECT Make, Model, CarYear
Returning a Value
One of the advantages of using procedures is that not only can they produce the same expressions as
we saw during analysis but also they can store such expressions to be recalled any time without
having to re-write them. Based on this, you can create an expression that combines a first and a last
name to produce and store a full name. Here is an example:
CREATE PROC GetFullName
AS
SELECT FullName = LastName + ', ' + LastName
FROM Students
Arguments and Parameters
Introduction
Imagine you are creating an application for a department store that sometimes applies discounts of
10%, 20%, 40%, 55%, 70%, etc on items its sells. Since the management decides when and what
discount would be applied on an item, you cannot predict all possibilities. One way to solve this type
of problem is to create a procedure that would receive the discount applied on an item and then
apply this discount to the price of the item.
All of the procedures we have created and used so far assumed that the values they needed were
already in a table of the database. In some cases, you may need to create a procedure that involves
values that are not part of the database. On such a scenario, for the procedure to carry its
assignment, you would supply it with one or more values.
An external value that is provided to a stored procedure is called a parameter. When you create a
procedure, you must also create the parameter if you judge it necessary. When a procedure's creation

78
is equipped with a parameter, it is said that the procedure takes an argument. A procedure can also
take more than one argument.
When you execute a procedure that takes one or more arguments, you must provide a value for each
argument. In this case, you are said to pass a value for the argument. There are cases when you don't
have to provide an argument. We will learn how this is done.
Passing Arguments
To create a procedure that takes an argument, type the formula CREATE PROCEDURE or
CREATE PROC followed by the name of the procedure, then type the name of the argument that
starts with @. The parameter is created like a column of a table. That is, a parameter must have a
name, a data type and an optional length. Here is the syntax you would use:
CREATE PROCEDURE ProcedureName
@ParameterName DataType
AS
Body of the Procedure
When implementing the procedure, you can define what you want to do with the parameters, in the
body of the procedure. One way you can use a parameter is to run a query whose factor the user
would provide. For example, imagine you want to create a procedure that, whenever executed, it
would be supplied with a gender, then it would display the list of students of that gender. Since you
want the user to specify the gender of students to display, you can create a procedure that receives
the gender. Here is an example:
CREATE PROC GetListOfStudentsByGender
@Gdr VARCHAR(12)
AS
SELECT FirstName, LastName, DateOfBirth, HomeOfBirth, HomePhone, Gender
FROM Students
WHERE Gender = @Gdr
As mentioned already, when executing a procedure that takes a parameter, make sure you provide a
value for the parameter. The syntax used is:
EXEC ProcedureName ParameterValue
If the parameter is Boolean or numeric, make sure you provide an appropriate value. If the parameter
is a character or a string, type its value in single-quotes. Here is an example:

Notice that we could/should have omitted to include the Gender column in the statement since it
would be implied to the user.
Another type of procedure can be made to take more than one parameter. In this case, create the
parameter in the section before the AS keyword, separated by a comma. The syntax you would use is:

79
CREATE PROCEDURE ProcedureName
@ParameterName1 DataType, @ParameterName2 DataType, @ParameterName_n DataType
AS
Body of the Procedure
When calling a procedure that takes more than one parameter, you must still provide a value for each
parameter but you have two alternatives. The simplest technique consists of providing a value for
each parameter in the exact order they appear in the procedure.
Alternatively, you can provide the value for each parameter in the order of your choice. In this case,
you must type the name of each parameter and assign it the corresponding value.
Default Arguments
Imagine you create a table for a department store and the table would be used to hold the names and
prices of items (in this example, the table is called SaleItems):

Supposed you have filled the table with a few items as follows:

Imagine you want to create a mechanism of calculating the price of an item after a discount has been
applied to it. Such a procedure can be created as follows:
CREATE PROC CalculateNetPrice
@discount Decimal
AS
SELECT ItemName, ItemPrice - (ItemPrice * @discount / 100)
FROM SaleItems
This can be executed as follows:

80
If you are planning to create a procedure that takes an argument and know that the argument will
likely have the same value most of the time, you can provide that value as parameter but leave a
room for other values of that argument. A value given to an argument is referred to as default. What
this implies is that, when the user calls that stored procedure, if the user doesn't provide a value for
the argument, the default value would be used.
To create a procedure that takes an argument that carries a default value, after declaring the value, on
its right side, type = followed by the desired value. Here is an example applied to the above database:
CREATE PROC CalculateNetPrice
@discount Decimal = 20.00
AS
SELECT ItemName, ItemPrice - (ItemPrice * @discount / 100)
FROM SaleItems
When executing a procedure that takes a default argument, you don't have to provide a value for the
argument if the default value suits you. Based on this, the above procedure can be called as follows:

If the default value doesn't apply to your current calculation, you can provide a value for the
argument. Here is an example:

81
Using this same approach, you can create a procedure that takes more than one argument with
default values. To provide a default value for each argument, after declaring it, type the desired value
to its right side. Here is an example of a procedure that takes two arguments, each with a default
value:
CREATE PROC CalculateSalePrice2
@Discount Decimal = 20.00,
@TaxRate Decimal = 7.75
AS
SELECT ItemName As [Item Description],
ItemPrice As [Marked Price],
ItemPrice * @Discount / 100 As [Discount Amt],
ItemPrice - (ItemPrice * @Discount / 100) As [After Discount],
ItemPrice * @TaxRate / 100 As [Tax Amount],
(ItemPrice * @TaxRate / 100) + ItemPrice - (ItemPrice * @Discount / 100) + (@TaxRate / 100) As [Net
Price]
FROM SaleItems
Here is an example of executing the procedure:

82
When calling a procedure that takes more than one argument and all arguments having default
values, you don't need to provide a value for each argument, you can provide a value for only one or
some of the arguments. The above procedure can be called with one argument as follows:
EXEC CalculateSalePrice2 55.00
In this case, the other argument(s) would use their default value.
We saw that, when calling a procedure that takes more than one argument, you didn't have to
provide the values of the argument in the exact order they appear in the procedure, you just had to
type the name of each argument and assign it the corresponding value. In the same way, if a
procedure takes more than one argument and some of the arguments have default values, when
calling it, you can provide the values in the order of your choice, by typing the name of each
argument and assigning it the desired value. Based on this, the above procedure can be called with
only the value of the second argument as follows:
EXEC CalculateSalePrice2 @TaxRate = 8.55
In this case, the first argument would use its default value.
Output Parameter
Many languages use the notion of passing an argument by reference. This type of argument is passed
to a procedure but it is meant to return a value. Transact-SQL uses the same technique. In other
words, you can create a procedure that takes a parameter but the purpose of the parameter is to carry
a new value when the procedure ends so you can use that value as you see fit.
To create a parameter that will return a value from the procedure, type the OUTPUT keyword on
the right side of the parameter. A syntax you can use is:
CREATE PROCEDURE ProcedureName
@ParameterName DataType OUTPUT
AS
Body of the Procedure
You can also create a procedure that takes a mix of value and output parameters.

Managing Procedures
Deleting a Procedure
One of the biggest characteristics of a stored procedure, as compared to functions in traditional
languages, is that a procedure is treated like an object in its own right. Therefore, after creating it, if
you don't need it anymore, you can get rid of it.
There are various types of procedures, some of which are considered temporary. Those types of
procedures delete themselves when not needed anymore, such as when the person who created the
procedure disconnects from the database or shuts down the computer. Otherwise, to delete a
procedure, you can use either Enterprise Manager or SQL Query Analyzer. As mentioned with
tables, even if you create a procedure in Enterprise Manager, you can delete it using SQL Query
Analyzer and vice-versa.
To remove a procedure in Enterprise Manager, after expanding the database, click the Stored
Procedure node. If you see the needed procedure in the list, fine. If you don't see the procedure in
the list but know for sure that the procedure was created, for example if you create a new procedure
in SQL Query Analyzer, it doesn't automatically appear in Enterprise Manager, make sure you refresh
the list first by pressing F5. After locating the procedure in the right frame, you can either right-click
it and click Delete, or click it to select it and then press Delete. Before the procedure gets removed,
you would be warned with a dialog box to make your final decision.
To delete a procedure in SQL Query Analyzer using Transact-SQL, the syntax to use is:
DROP PROCEDURE ProcedureName
Of course, you should make sure you are in the right database and also that the ProcedureName exists.

83
Chapter 11
Relationships and Data Integrity
Introduction to Keys
A relational database is a system in which information flows from one database object to another.
For example, on a bank database, you can use one object to create accounts for customers and use
another object to process transactions that the owners of bank accounts need. The reason is that the
same customer may need to perform various transactions, regularly. Instead of creating a new
account every time the customer wants to perform a new transaction, you can use one account as a
reference and bring up this account whenever the customer wants to deposit or withdraw money.
Practical Learning: Introducing Relationships
1. Open Enterprise Manager and expand everything.
2. Right-click the Databases node and click New Database
3. Specify the Name of the database as IceScream and click OK
The Primary Key
The transactions among various objects of a database should make sure information of one object is
accessible to another object. The objects that hold information, as we have mentioned already, are
the tables.
To manage the flow of information from one table (A) to another table (B), the table that holds the
information, A, must make it available to other tables, such as B. There are two issues that must be
dealt with:
1. Each record that a table (A) holds should/must be unique among all the other records of the
same table (A). For example, if you create a list of bank accounts for different customers on a table,
you should make sure that there is a unique (no duplicate) bank account number for each customer
because each customer should have one and must have one account number. This ensures that there
are no duplicate records on the table.
2. A table (A) that holds information must make it available to other tables (such as B). Two
tables must not serve the same purpose. Once you have unique information on each table, one table
can make its data available to other tables that need it.
These two problems are solved by specifying a particular column as the "key" of the table. Such a
column is referred to as the primary key.
In a relational database, which is the case for most of the databases you will be creating in SQL
Server, each table should have at least one primary key. As an example, a primary key on an Account
table of a bank database can be set on a Bank Account field because each customer should have a
unique bank account number. A table can also have more than one primary key if you judge it
necessary.
Once you have decided that a table will have a primary key, you must decide what type of data that
field will hold. If you are building a table that can use a known and obvious field as unique, an
example would be the shelf number of a library, you can set its data type as char or varchar and
make it a primary key. In many other cases, for example if you cannot decide on a particular field that
would hold unique information, an example would be customers Contact Name, you should create
your own unique field and make it the Primary Key constraint. Such a field should have an int data
type.
To specify a primary key on a table, you create one column as the PRIMARY KEY constraint and
there can be only one PRIMARY KEY constraint on a table. To do this in Enterprise Manager,

84
create a column and specify its data type. Then, on the toolbar, click the Set Primary Key button
.
To create a primary column using SQL, on the right side of the column definition, type PRIMARY
KEY.
Practical Learning: Setting a Primary Key
1. Right-click the new IceScream database and click New -> Table
2. Specify the first Column Name as HolderID, set its Data Type to int
3. To make it the Primary Key constraint, while the field is still selected, on the toolbar, click
the Set Primary Key button
4. Notice that the Allows Nulls check mark is removed
While the field is still selected, in the bottom section of the Design Table, set the Identity field to
Yes and accept the Identity Seed and the Identity Increment to 1 each
5. Create the rest of the table as follows:

Column Name
Data Type
Length
Allow Nulls
HolderID
int
4

Holder
varchar
40

6. To save the table, on the toolbar, click the Save button


7. Specify the name of the table as Holders and click OK
8. Create another table as follows:

Column Name
Data Type
Length
Allow Nulls
FlavorID
int
4

Flavor
varchar
40

Description
ntext
16
Checked

9. Save the table as Flavors


10. Open SQL Query Analyzer
11. To create another table, type the following:

85
USE IceScream

CREATE TABLE Ingredients


(
IngredientID int IDENTITY(1, 1) PRIMARY KEY
Ingredient varchar(32) NOT NULL DEFAULT 'None'
)
12. Press F5 to execute
13. Return to Enterprise Manager and refresh the list of the IceScream tables
Foreign Keys
A foreign key is a column on a table whose data is coming from another table. As mentioned above
for the primary key. Imagine you want to perform transactions for an ice scream shop. When a
customer places an order, she must specify the type of container (cup, cone, or bowl which exist in
their own table). To make this happen, you can create a table for orders. In that table, you can create
a column that would represent containers so the user would not have to type the name of a
container. The clerk would simply select one. Therefore, on the table for orders, the column that
represents containers is called a foreign key.
To create a foreign key, the table you want to link to must have a PRIMARY KEY constraint. In the
current table, you must add a column referred to as a FOREIGN KEY constraint. The new column
in this table should have the same name as the primary key column of the other table.

Practical Learning: Creating Foreign Keys


1. In Enterprise Manager, create a new table with the following columns:

Column Name
Data Type
Length
Allow Nulls
Properties
OrderID
int
4

Identity: Yes
OrderDate
smalldatetime
4
Checked

OrderTime
smalldatetime
4
Checked

ContainerID
int
4

Default Value: 1
FlavorID
int

86
4

Default Value: 1
NbrOfScoops
smallint
2

Default Value: 1
IngredientID
int
4

Default Value: 1
2. Save the table as Orders and leave it open in Design View

Tables Relationships
To help information flow from one table to another, there must be a relationship between both
tables. One table that holds information would supply it to the other table. The table that holds data
is considered the parent and must have a primary key column. The table that request the information
must have a foreign key that corresponds to the other's primary key.

Practical Learning: Creating a Relationship


1. Right-click somewhere in the table and click Relationships...
2. In the Relationships property page, click the New button
3. In the Primary Key Table combo box, select Containers (it should be selected already)
In the first combo box of the grid under Containers, select ContainerID
4. In the Foreign Key Table combo box, Orders should be selected already. Otherwise, select
it.
Click the grid under Orders to reveal a combo box. In the combo box, select ContainerID

5. Click Close
6. Close the table. When asked to save, click Yes and Yes

87
Diagrams
A diagram is a window that visually displays the relationships among tables of a database. To create a
diagram, use the Create Database Diagram Wizard.
Practical Learning: Creating a Diagram
1. Right-click the IceScream database and click New -> Database Diagram...
2. In the first page of the Create Database Diagram Wizard, click Next
3. In the second page, click Containers and click the Add > key
4. In the same way, add the Flavors, Ingredients, and Orders tables

5. Click Next and click Finish


6. On the toolbar, click the Zoom button and select 100%
7. To move a table, you drag its title bar.
Position the Containers and the Ingredients tables to the left of Orders and position Flavors to the
right of Orders
8. Click the gray box on the left of the IngredientID field in the Ingredients table.
Click and drag that box and drop it on the IngredientID field of the Orders table:

9. On the Create Relationship dialog box, make sure IngredientID is selected for the
Ingredients Primary Key Table and that IngredientID is selected for the Orders Foreign Key Table

88
10. Click the Cascade Update Related Fields and the Cascade Delete Related Fields check boxes

11. Click OK
12. In the same way, drag the FlavorID row button from Flavors to the FlavorID field on
Orders.
13. On the Create Relationship dialog box, make sure FlavorID is selected for the Flavors
Primary Key Table and that FlavorID is selected for the Orders Foreign Key Table.
Click the Cascade Update Related Fields and the Cascade Delete Related Fields check boxes

89
14. Click OK

15. Close the Diagram window. When asked to save the database diagram, set its name to
CustOrders and click OK
16. Click Yes to save the database

90
Chapter 12
Indexes
Introduction
Indexes in databases are similar to indexes in books. In a book, an index allows you to find
information quickly without reading the entire book. In a database, an index allows the database
program to find data in a table without scanning the entire table. An index in a book is a list of words
with the page numbers that contain each word. An index in a database is a list of values in a table
with the storage locations of rows in the table that contain each value. Indexes can be created on
either a single column or a combination of columns in a table and are implemented in the form of B-
trees. An index contains an entry with one or more columns (the search key) from each row in a
table. A B-tree is sorted on the search key, and can be searched efficiently on any leading subset of
the search key. For example, an index on columns A, B, C can be searched efficiently on A, on A, B,
and A, B, C.

Most books contain one general index of words, names, places, and so on. Databases contain
individual indexes for selected types or columns of data: this is similar to a book that contains one
index for names of people and another index for places. When you create a database and tune it for
performance, you should create indexes for the columns used in queries to find data.

In the pubs sample database provided with Microsoft® SQL Server™ 2000, the employee table has
an index on the emp_id column. The following illustration shows how the index stores each
emp_id value and points to the rows of data in the table with each value.

When SQL Server executes a statement to find data in the employee table based on a specified
emp_id value, it recognizes the index for the emp_id column and uses the index to find the data. If

91
the index is not present, it performs a full table scan starting at the beginning of the table and
stepping through each row, searching for the specified emp_id value.

SQL Server automatically creates indexes for certain types of constraints (for example, PRIMARY
KEY and UNIQUE constraints). You can further customize the table definitions by creating indexes
that are independent of constraints.

The performance benefits of indexes, however, do come with a cost. Tables with indexes require
more storage space in the database. Also, commands that insert, update, or delete data can take
longer and require more processing time to maintain the indexes. When you design and create
indexes, you should ensure that the performance benefits outweigh the extra cost in storage space
and processing resources.

Creating an Index
After the design has been determined, indexes can be created on the tables in a database.

Microsoft® SQL Server™ 2000 automatically creates unique indexes to enforce the uniqueness
requirements of PRIMARY KEY and UNIQUE constraints. Unless a clustered index already exists
on the table or a nonclustered index is explicitly specified, a unique, clustered index is created to
enforce the PRIMARY KEY constraint. Unless a clustered index is explicitly specified, a unique,
nonclustered index is created by default to enforce the UNIQUE constraint.

If you need to create an index that is independent of a constraint, you can use the CREATE INDEX
statement. By default, a nonclustered index is created if the clustering option is not specified.

Additional considerations for creating an index include:

• Only the owner of the table can create indexes on the same table.

• Only one clustered index can be created per table.

• The maximum number of nonclustered indexes that can be created per table is 249
(including any indexes created by PRIMARY KEY or UNIQUE constraints).

• The maximum size of all nonvariable-length columns that comprise the index is 900 bytes.
For example, a single index could not be created on three columns defined as char(300),
char(300), and char (301) because the total width exceeds 900 bytes.

• The maximum number of columns that can comprise the same index is 16.

When you create indexes with the CREATE INDEX statement, you must specify the name of the
index, table, and columns to which the index applies. New indexes created as part of a PRIMARY

92
KEY or UNIQUE constraint or using SQL Server Enterprise Manager are automatically given
system-defined names based on the database table name. If you create multiple indexes on a table,
the index names are appended with _1, _2, and so on. The index can be renamed if necessary.

If a clustered index is created on a table with several secondary indexes, all of the secondary indexes
must be rebuilt so that they contain the clustering key value instead of the row identifier (RID).
Likewise, if a clustered index is deleted on a table that has several nonclustered indexes, the
nonclustered indexes are all rebuilt as part of the DROP operation. This may take significant time on
large tables.

The preferred way to build indexes on large tables is to start with the clustered index and then build
the nonclustered indexes. When dropping all indexes, drop the nonclustered indexes first and the
clustered index last. That way, no indexes need to be rebuilt.

Clustered Indexes

When you create a clustered index, the table is copied, the data in the table is sorted, and then the
original table is deleted. Therefore, enough empty space must exist in the database to hold a copy of
the data.

By default, the data in the table is sorted when the index is created. However, if the data is already
sorted because the clustered index already exists and is being re-created using the same name and
columns, the sort operation can be automatically skipped by rebuilding the index, rather than creating
the index again. The rebuild operation checks that the rows are sorted while building the index. If
any rows are not correctly sorted, the operations cancels and the index is not created.

Unique Indexes

Creating a unique index ensures that any attempt to duplicate key values fails. If a single query is
created that causes duplicate and nonduplicate key values to be added, SQL Server rejects all rows,
including the nonduplicate key values. For example, if a single insert statement retrieves 20 rows
from table A and inserts them into table B, and 10 of those rows contain duplicate key values, by
default all 20 rows are rejected. However, the IGNORE_DUP_KEY clause can be specified when
creating the index that causes only the duplicate key values to be rejected; the nonduplicate key
values are added. In the previous example, only the 10 duplicate key values would be rejected; the
other 10 nonduplicate key values would be inserted into table B.

93
A unique index cannot be created if there are any duplicate key values. For example, if you want to
create a unique, Composite index on columns a and b, but there are two rows in the table that
contain the values 1 and 2 for a and b respectively, the unique index cannot be created.

Creating Indexes on Computed Columns


Indexes can be defined on computed columns, provided these requirements are met:

• The computed_column_expression must be deterministic. Expressions are deterministic if they


always return the same result for a given set of inputs. computed_column_expression is deterministic
if:

• All functions referenced by the expression are deterministic and precise. This includes both
user-defined and built-in functions.

• All columns referenced in the expression come from the table containing the computed
column.

• No column reference pulls data from multiple rows. For example, aggregate functions such
as SUM or AVG depend on data from multiple rows and would make a
computed_column_expression nondeterministic.

The IsDeterministic property of the COLUMNPROPERTY function reports whether a


computed_column_expression is deterministic.

A computed column expression is precise if:

• It is not an expression of the float data type

• It does not use in its definition a float data type. For example, in the following statement,
column y is int and deterministic, but not precise:

CREATE TABLE t2 (a int, b int, c int, x float,

y AS CASE x

WHEN 0 THEN a

WHEN 1 THEN b

ELSE c

END)

94
The IsPrecise property of the COLUMNPROPERTY function reports whether a
computed_column_expression is precise.

• The ANSI_NULL connection-level option must be set to ON when the CREATE TABLE
statement is executed. The OBJECTPROPERTY function reports whether the option is on
through the IsAnsiNullsOn property.

• The computed_column_expression defined for the computed column cannot evaluate to the text,
ntext, or image data types.

• The connection on which the index is created, and all connections attempting INSERT,
UPDATE, or DELETE statements that will change values in the index, must have six SET
options set to ON and one option set to OFF. The optimizer ignores an index on a computed
column for any SELECT statement executed by a connection that does not have these same
option settings.

These options must be set to ON:

• ANSI_NULLS

• ANSI_PADDING

• ANSI_WARNINGS

• ARITHABORT

• CONCAT_NULL_YIELDS_NULL

• QUOTED_IDENTIFIER

Creating Indexes on Views


Indexes can be defined on views. Indexed views are a method of storing the result set of the view in
the database, thereby reducing the overhead of dynamically building the result set. An indexed view
also automatically reflects modifications made to the data in the base tables after the index is created.

Indexed views include these benefits:

95
• Indexed views are implemented through simple syntax extensions to the CREATE INDEX
and CREATE VIEW statements.

• The data in indexed views are updated automatically as data in the base tables are updated, in
much the same way that the keys in indexes on base tables are updated automatically. You do
not need to synchronize the contents of the indexed view with the data in the underlying base
tables.

• Indexed views are considered by the SQL Server optimizer without the need to specify
special hints in queries. The optimizer considers the indexed view even if a query does not
directly reference the view in the FROM clause by trying to match the query plan generated for
the view with some portion of the plan generated for the query.

• To introduce indexed views in an existing database, you have to issue only the relevant
CREATE VIEW and CREATE INDEX statements. Few changes have to be made to
application code for SQL Server to take advantage of any indexes on views.

The Index Tuning Wizard recommends indexed views in addition to recommending indexes on base
tables. Using the wizard greatly enhances an administrator's ability to determine the combination of
indexes and indexed views that optimize the performance of the typical mix of queries executed
against a database.

Indexed views can be more complex to maintain than indexes based on base tables. You should
create indexes only on views where the improved speed in retrieving results outweighs the increased
overhead of making modifications.

Viewing an Index
After you have created indexes or PRIMARY KEY or UNIQUE constraints on tables, you may need
to find information about the indexes. For example, you may need to find out the types of indexes
and the columns that are indexes on a particular table or the total space in the database used by an
index.

Each table registered for full-text indexing has one of its indexes selected as the full-text key. You
can view the properties of an index to determine if an index is the full-text key.

96
Deleting an Index
When you no longer need an index, you can delete it from a database and reclaim the storage space it
currently uses. This reclaimed space can then be used by any object in the database.

Deleting a clustered index can take some time, because all nonclustered indexes on the same table
must be rebuilt.

You cannot delete an index used by either a PRIMARY KEY or UNIQUE constraint without
deleting the constraint. To delete and re-create an index used by a PRIMARY KEY or UNIQUE
constraint without having to delete and re-create the constraint An index specified as the full-text
key for the table cannot be deleted. View index properties to determine if the index is the full-text
key.

Rebuilding an index, rather than deleting and re-creating it, is also useful to re-create a clustered
index, because the process of rebuilding the index can remove the need to sort the data by the index
columns if the data is already in sorted order.

Indexes created on any views or tables (permanent and temporary) are automatically deleted when
the view or table is deleted.

97
Chapter 13
Views
Introduction
A view is a virtual table whose contents are defined by a query. Like a real table, a view consists of a
set of named columns and rows of data. However, a view does not exist as a stored set of data values
in a database. The rows and columns of data come from tables referenced in the query defining the
view and are produced dynamically when the view is referenced.

A view acts as a filter on the underlying tables referenced in the view. The query that defines the view
can be from one or more tables or from other views in the current or other databases. Distributed
queries can also be used to define views that use data from multiple heterogeneous sources. This is
useful, for example, if you want to combine similarly structured data from different servers each of
which stores data for a different region of your organization.

There are no restrictions on querying through views and few restrictions on modifying data through
them.

This illustration shows a view based on two tables.

98
Scenarios for Using Views
Views are generally used to focus, simplify, and customize the perception each user has of the
database. Views can be used as security mechanisms by allowing users to access data through the
view, without granting the users permissions to directly access the underlying base tables of the view.
Views can also be used, when copying data to and from Microsoft® SQL Server™ 2000, to improve
performance and to partition data.

To Focus on Specific Data

Views allow users to focus on specific data that interests them and on the specific tasks for which
they are responsible. Unnecessary data can be left out of the view. This also increases the security of
the data because users can see only the data that is defined in the view and not the data in the
underlying table.

To Simplify Data Manipulation

Views can simplify how users manipulate data. You can define frequently used joins, projections,
UNION queries, and SELECT queries as views so that users do not have to specify all the
conditions and qualifications each time an additional operation is performed on that data. For
example, a complex query that is used for reporting purposes and performs subqueries, outer joins,
and aggregation to retrieve data from a group of tables can be created as a view. The view simplifies
access to the data because the underlying query does not have to be written or submitted each time
the report is generated; the view is queried instead.

You can also create inline user-defined functions that logically operate as parameterized views, or
views that have parameters in WHERE-clause search conditions.

To Customize Data

Views allow different users to see data in different ways, even when they are using the same data
concurrently. This is particularly advantageous when users with many different interests and skill
levels share the same database. For example, a view can be created that retrieves only the data for the
customers with whom an account manager deals. The view can determine which data to retrieve
based on the login ID of the account manager who uses the view.

To Export and Import Data

Views can be used to export data to other applications. For example, you may want to use the stores
and sales tables in the pubs database to analyze sales data using Microsoft® Excel. To do this, you

99
can create a view based on the stores and sales tables. You can then use the bcp utility to export the
data defined by the view. Data can also be imported into certain views from data files using the bcp
utility or BULK INSERT statement providing that rows can be inserted into the view using the
INSERT statement.

To Combine Partitioned Data

The Transact-SQL UNION set operator can be used within a view to combine the results of two or
more queries from separate tables into a single result set. This appears to the user as a single table
called a partitioned view. For example, if one table contains sales data for Washington, and another
table contains sales data for California, a view could be created from the UNION of those tables.
The view represents the sales data for both regions.

To use partitioned views, you create several identical tables, specifying a constraint to determine the
range of data that can be added to each table. The view is then created using these base tables. When
the view is queried, SQL Server automatically determines which tables are affected by the query and
references only those tables. For example, if a query specifies that only sales data for the state of
Washington is required, SQL Server reads only the table containing the Washington sales data; no
other tables are accessed.

Partitioned views can be based on data from multiple heterogeneous sources, such as remote servers,
not just tables in the same database. For example, to combine data from different remote servers
each of which stores data for a different region of your organization, you can create distributed
queries that retrieve data from each data source, and then create a view based on those distributed
queries. Any queries read only data from the tables on the remote servers that contains the data
requested by the query; the other servers referenced by the distributed queries in the view are not
accessed.

When you partition data across multiple tables or multiple servers, queries accessing only a fraction
of the data can run faster because there is less data to scan. If the tables are located on different
servers, or on a computer with multiple processors, each table involved in the query can also be
scanned in parallel, thereby improving query performance. Additionally, maintenance tasks, such as
rebuilding indexes or backing up a table, can execute more quickly.

By using a partitioned view, the data still appears as a single table and can be queried as such without
having to reference the correct underlying table manually.

Partitioned views are updatable if either of these conditions is met:

100
• An INSTEAD OF trigger is defined on the view with logic to support INSERT, UPDATE,
and DELETE statements.

• Both the view and the INSERT, UPDATE, and DELETE statements follow the rules
defined for updatable partitioned views.

Creating a View
Before you create a view, consider these guidelines:

• You can create views only in the current database. However, the tables and views referenced
by the new view can exist in other databases or even other servers if the view is defined using
distributed queries.

• View names must follow the rules for identifiers and must be unique for each user.
Additionally, the name must not be the same as any tables owned by that user.

• You can build views on other views and on procedures that reference views. Microsoft®
SQL Server™ 2000 allows views to be nested up to 32 levels.

• You cannot associate rules or DEFAULT definitions with views.

• You cannot associate AFTER triggers with views, only INSTEAD OF triggers.

• The query defining the view cannot include the ORDER BY, COMPUTE, or COMPUTE
BY clauses or the INTO keyword.

• You cannot define full-text index definitions on views.

• You cannot create temporary views, and you cannot create views on temporary tables.

• Views or tables participating in a view created with the SCHEMABINDING clause cannot
be dropped, unless the view is dropped or changed so that it no longer has schema binding. In
addition, ALTER TABLE statements on tables that participate in views having schema binding
will fail if these statements affect the view definition.

• You cannot issue full-text queries against a view, although a view definition can include a
full-text query if the query references a table that has been configured for full-text indexing.

• You must specify the name of every column in the view if:

101
• Any of the columns in the view is derived from an arithmetic expression, a built-in
function, or a constant.

• Two or more of the columns in the view would otherwise have the same name
(usually because the view definition includes a join and the columns from two or more different
tables have the same name).

• You want to give any column in the view a name different from the column from
which it is derived. (You can also rename columns in the view.) A view column inherits the data
type of the column from which it is derived, whether or not you rename it.

Otherwise, you do not need to specify column names when creating the view. SQL Server gives the
columns of the view the same names and data types as the columns to which the query defining the
view refers. The select list can be a full or partial list of the column names in the base tables.

To create a view you must be granted permission to do so by the database owner and you must have
appropriate permissions on any tables or views referenced in the view definition.

By default, as rows are added or updated through a view, they disappear from the scope of the view
when they no longer fall into the criteria of the query defining the view. For example, a query can be
created, defining a view that retrieves all rows from a table where the employee's salary is less than
$30,000. If the employee's salary is increased to $32,000, then querying the view no longer displays
that particular employee because his or her salary does not conform to the criteria set by the view.
However, the WITH CHECK OPTION clause forces all data modification statements executed
against the view to adhere to the criteria set within the SELECT statement defining the view. If you
use this clause, rows cannot be modified in a way that causes them to disappear from the view. Any
modification that would cause this to happen is canceled and an error is displayed.

The definition of a sensitive view can be encrypted to ensure that its definition cannot be obtained by
anyone, including the owner of the view.

Creating an Indexed View


Views are also known as virtual tables because the result set returned by the view has the same
general form as a table with columns and rows, and views can be referenced the same way as tables
in SQL statements. The result set of a standard view is not stored permanently in the database. Each
time a query references the view, Microsoft® SQL Server™ 2000 dynamically merges the logic
needed to build the view result set into the logic needed to build the complete query result set from
the data in the base tables. The process of building the view results is called materializing the view.

102
For a standard view, the overhead of dynamically building the result set for each query that
references a view can be substantial for views that involve complex processing of large numbers of
rows, such as aggregating large amounts of data, or joining many rows. If such views are frequently
referenced in queries, you can improve performance by creating a unique clustered index on the
view. When a unique clustered index is created on a view, the view is executed and the result set is
stored in the database in the same way a table with a clustered index is stored.

Another benefit of creating an index on a view is that the optimizer starts using the view index in
queries that do not directly name the view in the FROM clause. Existing queries can benefit from the
improved efficiency of retrieving data from the indexed view without having to be recoded.

Creating a clustered index on a view stores the data as it exists at the time the index is created. An
indexed view also automatically reflects modifications made to the data in the base tables after the
index is created, the same way an index created on a base table does. As modifications are made to
the data in the base tables, the data modifications are also reflected in the data stored in the indexed
view. The requirement that the clustered index of the view be unique improves the efficiency with
which SQL Server can find the rows in the index that are affected by any data modification.

Indexed views can be more complex to maintain than indexes on base tables. You should create
indexes only on views where the improved speed in retrieving results outweighs the increased
overhead of making modifications. This usually occurs for views that are mapped over relatively
static data, process many rows, and are referenced by many queries.

Requirements for the View

A view must meet these requirements before you can create a clustered index on it:

• The ANSI_NULLS and QUOTED_IDENTIFIER options must have been set to ON


when the CREATE VIEW statement was executed. The OBJECTPROPERTY function reports
this for views through the ExecIsAnsiNullsOn or ExecIsQuotedIdentOn properties.

• The ANSI_NULLS option must have been set to ON for the execution of all CREATE
TABLE statements that create tables referenced by the view.

• The view must not reference any other views, only base tables.

• All base tables referenced by the view must be in the same database as the view and have the
same owner as the view.

103
• The view must be created with the SCHEMABINDING option. SCHEMABINDING
binds the view to the schema of the underlying base tables.

• User-defined functions referenced in the view must have been created with the
SCHEMABINDING option.

• Tables and user-defined functions must be referenced by two-part names. One-part, three-
part, and four-part names are not allowed.

• All functions referenced by expressions in the view must be deterministic. The


IsDeterministic property of the OBJECTPROPERTY function reports if a user-defined
function is deterministic.

• The SELECT statement in the view cannot contain these Transact-SQL syntax elements:

• The select list cannot use the * or table_name.* syntax to specify columns. Column names
must be explicitly stated.

• A table column name used as a simple expression cannot be specified in more than one view
column. A column can be referenced multiple times provided all, or all but one, reference to the
column is part of a complex expression or a parameter to a function. For example, this select list
is invalid:

SELECT ColumnA, ColumnB, ColumnA

These select lists are valid:

SELECT ColumnA, COUNT(ColumnA), ColumnA + Column B AS


AddColAColB FROM T1

SELECT SUM(ColumnA), ColumnA % ColumnB AS ModuloColAColB,


COUNT_BIG(*) FROM T1 GROUP BY ColumnA

• A derived table.

• Rowset functions.

• UNION operator.

• Subqueries.

104
• Outer or self joins.

• TOP clause.

• ORDER BY clause.

• DISTINCT keyword.

• COUNT(*) (COUNT_BIG(*) is allowed.)

• The AVG, MAX, MIN, STDEV, STDEVP, VAR, or VARP aggregate functions. If
AVG, MAX, MIN, STDEV, STDEVP, VAR, or VARP are specified in queries referencing
the indexed view, the optimizer can often calculate the needed result if the view select list
contains these substitute functions.

Complex aggregate function Substitute simple aggregate functions


AVG(X) SUM(X), COUNT_BIG(X)
STDEV(X) SUM(X), COUNT_BIG(X), SUM(X**2)
STDEVP(X) SUM(X), COUNT_BIG(X), SUM(X**2)
VAR(X) SUM(X), COUNT_BIG(X), SUM(X**2)
VARP(X) SUM(X), COUNT_BIG(X), SUM(X**2)

• For example, an indexed view select list cannot contain the expression AVG(SomeColumn).
If the view select list contains the expressions SUM(SomeColumn) and
COUNT_BIG(SomeColumn), SQL Server can calculate the average for a query that references
the view and specifies AVG(SomeColumn).

• A SUM function that references a nullable expression.

• The full-text predicates CONTAINS or FREETEXT.

• COMPUTE or COMPUTE BY clause.

• If GROUP BY is not specified, the view select list cannot contain aggregate expressions.

• If GROUP BY is specified, the view select list must contain a COUNT_BIG(*) expression,
and the view definition cannot specify HAVING, CUBE, or ROLLUP.

• A column resulting from an expression that either evaluates to a float value or uses float
expressions for its evaluation cannot be a key of an index in an indexed view or a table.

105
Requirements for the CREATE INDEX Statement

The first index created on a view must be a unique clustered index. After the unique clustered index
has been created, you can create additional nonclustered indexes. The naming conventions for
indexes on views are the same as for indexes on tables. The only difference is that the table name is
replaced with a view name.

The CREATE INDEX statement must meet these requirements in addition to the normal CREATE
INDEX requirements:

• The user executing the CREATE INDEX statement must be the view owner.

• These SET options must be set to ON when the CREATE INDEX statement is executed:

¾ ANSI_NULLS

¾ ANSI_PADDING

¾ ANSI_WARNINGS

¾ ARITHABORT

¾ CONCAT_NULL_YIELDS_NULL

¾ QUOTED_IDENTIFIERS

• The NUMERIC_ROUNDABORT option must be set to OFF.

• The view cannot include text, ntext, or image columns, even if they are not referenced in
the CREATE INDEX statement.

• If the SELECT statement in the view definition specifies a GROUP BY clause, the key of
the unique clustered index can reference only columns specified in the GROUP BY clause.

Considerations

After the clustered index is created, any connection attempting to modify the base data for the view
must also have the same option settings required to create the index. SQL Server generates an error
and rolls back any INSERT, UPDATE, or DELETE statement that will affect the result set of the
view if the connection executing the statement does not have the proper option settings.

106
All indexes on a view are dropped if the view is dropped. All nonclustered indexes on the view are
dropped if the clustered index is dropped. Nonclustered indexes can be dropped individually.
Dropping the clustered index on the view removes the stored result set, and the optimizer returns to
processing the view like a standard view.

Although only the columns that make up the clustered index key are specified in the CREATE
UNIQUE CLUSTERED INDEX statement, the complete result set of the view is stored in the
database. As in a clustered index on a base table, the B-tree structure of the clustered index contains
only the key columns, but the data rows contain all of the columns in the view result set.

If you want to add indexes to views in an existing system, you must schema bind any view on which
you want to place an index. You can:

• Drop the view and re-create it specifying WITH SCHEMABINDING.

• You can create a second view that has the same text as the existing view but a different
name. The optimizer considers the indexes on the new view, even if it is not directly referenced
in the FROM clause of queries.

Creating a Partitioned View


A partitioned view joins horizontally partitioned data from a set of member tables across one or
more servers, making the data appear as if from one table. Microsoft® SQL Server™ 2000
distinguishes between local and distributed partitioned views. In a local partitioned view, all
participating tables and the view reside on the same instance of SQL Server. In a distributed
partitioned view, at least one of the participating tables resides on a different (remote) server. In
addition, SQL Server 2000 differentiates between partitioned views that are updatable and views that
are read-only copies of the underlying tables.

Distributed partitioned views can be used to implement a federation of database servers. A


federation is a group of servers administered independently, but which cooperate to share the
processing load of a system. Forming a federation of database servers by partitioning data is the
mechanism that enables you to scale out a set of servers to support the processing requirements of
large, multi-tiered Web sites.

Before implementing a partitioned view, you must first partition a table horizontally. In designing a
partitioning scheme, it must be clear what data belongs to each member table. The original table is
replaced with several smaller member tables. Each member table has the same number of columns as
the original table, and each column has the same attributes (such as data type, size, collation) as the
corresponding column in the original table. If you are creating a distributed partitioned view, each
member table is on a separate member server. For the greatest location transparency, the name of the
member databases should be the same on each member server, although this is not a requirement.
For example: Server1.CustomerDB, Server2.CustomerDB, Server3.CustomerDB.

107
You design the member tables so that each table stores a horizontal slice of the original table based
on a range of key values. The ranges are based on the data values in a partitioning column. The range
of values in each member table is enforced by a CHECK constraint on the partitioning column, and
ranges cannot overlap. For example, you cannot have one table with a range from 1 through 200000,
and another with a range from 150000 through 300000 because it would not be clear which table
contains the values from 150000 through 200000.

For example, you are partitioning a Customer table into three tables. The CHECK constraint for
these tables is:

-- On Server1:
CREATE TABLE Customers_33
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 1 AND 32999),
... -- Additional column definitions)

-- On Server2:
CREATE TABLE Customers_66
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 33000 AND 65999),
... -- Additional column definitions)

-- On Server3:
CREATE TABLE Customers_99
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 66000 AND 99999),
... -- Additional column definitions)

After creating the member tables, you define a distributed partitioned view on each member server,
with each view having the same name. This allows queries referencing the distributed partitioned
view name to run on any of the member servers. The system operates as if a copy of the original
table is on each member server, but each server has only a member table and a distributed partitioned
view. The location of the data is transparent to the application.

You build the distributed partitioned views by:

• Adding linked server definitions on each member server containing the connection
information needed to execute distributed queries on the other member servers. This gives a
distributed partitioned view access to data on the other servers.

• Setting the lazy schema validation option, using sp_serveroption, for each linked server
definition used in distributed partitioned views. This optimizes performance by ensuring the
query processor does not request meta data for any of the linked tables until data is actually
needed from the remote member table.

108
• Creating a distributed partitioned view on each member server. The views use distributed
SELECT statements to access data from the linked member servers, and merges the distributed
rows with rows from the local member table.

To create distributed partitioned views for the preceding example, you must:

• Add a linked-server definition named Server2 with the connection information for Server2,
and a linked server definition named Server3 for access to Server3.

• Create this distributed partitioned view:

CREATE VIEW Customers AS


SELECT * FROM CompanyDatabase.TableOwner.Customers_33
UNION ALL
SELECT * FROM Server2.CompanyDatabase.TableOwner.Customers_66
UNION ALL
SELECT * FROM Server3.CompanyDatabase.TableOwner.Customers_99

• Perform the same steps on Server2 and Server3.

Updatable Partitioned Views

If a local or distributed partitioned view is not updatable, it can serve only as a read-only copy of the
original table. An updatable partitioned view can exhibit all the capabilities of the original table.

A view is considered an updatable partitioned view if:

• The view is a set of SELECT statements whose individual result sets are combined into one
using the UNION ALL statement. Each individual SELECT statement references one SQL
Server base table. The table can be either a local table or a linked table referenced using a four-
part name, the OPENROWSET function, or the OPENDATASOURCE function (you cannot
use an OPENDATASOURCE or OPENROWSET function that specifies a pass-through
query).

The view will not be updatable if a trigger or cascading update or delete is defined on one or more
member tables.

Table Rules

Member tables are defined in the FROM clause in each SELECT statement in the view definition.
Each member table must adhere to these rules:

109
• Member tables cannot be referenced more than once in the view.

• Member tables cannot have indexes created on any computed columns.

• Member tables must have all PRIMARY KEY constraints on an identical number of
columns.

• Member tables must have the same ANSI padding setting.

• Column Rules

Columns are defined in the select list of each SELECT statement in the view definition. The columns
must follow these rules.

• All columns in each member table must be included in the select list. SELECT * FROM
<member table> is acceptable syntax.

• Columns cannot be referenced more than once in the select list.

• The columns must be in the same ordinal position in the select list

• The columns in the select list of each SELECT statement must be of the same type
(including data type, precision, scale, and collation). For example, this view definition fails
because the first column in both SELECT statements does not have the same data type:

CREATE VIEW NonUpdatable


AS
SELECT IntPrimaryKey, IntPartNmbr
FROM FirstTable
UNION ALL
SELECT NumericPrimaryKey, IntPartNmbr
FROM SecondTable

Partitioning Column Rules

A partitioning column exists on each member table and, through CHECK constraints, identifies the
data available in that specific table. Partitioning columns must adhere to these rules:

• Each base table has a partitioning column whose key values are enforced by CHECK
constraints. The key ranges of the CHECK constraints in each table do not overlap with the
ranges of any other table. Any given value of the partitioning column must map to only one

110
table. The CHECK constraints can only use these operators: BETWEEN, AND, OR, <, <=, >,
>=, =.

• The partitioning column cannot be an identity, default or timestamp column.

• The partitioning column must be in the same ordinal location in the select list of each
SELECT statement in the view. For example, the partitioning column is always the first column
in each select list, or the second column in each select list, and so on.

• Partitioning columns cannot allow nulls.

• Partitioning columns must be a part of the primary key of the table.

• Partitioning columns cannot be computed columns.

• There must be only one constraint on the partitioning column. If there is more than one
constraint, SQL Server ignores all the constraints and will not consider them when determining
whether or not the view is a partitioned view.

• There are no restrictions on the updatability of the partitioning columns.

A partitioned column that meets all these rules will support all of the optimizations that are
supported by the SQL Server 2000 query optimizer.

Data Modification Rules

In addition to the rules defined for updatable partitioned views, data modification statements
referencing the view must adhere to the rules defined for INSERT, UPDATE and DELETE
statements.

INSERT Statements

INSERT statements add data to the member tables through the partitioned view. The INSERT
statements must adhere to these rules:

• All columns must be included in the INSERT statement even if the column can be NULL in
the base table or has a DEFAULT constraint defined in the base table.

111
• The DEFAULT keyword cannot be specified in the VALUES clause of the INSERT
statement.

• INSERT statements must supply a value that satisfies the logic of the CHECK constraint
defined on the partitioning column for one of the member tables.

• INSERT statements are not allowed if a member table contains a column with an identity
property.

• INSERT statements are not allowed if a member table contains a timestamp column.

• INSERT statements are not allowed if there is a self-join with the same view or any of the
member table.

UPDATE Statements

UPDATE statements modify data in one or more of the member tables through the partitioned
view. The UPDATE statements must adhere to these rules:

• UPDATE statements cannot specify the DEFAULT keyword as a value in the SET clause
even if the column has a DEFAULT value defined in the corresponding member table

• The value of a column with an identity property cannot be changed: however, the other
columns can be updated.

• The value of a PRIMARY KEY cannot be changed if the column contains text, image or
ntext data.

• Updates are not allowed if a base table contains a timestamp column.

• Updates are not allowed if there is a self-join with the same view or any of the member
tables.

• The DEFAULT keyword cannot be specified in the SET clause of the UPDATE statement.

DELETE Statements

DELETE statements remove data in one or more of the member tables through the partitioned
view. The DELETE statements must adhere to this rule:

• DELETE statements are not allowed if there is a self-join with the same view or any of the
member tables.

112
Distributed Partition View Rules

In addition to the rules defined for partitioned views, distributed (remote) partition views have these
additional conditions:

• A distributed transaction will be started to ensure atomicity across all nodes affected by the
update.

• The XACT_ABORT SET option must be set to ON.

• smallmoney and smalldatetime columns in remote tables are mapped as money and
datetime respectively. Consequently, the corresponding columns in the local tables should also
be money and datetime.

• Any linked server cannot be a loopback linked server, that is, a linked server that points to
the same instance of SQL Server.

A view that references partitioned tables without following all these rules may still be updatable if
there is an INSTEAD OF trigger on the view. The query optimizer, however, may not always be able
to build execution plans for a view with an INSTEAD OF trigger that are as efficient as the plans for
a partitioned view that follows all of the rules.

Deleting a View
After a view has been created, you can delete the view if it is not needed, or if you want to clear the
view definition and the permissions associated with it. When a view is deleted, the tables and the data
upon which it is based are not affected. Any queries that use objects that depend on the deleted view
fail when they are next executed, unless a view with the same name is created. However, if the new
view does not reference objects expected by any objects dependent on the new view, queries using
the dependent objects fail when executed. For example, a view my_view that retrieves all columns
from the authors table in the pubs database is deleted and replaced by a new view called my_view
that retrieves all columns from the titles table instead. Any stored procedures that reference columns
from the underlying authors table in my_view now fail because those columns are replaced by
columns from the titles table instead.

113
Chapter 14
Triggers
Enforcing Business Rules with Triggers
Microsoft® SQL Server™ 2000 provides two primary mechanisms for enforcing business rules and
data integrity: constraints and triggers. A trigger is a special type of stored procedure that
automatically takes effect when the data in a specified table is modified. A trigger is invoked in
response to an INSERT, UPDATE, or DELETE statement. A trigger can query other tables and can
include complex Transact-SQL statements. The trigger and the statement that fires it are treated as a
single transaction, which can be rolled back from within the trigger. If a severe error is detected (for
example, insufficient disk space), the entire transaction automatically rolls back.

Triggers are useful in these ways:

• Triggers can cascade changes through related tables in the database; however, these changes
can be executed more efficiently using cascading referential integrity constraints.

• Triggers can enforce restrictions that are more complex than those defined with CHECK
constraints.

Unlike CHECK constraints, triggers can reference columns in other tables. For example, a
trigger can use a SELECT from another table to compare to the inserted or updated data and to
perform additional actions, such as modify the data or display a user-defined error message.

• Triggers can also evaluate the state of a table before and after a data modification and take
action(s) based on that difference.

• Multiple triggers of the same type (INSERT, UPDATE, or DELETE) on a table allow
multiple, different actions to take place in response to the same modification statement.

Triggers Compared to Constraints

Constraints and triggers each have benefits that make them useful in special situations. The primary
benefit of triggers is that they can contain complex processing logic that uses Transact-SQL code.
Therefore, triggers can support all of the functionality of constraints; however, triggers are not always
the best method for a given feature.

114
Entity integrity should always be enforced at the lowest level by indexes that are part of PRIMARY
KEY and UNIQUE constraints or are created independently of constraints. Domain integrity should
be enforced through CHECK constraints, and referential integrity (RI) should be enforced through
FOREIGN KEY constraints, assuming their features meet the functional needs of the application.

Triggers are most useful when the features supported by constraints cannot meet the functional
needs of the application. For example:

• FOREIGN KEY constraints can validate a column value only with an exact match to a
value in another column, unless the REFERENCES clause defines a cascading referential action.

• A CHECK constraint can validate a column value only against a logical expression or
another column in the same table. If your application requires that a column value be validated
against a column in another table, you must use a trigger.

• Constraints can communicate about errors only through standardized system error messages.
If your application requires (or can benefit from) customized messages and more complex error
handling, you must use a trigger.

Triggers can cascade changes through related tables in the database; however, these changes can be
executed more efficiently through cascading referential integrity constraints.

• Triggers can disallow or roll back changes that violate referential integrity, thereby canceling
the attempted data modification. Such a trigger might go into effect when you change a foreign
key and the new value does not match its primary key. For example, you can create an insert
trigger on titleauthor.title_id that rolls back an insert if the new value does not match some
value in titles.title_id. However, FOREIGN KEY constraints are usually used for this purpose.

• If constraints exist on the trigger table, they are checked after the INSTEAD OF trigger
execution but prior to the AFTER trigger execution. If the constraints are violated, the
INSTEAD OF trigger actions are rolled back and the AFTER trigger is not executed.

Creating a Trigger
Before you create a trigger, consider that:

• The CREATE TRIGGER statement must be the first statement in the batch. All other
statements that follow in that batch are interpreted as part of the definition of the CREATE
TRIGGER statement.

115
• Permission to create triggers defaults to the table owner, who cannot transfer it to other
users.

• Triggers are database objects, and their names must follow the rules for identifiers.

• You can create a trigger only in the current database, although a trigger can reference objects
outside of the current database.

• A trigger cannot be created on a temporary or system table, although triggers can reference
temporary tables. System tables should not be referenced; use the Information Schema Views
instead.

• INSTEAD OF DELETE and INSTEAD OF UPDATE triggers cannot be defined on a


table that has a foreign key defined with a DELETE or UPDATE action.

• Although a TRUNCATE TABLE statement is like a DELETE statement without a


WHERE clause (it deletes all rows), it does not cause DELETE triggers to fire because the
TRUNCATE TABLE statement is not logged.

• The WRITETEXT statement does not cause the INSERT or UPDATE triggers to fire.

When you create a trigger, specify:

• The name.

• The table upon which the trigger is defined.

• When the trigger is to fire.

• The data modification statements that activate the trigger. Valid options are INSERT,
UPDATE, or DELETE. More than one data modification statement can activate the same
trigger. For example, a trigger can be activated by an INSERT and an UPDATE statement.

• The programming statements that perform the trigger action.

Multiple Triggers

A table can have multiple AFTER triggers of a given type provided they have different names; each
trigger can perform numerous functions. However, each trigger can apply to only one table, although
a single trigger can apply to any subset of three user actions (UPDATE, INSERT, and DELETE).

116
A table can have only one INSTEAD OF trigger of a given type.

Trigger Permissions and Ownership

CREATE TRIGGER permissions default to the table owner on which the trigger is defined, the
sysadmin fixed server role, and members of the db_owner and db_ddladmin fixed database roles,
and are not transferable.

If an INSTEAD OF trigger is created on a view, the ownership chain is broken if the view owner
does not also own the base tables referenced by the view and trigger. For a base table not owned by
the view owner, the table owner must separately grant the necessary permissions to anybody reading
or updating the view. If the same user owns both the view and the underlying base tables, they have
to grant other users permissions only on the view, not individual base tables.

Programming Triggers
Almost any Transact-SQL statement that can be written as a batch can be used to create a trigger,
except for these:

ALTER DATABASE CREATE DATABASE DISK INIT


DISK RESIZE DROP DATABASE LOAD DATABASE
LOAD LOG RECONFIGURE RESTORE DATABASE
RESTORE LOG

Encrypting Trigger Definitions

If you want to ensure that other users cannot view the trigger definition, you can use the WITH
ENCRYPTION clause. The trigger definition is then stored in an unreadable form.

Once encrypted, the definition of the trigger cannot be decrypted and cannot be viewed by anyone,
including the owner of the trigger or the system administrator.

SET Statement Options

When an ODBC application connects to SQL Server, the server automatically sets these options for
the session:

• SET QUOTED_IDENTIFIER ON

• SET TEXTSIZE 2147483647

• SET ANSI_DEFAULTS ON

117
• SET CURSOR_CLOSE_ON_COMMIT OFF

• SET IMPLICIT_TRANSACTIONS OFF

These settings increase the portability of ODBC applications. Because DB-Library–based


applications generally do not set these options, triggers should be tested with the SET options listed
above set to both ON and OFF. This ensures that the triggers work correctly regardless of the
options a particular connection may have set when it invokes the trigger. A trigger that requires a
particular setting for one of these options should issue a SET statement at the start of the trigger.
This SET statement remains in effect only for the execution of the trigger; when the trigger
completes, the original setting is restored.

Testing for Changes to Specific Columns

The IF UPDATE (column_name) clause in the definition of a trigger can be used to determine if an
INSERT or UPDATE statement affected a specific column in the table. The clause evaluates to
TRUE whenever the column is assigned a value.

Alternatively, the IF COLUMNS_UPDATED() clause can be used to check which columns in a


table were updated by an INSERT or UPDATE statement. This clause uses an integer bitmask to
specify the columns to test.

Examples

A. Use the IF UPDATE clause to test data modifications

This example creates an INSERT trigger my_trig on table my_table and tests whether column b
was affected by any INSERT statements.

CREATE TABLE my_table*


(a int NULL, b int NULL)
GO

CREATE TRIGGER my_trig


ON my_table
FOR INSERT
AS
IF UPDATE(b)
PRINT 'Column b Modified'
GO
B. Use the COLUMNS UPDATED() clause to test data modifications

This example obtains similar results using the COLUMNS_UPDATED() clause.

CREATE TRIGGER my_trig2


ON my_table

118
FOR INSERT
AS
IF ( COLUMNS_UPDATED() & 2 = 2 )
PRINT 'Column b Modified'
GO

Deferred Name Resolution

Triggers can refer to tables that do not exist at trigger creation time. This is called deferred name
resolution.

Returning Results

It is recommended that a trigger not return any results. This is because special handling for these
returned results must be written into every application in which modifications to the trigger table are
allowed. To prevent any results from being returned from a trigger, do not include either SELECT
statements or variable assignments in the definition of the trigger. If variable assignment must occur
in a trigger, use a SET NOCOUNT statement at the beginning of the trigger to eliminate the return
of any result sets.

Using Triggers that Include COMMIT or ROLLBACK


TRANSACTION
Microsoft SQL Server 2000 increments the transaction count within a statement only when the
transaction count is 0 at the start of the statement. In SQL Server version 7.0, the transaction count
is always incremented, regardless of the transaction count at the start of the statement. This can cause
the value returned by @@TRANCOUNT in triggers to be lower in SQL Server 2000 than it is in
SQL Server version 7.0.

In SQL Server 2000, if a COMMIT TRANSACTION or COMMIT WORK statement is executed in


a trigger, and there is no corresponding explicit or implicit BEGIN TRANSACTION statement at
the start of the trigger, users may see different behavior than on SQL Server version 7.0. Placing
COMMIT TRANSACTION or COMMIT WORK statements in a trigger is not recommended.

When triggers that include ROLLBACK TRANSACTION statements are executed from a batch,
they cancel the entire batch. In the following example, if the INSERT statement fires a trigger that
includes a ROLLBACK TRANSACTION, the DELETE statement is not executed because the
batch is canceled:

/* Start of Batch */
INSERT employee VALUES ('XYZ12345M', 'New', 'M', 'Employee', 1, 1, '9952',
'6/1/95') -- Causes trigger to fire and ROLLBACK TRANSACTION.
DELETE employee WHERE emp_id = 'PMA42628M'
GO

If triggers that include ROLLBACK TRANSACTION statements are fired from within a user-
defined transaction, the ROLLBACK TRANSACTION rolls back the entire transaction. In this

119
example, if the INSERT statement fires a trigger that includes a ROLLBACK TRANSACTION, the
UPDATE statement is also rolled back:

/* Start of Transaction */
BEGIN TRANSACTION
UPDATE employee SET hire_date = '7/1/94' WHERE emp_id = 'VPA30890F'
INSERT employee VALUES ('XYZ12345M', 'New', 'M', 'Employee', 1, 1, '9952',
'6/1/95') -- Causes trigger to fire and ROLLBACK TRANSACTION
Using the inserted and deleted Tables
Two special tables are used in trigger statements: the deleted table and the inserted table.
Microsoft® SQL Server™ 2000 automatically creates and manages these tables. You can use these
temporary, memory-resident tables to test the effects of certain data modifications and to set
conditions for trigger actions; however, you cannot alter the data in the tables directly.

The inserted and deleted tables are used primarily in triggers to:

• Extend referential integrity between tables.

• Insert or update data in base tables underlying a view.

• Check for errors and take action based on the error.

• Find the difference between the state of a table before and after a data modification and take
action(s) based on that difference.

The deleted table stores copies of the affected rows during DELETE and UPDATE statements.
During the execution of a DELETE or UPDATE statement, rows are deleted from the trigger table
and transferred to the deleted table. The deleted table and the trigger table ordinarily have no rows
in common.

The inserted table stores copies of the affected rows during INSERT and UPDATE statements.
During an insert or update transaction, new rows are added simultaneously to both the inserted
table and the trigger table. The rows in the inserted table are copies of the new rows in the trigger
table.

An update transaction is similar to a delete operation followed by an insert operation; the old rows
are copied to the deleted table first, and then the new rows are copied to the trigger table and to the
inserted table.

120
When you set trigger conditions, use the inserted and deleted tables appropriately for the action
that fired the trigger. Although referencing the deleted table while testing an INSERT, or the
inserted table while testing a DELETE does not cause any errors, these trigger test tables do not
contain any rows in these cases.

Note If trigger actions depend on the number of rows a data modification effects, use tests
(such as an examination of @@ROWCOUNT) for multirow data modifications (an INSERT,
DELETE, or UPDATE based on a SELECT statement), and take appropriate actions.

SQL Server 2000 does not allow text, ntext, or image column references in the inserted and
deleted tables for AFTER triggers; however, these column references are allowed for INSTEAD
OF triggers.

Using the inserted and deleted Tables in INSTEAD OF Triggers

The inserted and deleted tables passed to INSTEAD OF triggers defined on tables follow the same
rules as the inserted and deleted tables passed to AFTER triggers. The format of the inserted and
deleted tables is the same as the format of the table on which the INSTEAD OF trigger is defined.
Each column in the inserted and deleted tables maps directly to a column in the base table.

The rules regarding when an INSERT or UPDATE statement referencing a table with an INSTEAD
OF trigger must supply values for columns are the same as if the table did not have an INSTEAD
OF trigger:

• Values cannot be specified for computed columns or columns with a timestamp data type.

• Values cannot be specified for columns with an IDENTITY property, unless


IDENTITY_INSERT is ON for that table. When IDENTITY_INSERT is ON, INSERT
statements must supply a value.

• INSERT statements must supply values for all NOT NULL columns that do not have
DEFAULT constraints.

• For any columns except computed, identity, or timestamp columns, values are optional for
any column that allows nulls, or any NOT NULL column that has a DEFAULT definition.

When an INSERT, UPDATE, or DELETE statement references a view that has an INSTEAD OF
trigger, the database engine calls the trigger instead of taking any direct action against any table. The
trigger must use the information presented in the inserted and deleted tables to build any

121
statements needed to implement the requested action in the base tables even when the format of the
information in the inserted and deleted tables built for the view is different than the format of the
data in the base tables.

The format of the inserted and deleted tables passed to an INSTEAD OF trigger defined on a view
matches the select list of the SELECT statement defined for the view. For example:

CREATE VIEW EmployeeNames (EmployeeID, LName, FName)

AS

SELECT EmployeeID, LastName, FirstName

FROM Northwind.dbo.Employees

The result set for this view has three columns: an int column and two nvarchar columns. The
inserted and deleted tables passed to an INSTEAD OF trigger defined on the view also have an int
column named EmployeeID, an nvarchar column named LName, and an nvarchar column
named FName.

The select list of a view can also contain expressions that do not map directly to a single base table
column. Some view expressions, such as a constant or function invocation, may not reference any
columns and can be ignored. Complex expressions can reference multiple columns, yet the inserted
and deleted tables have only one value for each inserted row. The same issues apply to simple
expressions in a view if they reference a computed column that has a complex expression. An
INSTEAD OF trigger on the view must handle these types of expressions.

Conditional INSERT Trigger


A trigger rejects or accepts each data modification transaction as a whole. However, you do not have
to roll back all data modifications simply because some of them are unacceptable. Using a correlated
subquery in a trigger can force the trigger to examine the modified rows one by one.

Examples

A. Use an AFTER INSERT trigger

The following example assumes the existence of a table called newsale in the pubs database. This
the CREATE statement for newsale:

CREATE TABLE newsale


(stor_id char(4),
ord_num varchar(20),

122
date datetime,
qty smallint,
payterms varchar(12),
title_id tid)

If you want to examine each of the records you are trying to insert, the trigger conditionalinsert
analyzes the insert row by row, and then deletes the rows that do not have a title_id in titles.

CREATE TRIGGER conditionalinsert


ON sales
AFTER INSERT AS
IF
(SELECT COUNT(*) FROM titles, inserted
WHERE titles.title_id = inserted.title_id) <> @@ROWCOUNT
BEGIN
DELETE sales FROM sales, inserted
WHERE sales.title_id = inserted.title_id AND
inserted.title_id NOT IN
(SELECT title_id
FROM titles)
PRINT 'Only sales records with matching title_ids added.'
END

When unacceptable titles have been inserted, the transaction is not rolled back; instead, the trigger
deletes the unwanted rows. This ability to delete rows that have been inserted relies on the order in
which processing occurs when triggers are fired. First, rows are inserted into the sales table and the
inserted table, and then the trigger fires.

To test the trigger, insert four rows in the newsale table. Two of the newsale rows have title_ids
that do not match any of those already in the titles table:

newsale
stor_id ord_num date qty payterms title_id
------- -------- ------------------- --- -------- --------
7066 QA7442.3 Jul 25 1995 8:35AM 75 Net 30 PS1372
7066 QA7442.3 Jul 24 1995 8:35AM 75 Net 60 BU7832
7067 D4482 Jul 27 1995 12:00AM 10 Net 30 PSxxxx
7131 N914008 Jul 27 1995 12:00AM 20 Net 30 PSyyyy

Next, insert data from newsale into sales. The statement looks like this:

INSERT sales

123
SELECT * FROM newsale

The title_ids PSxxxx and PSyyyy do not match any in the titles table, and the conditionalinsert
trigger deletes these two rows from the sales and inserted tables.

Deleting a Trigger
When a trigger is no longer needed, you can delete it. When a trigger is deleted, the table and the data
upon which it is based are not affected. Deleting a table automatically deletes any triggers on the
table. Permissions to delete a trigger default to the owner of the table upon which the trigger is
defined.

124

Das könnte Ihnen auch gefallen