optional parameters in SQL Server stored proc?
You can declare 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
How can I use optional parameters in a T-SQL stored procedure?
Dynamically changing searches based on the given parameters is a complicated subject and doing it one way over another, even with only a very slight difference, can have massive performance implications. The key is to use an index, ignore compact code, ignore worrying about repeating code, you must make a good query execution plan (use an index).
Read this and consider all the methods. Your best method will depend on your parameters, your data, your schema, and your actual usage:
Dynamic Search Conditions in T-SQL by by Erland Sommarskog
The Curse and Blessings of Dynamic SQL by Erland Sommarskog
If you have the proper SQL Server 2008 version (SQL 2008 SP1 CU5 (10.0.2746) and later), you can use this little trick to actually use an index:
Add OPTION (RECOMPILE)
onto your query, see Erland's article, and SQL Server will resolve the OR
from within (@LastName IS NULL OR LastName= @LastName)
before the query plan is created based on the runtime values of the local variables, and an index can be used.
This will work for any SQL Server version (return proper results), but only include the OPTION(RECOMPILE) if you are on SQL 2008 SP1 CU5 (10.0.2746) and later. The OPTION(RECOMPILE) will recompile your query, only the verison listed will recompile it based on the current run time values of the local variables, which will give you the best performance. If not on that version of SQL Server 2008, just leave that line off.
CREATE PROCEDURE spDoSearch
@FirstName varchar(25) = null,
@LastName varchar(25) = null,
@Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
(@FirstName IS NULL OR (FirstName = @FirstName))
AND (@LastName IS NULL OR (LastName = @LastName ))
AND (@Title IS NULL OR (Title = @Title ))
OPTION (RECOMPILE) ---<<<
Stored Procedure with optional WHERE parameters
One of the easiest ways to accomplish this:
SELECT * FROM table
WHERE ((@status_id is null) or (status_id = @status_id))
and ((@date is null) or ([date] = @date))
and ((@other_parameter is null) or (other_parameter = @other_parameter))
etc.
This completely eliminates dynamic sql and allows you to search on one or more fields. By eliminating dynamic sql you remove yet another security concern regarding sql injection.
Stored procedure with optional parameter
Make the parameter nullable (optional) and change and d.codigo=@sucursal
to deal with the null
:
ALTER PROCEDURE Fichada_por_sucursal (
@fecha1 date,
@fecha2 date,
@sucursal int = NULL)
AS
select CASE DATENAME(dw, a.fecha )
WHEN 'Monday' then 'Lunes'
WHEN 'Tuesday ' then 'Martes'
WHEN 'Wednesday ' then 'Miércoles'
WHEN 'Thursday' then 'Jueves'
WHEN 'Friday' then 'Viernes'
WHEN 'Saturday' then 'Sábado'
ELSE 'Domingo' END
as Fechadia,
a.legajo,c.nombres,
e.abrv,CONVERT (char(10), a.fecha, 103) as Fecha,
f.entrada as Hora_IN,
a.hora as ENTRADA,
f.salida as Hora_out,
b.hora as SALIDA,
DATEDIFF(HOUR,a.hora,b.hora) as Horas_trabajadas,
c.hor_x_jor Horas_jornada,
DATEDIFF(HOUR,a.hora,b.hora) -hor_x_jor as Diferencia
from fichadas_in a, fichadas_out b, empleados c,
sucursales d,Clasificacion e, grupo_horario f
where a.Legajo=b.Legajo
and a.fecha=b.fecha
and a.fecha between @fecha1 and @fecha2
and d.codigo=ISNULL(@sucursal, d.codigo)
and a.legajo=c.legajo
and c.CCO=d.Codigo
and e.Codigo=c.Clasif
and c.grupo_h=f.codigo
Order by a.fecha,legajo
Call it:
EXEC Fichada_por_sucursal '2018-05-01','2018-05-05','9'
OREXEC Fichada_por_sucursal '2018-05-01','2018-05-05'
Stored procedure w/ multiple optional parameters
Having a single stored procedure that can do completely different things is a very bad design. It is like creating a method in dotnet that does something completely different depending on the parameters being passed. Just like your programming code you want your procedure to do one thing and do it really well.
This boils down to performance. An execution plan will be created for a stored procedure and stored in the cache. When you have multiple execution paths like this it totally destroys the engines ability to consistent generate an efficient execution plan. So even though the plan is great for one set of parameters it will be horrible for another. But it will use the plan that is already in cache if it exists. If anything you can create a procedure as a "driver" and have it call various other procedures based on the parameters. This allows a good plan for each path.
Optional parameters in stored procedure in SQL Server
First of all you should provide default values of parameters and then compare those to column values or to null:
create procedure somename
@p1 int,
@p2 int = null,
@p3 int = null
as
begin
select * from sometable
where col1 = @p1 and
(col2 = @p2 or @p2 is null) and
(col3 = @p3 or @p3 is null)
end
Then you can call the proc like:
exec somename @p1 = 1
exec somename @p1 = 1, @p2 = 2
exec somename @p1 = 1, @p2 = 2, @p3 = 3
And it will work as you expect. With your approach you will actually need 2^N
IF
checks where N
is number of such parameters. Imagine that for 5 parameters you will need to do 2^5 = 32
IF
checks. With provided approach you will have all in one query and only 5 checks.
optional parameters in stored procedure
If the parameters are optional in the stored procedure then you can choose whether to add them. For example, if you remove this line (above)
cmd1.Parameters.AddWithValue("@AccountName", AccountName);
then the stored procedure will use the default value of @AccountName
.
That means you just need a way to determine whether or not to pass each parameter. How you do that is tougher to answer because it depends on the behavior of your application.
You could, for example, do this:
if(AccountName != null)
cmd1.Parameters.AddWithValue("@AccountName", AccountName);
In other words, if a value wasn't provided for AccountName
then don't send one to the procedure. That works as long as you don't need to be able to set AccountName
to null
using this method.
You could pass a parameter to the method indicating what the account type is, and use that to determine which parameters to add and which to leave out.
I noticed that you have separate variables for each value (Account
, Address
, etc.) It might be easier to work with if you put them into a class, like
public class ClinicUpdate
{
public string AccountId {get;set;}
public string Address {get;set;}
//etc
}
That can make it a lot easier if you decide to rearrange your code. For example, you might decide to make two methods - one that adds the parameters for one type of account, and another to add parameters for the other type. That's a lot easier if you're passing around a single object instead of a big list of parameters.
It's good practice anyway. Opinions vary but I recommend a maximum of four parameters per method call. If you find yourself passing a similar list of parameters to many methods then you probably need a class for them.
Ways to create a procedure with optional parameters?
You can do this by DEFAULT
operator or '='
PROCEDURE ADD(NUMBER n1, NUMBER n2, NUMBER n3 DEFAULT 0)....
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/fundamentals.htm#CHDFADII
If you want to use it without explicit parameter naming in calls then you have to place your optional parameters at the end of the procedure signature list. With explicit parameter naming in call they can be placed anywhere
Stored procedure with optional parameter that doesn't show in SQL Server Management Studio execute stored procedure or script stored procedure
You could wrap your stored procedure with another:
CREATE PROCEDURE dbo.my_orig_proc
@id INT
,@some_param_default INT = 10
AS
BEGIN
...
END
Wrapper:
CREATE PROCEDURE dbo.my_wrapper_proc
@id INT
AS
BEGIN
EXEC dbo.my_orig_proc @id;
END
I would also restrict access to orignal procedures if necessary.
Another way is to add check and don't allow specific user to override value:
CREATE PROCEDRUE dbo.my_orig_proc
@id INT,
,@some_param_default INT = 10
AS
BEGIN
IF USER_NAME() = 'user_name' AND @some_param_default <> 10
RAISERROR('You cannot change @some_param_default value' ,16,1);
END
Drawback: You need to change parameter value in two places and if user has impersonate privilige he still can execute it.
Related Topics
Optimize Query With Offset on Large Table
How to Set Table Name in Dynamic SQL Query
Group by and Aggregate Sequential Numeric Values
Can a Table Field Contain a Hyphen
MySQL: Split Comma Separated List into Multiple Rows
Constraint Defined Deferrable Initially Immediate Is Still Deferred
A Beginner'S Guide to SQL Database Design
MySQL Search and Replace Some Text in a Field
Difference Between Natural Join and Inner Join
Getting Only Month and Year from SQL Date
SQL Order by Multiple Values in Specific Order
How to Print Varchar(Max) Using Print Statement
Count(*) VS Count(Column-Name) - Which Is More Correct
How to Delete from Multiple Tables Using Inner Join in SQL Server
What Are Your Most Common SQL Optimizations