Stored procedure without output parameter:
CREATE PROCEDURE Getstudentname
(#studentid INT -- Input parameter, Studentid of the student
)
AS
BEGIN
SELECT Firstname + ' ' + Lastname
FROM tbl_Students
WHERE studentid = #studentid
END
I executed the above stored procedure:
exec Getstudentname 2
Result is: Pankaj Kumar
where as stored procedure with output parameter:
CREATE PROCEDURE GetstudentnameInOutputVariable
(#studentid INT, -- Input parameter, Studentid of the student
#studentname VARCHAR(200) OUT -- Out parameter declared with the help of OUT keyword
)
AS
BEGIN
SELECT #studentname = Firstname + ' ' + Lastname
FROM tbl_Students
WHERE studentid = #studentid
END
I executed this stored procedure:
DECLARE #return_value int
EXEC #return_value = [dbo].[Getstudentname]
#studentid = 2
SELECT 'Return Value' = #return_value
GO
Result is: Pankaj Kumar
Your procedure may not select anything. Your OUT param could, for example, store the number of rows inserted into a programmatically created table. That output could then be the input for a subsequent EXEC.
Correct way to execute GetstudentnameInOutputVariable
DECLARE #return_value VARCHAR(200)
EXEC [dbo].[Getstudentname] 2,#return_value OUTPUT
SELECT 'Return Value' = #return_value
GO
There can be few number of scenario where you can use OUTPUT paramter,your example do not seem to be one of them.
When your proc return one value which normally indicate Flag .
Like in your example,
SELECT #studentname = Firstname + ' ' + Lastname FROM tbl_Students
I may need to select several column from tbl_Students ,so output column is not ideal.
Say I have a proc which does DML operation and in front end application like c#
I want only flag to know if given proc wa executed succesfully or some validation fail or some error,I need to know only Pass/Fail flag and will do work based on flag.
When you do DML operation only then ExecuteNonQuery is best choice.
Output paramter work best with EXecuteNonQuery.
So you should use Output parameter in this siutation.
Another situation is when you execute one proc and need 1 or 2 result of that proc to work in calling proc.
Then it is very convnient way.
You can return resultset also but to catch resultset you need to create temp
,it is little cumbersome.
Conclusion : It depend upon your real situation.
Related
I have a stored procedure A on server 1 that takes 2 parameters from the user, and then using a linked server (ew), pulls in the results (a table) from server 2.
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date OUTPUT,
#InvToDate date OUTPUT
AS
WITH CTE_Labor AS
(
SELECT blabla
FROM LinkedServer.Database.schema.table
<lots more ctes, etc.>
For performance, I'd like to instead have a stored procedure A still accept the 2 parameters, but then pass them on to stored procedure B that sits on Server 2, and return those results back to the user.
Say - I can put the stored procedure on server 2, and call it from Server 1
DECLARE #return_value int
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = '2022-10-01',
#InvToDate = '2022-10-31'
That works.
But I'm not clear on the syntax to do the above, but have those 2 parameters be entered by the user in stored procedure 1.
Clearly this attempt is wrong:
ALTER PROCEDURE dbo.StoredProc1
#InvFromDate DATE,
#InvToDate DATE
AS
BEGIN
DECLARE #return_value int;
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = #InvFromDate,
#InvToDate = #InvToDate;
RETURN #return_value;
END
Edit: Maybe this attempt isn't wrong.
It works when I right click and run the stored procedure, returning both the desired table and Return Value = 0. It just doesn't work when I point our front-end GUI at it. But that might not be a question for here.
Since you are already using a linked server you could utilise this openquery approach Insert results of a stored procedure into a temporary table
Noting the following:
OPENQUERY/ linked servers are generally bad but I'm sure you're all over this
parameter string concatenation is bad
Your wrapper proc has output parameters but I don't see any reason for it... so I've removed them. See if it makes a difference.
--
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date,
#InvToDate date
AS
DECLARE #sql VARCHAR(4000)
SET #sql = 'EXEC [DB].[Schema].[StoredProcB] #InvFromDate = ''' + FORMAT(#InvFromDate + 'yyyy-MM-dd') + ''',#InvToDate = ''' + FORMAT(#InvToDate,'yyy-MM-dd') + ''''
PRINT(#sql) -- for degbugging cause this never works first time
SELECT *
INTO #tmpTable
FROM OPENQUERY([LinkedServer], #SQL)
SELECT * FROM #tmpTable
Got it.
1.) For this method, have to go into the Linked Server, and set [Enable Promotion of Distribution Transaction] = FALSE.
2.) Syntax
Alter proc [dbo].[999_Test]
#InvFromDate date
,#InvToDate date
as
IF OBJECT_ID('tempdb..#tmpbus') IS NOT NULL drop table #tmpbus;
CREATE TABLE #tmpBus
(
Column 1 (datatype),
Column 2 (datatype),
etc. )
INSERT INTO #tmpBus
EXEC [LinkedServer].[DB].Schema.[StoredProcInLinkedServerO]
#InvFromDate,
#InvToDate;
select *
from #tmpBus
GO
I am facing some issues in saving the execution of stored procedure / scalar function into a table variable.
The function / stored procedure returns dynamic columns and I need to create a dynamic table to save the result of that function into it so that I can use the table.
Example: the stored procedure spGetEmployeeInfo could return employee name, employee id, etc. on such criteria they return only employee name,.
Is there a way to create a dynamic table and save the result into it after execute the stored procedure, or any suggestion.
Thanks
I don't like to get into this situation too often, but when I do, what I do is have the stored proc output into a global temp table. The name of the table is passed in as a parameter by the user. For instance:
create procedure dynamicBeCareful
#toggle bit,
#globalTempTableName varchar(50)
as
-- initializations
if left(#globalTempTableName,2) <> '##'
throw 50000, '#globalTempTableName must start with ##', 1;
declare #sql varchar(max);
-- build dynamic sql
if #toggle = 1
set #sql = 'select * into #tempTable from table1';
else
set #sql = 'select * into #tempTable from table2';
set #sql = replace(#sql, '#tempTable', #globalTempTableName);
-- terminations
exec (#sql);
declare #msg = 'Your results are in ' + #globalTempTableName;
print (#msg);
Then use it like this:
exec dynamicBeCareful 1, '##temp';
select * from ##temp;
Beyond just being dynamic in output, it also can get you out of nested insert-exec limitations.
When exactly do we use stored procedures with output parameters and when do we use stored procedures without parameters?
I base my question on an example:
Stored procedure with output parameter
CREATE PROCEDURE uspGetContactsCountByCity
#City nvarchar(60),
#ContactsCount int OUT
AS
BEGIN
SELECT #ContactsCount = COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing
DECLARE #ContactsTotal INT
EXEC uspGetContactsCountByCity #ContactsCount = #ContactsTotal OUT, #city = 'Berlin'
SELECT #ContactsTotal
Results: 2
Stored procedure without output parameter
CREATE PROCEDURE uspGetContactsCountByCity2
#City nvarchar(60)
AS
BEGIN
SELECT COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing:
EXEC uspGetContactsCountByCity2 #city = 'Berlin'
Results: 2
Both procedures return the same result, in same form, so what's the difference?
Basically, the result you're seeing is actually the result of your SELECT at the end of the procedure, which is doing the same thing.
Please take a look at this documentation:
If you specify the OUTPUT keyword for a parameter in the procedure definition, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits. To save the value of the parameter in a variable that can be used in the calling program, the calling program must use the OUTPUT keyword when executing the stored procedure.
So basically if you would like your stored procedure to just return just a value instead of a data set, you could use the output parameter. For example, let's take the procedures you have given as an example. They both do the same thing, this is why you got the same result. But what about changing a little bit in the first procedure that has the output parameter.
Here's an example:
create table OutputParameter (
ParaName varchar(100)
)
insert into OutputParameter values ('one'), ('two'),('three'),('one')
CREATE PROCEDURE AllDataAndCountWhereOne
#name nvarchar(60),
#count int OUT
as
Begin
SELECT #count = COUNT(*) from OutputParameter
Where ParaName = #name
select Distinct(ParaName) from OutputParameter
End
Declare #TotalCount int
Exec AllDataAndCountWhereOne #count = #TotalCount OUT, #name = 'One'
Select #TotalCount
With this example, you are getting all the distinct stored data in the table, plus getting the count of a given name.
ParaName
--------------------
one
three
two
(3 row(s) affected)
-----------
2
(1 row(s) affected)
This is one way of using the output parameter. You got both the distinct data and the count you wanted without doing extra query after getting the initial data set.
At the end, to answer your question:
Both procedures gives us the same result, in same form, so what's the difference?
You didn't make a difference in your own results, this is why you didn't really notice the difference.
Other Examples:
You could use the OUT parameter in other kinds of procedures. Let's assume that your stored procedure doesn't return anything, it's more like a command to the DB, but you still want a kind of message back, or more specifically a value. Take these two examples:
CREATE PROCEDURE InsertDbAndGetLastInsertedId
--This procedure will insert your name in the database, and return as output parameter the last inserted ID.
#name nvarchar(60),
#LastId int OUT
as
Begin
insert into OutputParameterWithId values (#name);
SELECT #LastId = SCOPE_IDENTITY()
End
or:
CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
--This procedure will only insert into the db if name does exist, but there's no more than 5 of it
#name nvarchar(60),
#ErrorMessage varchar(100) OUT
as
Begin
set #ErrorMessage = ''
if ((select count(*) from OutputParameterWithId) = 0)
begin
set #ErrorMessage = 'Name Does Not Exist'
return
end
if ((select count(*) from OutputParameterWithId) = 5)
begin
set #ErrorMessage = 'Already have five'
return
end
insert into OutputParameterWithId values (#name);
End
These are just dummy examples, but just to make the idea more clear.
An example, based on yours would be if you introduced paging to the query.
So the result set is constrained to 10 items, and you use a total count out parameter to drive paging on a grid on screen.
Answer from ozz regarding paging does not make sense because there is no input param that implements a contraint on the number of records returned.
However, to answer the question... the results returned by these stored procedures are not the same. The first returns the record count of contacts in given city in the out param ContactsCount. While the count may also be recieved in the second implement through examining the reader.Rows.Count, the actual records are also made a available. In the first, no records are returned - only the count.
I have a rather simple stored procedure that needs to return a results set, something like (the code is a highly simplified version of the real one, but is enough to describe my problem):
CREATE PROCEDURE MyProc(#Par1 VARCHAR(100))
AS
BEGIN
SELECT A,B,C FROM MyTable ;
END ;
This, so far, works perfectly as the invoking procedure does get the values A,B and C of all the records in that table.
Now, I need to allow the addition of "conditions" (i.e. WHERE clause) as provided through the received parameter Par1. To do that, I declare a new local variable aimed to hold a full SQL select statement that would include the conditions, so the same procedure would now look like:
CREATE PROCEDURE MyProc(#Par1 VARCHAR(100))
AS
BEGIN
DECLARE #SQLSTT VARCHAR(1000) ;
SET #SQLSTT = 'SELECT A,B,C FROM MyTable WHERE ' + #Par1 ;
EXECUTE ( #SQLSTT );
END ;
This ALMOST work: The correct number of records are affected, but they are not passed to the invoking procedure.
I thought of using a temporary table (or table variable), but it would be an unneeded overhead since, once the records are selected, there is no further manipulation to take place within this procedure and only need to be passed on to the invoking SP.
So, my question is: What should be the correct syntax to achieve what I want?
Thanks in advance.
EDIT
I found the issue. It had nothing to do with the procedure (i.e. MyProc) but rather with the way I was attempting to see the returned results. Quick fix and it all works are needed.
Thanks for all that took the time to walk though my question and send comments/suggestions/answers.
Declare a table to hold the return.
declare #ret table (a int, b int, c int)
insert into #ret
EXECUTE ( #SQLSTT );
You must use # in front of your parameter
The updated procedure is as follows
CREATE PROCEDURE MyProc(#Par1 VARCHAR(100))
AS
BEGIN
DECLARE #SQLSTT VARCHAR(1000) ;
SET #SQLSTT = 'SELECT A,B,C FROM MyTable WHERE ' + #Par1 ;
EXECUTE ( #SQLSTT );
END ;
This works fine. I changed it to use NVARCHAR. Please check how you are calling the procedure with appropriate single quotations:
CREATE PROCEDURE MyProc(#Par1 NVARCHAR(100))
AS
DECLARE #SQLSTT NVARCHAR(1000) ;
SET #SQLSTT = N'SELECT A,B,C FROM MyTable WHERE ' + #Par1 ;
EXEC( #SQLSTT )
Example call:
exec MyProc 'A <>''myvalue'''
I want to use SQL Server 2014 stored procedure in Report Builder.
ALTER PROCEDURE [dbo].[getCharacterDetails]
#id int
,#name VARCHAR(200) = '' OUTPUT
,#level int = 0 OUTPUT
AS
BEGIN
SELECT
#name = name, #level = level
FROM
dbo.Characters
WHERE
id = #id;
RETURN
END
I want to use #id as an input parameter and name and level as output only parameters.
When I call the procedure using Report Builder I get no data.
When I execute a query:
exec [dbo].[getCharacterDetails] #id= 1;
I also get no result values, only (1 row(s) affected) or Commands completed successfully.
The table Characters contains 1 row with id=1, so the select is correct.
Am I doing it right? Should I be using stored procedures or maybe UDF?
I'm new to SQL Server.
No, this stored procedure definitely doesn't return rows - because you're capturing the values into output parameters.
If you want to return rows - do not assign those columns to variables! Just write the select"as is".
So just this this SELECT statement instead:
SELECT
name, level
FROM
dbo.Characters
WHERE
id = #id;
and your stored procedure will now return a result set of data.
Try this:
ALTER PROCEDURE [dbo].[getCharacterDetails]
#id int
,#name VARCHAR(200) = '' OUTPUT
,#level int = 0 OUTPUT
AS
BEGIN
SELECT
name, level
FROM
dbo.Characters
WHERE
id = #id;
RETURN
END
Try running the stored procedure as:
declare #name VARCHAR(200);
declare #level int;
exec dbo.getCharacterDetails 1, #name output, #level output;
select #name, #level;
You have to provide the arguments and then look at them afterwards. That is how output parameters work.
If you want the stored procedure to return rows, then don't assign the values, or you can do both. The body could be:
SELECT #name = name, #level = level
FROM dbo.Characters
WHERE id = #id;
SELECT #name, #level;
And, for such a simple process, you might want just a view or user defined function.
Your data is cached, delete the data file (rdl.data) it's in the same folder your rdl is in
The name and level parameters serve no purpose. Remove them.
ALTER PROCEDURE [dbo].[getCharacterDetails]
#id int
AS
BEGIN
SELECT
name, level
FROM
dbo.Characters
WHERE
id = #id;
RETURN
END
call it like this:
EXEC [dbo].[getCharacterDetails] #ID
and make sure you map a SSRS parameter to the input parameter #ID in the parameters tab.
If you still don't get anything use SQL Profiler to work out what parameter it's passing in.