Trigers SP Views
Trigers SP Views
Trigers SP Views
Server computer.
The ability to log on to the Windows 2000 Server computer and to SQL Server
Transact-SQL commands that make it easy for you to view various properties of
objects in the database.
Performance
Every time a Transact-SQL command (or batch of commands) is sent to the server
for processing, the server must determine whether the sender has appropriate permissions
to execute the commands and whether the commands are valid. Once the
permissions and the syntax are verified, SQL Server builds an execution plan to
process the request.
Chapter 8 Implementing Stored Procedures 269
Stored procedures are more efficient in part because the procedure is stored in SQL
Server when it is created. Therefore, the content in the procedure runs at the server
when the stored procedure is executed. A complex Transact-SQL script contained
in a stored procedure is called by a single Transact-SQL statement, rather than by
sending hundreds of commands over the network.
Before a stored procedure is created, the command syntax is checked for accuracy.
If no errors are returned, the procedures name is stored in the SysObjects table and
the procedures text is stored in the SysComments table. The first time the stored
procedure is run, an execution plan is created and the stored procedure is compiled.
Subsequent processing of the compiled stored procedure is faster because SQL
Server does not recheck command syntax, re-create an execution plan, or recompile
the procedure. The cache is checked first for an execution plan before a new
plan is created.
Note The relative performance boost provided by placing stored procedure execution
plans in the procedure cache is reduced because execution plans for all SQL
statements are now stored in the procedure cache. A Transact-SQL statement will
attempt to use an existing execution plan if possible.
Programming Framework
Once a stored procedure is created, you can call it whenever its needed. This feature
provides modularity and encourages code reuse. Code reuse increases the maintainability
of a database by insulating the database from changing business practices. If
business rules change in an organization, a stored procedure can be modified to
comply with the new business rules. All applications that call the stored procedure
will then comply with the new business rules without direct modification.
Like other programming languages, stored procedures can accept input parameters,
return output parameters, provide execution feedback in the form of status codes
and descriptive text, and call other procedures. For example, a stored procedure can
return a status code to a calling procedure so that the calling procedure performs an
operation based on the code received.
Software developers can write sophisticated programs in a language such as Visual
C++; then, a special type of stored procedure called an extended stored procedure
can be used to invoke the program from within SQL Server.
You should write a stored procedure to complete a single task. The more generic
the stored procedure, the more useful it will be to many databases. For example,
the sp_rename stored procedure changes the name of a user-created object, such
as a table, a column, or a user-defined data type in the current database. Thus, you
can use sp_rename to rename a table in one database or a table column in another
database.
270 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
Security
Another important feature of stored procedures is that they enhance security
through isolation and encryption. Database users can be given permission to execute
a stored procedure without being granted permissions to directly access the
database objects on which the stored procedure operates. Additionally, a stored
procedure can be encrypted when it is created or modified so that users are unable
to read the Transact-SQL commands in the stored procedure. These security features
insulate the database structure from the database user, which further ensures
data integrity and database reliability.
Database security is critical to most organizations that store private data in a database.
The following statement uses the sp_validatelogins system stored procedure
to show any orphaned Windows NT or Windows 2000 user and group accounts that
no longer exist but still have entries in the SQL Server system tables:
EXECUTE sp_validatelogins
There are hundreds of system stored procedures included with SQL Server. For a
complete list of system stored procedures, refer to System Stored Procedures in
SQL Server Books Online. You will notice in the system stored procedures reference
that some extended stored procedures are listed. Extended stored procedures
are discussed later in this lesson.
They exist even after the connection used to create them is terminated.
Notice that the CREATE PROCEDURE keywords appear near the top of the
file. In the next lesson, you will learn more about creating stored procedures
using Transact-SQL. Notice that batches of commands are specified in the
stored procedure text. As you examine the text, you will see that the @loginame
input parameter appears in a number of places. Notice also that the
SysProcesses table is queried a number of times in the stored procedure using
its fully qualified name, master.dbo.sysprocesses.
Chapter 8 Implementing Stored Procedures 275
This code uses the sp_helptext system stored procedure to show the contents of
the sp_who system stored procedure contained in the Master database. It is not
necessary to fully qualify the name of the stored procedure, but it is a good
practice because it guarantees that you will open the object that you are interested
in viewing.
9. Execute the code.
The Grids tab of the Results pane displays the contents of the sp_who system
stored procedure.
Lesson Summary
Stored procedures contain Transact-SQL commands that are stored in a database
and are typically designed to run a single task. Stored procedures provide performance
gains, programming capabilities, and security features not available when
using individual Transact-SQL commands or batches. Storing the procedure in a
database, checking the syntax when the procedure is created, and creating a reusable
execution plan the first time the stored procedure is executed will enhance performance.
Stored procedures support parameters and return codes. Because stored
procedures are modular, they provide a layer of insulation between changing business
practices and the underlying database. The programming capabilities of stored
procedures are nearly unlimited because of support for extended stored procedures.
From a security perspective, users can be granted the right to execute a stored procedure
without being granted the right to manipulate the database outside the
stored procedure.
There are five general categories of stored procedures: system, local, temporary,
extended, and remote. SQL Server includes hundreds of system stored procedures
and extended stored procedures to perform tasks such as system administration.
Local stored procedures are created in a user database and are typically used to
complete tasks specific to the database in which they are created. Temporary stored
procedures look and act like any of the other categories of stored procedures, but
they are volatile and disappear upon the termination of a user connection (or when
the server is shut down). Remote stored procedures are available for backward
compatibility but have been replaced by distributed queries.
276 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
This query returns the create text of the ByRoyalty stored procedure, whose identification
number is 581577110.
Note The two previous SELECT statements could have been consolidated into a
single SELECT statement by using a JOIN. They are separated here for simplicity
and clarity.
Using the sp_helptext system stored procedure is a better option for displaying the
text used to create an object (such as an unencrypted stored procedure), because
the text is returned in multiple rows. You used the sp_helptext stored procedure in
the last practice of Exercise 1.
Define input and output parameters, their data types, and their default values
When input and output parameters are defined, they are always preceded by the
at sign (@), followed by the parameter name and then a data type designation.
Output parameters must include the OUTPUT keyword to distinguish them
from input parameters.
Use return codes to display information about the success or failure of a task
Specify the actions that the stored procedure should take when executed
Note Lesson 3 explores input and output parameters, programming actions that a
stored procedure should take when executed, and success or failure result sets. For
Notice that the procedure name is fully qualified in the example. A fully qualified
stored procedure name includes the procedures owner (in this case, dbo) and the
name of the procedure, ListAuthorNames. Specify dbo as the owner if you want to
ensure that the task in the stored procedure will run regardless of table ownership
Chapter 8 Implementing Stored Procedures 279
in the database. The database name is not part of a fully qualified stored procedure
name when using the CREATE PROCEDURE statement.
Fully qualified database names are specified in the SELECT statements. If the procedure
is not executed in the context of a specific database and the Transact-SQL
commands in the stored procedure are database-specific, then fully qualified database
names ensure that the proper database is referenced.
In the third example, when creating a temporary stored procedure directly in
TempDB, you must make TempDB the current database (USE TempDB) before
executing it, or you must fully qualify its name ([TempDB].[dbo].[directtemp]).
Like system stored procedures in the Master database, local and global temporary
stored procedures are available for execution using their short names (regardless of
the current database).
280 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
stored procedures parameters vary considerably from one execution to the next,
caching an execution plan is counterproductive. To cause a stored procedure to be
recompiled every time it is executed, add the WITH RECOMPILE keywords when
the stored procedure is created. You can also force a recompile by using the
sp_recompile stored procedure or by specifying WITH RECOMPILE when the
procedure is executed.
Encrypting a stored procedure protects its contents from being viewed. To encrypt
a stored procedure, use the WITH ENCRYPTION keywords when creating the
procedure. For example, the following code creates an encrypted procedure named
Protected:
USE Pubs
GO
CREATE PROC [dbo].[protected] WITH ENCRYPTION
AS
SELECT [au_fname], [au_lname] FROM [pubs].[dbo].[authors]
The WITH ENCRYPTION keywords encrypt the procedures text column in the
SysComments table. A simple way to determine whether a procedure is encrypted
is by using the OBJECTPROPERTY function
-check if stored procedure is encrypted and if so, return 1 for IsEncrypt
ed
SELECT OBJECTPROPERTY(object_id(protected), IsEncrypted)
Enterprise Manager
You can create a stored procedure directly in Enterprise Manager. To accomplish
this task, expand the console tree for your server and then expand the database
where a stored procedure should be created. Right-click the Stored Procedure node,
and then click New Stored Procedure. When the Stored Procedure Properties - New
Stored Procedure dialog box appears, enter the contents of the stored procedure.
Figure 8.1 shows the Stored Procedure Properties - New Stored Procedure dialog
box that contains the code from a previous example.
F08BQ01.eps
Figure 8.1. The General tab of the Stored Procedure Properties - New Stored Procedure
dialog box for a new stored procedure.
You can also check the syntax of the stored procedure before creating it and save a
template that will always appear when you create a new stored procedure by using
Enterprise Manager. Once the procedure is created, you can open the properties of
the procedure and configure permissions. By default, the stored procedures owner
and sysadmins have full permission to the stored procedure.
282 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
Templates are useful because they provide a framework for creating consistent
documentation
for stored procedures. Typically, text is added to the header of the template
that describes how each stored procedure should be documented.
Figure 8.2. The Welcome to the Create Stored Procedure Wizard screen.
The Create Stored Procedure wizard enables you to create procedures that insert,
delete, or update data in tables. To modify the stored procedure that the wizard
creates, you can edit it within the wizard or by using other tools (such as Query
Analyzer).
with SQL Server. To register the extended stored procedure, you can use the
sp_addextendedproc system stored procedure in Query Analyzer or use Enterprise
Manager. In Enterprise Manager, expand the Master database, right-click the
Extended Stored Procedures node, and then click New Extended Stored Procedure.
Extended stored procedures can be added only to the Master database.
Chapter 8 Implementing Stored Procedures 283
clarity and are used in the examples even when the object names do not violate the
rules for identifiers. Refer to Chapter 2, Using Transact-SQL on a SQL Server
Database (Lesson 3) for details.
Fully qualified names are not necessary when executing system stored procedures
that have an sp_ prefix, local temporary stored procedures, or global temporary
stored procedures. SQL Server will search the Master database for any stored procedures
that have an sp_ prefix where dbo is the owner. To avoid confusion, do not
name local stored procedures with the same names as stored procedures located in
the Master database. If you do name a local stored procedure with the same name
as a system stored procedure, make sure to append the procedure name with an
284 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
owner other than dbo. SQL Server does not automatically search the Master database
for extended stored procedures. Therefore, either fully qualify the name of an
extended stored procedure or change the active database to the location of the
extended stored procedure.
In the first example, the parameter values were specified but the parameter names
were not. If the values are specified without their corresponding names, the values
must be called in the same order as they were specified when the procedure was
created. In the second example, the parameter names and values were specified.
When both the names and the values are specified, they can be listed in any order.
Parameters assigned default values when a stored procedure is created might run
successfully without specifying a value upon execution.
The following list shows some of the optional syntax available when executing
stored procedures:
A return code variable of integer data type to store values returned from the
stored procedure
The RETURN keyword with an integer value (or values) must be specified in
the stored procedure for this optional variable to work.
For grouped stored procedures, you can either execute all stored procedures in
the group by simply specifying the stored procedure name, or you can include a
number to select which procedure in the group you wish to execute. For example,
if you create two stored procedures named GroupedProc;1 and
GroupedProc;2, you can run both of the stored procedures by typing EXEC
groupedproc. Or, you can run procedure 2 by typing EXEC groupedproc;2.
Chapter 8 Implementing Stored Procedures 285
Variables are defined by using the DECLARE keyword before using EXECUTE.
You will work with variables in Exercise 3.
Note For additional syntax details about EXECUTE, refer to the Transact-SQL
reference in SQL Server Books Online.
@optionname = startup,
@optionvalue = true
Only procedures owned by dbo and located in the Master database can be configured
to start automatically. To automatically start procedures in other databases,
you can call them from a procedure located in the Master database that is configured
to start automatically. Calling one procedure from another is called nesting.
You can configure a stored procedure to start automatically by using Enterprise
Manager. Access the Master database, then click the Stored Procedures node.
Select a stored procedure that you wish to start automatically, and then right-click
it. On the properties dialog box of the stored procedure, select the Execute Whenever
SQL Server Starts check box.
To determine whether a procedure is set to start automatically, run the OBJECTPROPERTY
function and check the ExecIsStartup property. For example, the following
code checks to determine whether the AutoStart stored procedure is
configured to start automatically:
USE Master
--determine whether a stored procedure is set to start automatically
SELECT OBJECTPROPERTY(object_id(autostart), ExecIsStartup)
286 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
To disable stored procedures from starting automatically, you can run the
sp_configure stored procedure. The following statement configures SQL Server so
that stored procedures flagged to start automatically will not be started the next
time SQL Server is started:
EXECUTE sp_configure
@configname = scan for startup procs, @configvalue = 0
RECONFIGURE
GO
Notice in the example that Pubs was made the current database. You cannot specify
the database name when specifying a procedure to drop. The fully qualified name
of the procedure is [owner].[procedure_name]. If you have created a user-defined
system stored procedure (sp_ prefix), the DROP PROCEDURE statement will
search the current database. If it doesnt find a user-defined system stored procedure
of the same name, it will search the Master database.
To drop a group of stored procedures, specify the name of the procedure. You cannot
delete part of a grouped procedure by using DROP PROCEDURE. For example,
if you have a set of grouped procedures named GroupedProc containing
GroupedProc;1 and GroupedProc;2, you cannot drop GroupedProc;1 without also
dropping GroupedProc;2. If you need to delete part of a grouped procedure, drop
the grouped procedure and re-create it.
Before dropping a stored procedure, you should check whether other database
objects depend on the stored procedure you are dropping. Use the sp_depends system
stored procedure to check for dependent objects. You need to be concerned
only with the objects that depend on the stored procedure you intend to delete.
Tip You can create, execute, alter, and drop user-defined stored procedures in
Query Analyzer by right-clicking the stored procedure and pointing to any of the
Script Object To... options. To generate the script in Query Analyzer, click Script
Object To New Window.
3. Expand the Query window so that it occupies all of the workspace in Query
Analyzer.
4. In the Editor pane of the Query window, enter and execute the following code:
USE northwind
GO
CREATE PROCEDURE dbo.CustOrderHistRep
@CustomerID char(5)
AS
SELECT ContactName, ContactTitle
FROM Customers WHERE CustomerID = @CustomerID
SELECT ProductName, Total=SUM(Quantity)
FROM Products P, [Order Details] OD, Orders O, Customers C
WHERE
C.CustomerID = @CustomerID AND C.CustomerID = O.CustomerID
The Northwind database is made the current database in the first batch. Then, a
procedure named CustOrderHistRep is created and a single input parameter,
@CustomerID, is defined. The input parameter can appear on the same line as
the CREATE PROCEDURE line, but it appears on its own line here for clarity.
A similar approach for separating the code appears below the SELECT statements.
Notice that the data type for @CustomerID is set to char(5). If you
query the [northwind].[dbo].[customers] table, you will see that all customer
IDs are five characters long. The line that has a single keyword, AS, is the
demarcation line between the procedures creation in the SysObjects table and
the text contained in the procedure and stored in the SysComments table.
5. Review but do not spend too much time on the SELECT statements that appear
below the AS keyword.
When the query is executed, the first SELECT statement displays a persons
name and title for the customer ID entered. The second SELECT statement displays
all product names purchased by the customer and the total quantity
(SUM) of each product. The result set returns the data grouped by product
name. You might notice that multiple joins were accomplished by the WHERE
clause, rather than by the FROM clause. When the procedure is modified, you
will move the JOIN expressions to the FROM clause.
Note You should be somewhat familiar with the code in the SELECT statements.
If you need a review of the language in the SELECT statement, refer to Chapter 6,
Accessing and Modifying Data.
Chapter 8 Implementing Stored Procedures 289
_
1. Open the Object Browser in Query Analyzer and expand the Northwind
database.
2. Expand the Stored Procedures node.
All stored procedures created for the Northwind database appear.
3. Expand the dbo.CustOrderHistRep stored procedure.
Notice that the stored procedure is owned by dbo and that two nodes appear
below dbo.CustOrderHistRep: Parameters and Dependencies.
4. Expand the Parameters node.
Notice that there are two parameters for this stored procedure: the @CustomerID
parameter that you created and the built-in return code parameter,
@RETURN_VALUE.
5. Expand the Dependencies node.
Notice that this stored procedure depends on four objects: the Orders, Products,
Order Details, and Customers tables in the Northwind database. No objects
depend on this stored procedure.
6. Switch to the Editor pane of the Query window.
7. On a blank line at the bottom of the Editor pane, enter and execute the following
line:
sp_depends custorderhistrep
1. On a blank line at the bottom of the Editor pane, enter and execute the following
code:
EXEC [northwind].[dbo].[custorderhistrep]
@CustomerID = thecr
The shortened version of the EXECUTE keyword, EXEC, is used to run the
stored procedure, CustOrderHistRep. Notice that the fully qualified name of the
procedure was specified. This specification is not necessary, but it enables you
to run the procedure without first making sure that the current database is
Northwind.
Two result sets are returned. The first result set (contact name and contact title)
appears in the upper portion of the Results pane. The second result set (product
name and product totals) appears in the bottom portion of the Results pane.
290 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
In the previous example, EXEC was specified to run the stored procedure. Was
it necessary to use this keyword?
2. Find the dbo.CustOrderHistRep stored procedure in the Object Browser and
right-click it.
3. From the context menu, point to Script Object to New Windows As and then
click Execute.
Query Analyzer loads a new page into the Query Window editor, and the EXECUTE
statement for dbo.CustOrderHistRep appears. Notice that two variables
are declared: @RC and @CustomerID. The first variable is used to hold any
return codes that are part of the procedure, and the second variable holds the
value of the input parameter, @CustomerID. Notice that in the EXEC statement,
@RC is equal to the stored procedure. This relationship captures any
return codes from the procedure and places them into @RC. In Lesson 3, you
will learn more about declaring variables when executing a stored procedure
and setting the return code parameter equal to the stored procedure.
4. In the Editor pane, click the mouse at the end of the EXEC statement so that a
blinking cursor appears after the word @CustomerID. Append the following
line to the end of the line: = thecr. The EXEC statement should look like the
following:
EXEC @RC = [Northwind].[dbo].[CustOrderHistRep] @CustomerID = thecr
1. In the Editor pane of the Query window, locate the following code:
USE Northwind
GO
CREATE PROCEDURE dbo.CustOrderHistRep
@CustomerID char(5)
AS
SELECT ContactName, ContactTitle
FROM Customers WHERE CustomerID = @CustomerID
SELECT ProductName, Total=SUM(Quantity)
FROM Products P, [Order Details] OD, Orders O, Customers C
WHERE
C.CustomerID = @CustomerID AND C.CustomerID = O.CustomerID
4. You have also decided to move the table joins from the WHERE clause to the
FROM clause. The final form of the code should be similar to the following:
USE Northwind
GO
ALTER PROCEDURE dbo.CustOrderHistRep
@CustomerID char(5)
AS
SELECT ContactName, ContactTitle
FROM Customers WHERE CustomerID = @CustomerID
SELECT ProductName, Total=SUM(Quantity)
FROM Products P INNER JOIN [Order Details] OD
ON P.ProductID = OD.ProductID JOIN Orders O
ON OD.OrderID = O.OrderID JOIN Customers C
ON O.CustomerID = C.CustomerID
WHERE C.CustomerID = @CustomerID
GROUP BY ProductName
ORDER BY Total DESC
GO
The stored procedure text appears on the Grids tab in the Results pane.
7. Leave the Query Analyzer open for the next exercise.
_
1. Go to the bottom of the Editor pane, press ENTER, then enter and execute the
following statement:
DROP PROCEDURE dbo.custorderhistrep
Lesson Summary
The CREATE PROCEDURE keywords are used to create procedures that are
stored in a database. Procedures are created using graphical tools such as Enterprise
Manager or command-prompt tools such as osql. Upon creation, the name of
the procedure appears in SysObjects, and the procedures content is stored in
SysComments. When a procedure is created, it can be grouped, include return
codes, require input parameters, supply default values for parameters, specify output
parameters, be encrypted, or specify whether an execution plan should be created
and whether the procedure should execute on a replication subscriber. The
fundamental reason for creating a procedure is to complete a task when the procedure
is executed. The EXECUTE keyword is used to run a procedure. A procedure
can be run manually or flagged so that it starts when SQL Server starts. If a procedure
requires modification, it is more efficient to use the ALTER PROCEDURE
statement instead of deleting a procedure and recreating it. ALTER PROCEDURE
maintains most of the original stored procedure objects properties. Deleting a
stored procedure is accomplished by using the DROP PROCEDURE statement. If a
user-defined system stored procedure is not located in the current database, SQL
Server will search the Master database to delete the procedure.
Chapter 8 Implementing Stored Procedures 293
The following procedure shows the use of both input and output parameters:
USE Pubs
GO
CREATE PROCEDURE dbo.SalesForTitle
@Title varchar(80), -- This is the input parameter.
@YtdSales int OUTPUT, -- This is the first output parameter.
@TitleText varchar(80) OUTPUT --This is the second output parameter.
AS
-- Assign the column data to the output parameters and
-- check for a title thats like the title input parameter.
SELECT @YtdSales = ytd_sales, @TitleText=title
FROM titles WHERE title LIKE @Title
GO
The input parameter is @Title, and the output parameters are @YtdSales and
@TitleText. Notice that all three parameters have defined data types. The output
parameters include the mandatory OUTPUT keyword. After the parameters are
defined, the SELECT statement uses all three parameters. First, the output parameters
are set equal to the column names in the query. When the query is run, the output
parameters will contain the values from these two columns. The WHERE
clause of the SELECT statement contains the input parameter, @Title. When the
procedure is executed, you must provide a value for this input parameter or the
query will fail. Later in this lesson, you will learn how to handle errors and provide
default values for parameters.
The following statement executes the stored procedure that you just examined:
-- Declare variables to receive output values from procedure.
DECLARE @y_YtdSales int, @t_TitleText varchar(80)
EXECUTE SalesForTitle
--set the values for output parameters to the variables.
@YtdSales = @y_YtdSales OUTPUT,
@TitleText = @t_TitleText OUTPUT,
@Title = %Garlic% --specify a value for input parameter.
-- Display the variables returned by executing the procedure.
Select Title = @t_TitleText, Number of Sales = @y_YtdSales
GO
Two variables are declared: @y_YtdSales and @t_TitleText. These two variables
will receive the values stored in the output parameters. Notice that the data types
declared for these two variables match the data types of their corresponding output
parameters. These two variables can be named the same as the output parameters
because the variables in a stored procedure are local to the batch that contains
them. For clarity, the variable names are different from the output parameters.
When the variable is declared, it is not matched with an output parameter. Variables
are matched with output parameters after the EXECUTE statement. Notice that the
OUTPUT keyword is specified when the output parameters are set as equal to the
Chapter 8 Implementing Stored Procedures 295
variables. If OUTPUT is not specified, the variables cannot display values in the
SELECT statement at the bottom of this batch. Finally, notice that the input parameter
@Title is set equal to %Garlic%. This value is sent to the WHERE clause of
the stored procedures SELECT statement. Because the WHERE clause uses the
LIKE keyword, you can use wildcards such as % so that the query searches for titles
that contain the word Garlic.
A more succinct way to execute the procedure is shown next. Notice that it is not
necessary to specifically assign the variables from the stored procedure to the value
of the input parameter or the output variables declared here:
DECLARE @y_YtdSales int, @t_TitleText varchar(80)
EXECUTE SalesForTitle
"%Garlic%", --sets the value of the input parameter.
@y_YtdSales OUTPUT, --receives the first output parameter
@t_TitleText OUTPUT --receives the second output parameter
-- Display the variables returned by executing the procedure.
Select Title = @t_TitleText, Number of Sales = @y_YtdSales
GO
Consider the SalesForTitle procedure that you created and executed in the last section.
If the value specified for the input parameter (@Title) does not exist in the
database, executing the procedure returns the following result set:
It is more instructive to explain to the user that there were no matching records.
The following example shows how to modify the SalesForTitle stored procedure to
use a RETURN code (and thus provide a more useful message):
ALTER PROCEDURE dbo.SalesForTitle
@Title varchar(80), @YtdSales int OUTPUT,
@TitleText varchar(80) OUTPUT
AS
--Check to see if the title is in the database. If it isnt,
--exit the procedure and set the return code to 1.
IF (SELECT COUNT(*) FROM titles WHERE title LIKE @Title) = 0
RETURN(1)
ELSE
SELECT @YtdSales = ytd_sales, @TitleText=title
FROM titles WHERE title LIKE @Title
GO
The IF statement below the AS keyword determines whether the input parameter is
provided when the procedure is executed and matches any records in the database.
If the COUNT function returns 0, then the return code is set to 1, RETURN(1). If
the COUNT function returns anything else, the SELECT statement queries the Title
table for annual sales and book title information. In this case, the return code is
equal to 0.
Note The initial USE Pubs statement has been removed from the script because it
isnt the focus of the sample code. If you run this code make sure that you have
switched to the Pubs database first. As you move through the code examples, you
might notice other space-saving code consolidations (such as removing code comments
and adding others). You should make a point of commenting your code so
that it is maintainable and relatively easy to understand.
Some recoding of the execution statement is necessary to use the return code. The
following example sets the input parameter @Title equal to Garlic%:
--Add @r_Code to hold the result code.
DECLARE @y_YtdSales int, @t_TitleText varchar(80), @r_Code int
--Run the procedure and set @r_Code equal to the procedure.
EXECUTE @r_Code = SalesForTitle
@YtdSales = @y_YtdSales OUTPUT,
@TitleText = @t_TitleText OUTPUT,
A new variable has been added to the end of the DECLARE statement: @r_Code.
Later in the code, this variable contains the value provided by the RETURN keyword.
This variable is defined as an integer data type because the return code sends
an integer value. The @r_Code variable is set to the return code on the EXECUTE
line. Notice that @r_Code is set equal to the stored procedure. The value for the
input parameter, @Title, is now Garlic% rather than %Garlic%. In other words, the
SELECT statement in the procedure will search for records in the Titles table starting
with the word Garlic. Conditional logic appears below the parameters and
comments. The first IF statement is tested. If the procedure finds a record, then the
return code is 0, and the SELECT statement runs. If the procedure doesnt find any
matching records, @r_Code will equal 1 and the PRINT statement will run.
Because there isnt a title in the database that begins with the word Garlic, executing
the procedure returns the PRINT statement:
No matching titles in the database. Return code=1
Changing the input parameter to %Garlic% and executing the code returns the following
result set:
If you dont enter a value for the @Title input parameter, the result of executing the
query is the following message:
Server: Msg 201, Level 16, State 3, Procedure SalesForTitle, Line 0
Procedure SalesForTitle expects parameter @Title, which was not supp
lied.
instructive to the user if you set a default of NULL for the input parameter and let a
RETURN code instruct the user on how to properly execute the procedure. Modifying
the procedure in the following way accomplishes this goal:
ALTER PROCEDURE dbo.SalesForTitle
@Title varchar(80) = NULL, @YtdSales int OUTPUT,
@TitleText varchar(80) OUTPUT
AS
IF @Title IS NULL
RETURN(2)
ELSE
IF (SELECT COUNT(*) FROM titles WHERE title LIKE @Title) = 0
RETURN(1)
ELSE
SELECT @YtdSales = ytd_sales, @TitleText=title
FROM titles WHERE title LIKE @Title
GO
the error. Common user errors that lead to database errors occur in INSERT and
UPDATE statements in which a user attempts to add data that violates the integrity
of the data (such as adding an invalid identification number). The error numbers
and their descriptions are stored in the master.dbo.sysmessages table. You can
query this table with the following SELECT statement:
SELECT error, description from master.dbo.sysmessages
Notice that the procedure checks for the value of @@ERROR after the SELECT
statement that returns a result set when the procedure is executed. This function is
important, because the goal of @@ERROR is to check for database errors after the
core task of the stored procedure occurs.
The following code executes the procedure and displays a generic error message if
300 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
IF @r_Code = 1
PRINT No matching titles in the database. Return code= + CONVERT(varch
ar(1),@r_Code)
ELSE
IF @r_Code = 2
PRINT You must add a value for @Title for this procedure to function pr
operly.
Return code= + CONVERT(varchar(1),@r_Code)
ELSE
IF @r_Code = 3
PRINT There was a database error.
GO
When you create a stored procedure for a production database system, you will
become familiar with the types of errors that users will make when they execute the
procedure. With this experience and your understanding of result codes, you can
write additional error-handling conditions into your procedures.
Note For more information about result codes and using the @@ERROR function,
perform a search for RESULT and @@ERROR in SQL Server Books Online.
Nesting Procedures
Nesting stored procedures simply involves calling one stored procedure from
another. A single stored procedure can perform multiple tasks, but it is better to
create simpler, more generic stored procedures that can call other stored procedures
to complete additional tasks. For example, you might write a stored procedure
called Procedure_A that inserts data into an existing table, and you might write
another stored procedure called Procedure_B that displays data from the table.
Procedure_A could call Procedure_B after successfully inserting data into a table.
Users can still run Procedure_B to view table information without having to run
Procedure_A to insert data into the table.
Procedures can be nested together up to 32 levels deep. However, there is no limit to
how many procedures a single procedure can call. A procedure can also call itself
recursively. A procedure is called from another procedure by using the EXECUTE
statement. You will nest a procedure for the BookShopDB database in Exercise 3.
Cursors
You can use cursors in stored procedures; however, you should avoid them if you
can find a way to do the same thing by using result sets. Procedures that use result
sets are more efficient on the database and on the network, and they are typically
less complex to write than cursors. Cursors are explored in Chapter 7, but are discussed
here so that you can see how to use them in stored procedures. To learn
more about cursors, read Lesson 3 in Chapter 7 of SQL Server Books Online and
Inside Microsoft SQL Server 2000 by Microsoft Press.
Chapter 8 Implementing Stored Procedures 301
Notice that all output parameters were removed from the stored procedure. To execute
this simple stored procedure, you can use the following sample code:
EXECUTE SalesForTitle
@Title = The%
each row of data into a cursor output parameter and returns the row of data before
fetching the next row:
ALTER PROCEDURE dbo.SalesForTitle
@ResultCrsr CURSOR VARYING OUTPUT, @Title varchar(80) = NULL
AS
The second line of code creates an output parameter called @ResultCrsr of the data
type cursor. This output parameter will hold each record returned by the cursor.
After the AS keyword, @ResultCrsr is set equal to the cursor that will eventually
contain each record of the SELECT statement. After the SELECT statement, the
OPEN statement populates the result set into the cursor.
The following code can be used to execute this stored procedure:
DECLARE @r_ResultCrsr CURSOR
EXECUTE dbo.SalesForTitle
@ResultCrsr = @r_ResultCrsr OUTPUT, @Title = The%"
FETCH NEXT FROM @r_ResultCrsr
WHILE (@@FETCH_STATUS <> -1)
BEGIN
FETCH NEXT FROM @r_ResultCrsr
END
CLOSE @r_ResultCrsr
DEALLOCATE @r_ResultCrsr
GO
All three records from the database are returned. The output data is the same as the
result set example shown earlier in this section, except that each record appears
separately in the results pane. An additional empty row is returned because the
@@FETCH_STATUS is not set to 1 until after an empty row is retrieved.
In this exercise, you will create a stored procedure to insert new customer records
into the BookShopDB database. You will then create a stored procedure that
checks for duplicate customer records in the database. The second procedure you
create will be nested in the first procedure. The stored procedures will include
parameters, variables, return codes, the @@ERROR function, and control of flow
language.
_
In this statement, you create a stored procedure named AddCustomer. You specify
all of the required input parameters. Notice that a default value of unknown
is provided for Address2. Address2 isnt always part of a customers address.
The value of unknown matches the default value of the check constraint
applied to this column. At the end of the code, the RETURN statement contains
the customer ID value, which is retrieved by the @@IDENTITY function.
3. In the Editor pane of the Query window, enter and execute the following code:
DECLARE @r_Code int
EXECUTE @r_Code=dbo.AddCustomer
@FirstName = Jamie, @LastName = Marra,
@Phone = 425-555-1212, @Address1 = 20 Oak St., SE,
@City = Remy, @State = WA, @Zip = 98888
SELECT [Customer ID] = The new customer ID is: + CONVERT(CHAR(2), @
r_Code)
The code creates a variable of type integer named @r_Code. This variable is set
equal to the stored procedure name upon execution. Lesson 3s code examples
showed an example of using a return code for error handling. In this procedure,
the return code will contain the value of the @@IDENTITY function when the
stored procedure executes.
_
1. The AddCustomer stored procedure does not contain any error handling. The
procedure needs to be modified to include error-handling logic. In the Editor
pane of the Query window, enter and execute the following code:
ALTER PROCEDURE dbo.AddCustomer
@FirstName varchar(30)= unknown,
@LastName varchar(30)= unknown, @Phone varchar(24) = NULL,
@Address1 varchar(60) = NULL,
@Address2 varchar(60) = unknown, @City varchar(15) = NULL,
@State varchar(7) = NULL, @Zip varchar(12) = NULL
AS
IF (@FirstName = unknown) AND (@LastName = unknown)
304 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
RETURN(1)
ELSE IF @Phone IS NULL
RETURN(2)
ELSE IF
@Address1 IS NULL OR @City IS NULL OR
@State IS NULL OR @Zip IS NULL
RETURN(3)
ELSE
INSERT [BookShopDB].[dbo].[Customers]
(FirstName, LastName, Phone, Address1,
Address2, City, State, Zip)
VALUES
(@FirstName, @LastName, @Phone, @Address1,
@Address2, @City, @State, @Zip)
RETURN(SELECT @@IDENTITY AS Identity)
IF @@ERROR <> 0
RETURN(4)
GO
All input variables now contain default values. This method is an important
error-avoidance technique. For example, if no value is specified for @FirstName, it will default to unknown and the procedure will execute properly. If
the user doesnt enter a first name or a last name for the customer, however, the
procedure returns a value of 1. This part of the code complies with the business
rule that a first name or a last name is required, and it matches with the check
constraint applied to the FirstName and LastName columns of BookShopDB. If
no phone number is entered, the default value of NULL is used, and a return
code of 2 is sent to the executing procedure. If any address information is missing,
a return code of 3 is sent to the executing procedure. Notice that the
@Address2 input parameter is not part of address error checking because it is
not always required. If all input parameters are specified, the INSERT statement
is called. If the INSERT statement fails because of a database error, a return
code of 4 is sent to the executing program.
As you work with the stored procedure, you will want to add additional error
handling to the code. For example, you should check the database for duplicate
customer information before creating a new customer record.
Comments were left out of the code to save space. Make sure that any code you
write is fully commented inline so that others will understand the purpose of
your code (and to help you remember the purpose of your code). Add comments
to the beginning of your code to summarize the purpose of the procedure,
the creation date, and your name or initials.
2. In the Editor pane of the Query window, enter and execute the following code:
DECLARE @r_Code int
EXECUTE @r_Code=dbo.AddCustomer
@FirstName= Jamie, @LastName = Marra,
@Phone = 425-555-1212, @Address1 = 20 Oak St., SE,
@City = Remy, @State = WA, @Zip = 98888
throughout the execution code. Examine each @r_Code value and the information
returned to the user in the event of an error.
Notice that the same customer information was entered as in the previous procedure
execution. In the next exercise, you will create a stored procedure to
check the Customers table to avoid creating duplicate customer information.
_
This stored procedure checks the Customers table to determine whether there is
a record with the same first name, last name, city, or phone number as the input
parameters specified. The input parameters begin with 1 to distinguish them
from the input parameters in the AddCustomer stored procedure. The output
parameters are set equal to the corresponding Customers table columns in the
306 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
SELECT statement. A test for a record match is made in the WHERE clause.
The column values are tested against the input parameters. If the @@ROWCOUNT
function returns a value greater than 0, then a return code of 5 is set for
the stored procedure.
2. In the Editor pane of the Query window, enter and execute the following code:
ALTER PROCEDURE dbo.AddCustomer
@FirstName varchar(30)= unknown,
@LastName varchar(30)= unknown, @Phone varchar(24) = NULL,
@Address1 varchar(60) = NULL,
1. In the Editor pane of the Query window, enter and execute the following code:
DECLARE @r_Code int
EXECUTE @r_Code=dbo.AddCustomer
@FirstName= Jamie, @LastName = Marra,
@Phone = 425-555-1212, @Address1 = 20 Oak St., SE,
@City = Remy, @State = WA, @Zip = 98888
IF @r_Code = 4
BEGIN
PRINT A database error has occured.
Please contact the help desk for assistance.
END
IF @r_Code = 1
PRINT You must specify a value for the firstname or lastname
ELSE IF @r_Code = 2
PRINT You must specify a value for the phone number
ELSE IF @r_Code = 3
PRINT You must provide all address information, Street address, City
, State and Zipcode
ELSE IF @r_Code = @@IDENTITY
SELECT [Customer ID] = The new customer ID is: + CONVERT(CHAR(2),
@r_Code)
The stored procedure returns a message stating that the record already exists.
2. Change the value of @FirstName to Jeff and @LastName to Fellinge, then execute
the query again.
The stored procedure returns a message with the new customer ID.
Lesson Summary
Important programming features available to stored procedures include parameters,
variables, return codes, functions, default values, nesting, and cursors. Input
parameters pass data to a stored procedure upon execution. Output parameters
receive data from the stored procedure. Variables are used to hold values from output
parameters. You specify an output parameter by using the OUTPUT keyword.
308 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
You specify a variable by using the DECLARE keyword. Return codes are primarily
used for error handling. Return codes are supplied by using the RETURN keyword,
Review
The following questions are intended to reinforce key information presented in this
chapter. If you are unable to answer a question, review the appropriate lesson and
then try the question again. You can find answers to the questions in the Appendix,
Questions and Answers.
1. You create a local temporary stored procedure and ask a colleague to execute
the stored procedure. Your colleague claims that she cannot execute the stored
procedure. Why cant she execute the stored procedure?
2. Why do complex stored procedures typically execute faster the second time
they are run than the first time?
3. What security features are available for stored procedures?
4. What function can you use to check the properties of a stored procedure and
other objects in SQL Server?
5. Why is it more efficient to modify a stored procedure by using the ALTER
PROCEDURE keywords than it is to drop and re-create a stored procedure?
6. You set the current database to Northwind, and then you create a stored procedure
named #Procedure01. You then check the Northwind database for the
stored procedure, but it doesnt appear. You can run the stored procedure using
Northwind as the current database. Why are you able to execute this stored procedure
but it doesnt appear in the Northwind database?
7. In what three ways is the RETURN statement used in a stored procedure?
311
Implementing Triggers
About This Chapter
Triggers are a special class of stored procedure defined to execute automatically in
place of or after data modification. The three commands that fire a trigger are
UPDATE, INSERT, and DELETE. Use triggers to extend data integrity and to
implement complex business logic. In this chapter, you will learn when it is appropriate
to implement triggers and when basic constraints will suffice. Create triggers
by using Transact-SQL language or SQL Enterprise Manager. Management tasks
include altering, renaming, viewing, dropping, and disabling triggers. Triggers use
two pseudo tables, Inserted and Deleted, to detect data modifications. Programming
triggers requires a thorough understanding of these pseudo tables and the
Transact-SQL language. In this chapter, you will learn how to program triggers and
how to use a number of system commands and functions commonly used in trigger
programming. Tasks commonly completed by implementing triggers include maintaining
running totals and other computed values, creating an audit record of data
modifications, invoking external actions, and implementing complex data integrity.
312 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
Server computer.
The ability to log on to the Windows 2000 Server computer and to SQL Server
Explain how to use trigger types (INSERT, UPDATE, and DELETE triggers)
and trigger classes (INSTEAD OF and AFTER triggers) to extend data integrity.
define default values (default constraints) and to restrict column data to acceptable
values (check and referential constraints). Use referential integrity to enforce logical
relationships between tables (foreign key and check constraints). Use default
314 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
constraints to provide a value for a required field when the field is not specified in
an INSERT statement. Use constraints before choosing to use triggers and rules.
Rules remain in SQL Server 2000 for backward compatibility, and the overuse of
triggers can degrade system performance. The query optimizer uses constraint definitions
to build high-performance query-execution plans. Chapter 5 discusses all
data integrity methods (except for triggers). Triggers are especially useful because
they can contain significantly more complex processing logic than is possible with
declarative integrity methods. Use triggers in the following instances:
If using declarative data integrity methods does not meet the functional needs
of the application. For example, create a trigger that changes a numeric value in
a table when a record in the same table is removed.
Changes must cascade through related tables in the database. For example, create
and apply a trigger to an Orders table so that when an order is placed, stock
quantity in an inventory table is changed. Create and apply another trigger to
the Inventory table so that when the quantity changes, a purchase request is
added to the Purchasing table.
Use cascading referential integrity constraints instead of a custom trigger if
your goal is to update or delete a foreign key constraint.
table.
INSERT, UPDATE, or DELETE occurs. Within the Transact-SQL code, you can
define business logic to handle each type of event.
Triggers cannot be created on a temporary or system table, although the TransactSQL language within the trigger can reference temporary tables or system tables.
An important limitation to be aware of is that INSTEAD OF DELETE and
INSTEAD OF UPDATE triggers cannot be defined on tables that have corresponding
ON DELETE or ON UPDATE cascading referential integrity defined. You will
learn more about INSTEAD OF triggers later in this lesson.
Chapter 9 Implementing Triggers 315
Trigger Events
Three events automatically fire a trigger: INSERT, UPDATE, and DELETE events
that occur on a table or on a view. Triggers cannot be fired manually. The trigger
syntax always includes defining one or more of these events before the taskspecific
Transact-SQL language is specified. Trigger types correspond to the event.
For example, you can create an update trigger so that when an update occurs to a
table, the update trigger is fired. A single trigger can be assigned multiple events so
that you could have a procedure that is both an update and an insert trigger. The
events can be listed in any order within the trigger definition. You will learn more
about trigger syntax in Lesson 2.
There are certain instances when an event that modifies or deletes data does not fire
a corresponding trigger. For example, the TRUNCATE TABLE statement does not
fire triggers defined for DELETE events. An important feature of triggers is that
unsuccessful transactions are automatically rolled back. Because TRUNCATE
TABLE is not a logged event, it cannot be rolled back so it doesnt fire the DELETE
trigger. Additionally, the WRITETEXT statement does not cause the INSERT or
UPDATE triggers to fire.
Trigger Execution
When a table insert or update fires a trigger, the trigger stores the new or modified
data in a table named Inserted. When a table delete fires a trigger, the trigger stores
the deleted data in a table named Deleted. The table exists in memory and is queried
within the trigger by using Transact-SQL commands. This capability is critical
to the function of most triggers because the task within the trigger, such as modifying
a value in an associated table, compares the data contained in the Inserted or
Deleted tables to the data in the modified table before the changes are committed.
By using the information stored in the Inserted or Deleted table, a trigger can roll
key
1. Open Query Analyzer and connect to your local server.
Characteristic INSTEAD OF AFTER
Applied to Defined on a table or a view. Defined on a table.
Defining a trigger on a view
extends the types of updates that
a view can support.
2. In the Editor pane of the Query window, enter and execute the following code:
USE BookShopDB
INSERT Orders (CustomerID, EmployeeID, Amount, OrderDate, DeliveryDat
e, PaymentID, StatusID)
VALUES (10, 1, 30, GetDate(), DATEADD(day, 5, GetDate()), 1, 1)
INSERT BookOrders (titleid, orderid) VALUES (aust1234, 3)
The first INSERT statement adds an order to the Orders table. The OrderDate
and DeliveryDate values are provided by functions. The first function returns
todays date (as specified by your computer). The second function adds five
days onto the value returned by GetDate. The second INSERT statement adds a
record to the BookOrders table. These two insert statements are important for
testing the effect of enabling cascading referential integrity for the TitleID foreign
key in the BookOrders table.
3. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
UPDATE Books
SET TitleID = AUST1235
WHERE TitleID = AUST1234
The following error message appears in the Message tab of the Results pane:
Server: Msg 547, Level 16, State 1, Line 1
UPDATE statement conflicted with COLUMN REFERENCE constraint titleid
_fk. The conflict occurred in database BookShopDB, table BookAuth
ors, column TitleID.
The statement has been terminated.
This error message is caused because the foreign key constraint, titleid_fk, is
violated by attempting to change the TitleID primary key value in the Books
table.
4. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
ALTER TABLE BookAuthors DROP CONSTRAINT titleid_fk
This ALTER TABLE statement removes the titleid_fk foreign key constraint
from the BookAuthors table.
5. In the Editor pane of the Query window, enter the following Transact-SQL
code:
ALTER TABLE BookAuthors
ADD CONSTRAINT titleid_fk FOREIGN KEY (TitleID) REFERENCES Books (Tit
leID)
ON UPDATE CASCADE ON DELETE CASCADE
This ALTER TABLE statement adds cascading referential integrity to the foreign
key constraint (titleid_fk) in the BookAuthors table. When an update to the
TitleID primary key occurs in the Books table, the corresponding foreign key
will be changed in the BookOrders table. The titleid_fk foreign key constraint
makes the Books table the parent of the BookAuthors table.
318 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
The first ALTER TABLE statement drops the titleid2_fk constraint from the
BookOrders table. The second ALTER TABLE statement adds cascading referential
integrity to the titleid2_fk foreign key constraint. The titleid2_fk foreign
key constraint makes the Books table the parent of the BookOrders table.
9. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
UPDATE Books
SET TitleID = AUST1235
WHERE TitleID = AUST1234
The TitleID is updated in the Books table, and because of cascading referential
integrity, it is also updated in the BookAuthors and BookOrders tables.
10. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
SELECT Books TitleID = b.titleID, BookAuthors TitleID
= ba.titleID,
"BookOrders TitleID = bo.titleID
FROM books b INNER JOIN bookauthors ba ON b.titleID=ba.titleID
INNER JOIN bookorders bo ON b.titleID=bo.titleID
WHERE b.titleid=aust1235
The Grids tab of the Results pane shows that the TitleID column has been
updated in all three tables.
11. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
DELETE FROM Books where TitleID = AUST1235
Lesson Summary
Procedural data integrity is often implemented by using triggers. Triggers are
invoked when table data is modified by an INSERT, UPDATE, or DELETE event.
Depending on the trigger class, a trigger can be applied to a table or view. Triggers
extend data integrity by enforcing complex business rules in the database. Always
implement constraints and rules before using triggers, because triggers will
degrade performance more quickly than constraints or rules. There are certain
instances in which a trigger is the best option (for example, when custom error
messages are required). Triggers can reference data inside or outside the current
database. A single trigger can run multiple tasks and can be fired by more than one
event. You cannot create a trigger on a temporary or system table, but these objects
can be referenced in a trigger. Some events, such as a truncate table event, do not
cause a DELETE trigger to fire. Triggers use Inserted and Deleted pseudo tables to
store modified or deleted data. These pseudo tables are referenced in the trigger
code. There are two classes of triggers: INSTEAD OF and AFTER. INSTEAD OF
triggers bypass the view or table modification that fired them and the code in the
trigger runs. AFTER triggers fire right after table constraints are processed. If the
INSERT, UPDATE, or DELETE event does not complete properly, the trigger rolls
back the transaction.
320 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
CREATE TRIGGER statement. In the trigger creation process, the trigger is applied
to a table or a view. After a trigger is created, it is modified by using the ALTER
TRIGGER statement. Triggers are renamed and viewed by using system stored procedures
or Enterprise Manager. The DROP TRIGGER statement is used to delete a
trigger, and the ALTER TABLE statement is used to enable or disable triggers.
Create triggers.
Trigger names must follow the rules for identifiers. For example, if you decide to
create a trigger named Alerter for the Employees Table, you must enclose the name
in brackets as shown:
CREATE TRIGGER dbo.[alerter for employees table]
Administering the trigger object, such as deleting it, also requires that you follow
the rules for identifiers.
The ON Clause
Triggers must be assigned to a table or view. Use the ON clause to instruct the trigger
on to what table or view it should be applied. When a trigger is applied, the
table or view is referred to as the trigger table or the trigger view. For consistency,
specify the table or view owner after the ON clause. For example, to apply a trigger
to the Employees table named Alerter (where both objectsthe table and the trigger
are owned by dbo), you can use the following Transact-SQL code:
CREATE TRIGGER dbo.alerter
ON dbo.employees
A trigger is applied only to a single table or view. If you need to apply the same
trigger task to another table in the database, create a trigger of a different name that
contains the same business logic. Then, apply the new trigger to the other table.
The default trigger class, AFTER, can be applied only to a table. The new trigger
class, INSTEAD OF, can be applied to either a table or a view.
fire on all events, follow the FOR, AFTER, or INSTEAD OF clause with INSERT,
UPDATE, and DELETE. The event types can be listed in any order. For example,
to make the trigger named Alerter fire on all events, you can use the following
Transact-SQL code:
CREATE TRIGGER dbo.alerter
ON dbo.employees
FOR INSERT, UPDATE, DELETE
The FOR clause is synonymous with the AFTER clause. Therefore, the previous
code example creates an AFTER trigger. To create Alerter as an INSTEAD OF
trigger, you can use the following Transact-SQL code:
CREATE TRIGGER dbo.alerter
ON dbo.employees
INSTEAD OF INSERT, UPDATE, DELETE
The AS Clause
The AS clause and the Transact-SQL language following it designates the task that
the trigger will perform. The following example shows how to create an Alerter
trigger that sends an e-mail to a user named BarryT when an INSERT, UPDATE, or
DELETE occurs on the employees table:
USE BookShopDB
GO
CREATE TRIGGER dbo.alerter
ON dbo.employees
AFTER INSERT, UPDATE, DELETE
AS
EXEC master..xp_sendmail BarryT,
A record was just inserted, updated or deleted in the Employees table.
GO
This example is kept simple so that you can see clearly how a task is created in a
trigger. There are a number of ways to make the task more useful. For example,
you could write the task so that the e-mail message details the exact change that
occurred. Lesson 3 explores more complex trigger tasks.
Trigger Properties dialog box, enter the trigger statement. Figure 9.1 shows the
Trigger Properties dialog box containing the code from the previous example.
F09BQ01.eps
Figure 9.1. The General tab of the Trigger Properties dialog box for a new trigger.
Trigger Management
Triggers are powerful database objects that run automatically when a table or view
is modified. There are a number of database tools and commands used to manage
triggers. Triggers can be:
system tables. The following example shows how you can modify the Alerter trigger
so that it only reports updates to the Employees table:
ALTER TRIGGER dbo.alerter
ON dbo.employees
AFTER UPDATE
AS
EXEC master..xp_sendmail BarryT,
A record was just updated in the Employees table.
GO
Notice that UPDATE is the only event specified following the AFTER clause, and
notice that the text in the e-mail message was changed.
Triggers are modified in Enterprise Manager from the Manage Triggers option.
You learned about the Manage Triggers option in the previous section of this lesson.
After you display the Trigger Properties dialog box, select the trigger that you
wish to modify. Then, change the word CREATE to ALTER. Figure 9.2 shows how
Figure 9.2. The General tab of the Trigger Properties dialog box with the ALTER syntax
shown.
Notice that the GO batch command has been removed. In the first released version
of SQL Server 2000, the GO batch command causes an error in Enterprise Manager
when attempting to modify a trigger.
There might be times that you need to rename a trigger to comply with new naming
conventions or because you are implementing more than one trigger on a table. You
can rename a trigger by using the sp_rename system stored procedure. The following
example shows how to rename the Alerter trigger to EmpAlerter:
sp_rename @objname = alerter, @newname = empalerter
Notice that dbo was not specified in the rename syntax. Trigger ownership cannot
be transferred by using the sp_rename system stored procedure. If you need to
change the ownership of a stored procedure, you must use CREATE TRIGGER. If
you are nesting a trigger that you rename, make sure that the calling trigger is modified
to call the correct trigger name.
You can query the Text column of the SysComments system table to see the contents
of the stored procedure. For a more organized display of information, use the
sp_helptext system stored procedure. For example, to show the text contained in a
trigger named alerter, type the following:
sp_helptext @objname = alerter
You can also use the Manage Triggers option of Enterprise Manager to view trigger
text.
Deleting a trigger removes it from the SysComments and SysObjects system
tables. Use the DROP TRIGGER statement to delete one or more triggers from a
database. If you drop a trigger table or a trigger view, any triggers assigned to the
table or view are also dropped. To delete the Alerter trigger in the BookShopDB
database, type the following:
USE BookShopDB
DROP TRIGGER [dbo].[alerter]
As with the CREATE TRIGGER statement, you cannot specify the database name in
the DROP TRIGGER statement. Unlike CREATE TRIGGER, DROP TRIGGER does
not have to be the first statement in the batch. For this reason, the code example does
not include a GO command between the USE and DROP TRIGGER statements.
326 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
You might have to disable a trigger (or triggers) on a table if, for example, you are
troubleshooting a problem with a database, testing a database modification, or
running a procedure that requires a trigger to be disabled on a table. To disable a
trigger, use the ALTER TABLE statement. The following code disables the Alerter
trigger on the Employees table:
ALTER TABLE employees DISABLE TRIGGER alerter
To disable all triggers on a table, use the ALL keyword following the DISABLE
TRIGGER clause. To enable one or all triggers, change DISABLE to ENABLE in
your ALTER TABLE statement.
AFTER INSERT
AS
PRINT The insert trigger fired.
1. In the Editor pane of the Query window, enter and execute the following code:
INSERT INTO authors (firstname, lastname, yearborn, yeardied)
VALUES (Max, Doe, 1962, N/A)
A record is inserted into the Authors table, and the InsertIndicator trigger fires
and prints the triggers message to the Messages tab of the Results pane.
2. In the Editor pane of the Query window, enter and execute the following code:
UPDATE authors
SET authors.firstname = Tucker
WHERE authors.firstname = Max
A record is updated in the Authors table, and the UpdateIndicator trigger fires
and prints the triggers message to the Messages tab of the Results pane.
3. In the Editor pane of the Query window, enter and execute the following code:
DELETE authors where firstname = Tucker
A record is deleted in the Authors table, and the DeleteIndicator trigger fires
and prints the triggers message to the Messages tab of the Results pane.
_
1. In the Editor pane of the Query window, enter the following stored procedure
code:
sp_rename @objname=insertindicator, @newname=insupdcontrol
3. In the Editor pane of the Query window, enter and execute the following stored
procedure code:
sp_helptrigger @tabname = authors
The INSTEAD OF trigger fires and displays a message stating that updates are
not allowed at this time. NOCOUNT is enabled so that a row-affected message
does not appear in the Messages tab of the Results pane.
6. Run a SELECT statement against the Authors table to verify that no record was
added.
7. In the Editor pane of the Query window, enter and execute the following stored
procedure code:
sp_helptext @objname=insupdcontrol
1. In the Editor pane of the Query window, enter and execute the following code:
ALTER TABLE authors DISABLE TRIGGER insupdcontrol
A record is successfully inserted into the Authors table, and the record appears
in the Grids tab of the Results pane.
Chapter 9 Implementing Triggers 329
3. In the Editor pane of the Query window, enter and execute the following code:
DROP TRIGGER insupdcontrol, updateindicator, deleteindicator
DELETE authors where firstname = Max
The DROP TRIGGER statement deletes all three triggers applied to the Authors
table. The DELETE statement removes the record added to the Authors table.
Lesson Summary
In this lesson, you learned how to create a trigger by using the CREATE TRIGGER
statement. You must specify the table or view to which the trigger is applied, the
event or events that fire the trigger, and any Transact-SQL code that should run
when the trigger fires. You have the option of specifying the trigger class, AFTER
or INSTEAD OF. AFTER is synonymous with FOR and is the more common trigger
to apply to tables. INSTEAD OF can be applied to tables or views. When using
CREATE TRIGGER, you must use it as the first statement in a batch. You can also
use Enterprise Manager to create triggers.
Triggers are managed using tools and Transact-SQL statements. In Enterprise
Manager, you can perform a number of trigger management tasks using the Manage
Triggers option. To modify a trigger in Query Analyzer, use ALTER TRIGGER.
To rename a trigger, use the sp_rename system stored procedure. To view the contents
of a trigger, use the sp_helptext system stored procedure. To view a triggers
Following a simple UPDATE statement that changes an authors name from Dean
to Denby, the trigger displays the following results:
The Inserted table:
Straight Denby Oakland CA 94609
The Deleted table:
Straight Dean Oakland CA 94609
The Authors table (trigger table) contains the updated record after the update trigger
runs. When the trigger fires, the update to the Authors table can be rolled back
by programming logic into the trigger. This transaction rollback capability also
applies to INSERT and DELETE triggers.
Chapter 9 Implementing Triggers 331
When a delete trigger fires, the Deleted logical table contains the deleted record
set. The Inserted table is not part of a DELETE event.
Note The SELECT statement appears in the previous code example for illustrative
purposes only. Never use statements in triggers that return a result unless you are
sure that the result returned by the trigger can be handled by any applications that
cause the trigger to fire.
The value of 40 is derived from summing 8 for column 4 and 32 for column 6. The
(COLUMNS_UPDATED()) expression tests whether the return value is greater
than 0. In other words, if either or both of the columns are updated, the columns
updated condition is met. If you set (COLUMNS_UPDATED() & 40) = 40, then you
are testing whether both of the columns are updated. Updates to one or the other
column do not meet the columns updated condition.
To test more than eight columns, you must use the SUBSTRING function so that
the trigger knows which bit mask to test. For example, to test for an update to the
ninth column, you can use the following code:
IF ((SUBSTRING(COLUMNS_UPDATED(),2,1)=1))
To test modifications to multiple columns, simply add the bit values for each column.
For example, to test columns 14 and 16, specify 160 (32 + 128) for the z value.
the trigger. If no rows are affected by an INSERT, UPDATE, or DELETE event, the
trigger still fires. Therefore, use the RETURN system command to exit the trigger
transparently when no table modifications are made.
Column 1 2 3 4 5 6 7 8
Bit Mask 1 2 4 8 16 32 64 128
Column 9 10 11 12 13 14 15 16
y and z 1 2 4 8 16 32 64 128
Chapter 9 Implementing Triggers 333
In the event of an error, you might want to display a message describing the reason
for the error. The RAISERROR system command is used to display error messages.
You can create custom error messages with the sp_addmessage system
stored procedure, or you can display ad hoc error messages when calling the RAISERROR
system command. Refer to SQL Server Books Online for more information
about the sp_addmessage system stored procedure.
The ROLLBACK TRANSACTION system command might also appear in the
Transact-SQL code for the trigger. This command explicitly rolls back the entire
batch of the trigger. A fatal error also causes an implicit rollback. You dont have to
specify ROLLBACK TRANSACTION in the trigger code if your goal is to complete
the transaction in all cases except if a fatal error occurs during the transaction.
RECONFIGURE
The following trigger is applied to the Purchasing table. It calculates the average
wholesale cost of inventory and increases the price by 30 percent, in addition to
updating the retail_price column of the inventory table with the new value:
CREATE TRIGGER Retail_Price_Update
ON purchasing
AFTER INSERT, UPDATE, DELETE AS
SET NOCOUNT ON
IF EXISTS (SELECT item_num FROM inserted)
BEGIN
UPDATE inventory
SET retail_price =
(SELECT (SUM(pur.total_cost)/SUM(pur.qty_ordered) * 1.30)
FROM purchasing pur INNER JOIN inserted ins
ON pur.item_num = ins.item_num)
FROM inventory inv, inserted ins
WHERE inv.item_num = ins.item_num
END
ELSE IF EXISTS (SELECT item_num from deleted)
BEGIN
UPDATE inventory
SET retail_price =
(SELECT (SUM(pur.total_cost)/SUM(pur.qty_ordered) * 1.30)
FROM purchasing pur INNER JOIN deleted del
ON pur.item_num = del.item_num)
FROM inventory inv, deleted del
WHERE inv.item_num=del.item_num
END
ELSE
BEGIN
RAISERROR (The retail price has not been adjusted for the product.,
16, 1)
RETURN
END
The trigger uses the SET NOCOUNT ON statement so that when the trigger fires
and updates information in the Inventory table, the SELECT statement result is not
displayed. Conditional processing checks for the existence of the Inserted or
Deleted tables. If neither the Inserted nor Deleted tables contain records, the trigger
inventory
item_num
item_desc
qty_in_stock
retail inventory
purchasing
order_id
item_num
wholesale_price
qty_ordered
total cost
uses RAISERROR to display an ad hoc message that no prices were adjusted. You
can use sp_addmessage to add a custom message to the SysMessages system table
and then specify the message number in place of the custom message.
table (or tables) in the database, you can create a trigger to update a table with
data inserted, updated, or deleted from another table or view.
measures are not enough. For example, the cascading delete action deletes
records in other tables when a delete action would violate referential integrity
between the tables. However, you might not want to allow a cascading delete
action to occur. You could use an INSTEAD OF trigger to delete records from
related tables but then log the deleted result to another table for later review. If
you use an INSTEAD OF trigger to delete records, you cannot implement a
delete action by using cascading referential integrity. To accomplish the same
task, you must program the cascading delete action in the trigger.
1. In the Editor pane of the Query window, enter and execute the following code:
ALTER TRIGGER dbo.update_book_status
ON dbo.bookorders
AFTER INSERT, DELETE
AS
SET NOCOUNT ON
IF EXISTS (SELECT * FROM inserted)
BEGIN
UPDATE books
SET Sold = 1
WHERE titleid =
(SELECT bo.titleid
FROM bookorders bo INNER JOIN inserted i
ON bo.orderid = i.orderid)
END
ELSE
BEGIN
UPDATE books
SET Sold = 0
WHERE titleid =
(SELECT d.titleid
FROM books b INNER JOIN deleted d
ON b.titleid = d.titleid)
END
SET Sold = 0
WHERE titleid =
(SELECT d.titleid
FROM books b INNER JOIN deleted d
ON b.titleid = d.titleid)
END
The trigger is modified to include UPDATES. Notice that the ELSE clause has
been removed. An UPDATE event always creates both the Inserted and Deleted
tables. Therefore, the first part of the code sets the Sold status to 1 for the new
TitleID value. The second part of the code detects the Deleted table and sets the
Sold status for the original TitleID to 0.
_
1. In the Editor pane of the Query window, enter and execute the following code:
SET IDENTITY_INSERT orders ON
INSERT INTO orders
(orderid, customerid, employeeid, amount, orderdate, deliverydate, pa
ymentid, statusid)
VALUES (20, 10, 1, 500, GETDATE(), GETDATE() + 5, 2, 1)
SET IDENTITY_INSERT orders OFF
GO
A book order for CustomerID 20 for TitleID carr9675 is inserted into the
BookOrders table.
3. In the Editor pane of the Query window, enter and execute the following code:
SELECT * from Books where titleid = carr9675
This command verifies that the Sold status for this book has changed to 1.
4. In the Editor pane of the Query window, enter and execute the following code:
UPDATE bookorders
set titleID = aust1234 where titleid = carr9675
338 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
5. In the Editor pane of the Query window, enter and execute the following code:
SELECT * from Books WHERE titleid = carr9675 OR titleid = aust1234
This command verifies that the Sold status for the original TitleID is 0 and that
the new TitleID is 1.
6. In the Editor pane of the Query window, enter and execute the following code:
DELETE bookorders WHERE titleid = aust1234
This command removes the book order from the BookOrders table, and the
trigger changes the Sold status back to 0.
7. In the Editor pane of the Query window, enter and execute the following code:
SELECT * from Books WHERE titleid = aust1234
8. In the Editor pane of the Query window, enter and execute the following code:
DROP TRIGGER dbo.update_book_status
Lesson Summary
In this lesson, you learned how to program triggers. Triggers create two logical
tables when an INSERT, UPDATE, or DELETE event occurs in a table to which a
trigger is applied. These tables enable you to determine exactly what data modifications
were made to a table when the trigger fired. Detecting data modifications is
an essential step toward programming business logic into triggers. CREATE and
ALTER TRIGGER syntaxes include two useful clauses for detecting column inserts
or updates: UPDATE (column_name) and (COLUMNS_UPDATED()). The
UPDATE (column_name) clause enables you to take an action based on modifications
occurring to a specific column. The (COLUMNS_UPDATED()) clause
enables you to detect multiple changes in columns designated by a varbinary bit
mask value. The first eight columns are represented by a bit mask ranging from 1
for column 1 to 128 for column 8. Column changes beyond column eight can be
detected using the SUBSTRING function.
Other functions exist besides SUBSTRING and system commands that are commonly
used in triggers. The @@ROWCOUNT function returns the number of rows
affected by a table modification. The RAISERROR system command displays
either custom messages or messages contained in the SysMessages system table.
Another important system command used in triggers is ROLLBACK TRANSACTION.
This command enables you to control events that cause the UPDATE,
INSERT, or DELETE event to be backed out. Use SET NOCOUNT ON in a trigger
to prevent it from returning the rows-affected message to the calling application.
Triggers are often used to maintain running totals or other computed values across
tables, to create audit records to track table data modifications, to invoke external
actions, and to implement complex data integrity features.
Chapter 9 Implementing Triggers 339
Review
The following questions are intended to reinforce key information presented in this
chapter. If you are unable to answer a question, review the appropriate lesson and
then try the question again. You can find answers to the questions in the Appendix,
Questions and Answers.
1. You have applied constraints, an INSTEAD OF trigger, and three AFTER triggers
to a table. A colleague tells you that there is no way to control trigger order
for the table. Is he correct? Why or why not?
2. You need to make sure that when a primary key is updated in one table, all foreign
key references to it are also updated. How should you accomplish this task?
3. Name four instances when triggers are appropriate.
4. When a trigger fires, how does it track the changes that have been made to the
modified table?
5. Name a table deletion event that does not fire a DELETE trigger.
6. Name a system stored procedure and a function used to view the properties of a
trigger.
7. Using Transact-SQL language, what are two methods to stop a trigger from
running?
8. Write a (COLUMNS_UPDATED()) clause that detects whether columns 10 and
11 are updated.
9. Name three common database tasks accomplished with triggers.
10. What command can you use to prevent a trigger from displaying row count
information to a calling application?
11. What type of event creates both Inserted and Deleted logical tables?
12. Is it possible to instruct a trigger to display result sets and print messages?
341
Implementing Views
About This Chapter
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 that defines the view and are produced
dynamically when the view is referenced. In this chapter, you will be introduced to
views and the various functionalities that they support. You will also learn how to
create, modify, and delete views. Finally, you will learn how to use views to insert,
update, and modify data.
Server computer.
The ability to log on to the Windows 2000 Server computer and to SQL Server
access the underlying base tables of the view. You can also use views to improve
performance and to partition data when you are copying data to and from SQL
Server 2000. This lesson will introduce you to views and the various functionalities
that they support.
Define what a view is and describe the functionalities that views support.
Overview of Views
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
database or other databases. You can also use distributed queries to define
views that use data from multiple heterogeneous sources. This functionality 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.
A view can be thought of as either a virtual table or a stored query. The data accessible
through a standard view is not stored in the database as a distinct object. What
is stored in the database is a SELECT statement. The result set of the SELECT
statement forms the virtual table returned by the view. A user can use this virtual
table by referencing the view name in Transact-SQL statements in the same way a
table is referenced.
Figure 10.1 shows a view based on a SELECT statement that retrieves data from the
Titles table and the Publishers table in the Pubs database.
There are no restrictions on querying through views and few restrictions on modifying
data through them. In addition, a view can reference another view.
You can use a view to perform any or all of the following functions:
Joining columns from multiple tables so that they look like a single table
Views can be used to partition data across multiple databases or instances of SQL
Server 2000. Partitioned views enable you to distribute database processing across
a group of servers.
f10bq01
SQL Server 2000 also supports indexed views, which greatly improve the performance
View
publishers table
titles table
type pub_id price advance royalty ytd_sales
BU1023
BU1111
BU2075
BU7832
MC2222
MC3021
The Busy Executive's Database Gui
Cooking with Compter: Surreptition
You Can Combat Computer Stress!
Straight Talk About Computers
Silicon Valley Gastronomic Treats
The Gourmet Microwave
business
business
business
business
mod_cook
mod_cook
19.99
11.95
2.99
19.99
19.99
2.99
10
10
24
10
12
24
4095
3876
18722
4095
2032
22246
5,000.00
5,000.00
10.125.00
5,000.00
0.00
15,000.00
1389
1389
0736
1389
0877
0877
pub_id pub_name city
0736
0877
1389
1622
1756
MA
DC
CA
IL
TX
Boston
Washington
Berkeley
Chicago
Dallas
title price
The Busy Executive's Database Gui
Cooking with Compter: Surreptition
You Can Combat Computer Stress!
New Moon Books
Binnet & Hardley
Algodata infosystems
Five Lakes Publishing
Ramona Publishers
19.99
11.95
2.99
Algodata infosystems
Algodata infosystems
New Moon Books
344 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
To Customize Data
Views enable different users to see data in different ways, even when they are using
the same data concurrently. This feature is particularly advantageous when users
who have 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.
The Transact-SQL UNION set operator can be used within a view to combine the
result of two or more queries from separate tables into a single result set. This display
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.
Chapter 10 Implementing Views 345
Both the view and the INSERT, UPDATE, and DELETE statements follow the
Lesson Summary
Views are generally used to focus, simplify, and customize each users perception of
the database. A view acts as a filter on the underlying tables referenced in the view.
A view can be thought of as either a virtual table or a stored query. There are no
restrictions on querying through views, and few restrictions exist on modifying data
through them. Views enable you to focus on specific data, simplify data manipulation,
customize data, export and import data, and combine partitioned data.
346 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
Creating Views
You can create views only in the current database. The tables and views referenced by
the new view can exist in other databases or even in other servers, however, if the view
is defined with 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. SQL Server 2000 enables views to be nested up to 32 levels.
When creating a view, you must adhere to the following restrictions:
You cannot associate AFTER triggers with views, only INSTEAD OF triggers.
The query that defines the view cannot include the ORDER BY, COMPUTE, or
You cannot create temporary views, and you cannot create views on temporary
tables.
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 any of the columns in
the view are derived from an arithmetic expression, a built-in function, a constant,
or if 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).
In addition, you must specify the name of every column in the view if you want
to give any column in the view a name that is 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. Note that this restriction does not apply if a view is based on a query
containing an outer join, because columns might change from not allowing null
values to allowing them. 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 in the query that defines the view. The
select list can be a full or partial list of the column names in the base tables.
owner, and you must have appropriate permissions for 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 that defines
the view. For example, a view can be defined that retrieves all rows in which the
employees salary is less than $30,000. If an employees salary is increased to
$32,000, then querying the view no longer displays that particular employee
because the 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 that
defines 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 situation
to happen is canceled, and an error is displayed.
Note The WITH CHECK OPTION on a view does not affect the underlying
tables when you modify those tables directly. Only the updates that are made
through the view itself are affected by WITH CHECK OPTION.
The definition of a view can be encrypted to ensure that its definition cannot be
obtained by anyone, including the owner of the view.
348 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
In this statement, you are creating the CustomerOrders view in the Northwind database.
The view uses a SELECT statement to select the order ID from the Orders
table and the company name and contact name from the Customers table. A join
connects the two tables.
tables. The process of building the view result is called materializing the view.
For a standard view, the overhead of dynamically building the result set for each
query that references the view can be substantial if the view involves 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 that a table with a clustered index is stored.
Note You can create indexed views only if you install Microsoft SQL Server 2000
Enterprise Edition or Microsoft SQL Server 2000 Developer Edition.
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.
Chapter 10 Implementing Views 349
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 as an index created
on a base table. As modifications are made to the data in the base tables, they are
also reflected in the data stored in the indexed view. Because the views clustered
index must be unique, SQL Server can more efficiently find the index rows affected
by any data modification.
Indexed views can be more complex to maintain than indexes on base tables. You
should create an index on a view only if the improved speed in retrieving the result
outweighs the increased overhead of making modifications. This improvement usually
occurs for views that are mapped over relatively static data, process many
rows, and are referenced by many queries.
A view must meet the following requirements before you can create a clustered
index on it:
The ANSI_NULLS option must have been set to ON for the execution of all
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
User-defined functions referenced in the view must have been created with the
SCHEMABINDING option.
If GROUP BY is not specified, the view select list cannot contain aggregate
expressions.
In addition to the previous restrictions, the SELECT statement in the view cannot
contain the following Transact-SQL syntax elements:
A table column name used as a simple expression that is specified in more than
A derived table
Rowset functions
A UNION operator
Subqueries
The AVG, MAX, MIN, STDEV, STDEVP, VAR, or VARP aggregate functions
The user executing the CREATE INDEX statement must be the views owner.
The view cannot include text, ntext, or image columns (even if they are not referenced
the key of the unique clustered index can reference only columns specified in
the GROUP BY clause.
Chapter 10 Implementing Views 351
The following 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
For example, suppose you are partitioning a Customer table into three tables. The
CHECK constraint for these tables should be defined as follows:
-- On Server1:
CREATE TABLE Customer_33
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 1 AND 32999),
... -- Additional column definitions)
-- On Server2:
CREATE TABLE Customer_66
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 33000 AND 65999),
... -- Additional column definitions)
-- On Server3:
CREATE TABLE Customer_99
(CustomerID INTEGER PRIMARY KEY
CHECK (CustomerID BETWEEN 66000 AND 99999),
... -- Additional column definitions)
After creating the member tables, define a distributed partitioned view on each
member server, with each view having the same name. This setup lets queries referencing
the distributed partitioned view name 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 can build the distributed partitioned views by taking the following steps:
1. Add linked server definitions on each member server containing the connection
information needed to execute distributed queries on the other member
servers. This action gives a distributed partitioned view access to data on the
other servers.
2. Set the lazy schema validation option (by using sp_serveroption) for each
linked server definition used in distributed partitioned views. This setting optimizes
performance by ensuring that the query processor does not request metadata
for any of the linked tables until data is actually needed from the remote
member table.
3. Create a distributed partitioned view on each member server. The views should
use distributed SELECT statements to access data from the linked member
server and merge the distributed rows with rows from the local member table.
To create distributed partitioned views for the preceding example, you should take
the following steps:
1. Add a linked server definition named Server2 with the connection information
for Server2 and a linked server definition named Server3 for access to Server3.
Chapter 10 Implementing Views 353
Modifying Views
After a view is defined, you can change its name or modify its definition without
dropping and recreating the view, which would cause it to lose its associated permissions.
When you rename a view, adhere to the following guidelines:
The database owner can change the name of any users view.
Altering a view does not affect any dependent objects (such as stored procedures or
triggers) unless the definition of the view changes in such a way that the dependent
object is no longer valid.
To modify a view, you can use Enterprise Manager or the Transact-SQL ALTER
VIEW statement to update the SELECT query, as shown in the following example:
ALTER VIEW CustomerOrders
AS
SELECT o.OrderID, o.OrderDate, c.CompanyName, c.ContactName
FROM Orders o JOIN Customers c
ON o.CustomerID = c.CustomerID
In this statement, you are modifying the select list so that it includes the order date.
The SELECT query in the ALTER VIEW statement replaces the SELECT query
that was defined in the original CREATE VIEW statement.
In addition, you can modify a view to encrypt its definition or to ensure that all data
modification statements executed against the view adhere to the criteria set within
the SELECT statement that defines the view.
354 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
Deleting Views
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). If the new view does not
reference objects expected by any objects dependent on the new view, however,
queries using the dependent objects will fail when executed.
For example, suppose you create a view named MyView that retrieves all columns
from the Authors table in the Pubs database, and this view is deleted and replaced
by a new view named MyView that retrieves all columns from the Titles table
instead. Any stored procedures that reference columns from the underlying
Authors table in MyView now fail because those columns are replaced by columns
from the Titles table instead.
To delete a view, you can use Enterprise Manager or the Transact-SQL DROP
VIEW statement, as shown in the following example:
DROP VIEW CustomerOrders
In this statement, you are defining the BookAuthorView view in the BookShopDB database. The CREATE VIEW statement contains a SELECT query
that joins the Authors table to the BookAuthors table and the BookAuthors
Chapter 10 Implementing Views 355
table to the Books table. The result set from this query will include the authors
first and last names and the books that this author has written.
3. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
4. If the Object Browser window is not displayed, open it now.
5. In the object tree of the Object Browser window, locate the new view that you
created.
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
GO
ALTER VIEW BookAuthorView
AS
SELECT a.FirstName, a.LastName, b.TitleID, b.Title
FROM Authors a JOIN BookAuthors ba
ON a.AuthorID = ba.AuthorID
JOIN Books b
ON ba.TitleID = b.TitleID
Tip You can copy and paste the code from the previous procedure and modify
it to contain an ALTER VIEW statement and the TitleID column.
In this statement, you are adding the TitleID column to the SELECT statement.
The result set will now include the additional column.
2. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
3. In the object tree of the Object Browser window, locate the BookAuthorView
view and expand the Columns node.
Notice that the TitleID column has been added to the list of columns.
4. Close Query Analyzer.
356 Part 1: Self-Paced Training Kit for Microsoft SQL Server 2000 Database Design and
Implementation
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
GO
DROP VIEW BookAuthorView
In this statement, you are deleting the BookAuthorView view from the BookShopDB database.
2. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
3. In the object tree of the Object Browser window, locate the Views node for the
BookShopDB database.
Notice that the BookAuthorView view no longer appears.
Note If the BookAuthorView view is still listed in the object tree, you will
need to refresh the screen to update the listings.
Lesson Summary
You can create a view as you would many other objects in a database, and once that
view is created, you can modify the view or delete it. When creating a view, you
must adhere to specific restrictions. You can use Enterprise Manager to create a
view, or you can use the CREATE VIEW statement in Transact-SQL. In addition to
standard views, you can create indexed views. 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 as a table with a clustered index is stored. 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 non-clustered indexes. In addition to indexed
views, you can create partitioned views. A partitioned view joins horizontally partitioned
data from a set of member tables across one or more servers, making the
data appear as if it is from one table. After a view is defined, you can change its
name or modify its definition without dropping and recreating the view, which
would cause it to lose its associated permissions. You can also delete a 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.
Chapter 10 Implementing Views 357
As with tables, you can be more specific about the type of data you return in a
view. The following SELECT statement retrieves the OrderID column and the
OrderDate column for any orders made for the QUICK-Stop company:
USE Northwind
SELECT OrderID, OrderDate
FROM CustomerOrders
WHERE CompanyName = quick-stop
ORDER BY OrderID
In this statement, you are also specifying for the result set to be ordered by the
OrderID values.
The view contains at least one table in the FROM clause of the view definition.
No derived columns are used in the select list. Derived columns are result set
All data modification statements executed against the view must adhere to the
criteria set within the SELECT statement defining the view if the WITH
CHECK OPTION clause is used in the definition of the view. If the WITH
CHECK OPTION clause is used, rows cannot be modified in a way that causes
them to disappear from the view. Any modification that would cause this situation
to happen is canceled, and an error is displayed.
operation to specific rows in one of the base tables referenced by the view. You
cannot use data modification statements on more than one underlying table in a
single statement. Therefore, the columns listed in the UPDATE or INSERT
statement must belong to a single base table within the view definition.
All of the columns in the underlying table that are being updated and that do not
allow null values have values specified in either the INSERT statement or
DEFAULT definitions. This feature ensures that all of the columns in the underlying
table that require values have them.
The modified data in the columns in the underlying table must adhere to the
To insert data through the CustomerView view, you should use the INSERT statement
(as shown in the following example):
USE Northwind
INSERT CustomerView
VALUES (TEST1, Test Company)
This statement inserts a new row into the Customers table. Because all other columns
in the table permit null values, you do not have to specify a value for those
columns.
This statement deletes the Test Company row from the Customers table.
INSERT Statements
INSERT statements add data to the member tables through the partitioned view.
The INSERT statements must adhere to the following 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.
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 that
column.
INSERT statements are not allowed if there is a self-join with the same view or
UPDATE Statements
UPDATE statements modify data in one or more of the member tables through the
partitioned view. The UPDATE statements must adhere to the following rules:
SET clause, even if the column has a DEFAULT value defined in the corresponding
member table.
The value of a PRIMARY KEY cannot be changed if the column contains text,
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 are not allowed if there is a self-join
with the same view or any of the member tables.
In this exercise, you will create a view on the Authors table that includes only the
first and last names of the authors. You will then use this view to add an author to the
database, modify that author, and then delete the author. To perform this exercise,
you should be logged into your Windows 2000 Server computer as Administrator.
_
In this statement, you are creating a view that returns the first and last names of
the authors listed in the Authors table of the BookShopDB database.
3. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
SELECT *
FROM AuthorNames
ORDER BY LastName
This statement uses the AuthorNames view to retrieve data. The result set is
ordered by the last names of the authors.
2. Execute the Transact-SQL statement.
The result set is displayed in the Grids tab of the Results pane.
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
INSERT AuthorNames
VALUES (William, Burroughs)
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
3. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
SELECT *
FROM Authors
The result set is displayed in the Grids tab of the Results pane.
4. Scroll to the last row of the result set.
Notice that William Burroughs has been added to the list of authors. Also
notice that the YearBorn, YearDied, and Description columns have been
assigned the default value of N/A.
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
UPDATE AuthorNames
SET FirstName = John
WHERE LastName = Burroughs
This statement changes the first name of the author whose last name is Burroughs.
2. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
3. In the Editor pane of the Query window, enter and execute the following
Transact-SQL code:
SELECT *
FROM AuthorNames
The result set is displayed in the Grids tab of the Results pane.
4. Scroll to the last row of the result set.
Notice that William Burroughs has been changed to John Burroughs.
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
DELETE AuthorNames
WHERE LastName = Burroughs
The result set is displayed in the Grids tab of the Results pane.
4. Scroll to the last row of the result set.
Notice that John Burroughs has been deleted from the Authors table.
_
1. In the Editor pane of the Query window, enter the following Transact-SQL
code:
USE BookShopDB
GO
DROP VIEW AuthorNames
In this statement, you are deleting the BookAuthorView view from the BookShopDB database.
2. Execute the Transact-SQL statement.
A message appears in the Messages tab of the Results pane, stating that the
command has been successfully completed.
Lesson Summary
Once a view has been created, you can use the view to access the data that is
returned by the SELECT query defined within that view. You can use a view in a
SELECT statement to return data in much the same way as you use a table. SQL
Server also enables you to use views to modify data. In addition to modifying data
through basic views, you can modify data through updateable partitioned views
and views that use INSTEAD OF triggers. If a view does not use an INSTEAD OF
trigger or is not an updateable partitioned view, it can still be updateable provided it
meets specific conditions. If the conditions are met, you can insert, update, or
delete data through the view. A view is considered an updateable partitioned view
if the view is a set of SELECT statements whose individual result sets are combined
into one by using the UNION ALL statement. In addition to the rules defined
for updateable partitioned views, data modification statements referencing the view
must adhere to the rules defined for INSERT, UPDATE, and DELETE statements.
INSTEAD OF triggers override the standard actions of the triggering statement
Review
The following questions are intended to reinforce key information presented in this
chapter. If you are unable to answer a question, review the appropriate lesson and
then try the question again. You can find the answers to these questions in the
Appendix, Questions and Answers.
1. What is a view?
2. What functions can a view be used to perform?
3. For what scenarios can views be used?
4. What are at least five restrictions that you must adhere to when creating views?
5. What two tools does SQL Server provide to create a view?
6. Where are the result sets stored for standard views and indexed views?
7. If a view is going to be indexed, what type of index must be the first index created
on that view?
8. Which Transact-SQL statement or statements should you use to change the definition
of a view or to delete that view from the database?
9. What Transact-SQL statement should you use if you want to view all of the
data in the AuthorNames view of the Northwind database?
10. Which Transact-SQL statement or statements should you use to insert, modify,
and delete data through a view?
11. What conditions must a view meet before you can modify data through that
view?
12. When is a view considered to be an updateable partitioned view?