SQL Stored Procedure Parameters Being Assigned to Variables - sql

I'm sure there is some sound logic/best practice but I'd like it explained to me if possible. Looking at SQL stored procedures written by a previous employee he always declares 1 variable for each parameter and sets the variable equal to the parameter value and then uses the variable throughout the remainder of the stored procedure. What is the added value in not just using the parameter vs assigning to a variable?
ALTER procedure [dbo].[sp_shipping]
(
#p_date varchar(10),
#p_status varchar(10),
#p_cust nvarchar(20)
)
as
set nocount on
declare #v_date datetime,
#v_status varchar(10),
#v_cust nvarchar(20)
select #v_date = convert(datetime,#p_date),
#v_status = #p_status,
#v_cust = #p_cust

It is likely just a preference/style but it is worth noting that it does have an impact on the #p_date variable,
select #v_date = convert(datetime,#p_date)
This will throw an error if it is unable to convert the parameter to a datetime and it stores the result of the conversion so you don't have to repeat it later in the stored procedure.

Related

Date problems inserting data using stored procedures

I have a table in my SQL Server database with a field DateAdded. I only want the date and time as the format dd/mm/yyyy hh:mm:ss so I have the smalldatetime data type selected for this field. I'm now creating a stored procedure to insert data into this table. Amongst other fields - not relevant to question - is the DateAdded as this is a non NULLABLE field.
My procedure is as follows:
alter procedure dbo.spAddStuffExample_Insert
#Name varchar(100),
#EmailAddress varchar(100),
#ContactNumber varchar(100),
#AdditionalInformation varchar(3000) = NULL,
#DateAdded smalldatetime = GetDate
as
begin
set nocount on;
insert into dbo.TableName (Name, EmailAddress, ContactNumber,AdditionalInformation , DateAdded)
values(#Name, #EmailAddress, #ContactNumber,#AdditionalInformation, #DateAdded)
end
The wrong date is added to the record. DateAdded is 1900-01-01 00:00:00. I don't care about the format but it certainly isn't the 1900s.
The only things you can pass to a stored procedure are constants and variables.
Per Microsoft Reference: https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/specify-parameters?view=sql-server-ver16
GETDATE() is a function and functions cannot be used to pass parameter values or used as the default parameter values. You have to remove the default value using the GETDATE() function.
Two possible workarounds to your problem.
Declare a local variable inside the stored procedure set to GETDATE(). Use that local variable.
Create a variable set to GETDATE(), and pass the variable to the stored procedure.
Ex of #1 above, declaring a local variable inside the stored procedure:
CREATE PROCEDURE dbo.spAddStuffExample
--These are Passed Parameters, these cannot use functions
#Name varchar(100),
#EmailAddress varchar(100),
#ContactNumber varchar(100),
#AdditionalInformation varchar(3000) = NULL -- = NULL is a default
AS
--Declare local variable using a function
DECLARE #DateAdded smalldatetime = GETDATE();
set nocount on;
--Use passed parameters and local variable together
insert into dbo.TableName (Name, EmailAddress, ContactNumber,AdditionalInformation , DateAdded)
values(#Name, #EmailAddress, #ContactNumber,#AdditionalInformation, #DateAdded);

A stored procedure returns multiple values but only need one

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

LINQ - return type could not be detected

I have a simple stored procedure that is returning a value. However when dropping that SP in LINQ dbml I get:
The return types for the following stored procedures could not be detected. Set the return type for each stored procedure in the Properties Window.
I have a few SPs that show this, but the majority come through fine. I don't want to have to set them manually if I don't absolutely have to - I want the SP to be correct and easy for LINQ to determine.
Here is the SP:
#intPD integer
AS
set nocount on
Declare
#dtmStart datetime, #dtmEnd datetime, #fltDown float
EXEC sp_ShiftStart #intPD, #dtmStart OUTPUT
Declare #results TABLE(Dur varchar(100))
Insert into #results
EXEC sp_Down 3, #intPD, #dtmStart, #dtmEnd, null, 10, #fltDown OUTPUT
Select #fltDown as Dur
The return is a single row with a single field called 'Dur'
But LINQ doesn't seem to understand even though I have specifically defined the output.

SQL stored proc: How to detect whether optional output argument was passed or not?

I am writing a stored procedure that takes one input argument and can return the related attributes via the optional output parameters. It is defined like this:
CREATE PROCEDURE dbo.sp_get_info
#Identifier nvarchar(50),
#Info1 uniqueidentifier = NULL OUTPUT,
#Info2 nvarchar(10) = NULL OUTPUT,
#Info3 int = NULL OUTPUT
I would like to call the procedure like:
DECLARE #uid uniqueidentifier
...
EXEC sp_get_info #Idenfier = 'a123',
#Info1 = #uid
Getting each output value leads to a different activity. This way, I would like to detect the fact that only the #Info1 output value should be retrieved from elsewhere. This way, the procedure need not to execute possibly costly code that retrieves the other output (now unwanted) arguments.
Firstly, I was thinking about testing like IF #Info1 IS NOT NULL do_something. However, as the OUTPUT says also that the argument can have also the input value (Microsoft SQL) the #uid itself can have the value NULL. This way, the above test does not work.
Is there any technique used to solve the situation?
Thanks, Petr
You could use a #field and #value parameter. The #field could be Info1, Info2, Info3. Now the #value can be null and you still know what field to search.
CREATE PROCEDURE dbo.sp_get_info
#Identifier nvarchar(50),
#field nvarchar(50),
#value nvarchar(50) output
The calling code would have to convert the #value from nvarchar(50) to the required type, but that's typically easy.
Since the default value is a valid input, you can't tell whether it was passed explicitly or not. You can add another parameter, e.g. #Use_Info1 BIT, to indicate whether a parameter should be used or ignored.

Is it possible to ignore an output param of a stored procedure?

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.