Can anyone tell me how I can control the output from an SQL stored procedure that returns more than one set of output?
I am currently doing the following:
DataTable allData = new DataTable();
SqlConnection connection = new SqlConnection(mySource);
SqlCommand cmd = new SqlCommand(procedureName, connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(paramName, SqlDbType.Int);
cmd.Parameters[paramName].Value = paramValue;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(allData);
connection.Close();
Now this works fine if the procedure has only one output value, but how do I deal with the following:
My stored procedure broadly does the following:
It calls a number of other stored procedures in order to construct a dynamic SQL query (lets call this #query) and then calls EXECUTE(#query) which does a SELECT.
Using the code snippet above returns the result from the SELECT query, which is fine. But what I would also like it so have the string #query returned. I can specify it as an output type and let SQL fetch it, but how do I access it from c#? (Actually, more specifically, when I do this the code snipped above returns only the string #query and no longer returns the results of the SELECT)
Thanks
Karl
You can do like this:
DataSet allData = new DataSet ();
...
...
...
adapter.Fill(allData);
then each result of the select is in different dataTable
Using SqlDataReader.NextResult .
This little bit shifts you from using SqlDataAdapter, but you still is able to populate DataTable with DataTable.Load
Related
[Edit - an explanation of the answer is at the foot of the question because the subtlety is not totally obvious from the accepted answer.]
Original question:
I am looking for a quick 'yes this approach should be possible' answer before I commit further effort.
Scenario:
I have a simple SQL Server stored procedure that runs a query. I also want to (1) return a varchar(100) parameter declared as OUTPUT, and (2) use the #ReturnValue to return a further (integer) value.
I call this procedure from C# using the SqlDatAdapter.DataSet.Fill() approach.
Back in the C# code, I can access the procedure parameters but I cannot get the values of either #ReturnValue or the other OUTPUT param.
What am I expecting ?
The SqlDataAdapter fill process to grab the data from the select. This works and I can access this data in C#.
The values of the SQL Server stored procedure params marked as OUTPUT, and the automatic #ReturnValue param, to be available in C#.
What do I see ?
Data is returned from the query as expected.
The SQL command parameters are present in C#, but their .Value properties are blank.
What research have I done ?
A lot of googling for hits containing SqlDataAdapter and #returnvalue. No significant positive results.
Perused the old SO questions related to SqlDataAdapter - nothing seems to overlap my question.
Posted this question.
I need to ask the SO community if this is even possible. So - is it possible to collect OUTPUT parameter values from a stored procedure that was used with SqlDatAdapter.DataSet.Fill() ?
If the answer is yes and there are no simple examples out there then I'll cut down my code to a representative case and post it here for (hopefully) community debugging.
EDIT
Thanks to #NDJ and the sample code supplied I was able to confirm that SqlDatAdapter.DataSet.Fill() DOES NOT interfere with stored procedure return values. I was then able to go on to discover that my issue was caused by an immediate call to SqlDatAdapter.DataSet.FillScheam(). This delivers the metadata for the data table into a handy matrix that we can access from C#, which is part of my use case.
However, FillSchema() clears the stored procedure parameter values. In my code I was trying to gather the stored procedure output parameter values after the call to FillSchema, which was the cause of what I witnessed. I could not find any documentation on this point.
If your code looks like this, it will work.
da.Fill(ds);
var returnVal = returnParam.Value; // value as expected
da.FillSchema(ds, SchemaType.Source);
If your code looks like this it will not work
da.Fill(ds);
da.FillSchema(ds, SchemaType.Source);
var returnVal = returnParam.Value; // value reset by prev line !!!!
yes you can.
Create PROCEDURE TestSP
#test varchar(max) output
AS
BEGIN
select #test = 'abc'
select top 10 * from MyTable
return 4
END
using (SqlConnection connection = new SqlConnection(conString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("TestSP", connection);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#test", SqlDbType.VarChar, -1);
param.Direction = ParameterDirection.Output;
var returnParam = cmd.Parameters.Add("#Return", SqlDbType.Int);
returnParam.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(param);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
var returnVal = returnParam.Value; //4
var output = param.Value; // abc
var data = ds.Tables[0].Rows[0][0]; //data from my table
}
In How to use a DataAdapter with stored procedure and parameter, the data adapter's selectCommand property has been used. Can the same be used if a stored procedure updates as well as retrieves data from a database?
On implementing it, and using the selectCommand (and not the property, it seems to work alright.
...
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlQuery, sqlConnection);
foreach (SqlParameter sqlParameter in sqlParameterCollection)
{
sqlCommand.Parameters.Add(new SqlParameter(sqlParameter.ParameterName, sqlParameter.Value));
}
sqlDataAdapter.SelectCommand = sqlCommand;
DataSet dataSet = new DataSet();
sqlDataAdapter.Fill(dataSet);
...
The short answer is yes. Passing parameters to a stored procedure which updates and returns values is no different from the SqlDataAdapter side compared to a stored procedure that only returns values based on parameters passed in.
How can i use an SqlDataAdapter to execute an sql stored procedure that contains statements which update one table and insert into another table, but returns no value?
EDIT:There are answers related to the execution of stored procedures with SELECT statements. However, that's not what i'm looking for.
I'm assuming you're using the SqlDataAdapter to populate a DataTable or DataSet object. If this is the case and you want the changes to the DataTable/DataSet to be persisted to your database and you require using stored procs then you'd need to set the UpdateCommand, InsertCommand, and/or DeleteCommand properties.
Example:
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM WHATEVER", connection);
adapter.UpdateCommand = new SqlCommand()
{
Connection = connection,
CommandText = "EXEC myStoredProc",
CommandType = CommandType.StoredProcedure
};
//Don't forget to set your parameters!
Otherwise if you don't need the adapter just use a SqlCommand and call ExecuteNonQuery()
If the statement returns no data, you wouldn't use a SqlDataAdapter. Just use a SqlCommand and call ExecuteNonQuery().
I have created a few stored functions in SQL Server that return a table via a select statement. Like so:
CREATE FUNCTION [dbo].[mFunSelectStudents] ()
RETURNS #result TABLE
(IDStudent int,
Name nchar(50),
Password nchar(50))
AS
BEGIN
INSERT INTO #result select * from School.dbo.Student
RETURN
END
I tried to assign the function to an SqlDataAdapter in c# like this:
SqlCommand cmd = new SqlCommand("mFunSelectStudents", con);
SqlDataAdapter adpStudents = new SqlDataAdapter();
adpStudents.SelectCommand = cmd;
But this doesn't work..
Where #result is a return parameter of the stored function. Now, how do I call the function in C# and assign the data to a grid ?
Any help is appreciated..
The command cannot be just the name of the function. You are supposed to put a SQL command there, and in SQL one retrieves data from a TVF by SELECTing from it, like this:
SELECT * FROM dbo.mFunSelectStudents()
Consequently, the first line of your C# code snippet should be:
SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.mFunSelectStudents()", con);
Wrap the function in a stored procedure, or do the work itself in a SP. The results of a single select statement will be accessible as a DataTable in the C# client.
create proc selectSomeData
.
.
.
In the client, your commandType would be StoredProcedure and the CommandText would be the name of the sp.
Your first line :
SqlCommand cmd = new SqlCommand("mFunSelectStudents", con);
Is correct, however this one you should check it
SqlDataAdapter adpStudents.SelectCommand = cmd;
First you need to use new with the SqlDataAdapter before you can assign the selectCommand, as follows:
SqlDataAdapter adpStudents = new SqlDataAdapter(cmd);
Assign the command to the DataAdapter
adpStudents.SelectCommand = cmd;
And then you prepare a Dataset
DataSet ds = new DataSet();
Fill it with your DataAdapter
adpStudents.Fill(ds);
Assign it to your grid
gridName.DataSource = ds;
And call DataBind to update the info on the grid
gridName.DataBind();
I have a procedure, I want to read schema of the procedure. To retrieve view schema I use the query shown here. Same way I want to get schema of stored procedure. How to get it? Plz show some syntax.
public static DataTable SchemaReader(string tableName)
{
string sql = string.Format("Select * from {0}", tableName);
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandType = CommandType.Text;
SqlDataReader reader = cmd.ExecuteReader();
DataTable schema = reader.GetSchemaTable();
reader.Close();
conn.Close();
return schema;
}
If have any query plz ask.Thanks in advance.
you could do
public static DataTable SchemaReader(string tableName)
{
string sql = "MySP";//replace this with your store procedure name
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader reader = cmd.ExecuteReader();
DataTable schema = reader.GetSchemaTable();
reader.Close();
conn.Close();
return schema;
}
Hope this help
This is an answer that does not call the SP - if you do, you may inadvertently affect data:
SELECT * FROM sys.dm_exec_describe_first_result_set ('owner.sprocName', NULL, 0) ;
This returns the result set :
is_hidden
column_ordinal
name
is_nullable
system_type_id
system_type_name
max_length
precision
scale
collation_name
user_type_id
user_type_database
user_type_schema
user_type_name
assembly_qualified_type_name
xml_collection_id
xml_collection_database
xml_collection_schema
xml_collection_name
is_xml_document
is_case_sensitive
is_fixed_length_clr_type
source_server
source_database
source_schema
source_table
source_column
is_identity_column
is_part_of_unique_key
is_updateable
is_computed_column
is_sparse_column_set
ordinal_in_order_by_list
order_by_is_descending
order_by_list_length
error_number
error_severity
error_state
error_message
error_type
error_type_desc
You could get information about a stored procedure's parameters but, without executing it, SQL Server cannot tell you the structure of the dataset(s) returned by the stored procedure. Since executing a stored procedure can have side effects, ADO.NET doesn't provide a method for telling you what the result set(s) would look like were the stored procedure to be executed. Furthermore, the result set(s) might change depending on the parameters passed to the procedure when it is executed.
I am not getting your question clearly I think this would work with you
Select *
from sys.objects
where type='p' and name = (procedure name)
Replace your query with this and it will work fine
I've created various code generators that use the output of stored procs. In my experience, most procedures that SELECT anything output their schema just the same if you call them with null (DbNull.Value) as the value for all parameters. You can get the parameter list itself from system views, though I find it convenient to use INFORMATION_SCHEMA.PARAMETERS.
By executing the procedure in a transaction and always rolling back you can safely execute stuff even when you have no idea what the procedure does.
You'll probably need a basic GUI and allow the user to modify the parameters - or a config file or some other way to provide parameter values for specific procedures. A stored proc may produce output with different schemas depending on the parameters, though I haven't seen many that do.
App.config
<appSettings>
<add key="Schema_Name" value ="[dev]."/> <!-- use any one [dev]. or [dbo]. -->
</appSettings>
c# read Key
string schema_Name = Configuration["Schema_Name"].ToString();
Store Procedure
SqlConnection objConn = new SqlConnection(Connection);
objConn.Open();
SqlCommand cmd = new SqlCommand("Exec WLTCVarification", objConn);
cmd.Parameters.Add("#SchemaName", SqlDbType.Text);
cmd.Parameters["#Schema_Name"].Value = schema_Name; // dev or dbo;
rowsAmount = (string)cmd.ExecuteScalar();
objConn.Close();
c# Sql Query
SqlConnection objConn = new SqlConnection(Connection);
objConn.Open();
SqlCommand cmd = new SqlCommand("select * from " + schema_Name + "receive_agv_onlyerror, objConn);
rowsAmount = (string)cmd.ExecuteScalar();
objConn.Close();