Is it possible to get the column name/types from a stored procedure in an empty DataTable without calling the stored procedure?
This stored procedures also have parameters which I dont want to provide.
Is this possible or do I have to rethink my approach?
In Sql Server 2012 they introduced a function called dm_exec_describe_first_result_set_for_object which does exactly what you want. As long as your procedure only is returning one result set.
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
OBJECT_ID('master.sys.sp_who'),
NULL
);
Another option is to use FMTONLY and then call the procedure. Executing this will get you an empty datatable with the correct column names.
In this case you would need to supply the parameters for the stored procedure.
SET FMTONLY ON;
exec sp_who
FMTONLY is deprecated as of Sql Server 2012 so I would avoid it if possible.
Related
I have a stored procedure with couple parameters. My data table type has 2 columns (int, nvarchar).
When I run this stored procedure and pass IEnumerable<SqlDataRecords> with defined type then query results on my machine is 9 times slower than the same stored procedure without passing this parameter.
The stored procedure doesn't touch this param. Only passing.
It looks like something (sql server?) do with data passed as structured (table-valued) value.
Maybe I am missing something. Maybe there is special switch to:
off any kind of validation
anything else?
Type:
CREATE TYPE dbo.MyData AS TABLE
(
[Ver] INT NOT NULL,
[Name] NVARCHAR(225) NOT NULL
)
Stored procedure:
CREATE PROCEDURE [dbo].[SaveData]
(#Id UNIQUEIDENTIFIER, #Data MyData READONLY)
AS
BEGIN
SET NOCOUNT ON;
END
UPDATE 1:
I've changed query. This stored procedure does nothing. Difference is in passing value or null.
UPDATE 2:
Added stored procedure and type definition.
UPDATE 3:
I'm using SQL Server 2014 Express.
UPDATE 4:
5000 iterations with parameter takes 11281ms (443/sec), without table-valued param - 1029ms (4856/sec).
I would advise running SQL Profiler to examine your queries on the database. You can also look into using SSMS Activity Monitor by right clicking on the database, by clicking on 'activity monitor', and may get lucky and see a 'recent expensive query'.
hth
I want to know whether there is any way besides the OUT parameter to get data from stored procedure into C# code.
Today my colleague told me that all select queries and the OUT parameters in a stored procedure are returned to the C# code. Is this correct? If yes, then how do I choose which results should be returned?
Is the answer same in case of VB6 code instead of c#?
Yes you can return values back to your application from a SP using either OUT parameters or a SELECT within the SP.
The OUT parameters are generally used for single values. The SELECT can be used for returning rows of results. A combination of both can be used in many different variations, such as the SP will return rows and a status OUT parameter can indicate row count or existence of the requested data.
CREATE PROC usp_MySpecialSP
#conditionValue INT, #SPStatus INT OUT
AS
IF EXISTS(SELECT * FROM TableName WHERE column1=conditionValue)
BEGIN
SELECT #SPStatus=COUNT(*) FROM TableName WHERE column1=conditionValue
SELECT Column2, Column3, Column4 FROM TableName WHERE column1=conditionValue
END
ELSE
BEGIN
SELECT #SPStatus=0
END
GO
Here you can pickup values if the m_SPStatusReturned>0.
Check out below MSDN article how to pick up returned rows from SP
http://msdn.microsoft.com/en-us/library/d7125bke.aspx
or a single value using SELECT
http://msdn.microsoft.com/en-us/library/37hwc7kt.aspx
Yes it is correct - and the way you handle this is:
to get an OUT parameter, you need define a SqlParameter on your SqlCommand with ParameterDirection.Output
to get the result set of the SELECT in a stored procedure, you need to use a SqlDataReader or a SqlDataAdapter to get the results (as if you execute an inline SQL SELECT query)
and there's actually a third way : the RETURN keyword inside a stored procedure - typically used to return a numeric status value. You can capture that by using a SqlParameter with a value of ParameterDirection.ReturnValue
On SQL 2005 I have a simple SP that selects rows from a table. The SP does not use temporary tables or return multiple result sets. In VS2010 I drag the SP from the Server Explorer to the DBML designer and the SP is added to the LINQ data context. Everything works okay. If I then script the table and SP on to another live SQL 2005 server I am getting the error "The return types for the following stored procedures could not be detected .. " Like I say, no temp tables or multiple result sets that would typically produce this error. Could there be something else on the server causing this?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spUsers]
AS
BEGIN
SET NOCOUNT ON;
SELECT top 100 * from Users
END
Make sure you have:
SET NOCOUNT ON;
as the first line in your SP after the 'BEGIN' statement.
If your SP does not have this, then it returns messages like
'10 Rows affected...'
Which Linq tries to interprete as part of the function result. Iv'e had it bite me loads of times!!
This is a known issue with Linq to SQL, and a frustrating one. It also seems to be somewhat unpredictable. The only way I have gotten around this, reliably, is by not having L2S call a stored procedure when I need it to return a result set. I have it call a table-valued UDF instead. L2S seems to have no problems with these, and I've never experienced any problems using them.
Okay, the reason it was failing on the live server is to do with privilages needed to access the meta-data on the DBMS. These are needed to create the return value data type from the SP. By elevating the SQL user account and then dragging the SP on onto the DBML designer .. bingo .. it works!
Use
create procedure Getxxxxxxx
#xxxxx uniqueidentifier
,#xxxxx uniqueidentifier
set fmtonly off
//you query
set fmtonly on
I have been using a stored procedure for more than 1.5 years. But I've never considered how data is retrieved from the UI or within another stored procedure.
When I write a simple stored procedure.
eg.
CREATE PROCEDURE sp_test
AS
BEGIN
SELECT * FROM tblTest --Considering table has 3 columns.
END
How does C# gets this result into DataTable.
Whenever I have to use the result of this procedure in another procedure, I think we have to create a table valued parameter using the table datatype and assign its result to a table variable. I've never tried it.
CREATE PROCEDURE sp_testcall
AS
BEGIN
#temp = exec sp_test -- I think this would be the way, never tried
END
If the above sample code is true, then what is the difference between using the above method and a query to insert records into a temporary table?
CREATE PROCEDURE sp_test
AS
BEGIN
SELECT * INTO #tmp FROM tblTest --Considering table has 3 columns.
END
It would seem that copying the result into a temporary table requires another effort by sql server.
But what would be going on behind the scenes? Would it directly assign references of the result into a table valued parameter or does it use the same process as a temporary table?
My question might not be clear. But I will try to improve.
For an beginer to intermediate level you should always consider #temp tables and #table variables two faces of the same coin. While there are some differences between them, for all practical purposes they cost the same and behave nearly identical. The sole major difference is that #table variables are not transacted and hence not affected by rollbacks.
If you drill down into details, #temp tables are slightly more expensive to process (since they are transacted) but on the other hand #table variables have only the lifetime of a variable scope.
As to other issues raised by your question:
table value parameters are always read only and you cannot modify them (insert/update/delete into them)
tacking the result set of a procedure into a table (real table, #temp table or #tabel variable, doesn't matter) can only be done by using INSERT INTO <table> EXEC sp_test
as a rule of thumb a procedure that produces a result that is needed in another procedure is likely to be better of as a User Defined Function
The topic of sharing data between procedures was analyzed at length by Erland Sommarskog, see How to Share Data Between Stored Procedures.
A select means "return data to client". C# is a client, therefore it gets the data.
Then again, it's not exactly C# that does it, it's ADO.NET. There's a data provider that knows how to use a network/memory/some other protocol to talk to the SQL server and read data streams it generates. This particular client (ADO.NET) uses the received data to construct certain classes, such as DataTable, other providers can do something completely different.
All that is irrelevant at SQL Server level, because as far as the server is concerned, the data has been sent out using the protocol with which the connection was established, that's it.
From inside, it doesn't make much sense to have a stored procedure return simply selected data to anything else.
When you need to do that, you have the means to explicitly tell SQL Server what you want, such as inserting the data into a temporary table available to both involved SPs, inserting data into a table-valued parameter passed to the procedure, or rewriting your stored procedure as a function that returns a table.
Then again, it's not exacly clear to me what you were asking about.
I am making a windows service to be able to run operations on a sql server database (insert, edit, etc) and invoke Stored Procs.
However, is there a way for me to know the type of the SP? When invoking from C#, I need to knof if it is returning 1 value, or more, or none (so I can use executereader, scalar, etc)?
Thanks
A non-query is usually called with SqlCommand.ExecuteNonQuery(). But it's valid to run it as SqlCommand.ExecuteReader(). The only difference is that the first call to DataReader.Read() returns false for a stored procedure that does not return a resultset.
A rowset is run as SqlCommand.ExecuteReader(). The first call to DataReader.Read() will return true.
A scalar is just a shortcut for a rowset with one column and one row.
So you can use ExecuteReader in all three scenarios.
Though it seems unnecessary for your question, you can retrieve meta-data for the resultset using the fmtonly option. The setting causes the statement to return the column information only; no rows of data are returned. So you could run:
SET FMTONLY ON;
EXEC dbo.YourProc #par1 = 1;
SET FMTONLY OFF;
Executing this as a CommandText from C#, you can examine the column names the stored procedure would return.
To verify that a stored procedure run in this way does not produce any side effects, I ran the following test case:
create table table1 (id int)
go
create procedure YourProc(#par1 int)
as
insert into table1 (id) values (#par1)
go
SET FMTONLY ON;
EXEC dbo.YourProc #par1 = 1;
SET FMTONLY OFF;
go
select * from table1
This did not return any rows. So the format-only option makes sure no actual updates or inserts occur.