Click here to Skip to main content
Click here to Skip to main content

Using C# to Enumerate Through Stored Procedures in MS SQL Server 2000

By , 3 Jan 2006
 

Introduction

This article will demonstrate how to enumerate through a stored procedure's parameters using C#, ASP.NET, and MS SQL Server 2000.

Background

After looking around 'net for some time trying to locate a simple way to enumerate through the parameters of a stored procedure, I decided to post the solution I have here. Why is it useful? Well, if you want to create a solution that can dynamically pass parameters to a stored procedure, it's quite useful. I used the solution to create a reporting application that will return data to a user (through a web application) by executing stored procedures on a SQL Server. But it was important that I allowed the user to provide parameters, such as report start date, or report end date, and I needed to be sure I could validate that the data from the input was the right type for the stored procedure's parameter. I'll show you how to do that in this article.

Using the Code

This code can be used in any C# application, web or otherwise, but the example will demonstrate usage in a web application. If you download the sample project, you will of course need VS.NET 2003, an instance of MS SQL Server 2000, and IIS running. You'll want to change the connection string in the Web.config to point to your local instance of MS SQL Server.

List the Stored Procedures

Since MS SQL Server doesn't provide an extended stored procedure for enumerating through stored procedures, we just do it directly using a SELECT command:

select name from dbo.sysobjects where type ='P' order by name asc

Our C#/ASP.NET function:

//Enumerate and load all stored procedures from the database 
private void loadStoredProcs()
{
    //Clear out the dropdownlist    
    ddlSPs.Items.Clear();
    SqlConnection cn = new SqlConnection(
      System.Configuration.ConfigurationSettings.
      AppSettings["ConnString"]);
    //We'll use a SQL command here. 
    //We use an adapter below. 
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "select name from sysobjects" + 
                      " where type='P' order by name asc";
    cmd.CommandType = CommandType.Text;
    cmd.Connection = cn;
     try 
    {
        cn.Open();
        SqlDataReader rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
             this.ddlSPs.Items.Add(rdr["name"].ToString());
        }
    }
     catch (Exception exc)
    {
         //Send the exception to our exception label 
         this.lblException.Text = exc.ToString();
    }
     finally 
    {
        cn.Close();
    }
}

List the Parameters for a Stored Procedure

Now that we can list all of the stored procedures, we'll use the following SQL to get a table listing the important columns for the parameters of a selected procedure. We can use the ID from sysobjects and the rest of the data from syscolumns to obtain all of the parameter and type information for each parameter of our selected stored procedure:

 select s.id , s.name, t.name as [type], t.length
 from  syscolumns s
 inner join systypes t
 on s.xtype = t.xtype 
 where id = (select id from sysobjects where name = 
             'sp_TheNameOfYourStoredProcedure')

Our C#/ASP.NET function:

 //Get all parameters for a specified stored procedure 
 private void bindParameters( string strName)
 {
    SqlConnection cn = new SqlConnection(
        System.Configuration.ConfigurationSettings.
        AppSettings["ConnString"]);
    //Use a string builder to hold our SQL command 
    StringBuilder sb = new StringBuilder();
    sb.Append("select s.id, s.name, t.name as [type], t.length ");
    sb.Append("from syscolumns s ");
    sb.Append("inner join systypes t ");
    sb.Append("on s.xtype = t.xtype ");
    sb.Append("where id = (select id from" + 
              " sysobjects where name='" + strName + "')");
    //Use a SqlDataAdapter to fill a datatable, 
    //using the above command 
    SqlDataAdapter adapter = new SqlDataAdapter(sb.ToString(), cn);
    DataTable dt = new DataTable();
    try 
    {
        cn.Open();
        adapter.Fill(dt);
        //Bind the resulting table to the grid 
        this.dgEnum.DataSource=dt;
        this.dgEnum.DataBind();
    }
     catch (Exception exc)
    {
         //Send the exception to our exception label 
         this.lblException.Text = exc.ToString();
    }
    finally 
    {
        //Clean up the connection
        cn.Close();
    }
}

Points of Interest

There has been a lot of concern over the past few years about SQL injection attacks. As a web programmer, you leave yourself wide open to this when you utilize raw SQL and query strings. If you decide to use the above SQL or code, I'd recommend compiling the SQL into parameterized stored procedures, and executing them that way. I left them as raw SQL here for the purpose of illustration.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

UsualDosage
Web Developer
United States United States
Member
I have been an ASP.NET/C# Programmer for about 7 years, specializing in business applications for financial institutions. I formerly wrote business applications for mortgage banking front-ends in C++ before switching to the .NET Framework, which I program in almost exclusively, now, except for my occasional contract dalliances in PHP and MySQL, which I really like. I especially enjoy graphic design, and web work.

In my spare time I run the local internet radio portal Jaxrockradio.com.

I have long moonlighted as an ANSI C programmer for several online MUDs (still a hobby of mine), and probably will continue to as long as they let me.

You can view my blog by visiting http://www.usualdosage.com.

My site design portfolio is located at http://design.usualdosage.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionC# access to SQL Server Stored ProcedurememberLeifDalkarChr12 Jan '10 - 4:03 
When using the code below, I got the message:
 
Could not find stored procedure 'sp_xxx'
The database open is OK
The SP exist.
 
Using .Net 3.5 and SQL Server 2005
 
Hope anybody can help me.
Thanks in advance.
 

The code:
 
SqlConnection Connection = new SqlConnection(
@"Data Source=" + Utility.str_Server +
"Initial Catalog=" + Utility.str_Catalog);
 
Connection.Open();

SqlCommand Command = new SqlCommand("SP_Login", Connection);
 
Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = Utility.var_Brugernavn;
Command.Parameters.Add("@password", SqlDbType.NVarChar, 50).Value = Utility.var_Kodeord;
 
// OUTPUT parametre
SqlParameter param2 = new SqlParameter("@accessLevel", SqlDbType.Int, 0, ParameterDirection.Output, false, 0, 0, "accessLevel", DataRowVersion.Default, null);
Command.Parameters.Add(param2);
 
SqlParameter param3 = new SqlParameter("@UserID", SqlDbType.Int, 0, ParameterDirection.Output, false, 0, 0, "UserID", DataRowVersion.Default, null);
Command.Parameters.Add(param3);

if ( ConnectionState.Open == Connection.State )
{
Command.Connection = Connection;
 
try
{
Command.ExecuteNonQuery();
Utility.var_pwLevel = Convert.ToUInt32(((SqlCommand)Command).Parameters["@accessLevel"].Value);
Utility.var_UserID = Convert.ToUInt32(((SqlCommand)Command).Parameters["@UserID"].Value);
return true;
}
catch (Exception e)
{
//Send the exception to our exception label
//this.lblException.Text = exc.ToString();
Console.WriteLine(e.ToString());
return false;
}
finally
{
Connection.Close();
}
 
}
else
{
return false;
}
}
GeneralThanksmemberAhmed R El Bohoty17 Nov '08 - 7:42 
Thanks for your effort
 
Discover Other ....
http://www.islamHouse.com

GeneralFix for NVARCHARmemberTallBear11 Dec '07 - 6:50 
The SQL code you have will return 2 records for a parameter of type NVARCHAR. Change it to:
inner join systypes t on s.xtype = t.xusertype
 
Thanks for the article.
GeneralLong LinememberJay Giganti25 Jan '07 - 11:42 
How do you handle the case when the stored procedure is more than 4000 characters?
 
Some of my procedure text is getting chopped off after 4000 characters
GeneralRe: Long LinememberUsualDosage26 Jan '07 - 4:07 
The name of your stored procedure is over 4000 characters long?! If that's what you're saying, I'm not sure it's possible. The datatype for the [name] column in sysobjects is sysname, which is a user-defined datatype that is used in the system tables whose definition is varchar(30) "NULL". So, I'm not sure how a 4,000 character SP name would fit into that column...
 
If your talking about the stored procedure text, I'm not enumerating that in this example, so you must have changed something in the code. This example enumerates names and parameters of stored procedures. If you have a name or a parameter name > 4000 characters...well...I don't know what to tell you...

 
Quae narravi nullo modo negabo.

GeneralRe: Long LinememberJay Giganti26 Jan '07 - 5:28 
Yes I had changed it to retrieve the text of the stored procedure,
 
I was hoping for an automated way to track the changes to the stored procs across multiple databases but it seems if the stored proc is more than 4000 characters it gets truncated.
 
I figure it is kept somewhere .. I am in the process of tracking it down.
GeneralShould use standard SQL sp for thismemberJanvdK10 Jan '06 - 8:33 
I recommend to use sp_sproc_columns to get parameter info.
 
Jan van der Kruyk
GeneralRe: Should use standard SQL sp for thismemberHyperX2 Feb '06 - 5:17 
Excellent tip! Thanks!
GeneralRe: Should use standard SQL sp for this [modified]memberLeblanc Meneses19 Jul '06 - 22:03 
Thats true but sometimes the sql is better in certain situations.
 
Probably the best example is if you were making a tree control that listed db items. sp, vw, tbl for a given database, but not just for mssql.
 
different databases will have a different hash other than ['PROCEDURE_NAME']
 
being able to use "AS" in plain sql will allow u to do something like this
 
while (reader.Read())
{
TreeNode spNode = new TreeNode(reader["STORED_PROCEDURE_NAME"].ToString(), 2,2);
parentNode.Nodes.Add(spNode);
}
 
where the reader contains data from mssql or mysql or ...
 

Although this is a specific example the example presented here is not obsolete. [i'm sure there are other reasons]
 
but yes i agree for simple use the sp is a good idea...way easier to remember

 
Object type. Can be one of these values:
C = CHECK constraint
D = Default or DEFAULT constraint
F = FOREIGN KEY constraint
FN = Scalar function
IF = Inlined table-function
K = PRIMARY KEY or UNIQUE constraint
L = Log
P = Stored procedure
R = Rule
RF = Replication filter stored procedure
S = System table
TF = Table function
TR = Trigger
U = User table
V = View
X = Extended stored procedure
 

another reason is for furthur filtering: consider the possible functions: IF, FN, TF
or stored procedures RF, X, P... you can't modify the where cause easily if your running an sp.
 

Leblanc Meneses
http://www.blogsyndrome.com
http://www.robusthaven.com
 

-- modified at 4:59 Thursday 20th July, 2006
NewsBad IdeamemberGrimolfr4 Jan '06 - 3:49 
You should never pull data directly from the sys... tables in a SQL Server database. That's what the INFORMATION_SCHEMA views exist for. (As Michael indicated.)
 
The system tables in a SQL Server database are undocumented for a reason. This gives Microsoft the ability to completely restructure the tables and their usage as they see fit from one SP to the next, and if it blows up someone's code (that did something along the lines of your article), then it's their own fault for selecting from undocumented data structures.
 
You should seriously consider looking into the INFORMATION_SCHEMA views and re-write your article to use that, instead.
 
(BTW, there's a function in SQL Server called object_id() that will give you the identity of an object in the database for use with other functions that require the object id.)
 

Grim
(aka Toby)
MCDBA, MCSD, MCP+SB

SELECT * FROM users WHERE clue IS NOT NULL
GO
(0 row(s) affected)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 3 Jan 2006
Article Copyright 2006 by UsualDosage
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid