Chapter 5. Transact-SQL

Transact-SQL (T-SQL) is the dialect of the Structured Query Language (SQL) adopted by Microsoft's SQL Server database engine. T-SQL has been around since the early days of the Sybase code in the early 1990s. It has evolved throughout the years and today is a robust programming language based on the ANSI SQL:2008 standard. In this chapter, you will learn how to access data using T-SQL statements as well as how to use many of the programming capabilities within the database engine, including stored procedures and functions.

The VetClinic Sample Database Revisited

Before diving in, it is important to revisit the VetClinic database that you created in the previous chapter. You'll use that database for all of the examples in this chapter. If you haven't already created that database, you can create it now by executing the following code:

USE [master]
GO

CREATE DATABASE [VetClinic]
GO

USE [master]
GO

ALTER DATABASE VetClinic
SET RECOVERY FULL
GO

USE [VetClinic]
GO

CREATE TABLE [Pets]
(pet_id         INT                       PRIMARY KEY,
pet_name    VARCHAR(50)    NOT NULL,
pet_weight  INT                       NULL)
GO

ALTER TABLE [Pets]
ADD [MicroChipID] VARCHAR(100) NOT NULL
CONSTRAINT [MicroChip_Unique] UNIQUE
GO

USE [VetClinic]
GO

INSERT INTO Pets
VALUES(1,'Zeus',185,'398BF49'),
(2,'Lady',155,'191ABBC'),
(3,'Deno',50,'790AG441'),
(4,'Rex',44,'CDD81322'),
(5,'Rover',15,'A8719841')
GO

CREATE TABLE [Owners]
(owner_id         INT                     PRIMARY KEY,
pet_id                INT                     REFERENCES Pets(pet_id),
owner_name    VARCHAR(50)   NOT NULL)
GO

INSERT INTO Owners VALUES(1,2,'Bryan'),
(2,3,'Rob'),
(3,1,'Rob')

CREATE TABLE MicroChips
(MicroChipID VARCHAR(100) UNIQUE)
GO

INSERT INTO MicroChips VALUES('34BA123')
GO

Data Types

By now you may be familiar with some of the data types available. The common ones that are used throughout this book are INT and VARCHAR. SQL Server Books Online has a complete list of all the data types that are supported within SQL Server. You can find the "Data Types (Transact-SQL)" article at http://msdn.microsoft.com/en-us/library/ms187752.aspx. Data types are used in many places within SQL Server, including as column definitions, as parameters to functions and stored procedures, and as variables. Table 5-1 describes a few of the common data types you may use in everyday tasks.

Table 5.1. Common Data Types

Data Type

Description

INT

Ranges from −2,147,483,648 to 2,147,483,647.

DECIMAL(p,s)

Stores decimal numbers; p is for precision (the maximum number that can be stored), and s is for scale (the maximum number that can be stored to the right of the decimal point).

DATETIME

Stores date and time, similar to the DATE and TIME data types, which store only the date or time, respectively.

CHAR, NCHAR

Stores fixed-length non-Unicode (CHAR) or Unicode (NCHAR) character data.

VARCHAR, NVARCHAR

Stores variable-length non-Unicode (VARCHAR) or Unicode (NVARCHAR) character data.

BINARY, VARBINARY

Stores fixed-length (BINARY) or variable-length (VARBINARY) binary data.

Each data type has different characteristics including how much space on disk each value takes up. A VARCHAR data type can be defined for 20 characters but takes up only a few bytes on disk. A quick way to determine how many bytes are used is to use the DATALENGTH function. In the following example, the @name variable has the text Rob:

DECLARE @name VARCHAR(20)
SET @name='Rob'
SELECT DATALENGTH(@name)

When this script is run, the size of @name is 3 bytes. If you were to change it to SET @name='Robert' and rerun the query, the size would be 6 bytes.

Fixed data types such as integers and money always take the same storage space regardless of the value. Taking up more storage space than is needed not only takes up disk space but also decreases query performance because there will be more disk I/O as a result. SQL Server 2008 provides native data compression technologies that compress at the row and page levels, which helps to mitigate the performance and storage issues. Regardless of whether you decide to compress your data, it's a good idea to analyze your database and determine whether the data types are defined appropriately for the given data.

Unicode vs. ANSI

If you are new to the database world and haven't had a lot of experience programming, you may be curious about Unicode character strings vs. ANSI character strings. To truly understand this, you must look to the origins of computers. The American National Standards Institute (ANSI) came out with a standard known as American Standard Code for Information Interchange (ASCII). This standard defines letters, numbers, and symbols that are referred to as a character set. The ASCII character set handles 256 different characters generally stored as 1 byte within a computer. With only 26 letters in the English language, you may be wondering why anyone would need more than 256 characters. If the world spoke only English, they wouldn't, but our friends in China struggled to figure out how to represent all their thousands of characters within this 256-character limit. What Unicode allows is the storage of 2 bytes per character. These two bytes allow for more than 65,000 different characters. All modern operating systems use Unicode, and SQL Server supports both the Unicode and ANSI character sets.

Living with NULL

NULL is not your annoying cousin; it identifies that a value does not exist in the database. Take the Pets table definition, for example:

CREATE TABLE [Pets]
(pet_id         INT                         PRIMARY KEY,
pet_name    VARCHAR(50)      NOT NULL,
pet_weight  INT                         NULL)
GO

In this scenario, it's OK that the pet weight is not entered. However, it is not acceptable for the pet to not have a name. In the table definition, you see pet_name was defined with a NOT NULL keyword. This means that the absence of a value cannot be a valid value for the pet_name column. Conversely, pet_weight was defined as NULL, meaning that you could insert a value into the table and leave out the pet's weight. If you queried the newly entered data, you would see that pet_weight is NULL.

Data Manipulation Language

Most of what you'll do with Transact-SQL centers around the Data Manipulation Language (DML). DML consists of the four statements SELECT, INSERT, UPDATE, and DELETE. These are the four statements that you use to get data into a database, update and delete that data, and get it back out again.

SELECT

The SELECT statement is a DML statement that allows users to retrieve data from the database. A simplified version of the syntax is as follows:

SELECT <select_list> FROM <table_source> [WHERE <search_condition>]

where the parameters are defined as follows:

  • <select_list> specifies the columns that you want to return in the query.

  • <table_source> is the table that you want to retrieve data from.

  • <search_condition> is used to filter or scope the results that you are seeking.

The WHERE clause is optional. If you omit this clause, you will return all the rows from the given table. You can think of the WHERE clause like a Boolean expression. That is, the expression will be evaluated across every row in the table.

Let's look at an example. If you wanted to return all the pets' names and weights, you would issue the following SELECT query:

SELECT pet_name, pet_weight FROM Pets

This statement would return the following result set:

pet_name     pet_weight
Zeus             185
Lady             155
Deno              50
Rex               44
Rover             15

If you wanted to narrow down the result set, you could add a WHERE clause like the following:

SELECT pet_name, pet_weight FROM Pets WHERE pet_weight > 100

This WHERE expression would cause the result set to return only pets whose weight was greater than the value 100.

In the example, you explicitly asked SQL Server to return specific columns from the table. You could have used an asterisk (*) instead, and this would have returned all the columns in the table. To return all the columns in the Pets table, you would issue the following statement:

SELECT * FROM Pets

Sometimes tables have millions or billions of rows, and you don't really want to enumerate all of them at once. There are expressions like TOP that you can use to limit the result set. TOP specifies that only a specific number of results or percentage of results will be returned from the query. For example, SELECT TOP 3 * FROM Pets will return the first three pets stored within the table, as shown here:

Pet_id   pet_name   pet_weight   MicroChipID
1           Zeus          185        398BF49
2           Lady          155        191ABBC
3           Deno           50       790AG441

This limiting capability is also useful when used in conjunction with other clauses defined within the query. The ORDER BY clause is used to instruct SQL Server to order the result set in a particular way. You specify the columns to sort by and the direction of the sort as parameters of the ORDER BY clause. For example, if you wanted to know the top three lightest pets, you would issue the following query:

SELECT TOP 3 * FROM Pets ORDER BY pet_weight ASC

This would yield the following result:

Pet_id   pet_name   pet_weight   MicroChipID
5           Rover         15        A8719841
4           Rex           44        CDD81322
3           Deno          50        790AG441

The ASC parameter instructs SQL Server to order the results in ascending order, or lowest to highest. If you wanted to go the other way and order from highest to lowest, you could have specified DESC, which means descending.

A key value for relational databases is the fact that sometimes different tables hold data that is related to each other. This data can be combined and returned in a single result set. In this example, you have a Pets table and an Owners table. In this scenario, pets have owners, so if you wanted to answer a question like which owners have pets with a weight greater than 100, you could accomplish this by joining the tables within the query. When you join tables together, you have the option of specifying what to do with the rows that are matched and what to do with the ones that are not matched. What happens depends on what kind of JOIN you include in your query. For example, if you wanted to know all the pets who have owners, you could execute this statement:

SELECT pet_name,owner_name FROM Pets
 INNER JOIN Owners
 ON Pets.pet_id=Owners.pet_id

This statement will yield the following results:

pet_name     owner_name
Lady            Bryan
Deno            Rob
Zeus            Rob

If you look at the data in both the Pets table and the Owners table, you can see that there were two additional pets, Rex and Rover, that were not displayed. This is because the Owners table does not have a matching pet_id for these two pets.

If you wanted to list all the pets regardless of whether they had an owner, you could issue a LEFT OUTER JOIN, which will always include the data from the table defined on the left side of the JOIN statement. The following is an example of listing all the pets and their owners, if they have any.

SELECT pet_name,owner_name FROM Pets
 LEFT OUTER JOIN Owners
 ON Pets.pet_id=Owners.pet_id

This statement will yield the following result:

pet_name   owner_name
Zeus           Rob
Lady           Bryan
Deno           Rob
Rex            NULL
Rover          NULL

Notice that NULL values result when owners do not exist. Rex has no owner name on record. The system doesn't make up a name where none exists. When no value exists, the system will return a NULL.

Note

An INNER JOIN is the default join if you do not specify the join type.

There are other types of joins; RIGHT OUTER joins are similar to LEFT OUTER joins except they include the result set for the table to the right of the JOIN statement. A FULL OUTER join lists all results for both tables to the left and right of the JOIN statement. For more information on the different join types, see the SQL Server Books Online article "Using Joins" at http://msdn.microsoft.com/en-us/library/ms191472.aspx.

SELECT is arguably the most used DML statement. There are many different expressions and clauses that are possible to use with SELECT. Mastering the use of this statement will be important in your daily use of SQL Server or any other database platform. SQL Server Books Online covers the syntax in the article "SELECT (Transact-SQL)" located at http://msdn.microsoft.com/en-us/library/ms189499.aspx.

INSERT

The INSERT statement is a DML statement that allows users to write data into a database. A simplified syntax is as follows:

INSERT <table_name> [(column list)]
VALUES( { DEFAULT | NULL | <expression> } [ ,...n] )

where the parameters are defined as follows:

  • <table_name> is the table that you want to insert data into.

  • <column list> is a list of specific columns you want to insert data into. This is optional.

  • <expression> is the actual data that you want to insert. The type of data depends on the data type that is defined for the particular column.

The following sample script will add more pets to the Pets table:

INSERT INTO Pets (pet_id, pet_name, pet_weight, MicroChipID)
 VALUES (6,'Roxy',7,'1A8AF59'),
(7,'Champ',95,'81CB910'),
(8,'Penny',80,'C710A6B')

Alternatively, you could have omitted the specific columns you wanted to insert. If you do this, SQL Server will assume that the first value will be for the first column definition, the second value entered will be for the second columns definition, and so on. For example, since you are inserting information into all the columns in the Owners table, you could issue this statement and omit owner_id, pet_id, and owner_name from the statement:

INSERT INTO Owners VALUES (4,5,'Frank')

UPDATE

The UPDATE statement is a DML statement that allows the user to modify existing data within the database. A simplified definition is as follows:

UPDATE <object>
SET { column_name = { <expression> | DEFAULT | NULL }
[ WHERE <search_condition> ]

where the parameters are defined as follows:

  • <object> is the table or view that is being updated.

  • column_name is the name of the column of data that will be updated.

  • <search_condition> is used to filter or scope the list of rows to update.

As an example, let's update the Owners table and change the ownership of dogs owned by Frank to Courtney. You can do this with the following UPDATE statement:

UPDATE Owners SET owner_name='Courtney' WHERE owner_name='Frank'

The WHERE clause is optional. However, if you do not specify a search condition, you will update every row. So, unless updating all rows is what you intend to do, you should always specify a WHERE clause.

DELETE

The DELETE statement is a DML statement that allows users to remove data from the database. A simplified definition is as follows:

DELETE FROM <table_source> [ WHERE <search_condition> ]

where the parameters are defined as follows:

  • <table_source> specifies the table that you want to remove items from.

  • <search_condition> is used to scope the amount of rows that will be deleted.

The following example uses the DELETE statement to remove the pet named Penny:

DELETE FROM Pets WHERE pet_name = 'Penny'

The WHERE clause is optional. If you omit it, you will delete all rows in the specified table. Be very careful about omitting it. Omitting the WHERE clause and inadvertently deleting all data from a table is a common mistake. It's a mistake that you really want to avoid making.

Transactions

Transactions enable users to create T-SQL batch statements that are either completely applied or do nothing to the existing data. When changes are applied, it is said that the transaction has committed. When the batch is stopped for any reason such as an error or intentionally canceled, the transaction will be rolled back, and changes made within the transaction will not be made to the data.

Execution

The following is an example showing how to begin a transaction, execute some statements, and then commit the transaction. The example swaps the names of the two pets, Lady and Deno:

BEGIN TRANSACTION
UPDATE Pets SET pet_name='Lady' WHERE pet_id=3
UPDATE Pets SET pet_name='Deno' WHERE pet_id=2
COMMIT

Notice how the two UPDATE statements are bracketed by the statements BEGIN TRANSACTION and COMMIT. The two UPDATE statements form a transaction. Either they will both succeed or they will both fail. And if they succeed, they will both appear to other database users to have executed simultaneously. No other user but you will ever see both pets having the same name of Lady. You as the person executing the transaction are the only user with the ability to query the intermediate state between the two UPDATE statements. I'll talk more about this in the "Transaction Isolation" section.

If you are executing a transaction and change your mind or make a mistake, you can issue a ROLLBACK statement to undo the damage. For example:

BEGIN TRANSACTION
DELETE FROM Pets
ROLLBACK

This example deletes all data from the Pets table and then issues a ROLLBACK statement to undo that deletion. You can protect yourself by following this pattern. Wrap critical DELETE and UPDATE statements in a transaction. Then you can roll back in the event you mistype, omit the WHERE clause, or otherwise make a mistake.

Transaction Isolation

When you issue a BEGIN TRANSACTION statement, you are telling SQL Server that from this point in the T-SQL batch, isolate the effect of the statements from the rest of the user connections. Each transaction lasts either until it completes without errors and a COMMIT TRANSACTION statement is issued or until errors are encountered and all modifications are erased with a ROLLBACK TRANSACTION statement.

To help illustrate the transactional isolation from the rest of user connections, consider the following case where there are two different connections to SQL Server. User1 is connected and issues the following statement:

BEGIN TRANSACTION
UPDATE Pets SET pet_name='Big Boy' WHERE pet_id=5
SELECT pet_name FROM Pets WHERE pet_id=5

At this point, the result set for the SELECT statement is as follows:

pet_name
Big Boy

User2 is connected to the same SQL Server and issues the following statement:

SELECT pet_name FROM Pets WHERE pet_id=5

The result set for User2's SELECT statement is as follows:

pet_name
Rover

User2 still sees the old value until User1 issues a COMMIT TRANSACTION statement.

This isolation is valuable and critical to maintain consistency of the database. As a user, you can change the behavior of the isolation. If User2 wanted to know the value even though User1 did not commit the transaction yet, User2 could manually set the transaction isolation level using the SET TRANSACTION ISOLATION statement.

To read the uncommitted data in the Pets table, User2 would issue the following code:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
SELECT pet_name FROM Pets WHERE pet_id=5
GO

This would return the uncommitted "Big Boy" value instead of the original "Rover" value. It is important to note that it is not a best practice to keep transactions open; they take up valuable server resources, and other users could be depending on the data being used within the transaction. In this example, User1 should commit or roll back the transaction as soon as possible.

There are many different isolation levels that can be set. SQL Server Books Online describes all of these in detail in the article "Set Transaction Isolation Level (Transact-SQL)" at http://msdn.microsoft.com/en-us/library/ms173763.aspx.

Deadlocks

Any time you have multiple users trying to access and update the same piece of data, you will run into problems. One user may have read a value and, based on that value, performed some work, when in reality the value was updated right after the original read and now causes problems for the user. SQL Server places locks at different levels within the database such as rows or the entire table itself. This makes the multiuser scenario possible.

A lock is a way to synchronize multiple user access to the same piece of data. Locks have different modes such as shared or exclusive. Depending on the lock type and the actions each user is trying to perform, you may end up in a deadlock situation. Deadlocks occur when User1 holds a lock on a resource and is requesting access to another resource that User2 holds a lock on. User1 has to wait for User2 to release the lock. However, User2 is also requesting a lock on User1's resource. Thus, User1 and User2 are both waiting for each other to release the locks. In the end, SQL Server will choose one to be the victim and roll back that user's transaction. You can find an in-depth discussion on deadlocking in the SQL Server Books Online article called "Deadlocking" at http://msdn.microsoft.com/en-us/library/ms177433.aspx.

SQL Server does a good job of providing tools to debug deadlock situations. You can use SQL Server Profiler to capture a SQL trace. Figure 5-1 shows the output of SQL Server Profiler when a deadlock was encountered.

SQL Server Profiler trace showing a deadlock event

Figure 5.1. SQL Server Profiler trace showing a deadlock event

For a deadlock event, SQL Server Profiler displays the server process IDs that were involved with the deadlock as well as who the deadlock victim was. Figure 5-2 shows a detailed view of the deadlock graph showing the actual T-SQL statement that was issued by the deadlock victim.

Deadlock event showing T-SQL statement issued by deadlock victim

Figure 5.2. Deadlock event showing T-SQL statement issued by deadlock victim

Alternatively, the Performance Data Collector feature in SQL Server 2008 also captures locking as part of the Server Activity collection set. You'll learn more about SQL Server Profiler and the Performance Data Collector in Chapter 11.

Stored Procedures

A stored procedure is a T-SQL or .NET block of code that is stored within a database. This code is similar to other procedures in other languages because it accepts parameters as inputs and can provide output to the calling application or user. Stored procedures make it easy to build database applications.

Stored procedures contain a header and a body. In the header, you define the input and output parameters. In the body is the code. For example, the following CREATE PROCEDURE statement creates a procedure that will take a pet name and return the micro chip ID for that pet:

CREATE PROCEDURE GetID
@name VARCHAR(50)

AS

BEGIN

SELECT MicroChipID FROM Pets WHERE pet_name=@name

END

Parameters are optional. In this example, you need to specify a name. To execute this procedure, you can issue the following statement:

EXEC GetID 'Roxy'

The return the value is 1A8AF59, which is the value of Roxy's micro chip.

Creating Stored Procedures Using Templates

SSMS provides a template to use when creating a new stored procedure. To view this template, navigate to the Stored Procedures node within the Programmability node of the VetClinic database. Select New Stored Procedure from the context menu. This will open a Query Editor window with the following template:

-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:         <Author,,Name>
-- Create date:  <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE <Procedure_Name, sysname, ProcedureName>
  -- Add the parameters for the stored procedure here
  <@Param1, sysname, @p1> <Datatype_For_Param1, , int> =
     <Default_Value_For_Param1, , 0>,
  <@Param2, sysname, @p2> <Datatype_For_Param2, , int> =
     <Default_Value_For_Param2, , 0>
AS
BEGIN
   -- SET NOCOUNT ON added to prevent extra result sets from
   -- interfering with SELECT statements.
   SET NOCOUNT ON;

    -- Insert statements for procedure here
   SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>
END
GO

Having the syntax already present is helpful, but SSMS makes working with templates easy by giving you a dialog box to use to fill in the values. To launch the Specify Values for Template Parameters dialog box, select this option from the Query menu in SSMS. Figure 5-3 shows this dialog box.

Input dialog box for templates

Figure 5.3. Input dialog box for templates

Once you fill the values in the dialog box and click OK, the template automatically updates the CREATE STORED PROCEDURE text in the Query Editor with the data you provided in the dialog box.

Templates make it really easy to create procedures. Many templates are available for SQL Server. To access the list of templates, select Template Explorer from the View menu in SSMS. This will launch a Template Explorer window, as shown in Figure 5-4.

Template Explorer window in SSMS

Figure 5.4. Template Explorer window in SSMS

Note that there are three buttons on the top of this dialog box; the first one shows SQL Server templates, the second shows Analysis Services templates, and the last one shows templates for SQL Server Compact Edition. To use a template, simply double-click it, and the template will load in a new Query Editor window.

Modifying Stored Procedures

SSMS does a great job of enumerating all the stored procedures within the database. They are all listed under the Programmability node, which is under a specific database. To modify a stored procedure, you need to issue an ALTER STORED PROCEDURE statement. To modify the GetID procedure created earlier using SSMS, select Modify from the context menu of the GetID stored procedure. This will launch a Query Editor window with the ALTER STORED PROCEDURE text in it. The actual script generated by SSMS is as follows:

USE [VetClinic]
GO
/** Object:  StoredProcedure [dbo].[GetID]    Script Date: 04/29/2009 **/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetID]
@name VARCHAR(50)
AS
BEGIN
SELECT MicroChipID FROM Pets WHERE pet_name=@name
END

SSMS saves you from a lot of typing when you are working with stored procedures.

System Stored Procedures

If you navigate around SSMS and the Programmability node as described earlier, you may have noticed a System Stored Procedures folder. There are quite a number of these that all serve their own purpose within SQL Server. For example, SQL Server Agent job scheduler does not have native DDL statements for creating jobs, so it uses system stored procedures to create and manage jobs. For a complete list, see the SQL Server Books Online article called "System Stored Procedures (Transact-SQL)" at http://msdn.microsoft.com/en-us/library/ms187961.aspx.

Note

System stored procedures usually start with the characters sp_. Thus, it is a good idea to not start your stored procedures with the same three characters.

Functions

In many instances, you can accomplish the same task using either a stored procedure or a function. Both functions and stored procedures can be custom defined and part of any application. They both can be written in T-SQL or .NET and contain a header and body. They can both accept parameters and provide output to the calling application or user.

Creating a Function

To illustrate, let's create a function that accepts a pet weight and returns a table that lists the pets who exceed that weight and their owners. The sample script is as follows:

CREATE FUNCTION GiantPets (@minWeight INTEGER)
RETURNS @retGiantPetsTable TABLE
(
pet_name     VARCHAR(50) NOT NULL,
pet_weight    INT                   NOT NULL,
owner_name VARCHAR(50) NOT NULL
)
AS
BEGIN
     INSERT @retGiantPetsTable
     SELECT p.pet_name, p.pet_weight,o.owner_name
     FROM Pets p, Owners o
     WHERE p.pet_id=o.pet_id AND p.pet_weight > @minWeight

     RETURN
END

Invoking a Function

Functions are designed with the idea that they will send their output to a query or T-SQL statement. With the exception of scalar functions, functions are called differently than stored procedures. Since the example function returns a table, you can call it as part of a SELECT statement by referencing it in the FROM clause. For example:

SELECT * FROM GiantPets(50)

This will return the following result set:

pet_name   pet_weight      owner_name
Lady          155              Bryan
Zeus          185                Rob

System-Defined Functions

The GiantPets function is a user-defined function. As with system stored procedures, SQL Server comes with many built-in functions. There are so many that they are grouped into different categories. Scalar functions use a single value or list of values as opposed to data from multiple rows of a table. An example of a scalar function is GETDATE(), which returns the current date. For example:

SELECT GETDATE()

Aggregate functions utilize multiple rows of data and return a value to the user. To find the average value for all the rows in a column, you use the AVG function as follows:

SELECT AVG(pet_weight) FROM Pets

There are also a lot of security-related functions. If you wanted to know whether the current user is a member of the sysadmin group, you would use the IS_ SVRROLEMEMBER as follows:

SELECT IS_SRVROLEMEMBER('sysadmin')

This function will return 1 for true and 0 for false.

For a complete list of built-in functions, see the SQL Server Books Online article called "Functions (Transact-SQL)" at http://msdn.microsoft.com/en-us/library/ms174318.aspx.

Triggers

A trigger is a special kind of stored procedure that is executed when a special event happens within SQL Server. An event could include the execution of a given DDL or DML statement or a login to SQL Server. For example, if you wanted to make sure MicroChipID was valid before allowing a new pet to be added to the Pets table, you could create a trigger on INSERT.

The script is as follows:

USE [VetClinic]
GO
CREATE TRIGGER ValidateMicroChip
ON Pets
FOR INSERT
AS

IF EXISTS(
SELECT MicroChipID FROM MicroChips
WHERE MicroChipID IN (
SELECT MicroChipID FROM inserted)
)

RAISERROR ('The chip was found!', 16, 1)
ELSE

BEGIN
     RAISERROR ('The chip was NOT found!', 16, 1)
     ROLLBACK
END

GO

Now when you attempt to insert a new pet into the table using a micro chip ID that is not in the MicroChips table, an error will be issued, and the pet information will not be added to the table, as shown in the following script:

INSERT INTO Pets VALUES (8,'Sushi',5,'0034DDA')

This will result in the following result:

Msg 50000, Level 16, State 1, Procedure ValidateMicroChip, Line 13
The chip was NOT found!
Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.

Since the only valid micro chip ID is 34BA123, if you used this value, the result would be as follows:

Msg 50000, Level 16, State 1, Procedure ValidateMicroChip, Line 10
The chip was found!

(1 row(s) affected)

Normally you would not have to raise an error on a successful insert; this was done here only to help illustrate the code path that was executed in the trigger.

If you take a look at the trigger definition, you'll see that a table called "inserted" was referenced in the IF EXISTS clause. Within a DML trigger, SQL Server provides this table and a "deleted" table for DELETE triggers. Together these tables allow your triggers to do something with the data and, depending on your business requirements, roll back any transactions. In this sample scenario, if the chip wasn't found, the trigger rolled back the transaction, causing the pet information not to be written to the table. For more information on the inserted and deleted tables, see the SQL Server Books Online article "Using the Inserted and Deleted Tables" at http://msdn.microsoft.com/en-us/library/ms191300.aspx.

Summary

In this chapter you learned how to perform basic data retrieval and management using SELECT, INSERT, UPDATE, and DELETE DML statements. Remember that the definitions given in this chapter are simplified. The capabilities of these statements far exceed what was presented here, and you should study these in more detail when time permits.

SQL Server provides a robust dialect of the SQL language called Transact-SQL. With T-SQL you can easily create reusable components such as stored procedures and functions. SQL Server provides many stored procedures and functions out of the box, making administering SQL Server very easy.

The concepts discussed in this chapter are all core to using the SQL Server relational database engine. Thus, a lot of the content is explained in much more detail within SQL Server Books Online. Table 5-2 provides links for all the articled cited in this chapter.

Table 5.2. Links to SQL Server Books Online Articles

Article Title

URL

"Using Joins"

http://msdn.microsoft.com/en-us/library/ms191472.aspx

"Set Transaction Isolation Level"

http://msdn.microsoft.com/en-us/library/ms173763.aspx

"Deadlocking"

http://msdn.microsoft.com/en-us/library/ms177433.aspx

"System Stored Procedures (Transact-SQL)"

http://msdn.microsoft.com/en-us/library/ms187961.aspx

"Functions (Transact-SQL)"

http://msdn.microsoft.com/en-us/library/ms174318.aspx

"Using the Inserted and Deleted Tables"

http://msdn.microsoft.com/en-us/library/ms191300.aspx

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset