Optional parameters in SQL Server stored procedure - sql-server-2008

I'm writing some stored procedures in SQL Server 2008. Is the concept of optional input parameters possible here?
I suppose I could always pass in NULL for parameters I don't want to use, check the value in the stored procedure, and then take things from there, but I was interested if the concept is available here.

You can declare it like this:
CREATE PROCEDURE MyProcName
#Parameter1 INT = 1,
#Parameter2 VARCHAR (100) = 'StringValue',
#Parameter3 VARCHAR (100) = NULL
AS
/* Check for the NULL / default value (indicating nothing was passed) */
if (#Parameter3 IS NULL)
BEGIN
/* Whatever code you desire for a missing parameter */
INSERT INTO ........
END
/* And use it in the query as so */
SELECT *
FROM Table
WHERE Column = #Parameter

Yes, it is. Declare the parameter as so:
#Sort varchar(50) = NULL
Now you don't even have to pass the parameter in. It will default to NULL (or whatever you choose to default to).

In SQL Server 2014 and above at least, you can set a default, and it will take that and not error when you do not pass that parameter.
Partial example: the third parameter is added as optional. Execution (exec) of the actual procedure with only the first two parameters worked fine.
exec getlist 47,1,0
create procedure getlist
#convId int,
#SortOrder int,
#contestantsOnly bit = 0
as

The default mentioned in previous answers only works for simple cases. In more complicated cases, I use an IF clause near the beginning of the stored procedure to provide a value, if the parameter is NULL or empty and calculations are required.
I often use optional parameters in the WHERE clause, and discovered that SQL does not short circuit logic, so use a CASE statement to make sure not to try to evaluate NULL or empty dates or unique identifiers, like so:
CREATE Procedure ActivityReport
(
#FromDate varchar(50) = NULL,
#ToDate varchar(50) = NULL
)
AS
SET ARITHABORT ON
IF #ToDate IS NULL OR #ToDate = '' BEGIN
SET #ToDate = CONVERT(varchar, GETDATE(), 101)
END
SELECT ActivityDate, Details
FROM Activity
WHERE
1 = CASE
WHEN #FromDate IS NULL THEN 1
WHEN #FromDate = '' THEN 1
WHEN ActivityDate >= #FromDate AND ActivityDate < DATEADD(DD,1,#ToDate) THEN 1
ELSE 0
END

Related

Truncated Inccorrect date value while calling nested function

I have two function.
fn_validate_date
fn_validation
fn_validate_date code:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_validate_date`(
`dt_date` DATE
)
RETURNS date
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Returns the associated value of given attribute for given employee for a particular date.'
BEGIN
SET dt_date = IF(dt_date IS NULL OR dt_date ='', CURRENT_DATE, dt_date);
RETURN dt_date;
END
fn_validation code:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_validation`(
`dt_date` DATE
)
RETURNS date
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
RETURN fn_validate_date(dt_date);
END
Now when I am calling fn_validate_date as below
SELECT `fn_validate_date`(null);
It's working well but when I calling fn_validation it's giving me an error.
SELECT `fn_validation`(null);
My question is why I didn't get error while calling fn_validate_date?
In fn_validate_date, the dt_date-parameter is type of date and you are comparing it to a string datatype. No need for that. Date datatype cannot contain ''. It either is NULL or has a date value in it.
So instead of:
SET dt_date = IF(dt_date IS NULL OR dt_date ='', CURRENT_DATE, dt_date);
You can simply use:
return ifnull( dt_date, current_date() );
I disable strict mode and it's working well.
SET sql_mode =''
To disable strict mode in MySQL. I am not sure why MySql short-circuited IF condition as I am passing NULL in the input parameter of fn_validation.

getting wrong value of out param on mysql procedure

I created a procedure on mysql.
Here's my sql.
drop procedure if exists proc_serial_no;
DELIMITER //
CREATE PROCEDURE `proc_serial_no`(IN comp_code varchar(20), IN meat_rule_one varchar(20),OUT serial_no int)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY INVOKER
COMMENT 'serial no generator for trace code'
begin
declare current_no int default 0;
select serial_no into current_no from t_serial_no where comp_code = comp_code and rule = meat_rule_one;
if current_no = 0
then insert into t_serial_no (id,no,comp_code,rule) values ( replace(uuid(),'-',''),1,comp_code,meat_rule_one);
else update t_serial_no set no = no + 1 where comp_code = comp_code and rule = meat_rule_one;
end if;
select serial_no = current_no + 1;
end
I'm expecting the out param [serial_no] to increase every time I call the procedure,but it's always zero.
When I change sql related to the out param to
select no into serial_no from t_serial_no where comp_code = comp_code and rule = meat_rule_one;
It worked!
I could't figure out why. Anyone can answer this would be in great help!
This may be right or wrong. But it may be due to ,
Everytime you call the procedure , the local variable current_no is by its default value it is 0.
When the scope moves out of the procedure and again when you call that procedure, it again starts with its default value 0 again and again.
And also,
May be everytime you pass the value 0 to serial_no param everytime you call that procedure and it again starts with 0 everytime when the scope moves out and comes in.

Determine what param to use in Select statement in a Stored Procedure

I have a stored procedure that returns a common query, I need to call it in several functions but some functions may call it through Period Id or others through Header Id, so far I would like to know how can I determine what param to use in order to retrive data properly, I have something like this implemented.
CREATE PROCEDURE dbo.GetTFDRecordInfo
#PeriodId int = null,
#HeaderId int = null
AS
BEGIN
SELECT
-- I have a lot more fields and joins here, that's why I need to get the statement in a single call through either period id or header id
*
From NT_CSRTNVPeriodInfo t
-- how can I make possible something like shown above, can I use a "Case When"?
Where (
/*
if #PeriodId is null
Where t.HeaderId = #HeaderId
if #HeaderId is null
Where t.PeriodId = #PeriodId
*/
)
END
GO
-- swtich between params
Exec NT_CSRTNVPeriodInfo null, 2654
Exec NT_CSRTNVPeriodInfo 196, null
This is the answer:
CREATE PROCEDURE dbo.GetTFDRecordInfo
#PeriodId int = null,
#HeaderId int = null
AS
BEGIN
SELECT
-- I have a lot more fields and joins here, that's why I need to get the statement in a single call through either period id or header id
*
From NT_CSRTNVPeriodInfo t
-- how can I make possible something like shown above, can I use a "Case When"?
Where ((#PeriodId IS NULL) or (t.PeriodId = #PeriodId))
And ((#HeaderId IS NULL) or (t.HeaderId = #HeaderId))
END
GO
You have to use conditional OR to check NULLs, if param is set, the second condition is checked, if not, the procedure will consider always true the statement and go to the next.

Multiple Variable If Statement

I have recently been able to produce a procedure where if a variable is not set I can set it to null. Now I am now looking to have multiple variables, but if a value has not been set to that variable, for it then to return all rows.
BEGIN
DECLARE ps_Project_Leader VARCHAR(15);
DECLARE ps_RD_Plan VARCHAR (15);
DECLARE ps_Approval_Status VARCHAR (15);
DECLARE ps_Design_Plan VARCHAR (15);
SET ps_Project_Leader = ifnull(Project_Leader,null);
SET ps_RD_Plan = ifnull(RD_Plan,null);
SET ps_Approval_Status = ifnull(Approval_Status,null);
SET ps_Design_Plan = ifnull(Design_Plan,null);
SELECT pp.pid,
pp.description,
pp.approval_status,
pp.design_plan,
pp.rd_plan,
pp.estimated_completion,
pp.project_leader,
pp.actual_completion
FROM project_register pp
WHERE pp.project_leader =Project_Leader
OR Project_Leader is null
and pp.rd_plan =RD_Plan
OR RD_Plan is null
and pp.approval_status = Approval_Status
OR Approval_Status is null
and pp.design_plan = Design_Plan
OR Design_Plan is null
and
PP.actual_completion is null;
end
For instance if i have set 2 of the variables and not the other 2, I do not want it to search on the variables that have not been set.
Many Thanks in advance, if i have not made complete sense (i am new to this so i appologies) I will be happy to clear things up.
You need to parenthesize your WHERE expression correctly:
WHERE (pp.project_leader = ps_Project_Leader
OR ps_Project_Leader is null)
and (pp.rd_plan = ps_RD_Plan
OR ps_RD_Plan is null)
and (pp.approval_status = ps_Approval_Status
OR ps_Approval_Status is null)
and (pp.design_plan = ps_Design_Plan
OR ps_Design_Plan is null)
and PP.actual_completion is null;
because AND has higher precedence than OR.
You aren't referencing the local variables, only the procedure arguments. (It doesn't look like you actually need local variables.)
I prefer to use parens around the AND and OR predicates, even if they aren't required. I never have to lookup if AND or OR takes precedence when I use parens, because it doesn't matter, because I'm always specifying the precedence.
I'd help the reader out, and format my SQL like this:
WHERE ( pp.project_leader = Project_Leader OR Project_Leader IS NULL )
AND ( pp.rd_plan = RD_Plan OR RD_Plan IS NULL )
AND ( pp.approval_status = Approval_Status OR Approval_Status IS NULL )
AND ( pp.design_plan = Design_Plan OR Design_Plan IS NULL )
That way, each line is a "check" of a single column, which is either enabled (with a non-NULL value) or disabled with NULL value.
Really just personal preference, I just find it easier to read that way, even if the line is a little bit longer, I'd rather have the check all one one line.
Again, the local variables aren't needed.
But, you could just set local variables equal to the parameter values, and then reference the local variables in your SQL statement. That really helps out when a variable has the same name as a column, because if the are named the same, MySQL is going to assume it's a reference to column name rather than a variable name. Using a local variable gives you a chance to rename it so it won't be confused with a column name.
UPDATE
I just noticed that the parameter variables names ARE the same as the column names, and that's going to be a problem.
You want your variable names to be DIFFERENT than the column names. You want to make sure that the datatypes of the variables match the columns... later, when you change a column from VARCHAR(15) to VARCHAR(30), you'll need to revisit the procedure and change the definitions of the procedure arguments as well as the local variables.
BEGIN
-- local variable names are DISTINCT from any column name
-- in any table referenced by a query these are used in
DECLARE ps_Project_Leader VARCHAR(15);
DECLARE ps_RD_Plan VARCHAR(15);
...
-- copy parameter values to local variables
SET ps_Project_Leader = Project_Leader ;
SET ps_RD_Plan = RD_Plan ;
...
-- query references local variable names
...
WHERE ( pp.project_leader = ps_Project_Leader OR ps_Project_Leader IS NULL )
AND ( pp.rd_plan = ps_RD_Plan OR ps_RD_Plan IS NULL )
...

SQL Stored Procedure Parameters being Corrupted?

I have a stored procedure that for now is just suppose to validate your string input as a valid date. I've tried running this outside of a procedure and it works flawlessly, but as soon as I stick it in a procedure, the parameters get changed to zero.
My procedure is as follows:
CREATE PROCEDURE spDateRange
#DateMin varchar = NULL,
#DateMax varchar = NULL
AS
PRINT #DateMin;
PRINT #DateMax;
IF #DateMin IS NOT NULL AND #DateMax IS NOT NULL
BEGIN
PRINT #DateMin;
IF(ISDATE(#DateMin)=1 AND ISDATE(#DateMax)=1)
PRINT 'Valid Date';
ELSE
RAISERROR('Parameters not date format', 10, 1);
END
ELSE
RAISERROR ('Invalid parameters', 10, 1);
And my execute statement is:
EXECUTE spDateRange #DateMin='01/11/2011', #DateMax='01/12/2011';
And my output is:
0
0
0
Parameters not date format
You need to give an explicit length for the varchar parameters. It defaults to 1 character.
char(10) should be enough for valid dates in dd/mm/yyyy format but I guess you might want longer as this is validating potentially invalid dates!
CREATE PROCEDURE spDateRange
#DateMin varchar(30) = NULL,
#DateMax varchar(30) = NULL
AS