Professional Documents
Culture Documents
C HAPTER 9
Stored Procedures
WHEN YOU EXECUTED Structured Query Language (SQL) queries against the database
in previous chapters, the one commonality is that the query is contained within
the page where the execution will apply. Although you saw that this works effec-
tively with simple SELECT, INSERT, UPDATE, and DELETE queries, you’ll soon
see that formulating a query this way isn’t always a suitable solution.
SQL provides you with a better solution for executing queries against a database
that’s beneficial for both runtime performance and design-time development—
stored procedures. Put simply, a stored procedure is a construct to store queries on
the server, so the same query is available for any application that wants to use it.
The queries you’ve looked at so far have always been single queries that per-
formed only one action; for example, you’ve performed SELECT queries that return
one set of results and INSERT queries that insert data into a single table. When you
step into more complex data (and a need for more complex results), you’ll find this
way of working constrictive.
Stored procedures can contain just single SQL queries, and when they do so,
they’re naturally direct replacements for single queries. However, stored proce-
dures are a powerful tool that can deliver much more than this. As you’ll shortly
see, they can increase the performance of your queries and make maintaining
Web sites a whole lot easier. They may contain multiple queries and exploit the
power of SQL itself, which has more facility than you’d think, as it’s a mature
language in its own right.
NOTE We won’t present all the intricacies of SQL and all the different commands
that are supported. You can find an introduction to SQL in Appendix B.
• How you can alter and delete stored procedures you’ve already created
327
3693_Ch09_FINAL 7/7/04 4:23 PM Page 328
Chapter 9
Security: Allowing direct access to the tables within the database to applica-
tions, as you’ve already seen in Chapter 2, forces you to grant “too much” access
to the database. By using stored procedures, you only allow the user access to
the tables through stored procedures, and you can apply suitable controls.
Speed: If you pass a query string to the server, you have to compile it before it
can be executed. If you pass the same query three times, the database has to
compile the query three times. Stored procedures are compiled when they’re
created, which is the end of it—all subsequent usage is with a speedy, pre-
compiled piece of code. In addition, the database also optimizes the stored
procedure, by using information related to the structure of the database.
Flow control: SQL defines several flow-control structures that you’re familiar
with from C# (such as the IF statement and WHILE and FOR loops), and these
aren’t available if you pass the SQL query directly from the page. With stored
procedures, you can perform all the flow control you need within the database,
thus removing the data processing burden from within the page. A database
is designed to process data—so you should take advantage of the database’s
natural talent.
Reduced network traffic: Stored procedures allow you to process the results
at the database and return only the required results to the page.
328
3693_Ch09_FINAL 7/7/04 4:23 PM Page 329
Stored Procedures
To create a stored procedure, you must use a Data Definition Language (DDL)
query. You’ll look at DDL queries in more detail in Chapter 10 and see several dif-
ferent DDL queries, but for now all you need to know is that DDL queries allow
you to change the structure of the database.
The DDL query to create stored procedures is CREATE PROCEDURE, which,
in its simplest form, is as follows:
You give the stored procedure a name, and you can include whatever SQL
queries you want after the AS command.
This introduction to stored procedures will start with using SQL Web Data Admin-
istrator to create a stored procedure that returns all the publishers from the data-
base. You’ll see here that the tools you have at your disposal make it quite easy to
create stored procedures. Follow these steps:
1. Open SQL Web Data Administrator, and log into the (local)\BAND server
using the sa account.
2. Select the Books database, and then select the Stored Procedures option
in the left menu. This will give a list of all the stored procedures in the
database, currently none, as shown in Figure 9-1.
3. Click the Create New Stored Procedure option, and enter stpGetPublishers
as the name of the stored procedure.
4. Click the Create button to proceed to the page that allows you to enter the
stored procedure (see Figure 9-2).
SELECT PublisherName
FROM Publisher
ORDER BY PublisherName
329
3693_Ch09_FINAL 7/7/04 4:23 PM Page 330
Chapter 9
330
3693_Ch09_FINAL 7/7/04 4:23 PM Page 331
Stored Procedures
6. Click Save to save the stored procedure. This will return you to the list
of stored procedures in the database, and you’ll see the one you’ve just
created, as shown in Figure 9-3.
Figure 9-3. The new stored procedure has been saved to the database.
7. Select the Query option in the left menu, and enter the following query
into the text area:
How It Works
In this example, you’ve created your first stored procedure in the Books database.
Granted, it’s a simple stored procedure that doesn’t do a lot of work, but it does
give you a gradual introduction to the basic concept.
The first thing to look at is the account you use to access SQL Web Data
Administrator. To execute DDL queries, you must use an account with administra-
tor privileges within the database. In this case, you must use the sa account
because the band account has permissions only on certain objects and doesn’t
have any administrator privileges.
331
3693_Ch09_FINAL 7/7/04 4:23 PM Page 332
Chapter 9
Creating a stored procedure using SQL Web Data Administrator, as you can
see in step 4, does some of the work for you and automatically adds the CREATE
PROCEDURE [dbo].[stpGetPublishers] AS code for you. All you have to do is add the
queries you want to execute.
In this case, you use the following simple query, which returns the PublisherName
field for all the publishers in the database, ordered by the PublisherName field:
SELECT PublisherName
FROM Publisher
ORDER BY PublisherName
After you click the Save button, the database checks that the stored procedure
is valid. If it’s valid, you return to the list of stored procedures with your new stored
procedure added. If, however, there’s a problem with the stored procedure, such as
spelling a column name incorrectly, an error message is returned. The error mes-
sage, as shown in Figure 9-4, details what the error is.
Figure 9-4. Errors are returned if you try to save an invalid stored procedure.
Once any errors are corrected, the stored procedure will be saved, and you
then need to turn your attention to allowing users access to the stored procedure.
By default, this stored procedure won’t be available for use with any of the
accounts in the database other than the account that created the stored proce-
dure—in this case, the sa account. As you’ve already seen, running applications
using this account isn’t recommended. We’ve created a login called band that we’re
using to access the database from our Web pages. You can give an account permis-
sion to execute the stored procedure by granting it the EXEC permission using a
GRANT similar to the ones you saw in Chapter 2, like so:
Unfortunately, SQL Web Data Administrator suffers from quite a major prob-
lem. For queries that don’t return any results—that is, any query except SELECT—
you don’t have any results to display. You have to simply assume that, unless you
332
3693_Ch09_FINAL 7/7/04 4:23 PM Page 333
Stored Procedures
have an error when you execute the GRANT query, the permissions have been
applied correctly.
As you know, you must explicitly grant permissions for users to access the objects
in the database. In Chapter 2, you saw that to enable a SELECT query to be exe-
cuted against a table, you needed to give the user specific permissions to SELECT
information from the table. So to give the band account SELECT permissions on
the Publisher table, you’d execute the following:
You’d have to also give similar permission if you wanted to grant the band
account INSERT, UPDATE, or DELETE permissions on the table.
Stored procedures also have to have permissions applied in order for an
account to be able to execute them. Stored procedures don’t have SELECT, INSERT,
UPDATE, or DELETE permissions but instead have a single permission, EXEC.
The syntax to grant the EXEC permission for a stored procedure is the same as
granting any other permission. Use the following:
And similarly, if you want to remove an existing EXEC permission, you can use
the REVOKE query to remove the permission, like so:
You can also explicitly deny using the EXEC permission on a stored procedure
with the following DENY query:
NOTE Once a user has been granted the EXEC permission on a stored procedure,
no other permissions are required for that user to execute the stored procedure.
The user executing the stored procedure doesn’t need any permissions on the
tables that the stored procedure accesses—the database assumes that the stored
procedure is correct and allows it access to all the tables within the database.
333
3693_Ch09_FINAL 7/7/04 4:23 PM Page 334
Chapter 9
You’ve now got a stored procedure in the database that will return all the publish-
ers in the database. Next you need to look at how you call the stored procedure
for execution instead of passing a query. Thankfully, there isn’t an awful lot that
changes between passing queries and calling a stored procedure.
Whenever you’ve executed queries against the database, you’ve always just
passed the query into the Command object and used the correct execute method.
For example:
To use a stored procedure in place of a query, you need to tell the Command
object that you’re using a stored procedure rather than a query. You do this by set-
ting the CommandType property of the Command object.
When executing a SQL query, you use the default CommandType of
CommandType.Text. Executing a query is the default, so you don’t need to set the
CommandType property, which is why you haven’t seen this property before now.
So, to call a stored procedure, you simply pass the name of the procedure
instead of a SQL query and tell the SqlCommand object you’re passing the name of
a stored procedure by setting the CommandType property to CommandType.Stored-
Procedure.
Now that you have a stored procedure in the database and have set its permissions
correctly, you can use that stored procedure in place of a SQL query within a page.
We’ll quickly show how to do this and use the Simple Data Report template in Web
Matrix to cut down on the amount of code you need to write. Follow these steps:
1. Open Web Matrix, and navigate to the C:\BAND\ folder. Create a new folder
called Chapter09.
2. In the Chapter09 folder, create a new web.config file and replace its contents
with the following:
334
3693_Ch09_FINAL 7/7/04 4:23 PM Page 335
Stored Procedures
<configuration>
<appSettings>
<add key="MSDEConnectString"
value="server=(local)\BAND;database=Books;uid=BAND;pwd=letmein" />
</appSettings>
</configuration>
4. Switch to the Code view in Web Matrix, and change the Page_Load event to
the following:
try
{
string ConnectionString =
ConfigurationSettings.AppSettings["MSDEConnectString"];
string CommandText = "stpGetPublishers";
myConnection.ConnectionString = ConnectionString;
SqlCommand myCommand = new SqlCommand(CommandText, myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
myConnection.Open();
DataGrid1.DataSource = myCommand.ExecuteReader();
DataGrid1.DataBind();
}
catch (Exception ex)
{
throw(ex);
}
finally
{
myConnection.Close();
}
}
335
3693_Ch09_FINAL 7/7/04 4:23 PM Page 336
Chapter 9
5. Execute the page, and you’ll see that the stored procedure you’ve created
is executed and that the results are returned as expected (see Figure 9-5).
How It Works
The code for the Page_Load event is almost identical to the code you looked at in
Chapter 4 for passing a SQL query to the database. The three lines of code that are
of particular interest to you are as follows:
Instead of a SQL query, you give the name of the stored procedure as
the CommandText to the constructor for the SqlCommand object. You then tell the
SqlCommand object that what you’re passing in is the name of a stored procedure
and not a SQL query by setting the CommandType property to CommandType.Stored-
Procedure.
336
3693_Ch09_FINAL 7/7/04 4:23 PM Page 337
Stored Procedures
NOTE If you don’t set the CommandType correctly for the stored procedure, the stored
procedure will still execute because the database makes an intelligent guess. That
is, an invalid query is probably a stored procedure name. However, if you explic-
itly instruct the database that you’re passing in a stored procedure name, it not
only makes your code more readable, but it also makes it slightly quicker because
you’re removing the weight of forcing the database to choose a “best fit” from the
instruction it receives.
As you learned in the earlier chapters, you can use three execute methods to execute
a query against the database. Which one you use depends upon what the query that
you’re executing is doing. To recap, the three methods that you can use are as follows:
• ExecuteNonQuery(): You use this when the query doesn’t return any results
from the database.
• ExecuteReader(): You use this when you want to return a result set from a
SELECT query.
• ExecuteScalar(): You use this when you want to return only the first field
from the first row of the returned result set.
You also have the same choice when you use stored procedures, and you
should choose the method that matches what the stored procedure does.
Being able to add stored procedures to your database is all well and good, but you
also need some way of modifying or deleting them. You can accomplish both of
these tasks using two other DDL commands.
To modify a stored procedure, you use the ALTER PROCEDURE query, specify-
ing the name of the stored procedure you want to modify as well as the complete
new contents of the stored procedure, like so:
337
3693_Ch09_FINAL 7/7/04 4:23 PM Page 338
Chapter 9
To delete a stored procedure from the database, you simply use the DROP
PROCEDURE query, like so:
SQL Web Data Administrator shields you from having to remember the syntax
of these commands by providing options to complete both of these tasks from the
user interface; if you look at Figure 9-3, you’ll see that along with the name, owner,
and type of stored procedure, you have options to both edit and delete the stored
procedure.
You’ll take a quick look at modifying stored procedures, but we’ll skip a discus-
sion of how to delete stored procedures using SQL Web Data Administrator, as
there’s not a lot to say. Clicking Delete gives a Yes/No prompt, and if you click Yes,
you’ll delete the stored procedure.
Sometimes it’ll become necessary to change the stored procedures you’ve already
created. SQL Web Data Administrator makes this task easy. Follow these steps:
1. Open SQL Web Data Administrator, and log into the (local)\BAND server
using the sa account.
2. Select the Books database, and then select the Stored Procedures option
in the left menu. This will give the list of stored procedures in the data-
base, as shown in Figure 9-3 earlier.
6. Open Web Matrix, and execute the simple.aspx page you created in the
previous example. As shown in Figure 9-7, this will return the results from
the stored procedure, with the addition of the PublisherID field.
338
3693_Ch09_FINAL 7/7/04 4:23 PM Page 339
Stored Procedures
339
3693_Ch09_FINAL 7/7/04 4:23 PM Page 340
Chapter 9
How It Works
You’ve specified the new query for the stored procedure and saved it to the data-
base. When you now execute the page and call the stpGetPublishers stored proce-
dure, you get the results from the new query rather than the old one.
However, you may have noticed the change you made in the query that you
used to modify the stored procedure. When we talked about changing the stored
procedure, we stipulated using ALTER PROCEDURE, yet SQL Web Data Adminis-
trator presents you with the stored procedure using CREATE PROCEDURE.
When you modified the stored procedure, you changed this to use ALTER
instead of CREATE before you saved the modified stored procedure. When using
SQL Web Data Administrator, this isn’t necessary because you can use CREATE
PROCEDURE and ALTER PROCEDURE interchangeably. However, it makes more
sense to use the correct DDL query, so always use ALTER PROCEDURE when
changing stored procedures—it’ll stop any problems you may encounter when
using other tools.
The simple stored procedure you looked at returns all the publishers in the data-
base. This is just the beginning of the story. By responding dynamically to users
and their interaction with your pages, as you’ve seen in the earlier chapters, you
can impart real power to your applications.
In Chapter 4 you looked at two methods of modifying queries. We mentioned
that one of these methods, using parameters, was how you’d pass data into stored
procedures.
SQL defines two types of parameters (input parameters and output parame-
ters), and you’ll look at using each of these in turn.
340
3693_Ch09_FINAL 7/7/04 4:23 PM Page 341
Stored Procedures
You saw that parameters can pass data into the SqlCommand object to modify the
query you want to execute. The way you pass parameters into stored procedures
is the same.
Using input parameters with stored procedures is a two-stage process:
2. Add the parameters to the SqlCommand object before the call is made to
execute the stored procedure.
The parameters list is simply a list giving the name of the parameter, its type,
and any default value it may have. If there’s more than one parameter, you sepa-
rate them with commas, like so:
All parameters that you include in the stored procedure declaration must be
passed to the stored procedure by the calling application—if they aren’t, an error is
thrown. If you’re sure you don’t want to pass the parameter, you can override this
behavior by giving the parameter a default value. This will be used if the parameter
isn’t supplied a value by the calling application. If you always want a value to be
passed to the stored procedure, then you don’t specify a default value.
341
3693_Ch09_FINAL 7/7/04 4:23 PM Page 342
Chapter 9
You’ll now look at creating a stored procedure using SQL Web Data Adminis-
trator that accepts a parameter that modifies the results that are returned as part
of the query. This stored procedure will also introduce you to the idea of flow con-
trol and in particular the IF statement to control what actions the stored proce-
dure takes.
You’ll create a new stored procedure that accepts a PublisherID and returns a list
of published books or, if a PublisherID isn’t specified, returns all the books in the
database. Follow these steps:
1. Open SQL Web Data Administrator, and log into the (local)\BAND server
using the sa account. Open the Books database, select the Stored Proce-
dures option in the left menu, and then click the Create New Stored
Procedure link at the top of the page.
3. In the dialog box for entering the stored procedure, add the following:
342
3693_Ch09_FINAL 7/7/04 4:23 PM Page 343
Stored Procedures
5. Select the Query option in the left menu, and enter the following query into
the text area:
How It Works
The way you’ve created this new stored procedure is the same way you created the
stpGetPublishers stored procedure, and, unsurprisingly, you’ll create every stored
procedure this way. It’s the structure of the stored procedure in which you should
be interested.
SQL Web Data Administrator creates the basics of the stored procedure for you,
and the first thing you must do is add the parameters you want to the definition.
You do this between the stored procedure name and the AS statement, like so:
You’ve only got one parameter in this particular query, and it’s called @publisher.
The name must be prefixed by the @ symbol to indicate that it’s a user variable (as
opposed to a system variable that will have @@ at the front), and, as you’ll see when
you call the stored procedure in the next example, this is the name you’ll need to
use when adding the parameter to the SqlCommand object.
After the name of the parameter, you have the parameter’s type. For types that
require a size as well (such as the varchar type), you also have to include the size
you’re expecting.
343
3693_Ch09_FINAL 7/7/04 4:23 PM Page 344
Chapter 9
The final detail you specify for the parameter is any default value you want the
parameter to take. The default value you specify can be any value that’s valid for
the parameter’s type, or, as shown here, you can specify that it has a value of null.
As you’ll see, you want to trap the condition whereby the parameter isn’t supplied.
Using null provides the simplest way of doing this—if you use a valid parameter
value as the default, there’s always a chance that the default value you’ve chosen
is a value that may be passed into the stored procedure.
CAUTION One caveat exists for using null as the default value for parameters.
Using the SqlCommand object to pass an empty string (in other words, one that
contains nothing at all) to a stored procedure results in the pass action failing—
the empty string is not passed to the stored procedure. In this case, using null may
not be appropriate, and you should stipulate an empty string explicitly using two
single quotes.
Now that you’ve added the parameter to the stored procedure, you must then
use it. You’re obviously going to use it to modify what’s returned from the SELECT
query, but you’ll go a little further and use the parameter to determine which of
two SELECT queries you want to execute.
If you don’t want to filter the books that are returned as part of the query, you can
assume that you won’t pass a value into the stored procedure and that it’ll take the
default value of null. You can use the following to determine the route through the
stored procedure by using the IF statement and in particular whether it’s equal to
the default value of null:
Using the IF statement, as in C#, you can control what’s executed within the
stored procedure. As the condition of the IF statement, you can use any valid SQL
that returns a true or false value—you can do simple comparisons as you have
here (all the usual operators are here), or you can use scalar functions (such as
EXISTS) to control execution.
344
3693_Ch09_FINAL 7/7/04 4:23 PM Page 345
Stored Procedures
Depending upon whether the condition evaluates to true or false, you take a
different path. If true, you follow the path before the ELSE statement, and if false,
you follow the path after the ELSE statement.
NOTE The BEGIN and END statements in SQL are equivalent to the opening and
closing braces in C#. As with C#, you don’t need them if you have only one state-
ment as part of the conditional path, but it makes the SQL code a lot easier to
read if they’re present.
If you have a null value for @publisher, you know that you don’t want to filter
the query and execute a SELECT query that returns the BookID, BookTitle, Book-
MainTopic, and PublisherName for all the books in the database.
If, however, you have a non-null value for @publisher, indicating that one has
been passed into the stored procedure, you use this to constrain the SELECT
query and return a slightly different list of columns, like so:
You’ve already seen in Chapter 4 how to pass parameters to a query, and the
method of passing them to a stored procedure is no different.
You need to create a SqlParameter object and set the name, type, and value
before adding it to the Parameters collection of the SqlCommand object.
345
3693_Ch09_FINAL 7/7/04 4:23 PM Page 346
Chapter 9
You’ll now build a slightly more complex example that displays the books in the
database and uses the stpGetBooksByPublisher stored procedure to filter for which
publisher you’re returning the books. You’ll populate the list of publishers by using
the stpGetPublishers stored procedure you saw earlier. Follow these steps:
3. Switch to the Code view in Web Matrix, and change the Page_Load event to
the following:
try
{
string ConnectionString =
ConfigurationSettings.AppSettings["MSDEConnectString"];
string CommandText = "stpGetPublishers";
myConnection.ConnectionString = ConnectionString;
SqlCommand myCommand = new SqlCommand(CommandText, myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
myConnection.Open();
346
3693_Ch09_FINAL 7/7/04 4:23 PM Page 347
Stored Procedures
myConnection.Close();
}
}
}
try
{
// create the connection and open it
string ConnectionString =
ConfigurationSettings.AppSettings["MSDEConnectString"];
string CommandText = "stpGetBooksByPublisher";
myConnection.ConnectionString = ConnectionString;
SqlCommand myCommand = new SqlCommand(CommandText, myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
myConnection.Open();
347
3693_Ch09_FINAL 7/7/04 4:23 PM Page 348
Chapter 9
5. Execute the page, and you’ll see that the drop-down list is populated with
the list of publishers. Make sure the -- All Publishers -- option is selected,
and click the Show Titles button. This will execute the stored procedure
and return all the books in the database, as shown in Figure 9-8.
6. Select the Apress option in the drop-down list, and click the Show Titles
button. This will execute the stored procedure, passing in the publisher
details that you require and returning the results as shown in Figure 9-9.
348
3693_Ch09_FINAL 7/7/04 4:23 PM Page 349
Stored Procedures
How It Works
This example is the same example as you saw in Chapter 4 when you looked at
passing parameters to queries—all you’ve changed is the use of stored procedures
rather than a direct SQL query.
This example has the following two parts:
• Populating the drop-down list when the page first loads in the Page_Load
event handler
• Applying the ApplyFilter_Click event handler that’s fired when clicking the
Show Titles button
Populating the drop-down list in the Page_Load event handler happens by call-
ing the stpGetPublishers stored procedure you created and then modified in the
earlier examples. You use the ExecuteReader() method to return a SqlDataReader
containing the PublisherID and PublisherName for all the publishers in the data-
base, and you bind this to the drop-down list. You then add the -- All Publishers --
entry that has a value of 0.
The part you’re most interested in for this example is the code within the Apply–
Filter_Click event handler.
You’ll call the stpGetBooksByPublisher stored procedure and create the Com-
mand object, passing in the name of the stored procedure and the connection you
want to use. You then set the CommandType property to CommandType.StoredProcedure.
A check is then made of the selection from the drop-down list to determine if
you need to add the parameter; as you’ll recall, you don’t have to add this if you
don’t need to do so. You added an -- All Publishers -- entry to the drop-down list
with a value of 0, so you can simply check that the SelectedValue of the drop-down
list is equal to 0. If it is, you don’t want to add the parameter, and if it isn’t, you
want to add the parameter with the correct value.
You’ve already looked at adding parameters to a SqlCommand object; there’s
nothing here you haven’t seen before.
The first thing you have to do is create a SqlParameter object and give it the
correct name. Because you’re using the SqlCommand object, you need to use the
name that the stored procedure expects, so you use @publisher, like so:
349
3693_Ch09_FINAL 7/7/04 4:23 PM Page 350
Chapter 9
You then specify the type of the parameter from the SqlDbType enumeration and
set the value of the parameter to the value selected in the drop-down list, like so:
myParameter1.SqlDbType = SqlDbType.Int;
myParameter1.Value = DropDownList1.SelectedValue;
Once the parameter has been created and correctly populated, you can add it
to the Parameters collection of the SqlCommand object, like so:
You then use the ExecuteReader() method of the SqlCommand object to return a
SqlDataReader object and bind this to the data grid.
When the stored procedure is executed, the route that’s taken depends upon
whether you’ve added the parameter to the SqlCommand object or not, as we dis-
cussed when you created the stored procedure in the previous example.
Although you’ve now seen how you can pass parameters to a stored procedure,
this isn’t the end of parameters. You can also use them to return values from a
stored procedure.
You’ve already looked at two ways of returning data from the database in the
ExecuteReader() and ExecuteScalar() methods, which are used to return informa-
tion from a SELECT query. Sometimes, however, you want to execute a query that
doesn’t return any results directly but returns information detailing what you’ve
just done. If you’re inserting information into the database, you may want to
return a key for what you’ve just inserted. Output parameters are the key to this.
You can modify the values of user variables within stored procedures, and if
they’re parameters, the changed value may be returned to the calling application.
If the parameter is an input parameter, the value isn’t returned, but for output
parameters the changed value is returned.
350
3693_Ch09_FINAL 7/7/04 4:23 PM Page 351
Stored Procedures
To use output parameters instead of input parameters, you don’t actually have
to do a lot of work. You can accomplish it in the following two stages:
2. Tell the SqlCommand object that the stored procedure is an output parame-
ter and then retrieve the changed value from the Parameters collection
after the stored procedure has executed.
To use output parameters within the stored procedure, you use the OUTPUT
statement with the definition of the parameter, like so:
You’re free to mix input and output stored procedures however you want in
the stored procedure declaration.
As with input parameters, you can also give output parameters default values
that will be used if the parameter isn’t passed to the stored procedure by the call-
ing application. You may be wondering why you’d create an output parameter that
you may not use, but as you’ll see in the example, they can come in quite handy.
You’ll now look at building upon the stored procedure in the previous example to
include an output parameter that returns the number of books for the selected
publisher. Follow these steps:
1. Open SQL Web Data Administrator, and log into the (local)\BAND server
using the sa account. Open the Books database, and select the Stored
Procedures option in the left menu.
351
3693_Ch09_FINAL 7/7/04 4:23 PM Page 352
Chapter 9
How It Works
As you can see from the stored procedure declaration, you’ve added the following
output parameter of type int called @rows:
You’ll use this to return the count of the number of rows that are returned for
the publisher you’ve selected.
You’ve given @rows a default value, as you’re now going to be using the stored
procedure in at least two places. If you open the input.aspx page from the previous
example, you’ll see it still performs the same way even though the stored procedure
that’s being called has an output parameter that you don’t specify. If you didn’t have
a default value for @rows, an error would be generated if you tried to call the stored
procedure without adding the parameter.
You use the SET statement to assign values to variables, and you can set @rows
to the number of rows returned using the @@ROWCOUNT system variable, like so:
@@ROWCOUNT returns the number of rows that the previous SQL query returned
or affected and is valid not only for SELECT but also for DELETE, INSERT, and
UPDATE.
352
3693_Ch09_FINAL 7/7/04 4:23 PM Page 353
Stored Procedures
You’ve already seen how you add input parameters to the SqlCommand object;
adding output parameters is no more difficult. The only thing you have to change
is the direction of the parameter.
Parameters by default are defined as input parameters. In the previous exam-
ples, you haven’t had to specify a direction for the parameter, as you’ve been using
only input parameters. For output parameters, you need to specify the direction.
You specify the direction for a parameter using the Direction property and
setting it to one of the values in the System.Data.ParameterDirection enumeration.
The default value for the Direction property is ParameterDirection.Input. If
you wanted to specify it for an input parameter, you’d specify it as follows:
myParameter.Direction = ParameterDirection.Input
For output parameters, you have the following two possible values:
Although you’d be forgiven for thinking that you need only one possible
option for output parameters, ADO.NET provides two. Although MSDE allows
all OUTPUT parameters to accept an input value, ADO.NET makes a distinction
between the two.
If you declare a parameter as solely an output parameter, as follows:
myParameter.Direction = ParameterDirection.Output
then even if you give it a value before calling the stored procedure, the value will
not be passed to the stored procedure. The output value will be set correctly, but
any input value is completely ignored.
On the other hand, if you define the parameter as an InputOutput parameter:
myParameter.Direction = Parameter.Direction.InputOutput
then any value you give it will also be passed to the stored procedure.
353
3693_Ch09_FINAL 7/7/04 4:23 PM Page 354
Chapter 9
You’ll build on the last example and return the number of rows from the stpGet-
BooksByPublisher stored procedure using an output parameter. Follow these steps:
2. Switch to the HTML view of the page, and add the following bold code to
the contents of the <form> tag:
<p>
Select a Publisher:
<asp:DropDownList id="DropDownList1" runat="server">
</asp:DropDownList>
<asp:Button id="Button1" onclick="ApplyFilter_Click" runat="server"
Text="Show Titles"></asp:Button>
</p>
<p>
Returned <asp:Label id="Label1" runat="server">0</asp:Label> books.
</p>
<asp:datagrid id="DataGrid1" runat="server" EnableViewState="False"
ForeColor="Black" BackColor="White" CellPadding="3" GridLines="None"
CellSpacing="1">
<HeaderStyle font-bold="True" forecolor="white"
backcolor="#4A3C8C"></HeaderStyle>
<ItemStyle backcolor="#DEDFDE"></ItemStyle>
</asp:datagrid>
3. Switch to the Code view for the page, and modify the code in the Apply-
Filter_Click event handler to add the second parameter and retrieve the
output parameter after the stored procedure has executed, like so:
myCommand.Parameters.Add (myParameter1);
}
354
3693_Ch09_FINAL 7/7/04 4:23 PM Page 355
Stored Procedures
myConnection.Open();
4. Execute the page, select the -- All Publishers -- option in the drop-down
list, and click the Show Titles button. This will execute the stored proce-
dure, return all the books in the database, and update the count of the
number of books returned, as shown in Figure 9-10.
Figure 9-10. Results showing the books and the book count for all the books
355
3693_Ch09_FINAL 7/7/04 4:23 PM Page 356
Chapter 9
5. Select the Apress option in the drop-down list, and click the Show Titles
button. This will execute the stored procedure returning only the books
for Apress and the count of the number of books that have been returned,
as shown in Figure 9-11.
How It Works
All the changes you’ve made are again to the ApplyFilter_Click event handler, as
you’re still happy with the population of the drop-down list of publishers.
The first change you make is to add the output parameter. As you can see, you
declare the parameter as you have all the other parameters you’ve used. The only
thing you’ve done differently is to specify the direction of the parameter, like so:
356
3693_Ch09_FINAL 7/7/04 4:23 PM Page 357
Stored Procedures
The one change you’ve had to make to the code is the way you retrieve the
results and bind them to the data grid, like so:
You have to deal with the ExecuteReader() method and the SqlDataReader
that it returns in this manner because of the way that the data is returned from
the database when you’re retrieving a SqlDataReader. The SqlDataReader must be
closed before the output parameters are populated, and to do that you must cre-
ate a local instance of the reader, bind it to the data grid, and then manually close
the reader. Only at this point are you able to use the output parameters from the
stored procedure.
Once the SqlDataReader has been closed, you can retrieve the values of the
output parameters simply by using the name of the parameter as the indexer to
the Parameters collection of the Command object, like so:
You’re after the value of the parameter, so you use the Value property. This
property returns an object that you can then cast to whatever type you want. In
this case, you want to set the Text property of a label control, so you convert the
value to a string.
357
3693_Ch09_FINAL 7/7/04 4:23 PM Page 358
Chapter 9
Summary
You started this chapter by looking at stored procedures and why you’d use them.
The chapter covered the following reasons for using stored procedures:
• Simplified maintenance
• Increased security
• Increased performance
After looking at why you’d use stored procedures over direct SQL queries, you
then took a step back from the relative complexities of the previous chapters. You
created several stored procedures that utilized the following options you have for
passing and returning data to and from stored procedures:
You also saw that there’s very little difference between calling a stored proce-
dure and executing a SQL command; you pass the stored procedure name as the
query to execute and tell the SqlCommand object you’re executing a stored procedure
by specifying CommandType.StoredProcedure.
In the next chapter, you’ll look at the DDL subset of SQL and see what it can
do. You can perform all the actions graphically in the book until this point using
SQL itself. You’ve seen this in action with the CREATE PROCEDURE and ALTER
PROCEDURE queries used in this chapter. But as you’ll soon see, you can use SQL
to create the entire database without ever going near a graphical tool.
358