The first half of this chapter is devoted to understanding how stored procedures work. You'll learn what stored procedures are, how they are created and managed, how they are executed, why they are so important, and finally some error handling strategies for stored procedures. What Is a Stored Procedure?According to SQL Server Books Online, a stored procedure is "a group of Transact-SQL statements compiled into a single execution plan." What does that mean? Well, it's a group of Transact-SQL statements, which is similar in nature to the idea of a batch discussed in Chapter 6. It's compiled into an execution plan, which means it can be compiled once and the execution plan may be reused, which reduces overhead somewhat. Guessing from the name , a stored procedure is probably, well, stored somewhere. In this case, a stored procedure is actually stored in a databaseany database you want. Specifically, if you're really interested, stored procedures are stored in the syscomments system table in each database. This table contains the source codethe T-SQLthat you write to create the stored procedure. A stored procedure can have input parameters, which make it possible to tell the stored procedure things, such as the parameters for the queries it should run. A stored procedure can return results in several ways: with an integer return code, with one or more resultsets, and with output parameters. This is all very abstract. Take a look at how stored procedures are created; that should make things a bit more solid. Creating and Managing Stored ProceduresStored procedures are created using the aptly named CREATE PROCEDURE statement. The CREATE PROCEDURE statement has to be the first executable line in a batch, and the stored procedure continues until the end of the batch, which is until the end of the file or until the word GO . You can abbreviate the word PROCEDURE to just PROC . Here's an example: CREATE PROCEDURE TableList AS SELECT name FROM sysobjects WHERE type = 'u' GO This stored procedure returns the same thing all the time: the list of tables, which includes the objects of type 'u' , in the database in which the stored procedure was created. The name of the stored procedure is TableList . Stored procedure names follow the same rules as other object names . The keyword AS marks the beginning of the actual code to be executed. The end, of course, is marked with GO , which tells SQL Server that the batch is at a close and the stored procedure should be compiled. That's not particularly a useful or helpful stored procedure; it's almost faster to type the entire query than it is to try and remember the stored procedure name. How about something a bit more interesting: CREATE PROCEDURE TableList2 @NamePattern sysname = null AS if @NamePattern is null SELECT name FROM sysobjects WHERE type = 'u' else SELECT name FROM sysobjects WHERE type = 'u' and name like '%' + @NamePattern + '%' GO Now you have a stored procedure that can do something almost helpful. The @NamePattern sysname = null looks like a variable declaration, but it's actually a parameter declaration. A parameter is a variable that is passed in to a stored procedure to give the stored procedure a little guidance on how to get things done. NOTE Variables and Datatypes The sysname variable type is frequently used when you're going to be handling object names, such as table names, column names, or database names, because it's the data type that SQL Server uses in system tables. It's the preferred type to use for this type of information because as Microsoft changes the specifications for what an object name can and cannot be, the sysname type changes also, which should cause fewer coding revisions if you move to a different version of SQL Server. In this case, it's a parameter of type sysname . The = null part means that the parameter is optional, and if it's not specified it should be null. It's just as proper to do "= ''" to default it to an empty string, or any other arbitrary string that makes sense as a default. The only rule is that the default has to be the correct datatype and length to fit into the parameter. Notice that the AS keyword goes before the code starts, but after the parameter declarations. A stored procedure can have up to 2,100 parameters. A default can be any value, including NULL . It can contain the wildcards and pattern matching characters , such as asterisks and square brackets. All the parameters can have defaults, so you can call the stored procedure with no parameters if you want just the defaults. The code in the example is fairly straightforward, if the @NamePattern is null, the stored procedure returns all the tables in the database; if the parameter has a value, it returns tables that contain the string that is contained in @NamePattern . Step by Step 9.1 shows you how to create the same stored procedure with Enterprise Manager:
The stored procedures you've seen in this chapter so far provide output by creating an output record set. Stored procedures can also pass back return valuesintegers that usually relay status information to the caller. To pass back a number to the caller, use the RETURN statement. The RETURN statement immediately exits the stored procedure, so don't use it until the stored procedure is all done, like this: CREATE PROCEDURE TableList3 @NamePattern sysname = null AS if @NamePattern is null begin SELECT name FROM sysobjects WHERE type = 'u' RETURN 1 end else begin SELECT name FROM sysobjects WHERE type = 'u' and name like '%' + @NamePattern + '%' RETURN 0 end GO This returns a value of 1 if the resultset contains all the tables, or a zero if it is returning a filtered set. Provided that the calling application is expecting the return value and knows how to decipher it, return values can be very helpful for returning record counts, error messages, or anything else meaningful back to the calling application. All the system stored procedures, for example, return a value of for success and some non-zero result for failure. The RETURN statement can be used only to return integers. In addition to return codes, stored procedures can also pass data to the calling application by using output parameters. Output parameters are declared like other parameters in the CREATE PROCEDURE statement with the word OUTPUT after them, like this: CREATE PROCEDURE TableList4 @NamePattern sysname = null, @RowCT int OUTPUT AS if @NamePattern is null begin SELECT name FROM sysobjects WHERE type = 'u' SET @RowCT = @@ROWCOUNT RETURN 1 end else begin SELECT name FROM sysobjects WHERE type = 'u' and name like '%' + @NamePattern + '%' SET @RowCT = @@ROWCOUNT RETURN 0 end GO This enables the calling program to accept the number of rows returned in a variable. You can also use an output parameter of type cursor to return the rowset, like this: CREATE PROCEDURE TableList5 @NamePattern sysname = null, @RowCT int OUTPUT, @OutputCursor CURSOR VARYING OUTPUT AS if @NamePattern is null begin SET @OutputCursor = CURSOR FORWARD_ONLY STATIC FOR SELECT name FROM sysobjects WHERE type = 'u' SET @RowCT = @@ROWCOUNT OPEN @OutputCursor RETURN 1 end else begin SET @OutputCursor = CURSOR FORWARD_ONLY STATIC FOR SELECT name FROM sysobjects WHERE type = 'u' and name like '%' + @NamePattern + '%' SET @RowCT = @@ROWCOUNT OPEN @OutputCursor RETURN 0 end GO Notice that the OPEN statement absolutely has to be in the procedure, or the cursor does not return properly. There are a few additional rules with using cursors for output:
If you're in doubt about the validity of the cursor variable, you can use the CURSOR_STATUS() function. This function returns different values depending on the condition of the cursor, provided that you know the type of cursor (local, global, or variable). The syntax is CURSOR_STATUS('<type>', '<variable>') . The single ticks are mandatory. For example, to diagnose the preceding cursor, you could use CURSOR_STATUS('variable', '@OutputCursor') . Table 9.1 shows what the CURSOR_STATUS function returns: Table 9.1. CURSOR_STATUS Return Values
Stored Procedure GroupsWhen you create a set of stored procedures, you can also add them all into a group by specifying a number after the stored procedure namefor example: CREATE PROCEDURE TableList;1 You can then create a whole bunch of procedures with the same name and different numbers. This is called a stored procedure group. For example, if you have several applications that all run in one database, you can assign them all the same name and different numbers . That way when the application is removed from the database, it's easy to remove the associated stored procedures. Stored procedure groups is a feature that is not used very often because it hides the functionality of the stored procedure by keeping it out of the name of the stored procedure. However, it's part of the syntax for CREATE PROCEDURE , so you should know what it does. WARNING Don't Use Stored Procedure Groups! Some features discussed in this chapter aren't widely used, but have to be discussed because they may be on the test. Stored procedure groups are one of them. Don't use stored procedure groups in real life because you may drop procedures inadvertently and it hides the true nature of a stored procedure by forcing it to have an artificial name. |