I am using SQL Server 2008 Enterprise. I am learning OUTPUT parameter of SQL Server stored procedure. For example, stored procedure sp_add_jobschedule has an OUTPUT parameter called schedule_id.
http://msdn.microsoft.com/en-us/library/ms366342.aspx
My confusion is, looks like OUTPUT parameter could be provided an input value and also returns a value, looks like it has behaviors of both INPUT and OUTPUT parameter? Is it allowed not to provide any INPUT values for OUTPUT parameter (to make it look like pure output parameter behavior)?
The confusion is justified to a degree - and other RDBMS like Oracle do have stored procedure parameters which can be of type IN (input only), OUT (output only), or INOUT (both ways - "pass by reference" type of parameter).
SQL Server is a bit sloppy here since it labels the parameter as OUTPUT, but really, this means INPUT/OUTPUT - it basically just means that the stored proc has a chance of returning a value from its call in that parameter.
So yes - even though it's called OUTPUT parameter, it's really more of an INPUT/OUTPUT parameter, and those IN, INOUT, OUT like in Oracle do not exist in SQL Server (in T-SQL).
I can give you short example on how to create stored procedure with output parameter.
CREATE PROCEDURE test_proc
#intInput int,
#intOutput int OUTPUT
AS
set #intOutput = #intInput + 1
go
And to call this procedure and then use output parameter do as following:
declare #intResult int
exec test_proc 3 ,#intResult OUT
select #intResult
You see, that you should declare ouput variable first. And after executing stored procedure, the output value will be in your variable. You can set any value to your output variable, but after executing stored procedure it will contain exactly what stored procedure return (no matter what value was in the output variable).
For example:
declare #intResult int
exec test_proc 3 ,#intResult OUT
select #intResult
It will return 4. And:
declare #intResult int
set #intResult = 8
exec test_proc 3 ,#intResult OUT
select #intResult
Also return 4.
Yes, you can use an OUTPUT parameter for both passing in and retrieving values (although I can't think of a good reason to do that at the moment).
Here's a trivial example that demonstrates this:
-- The stored procedure
CREATE PROCEDURE OutParamExample
#pNum int OUTPUT
AS
BEGIN
select #pNum
set #pNum = #pNum + 5
END
GO
-- use a local variable to retrieve your output param value
declare #TheNumber int
set #TheNumber = 10
print #TheNumber
exec OutParamExample #TheNumber OUTPUT
print #TheNumber
The results will look like this:
10
-----------
10
(1 row(s) affected)
15
EDIT: OK, I think I missed a "not" in the second paragraph and may not have answered the question you asked. If you want a strict output parameter (e.g. something like a return code), you certainly don't have to provide a value to the local variable passed as the output parameter, but you still have to declare that local variable so that you'll have a way of accessing the returned value outside of the scope of the procedure itself.
For example:
declare #LocalNumber int
-- I don't have to assign a value to #LocalNumber to pass it as a parameter
exex OutParamExample #LocalNumber OUTPUT
-- (assume SP has been altered to assign some reasonable value)
-- but I do have to declare it as a local variable so I can get to
-- the return value after the stored procedure has been called
print #LocalNumber
Adding further to what others have said above, OUTPUT parameters can act as INPUT as well as OUTPUT. But, it depends on the stored procedure to use the value passed to it.
If the stored procedures ignores the value passed in for OUTPUT parameter (which it generally should), the INPUT value gets ignored anyway.
Using Sergey's code, I can use the value user passed for #intOutput (if I need to)
create PROCEDURE test_proc
#intInput int,
#intOutput int OUTPUT
AS
set #intOutput = #intOutput + 1
go
But, that defeats the purpose of OUTPUT parameter.
To give a different view, c# compiler forces you to overwrite the out parameter's value by assignment (without using the output parameter).
e.g. I cannot do this in c#. Here it acts as only out parameter (i.e ignore the value user passed to this function)
static void dosomething(out int i)
{
//i = 0;
i = i + 1;
}
The question is - why do you want to disallow to provide input? This makes no sense whatsoever. Consider this simple example:
CREATE PROCEDURE test (#param AS INT OUTPUT) AS
BEGIN
SET #param = 100
END
GO
DECLARE #i INT
SET #i = 0
EXECUTE test #i OUTPUT
PRINT #i
DROP PROCEDURE test
This prints
100
See - how are you supposed to get a value out if you do not put a variable in first?
Think about OUTPUT PARAMETERS as passed by reference in programming languages, it's the same. The best example I can think right now is returning error code. You want some insert... if you select the return code from the SP you have to fetch it back in your code, with OUTPUT parameter you don't have, it will be already in your parameter (I mean using C# commands, PHP init stored proc methods, or something different then constructing strings)
One additional note regarding part of the original question:
"Is it allowed not to provide any INPUT values for OUTPUT parameter (..)?"
In SQLServer it is possible to specify a default value for an OUTPUT parameter (which as others have pointed out actually INOUT). Consider the following example in which you could specify a explicit value or let the function itself generate an ID.
CREATE PROCEDURE test (#id uniqueidentifier = NULL OUTPUT) AS
BEGIN
IF #id IS NULL SET #id = NEWID()
-- INSERT INTO xyz (...) VALUES (#id, ...)
PRINT 'Insert with id: ' + CAST (#id as nvarchar(36))
END
GO
DECLARE #insertedId uniqueidentifier
EXECUTE test '00000000-0000-0000-0000-000000000000'
EXECUTE test #insertedId OUTPUT
PRINT #insertedId
DROP PROCEDURE test
This prints
Insert with id: 00000000-0000-0000-0000-000000000000
Insert with id: 67AE3D27-8EAB-4301-B384-30EEA1488440
67AE3D27-8EAB-4301-B384-30EEA1488440
Two other things I think that are worth noting:
1) You can pass more than one parameter as OUTPUT,
2) You do not have to call the parameters with OUTPUT if you don't want the results
CREATE PROCEDURE ManyOutputs #a int, #b int output, #c varchar(100) output, #d bit output
AS
BEGIN
SET #b = #a + 11
SET #c = 'The Value of A is ' + CAST(#a AS varchar(5)) + ', and the value of B is ' + CAST(#b AS varchar(5))
IF (#a % 2 = 1)
SET #d = 1
ELSE
SET #d = 0
END
GO
Calling this routine:
DECLARE #bVal int
DECLARE #cVal varchar(100)
DECLARE #dVal bit
EXEC ManyOutputs 1, #bVal, #cVal, #dVal
SELECT #bVal AS bVal, #cVal as cVal, #dVal as dVal
Returns NULL, NULL, NULL
EXEC ManyOutputs 2, #bVal OUT, #cVal OUT, #dVal OUT
SELECT #bVal AS bVal, #cVal as cVal, #dVal as dVal
Returns 13, "The Value of A is 2, and the value of B is 13", 0
EXEC ManyOutputs 3, #bVal, #cVal, #dVal
SELECT #bVal AS bVal, #cVal as cVal, #dVal as dVal
Returns 13, "The Value of A is 2, and the value of B is 13", 0
(the same as the last call, because we didn't get new values by using OUTPUT, so it retained the old values.)
EXEC ManyOutputs 5, #bVal OUT, #cVal OUT, #dVal OUT
SELECT #bVal AS bVal, #cVal as cVal, #dVal as dVal
Returns 16, "The Value of A is 5, and the value of B is 16", 1
Related
I have a stored procedure that has a bunch of input and output parameters because it is Inserting values to multiple tables. In some cases the stored proc only inserts to a single table (depending on the input parameters). Here is a mocked up scenario to illustrate.
Tables / Data Objects:
Person
Id
Name
Address
Name
Id
FirstName
LastName
Address
Id
Country
City
Say I have a stored procedure that inserts a person. If the address doesn't exist I won't add it to the Address table in the database.
Thus when I generate the code to call the stored procedure I don't want to bother adding the Address parameter. For INPUT parameters this is ok because SQL Server allows me to supply default values. But for the OUTPUT parameter what do I do in the stored procedure to make it optional so I do not receive an error...
Procedure or function 'Person_InsertPerson' expects parameter
'#AddressId', which was not supplied.
Both input and output parameters can be assigned defaults. In this example:
CREATE PROCEDURE MyTest
#Data1 int
,#Data2 int = 0
,#Data3 int = null output
AS
PRINT #Data1
PRINT #Data2
PRINT isnull(#Data3, -1)
SET #Data3 = #Data3 + 1
RETURN 0
the first paramter is required, and the second and third are optional--if not set by the calling routine, they will be assigned the default values. Try messing around with it and the following test-call routine in SSMS using different values and settings to see how it all works together.
DECLARE #Output int
SET #Output = 3
EXECUTE MyTest
#Data1 = 1
,#Data2 = 2
,#Data3 = #Output output
PRINT '---------'
PRINT #Output
Output parameters and default values do not work well together! This is from SQL 10.50.1617 (2008 R2). Do not be fooled into believing this construct magically does a SET to that value on your behalf (like my co-worker did)!
This "toy" SP interrogates the OUTPUT parameter value, whether it is the default value or NULL.
CREATE PROCEDURE [dbo].[omgwtf] (#Qty INT, #QtyRetrieved INT = 0 OUTPUT)
AS
IF #QtyRetrieved = 0
BEGIN
print 'yay its zero'
END
IF #QtyRetrieved is null
BEGIN
print 'wtf its NULL'
END
RETURN
If you send in an uninitialized value (i.e. NULL) for the OUTPUT, you really got NULL inside the SP, and not 0. Makes sense, something got passed for that parameter.
declare #QR int
exec [dbo].[omgwtf] 1, #QR output
print '#QR=' + coalesce(convert(varchar, #QR),'NULL')
output is:
wtf its NULL
#QR=NULL
If we add an explicit SET from the caller we get:
declare #QR int
set #QR = 999
exec [dbo].[omgwtf] 1, #QR output
print '#QR=' + coalesce(convert(varchar, #QR),'NULL')
and the (unsurprising) output:
#QR=999
Again, makes sense, a parameter is passed, and SP took no explicit action to SET a value.
Add a SET of the OUTPUT parameter in the SP (like you're supposed to do), but do not set anything from the caller:
ALTER PROCEDURE [dbo].[omgwtf] (#Qty INT, #QtyRetrieved INT = 0 OUTPUT)
AS
IF #QtyRetrieved = 0
BEGIN
print 'yay its zero'
END
IF #QtyRetrieved is null
BEGIN
print 'wtf its NULL'
END
SET #QtyRetrieved = #Qty
RETURN
Now when executed:
declare #QR int
exec [dbo].[omgwtf] 1234, #QR output
print '#QR=' + coalesce(convert(varchar, #QR),'NULL')
the output is:
wtf its NULL
#QR=1234
This is the "standard" behavior for OUTPUT parameter handling in SPs.
Now for the plot twist: The only way to get the default value to "activate", is to not pass the OUTPUT parameter at all, which IMHO makes little sense: since it's set up as an OUTPUT parameter, that would mean returning something "important" that should be collected.
declare #QR int
exec [dbo].[omgwtf] 1
print '#QR=' + coalesce(convert(varchar, #QR),'NULL')
gives this output:
yay its zero
#QR=NULL
But this fails to capture the SPs output, presumably the purpose of that SP to begin with.
IMHO this feature combination is a dubious construct I would consider a code smell (phew!!)
Looks like I can just add a default value to the OUTPUT parameter such as:
#AddressId int = -1 Output
Seems like its poor in terms of readability since AddressId is intended strictly as an OUTPUT variable. But it works. Please let me know if you have a better solution.
Adding on to what Philip said:
I had a stored procedure in my sql server database that looked like the following:
dbo.<storedProcedure>
(#current_user char(8) = NULL,
#current_phase char(3) OUTPUT)
And I was calling it from my .net code as the following:
DataTable dt = SqlClient.ExecuteDataTable(<connectionString>, <storedProcedure>);
I was getting an System.Data.SqlClient.SqlException: Procedure or function expects parameter '#current_phase', which was not supplied.
I am also using this function somewhere else in my program and passing in a parameter and handling the output one. So that I didn't have to modify the current call I was making I just changed the stored procedure to make the output parameter also optional.
So it now looks as the following:
dbo.<storedProcedure>
(#current_user char(8) = NULL,
#current_phase char(3) = NULL OUTPUT)
Since you are executing a stored procedure and not a SQL statement, you have to set the command type of your SQL Command to Stored Procedure:
cmd.CommandType = CommandType.StoredProcedure;
Taken from here.
Also, once you get that error removed, you can use SQL's nvl() function in your procedure to specify what you want displayed when a NULL value is encountered.
Sorry about not properly addressing the question...must have misunderstood you. Here's an example of nvl, which I think might address it a little better?
select NVL(supplier_city, 'n/a')
from suppliers;
The SQL statement above would return 'n/a' if the supplier_city field contained a null value. Otherwise, it would return the supplier_city value.
I'm trying to build a stored procedure that seems to return a grid. But I only need the first column of that grid. Below is the code I'm using to call the procedure
USE [OperationsView]
DECLARE #ProductionDate As DateTime
DECLARE #tag_in As VARCHAR(80)
DECLARE #FCChemGALPERMIN float
DECLARE #pi_server As VARCHAR(32)
DECLARE #endDate As DateTime
DECLARE #Debug As Bit
DECLARE #result As Float
SELECT #ProductionDate = '2016-12-01 07:00:00'
SELECT #tag_in = 'I-FC-835'
SELECT #pi_server = 'valpi'
SELECT #endDate = DATEADD(DAY, 1, #productionDate)
SELECT #Debug = 1
EXEC #FCChemGALPERMIN = Interface.proc_GetPIValueAverageTime
#result, #tag_in, #ProductionDate, #endDate, #pi_server, #Debug
PRINT #FCChemGALPERMIN
PRINT 'done'
Under the results tab I need that float value, I don't care about the percentage next to it. Below this picture is what I get from the messages tab. Basically I want to grab that float value and assign it to a variable so I can display it in the messages tab also.
Results tab looks like this:
Messages tab looks like this:
The ChemGALPERMIN displays 0 when I simply print that variable. What do I do to get desired float number?
If Interface.Proc_getpivalueaveragetime is a stored procedure and NOT a user defined function, then you CANNOT return a value from stored procedure like that.
UPDATE: if you are sure that your stored procedure will ALWAYS return only 1 float value and the stored procedure doesn't update physical tables data, then you can convert it to a user defined function (CREATE FUNCTION examples) then you will be able to use it the way you have it in your original post, i.e. #result = Interface.Proc_GetPIvalueAverageTime(...) .
But if you still want to keep it as a stored procedure call then you need to pass an additional parameter to Interface.Proc_GetPIValueAverageTime and mark it as OUTPUT. Then in the body of your stored procedure, probably in the end of it when you already have the needed float value, you need to set that additional OUTPUT param to the calculated float value.
So, in code it will look something like this (you need to update your stored procedure definition):
CREATE PROCEDURE Interface.proc_GetPIValueAverageTime
#result float,
#tag_in varchar(80),
#ProductionDate DATETIME,
#endDate DATETIME,
#pi_server VARCHAR(32),
#Debug bit,
-- new param below
#sproc_result float OUTPUT
AS
BEGIN
... do your calc ..
set #sproc_result = #calculation_result_as_float
END
Then in the calling context you need to define that extra result var (or use the one you already have called #result ) and pass that extra param to the stored procedure call:
declare #sproc_result float;
EXEC #FCChemGALPERMIN = Interface.proc_GetPIValueAverageTime
#result, #tag_in, #ProductionDate, #endDate, #pi_server, #Debug,
#sproc_result OUTPUT
-- here #sproc_result will have the float value you've assigned to it in the stored procedure body.
print cast(#sproc_result as varchar(15))
Note, IIRC you need to specify OUTPUT after the returning param both in the stored procedure definition and in the calling statement.
Note, you're already passing the #result var as the first param into your stored procedure. then just add OUTPUT modifier to it both in the stored procedure definition and calling statement and assign the value to it in the stored procedure body. This way you won't need the new stored procedure param which I've named #sproc_result.
HTH
Considering there is a need for second column some where else.
Insert the result into temp table and take the float value from there
Insert into #temp(float_col,percent_col)
EXEC Interface.Proc_getpivalueaveragetime
#result,
#tag_in,
#ProductionDate,
#endDate,
#pi_server,
#Debug
select #FCChemGALPERMIN= float_col
From #temp
If your second column is not useful at any case then alter your procedure from resulting percentage column
I have this stored procedure:
ALTER PROCEDURE spCertificationType
#result nvarchar(15) output,
#mode int
AS
BEGIN
if #mode = 1
begin
exec spGeneratedID 2, #result output
print #result
end
END
but when I tried to execute it,it has this error
The formal parameter “#mode” was not declared as an OUTPUT parameter, but the actual parameter passed in requested output.
I tried to set #mode as output like this:
ALTER PROCEDURE spCertificationType
#result nvarchar(15) output,
#mode int output
AS
BEGIN
if #mode = 1
begin
exec spGeneratedID 2, #result output
print #result
end
END
but the it returns a null value.
Any fix for this? Thanks in advance.
the sequence of parameter in store procedure is that first use input parameter then use output parameter:-
you can see this link for more knowledge of store procedure:-
http://www.codeproject.com/Articles/126898/Sql-Server-How-To-Write-a-Stored-Procedure-in-SQL
ALTER PROCEDURE spCertificationType
#mode int,
#result nvarchar(15) output
AS
BEGIN
if #mode = 1
begin
exec spGeneratedID 2, #result output
print #result
end
END
I fixed this error a different way.
I had removed the OUTPUT statement after a parameter in my SP.
I then got the error.
I then went back to the SQLDataSource Configure Data Source wizard and went through the steps again. I discovered that changing the SP made the wizard delete the settings associated with the parameter that used to have OUTPUT after it.
In my case, I had declared the OUTPUT parameter last but was also getting a similar exception.
I moved the default parameters (like #var FLOAT = null) to the end after the output parameter then it started working.
create procedure [dbo].[basic_und6] (#name varchar(500), #email varchar(500), #result int out)
as
begin
Select #result=COUNT(*) from tbl_Students
where Firstname= #name and Email=#email
print #result
end
Given below is the query which I am running to execute the stored procedure
**declare #result1 int
execute basic_und6 Amit,'amit#abc.com',#result1
print #result1**
I am getting result as 1.
But according to my understanding, it should have displayed two 1's
First 1 is from the stored procedure print and second 1 from the query which had print statement.
Modify your execute statement to this :
declare #result1 int
execute basic_und6 Amit,'amit#abc.com', #result1 OUTPUT
print #result1
This is because, you haven't specified a variable where the output value must be returned to. The calling statement must do this by explicitly using the OUTPUT keyword. More info here
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.
No it will show only one 1
when we select a value into a variable the row count will not be shown
How can I ignore an output parameter of a stored procedure? I'm calling the procedure from another procedure, e.g.:
DECLARE #param1 integer
EXEC mystoredprocedure
#in_param_1,
#in_param2_,
#param1 OUTPUT,
-- what do I type here to ignore the second output param??
I'm using T-SQL (MS SQL 2005).
You can just use NULL as the last parameter, and it should work fine - as long as that parameter isn't expected for input logic in the proc as well.
In your case, you'd call the proc as
exec mystoredproc #in_param_1, #in_param2_, #param1 OUTPUT, null
Here's another example that for the same scenario...
create proc MyTempProc
(#one int,
#two int out,
#three int out)
AS
begin
set #two = 2
set #three = 3
select #one as One
end
go
declare #p1 int,
#p2 int
set #p1 = 1
exec MyTempProc #p1, #p2 out, null
print #p1
print #p2
The output parameter has to have a default in order for you to not pass it. See below
create proc x (#in int = null, #out int = null OUTPUT)
as
Begin
Select #in
End
exec x 1
EDIT
To clarify a little, the error is being returned because the stored procedure that is being called has a parameter defined (in this case #param1), for which no default is defined. (i.e. #param1 int rather than #param int = -1) In the case where neither a parameter or default is specified for a defined parameter of a stored procedure when calling the stored procedure an error will occur. The same thing would happen if you tired to omit an input parameter that does not have a default specified.
You'll probably have to just ignore the OUTPUT param yourself by just not doing anything with the value. It's not like the overhead of that variable is an issue or anything. The only issue here is that your code will be a little bit uglier. So slap a comment on there explaining that the OUTPUT param isn't being used and everything should be alright.
If the SP you're calling expects a parameter to be passed, you have to have one there. Even if you disregard the output of it, it is part of the structure of the SP.
Think of parameters as a "Data Contract". If they're not defaulted, they're required. Even if the values are disregarded.
Forcing you to declare a dummy value you'll never read is the cost of calling that stored proc that may be used by something that DOES need to utilize the value of the output parameter.