Optional parameters in SQL UDF without DEFAULT keyword [duplicate] - sql

This question already has answers here:
Alter a SQL server function to accept new optional parameter
(3 answers)
Closed 8 years ago.
I am looking for a solution, how to create SQL UDF with optional params.
Pseudocode for function where Param1 is necessary and Param2 may be filled (but not needed):
dbo.myFnc(Param1 int [, Param2 int])
Is there a way to create thislike function? For existing built-in sample watch the STR function
STR ( float_expression [ , length [ , decimal ] ] )

You need to pass all arguments to functions, unlike stored procedures. You can use the default keyword to indicate that default value is to be used for the parameter, rather than a user-specified value.
So you can create your function like this:
CREATE FUNCTION dbo.myFnc
(
#param1 int,
#param2 int)
...
and then call the function like this:
dbo.myFnc(Param1, default)

You can define default parameters in the create statement (= default):
--Transact-SQL Inline Table-Valued Function Syntax
CREATE FUNCTION [ schema_name. ] function_name
( [ { #parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
[ = default ] [ READONLY ] }
[ ,...n ]
]
)
RETURNS TABLE
[ WITH <function_option> [ ,...n ] ]
[ AS ]
RETURN [ ( ] select_stmt [ ) ]
[ ; ]
Source MSDN
So you can do something like:
CREATE FUNCTION dbo.myFnc(
#param1 int, -- necessary
#param2 int = 5 -- 5 as default
)
But as shree.pat18 said you need to call the optional function parameter with the "default".
Like:
dbo.myFnc(5, default)

I am not sure which SQL you are referring to, but is it possible to overload the UDF?
dbo.myFnc(Param1 int )
dbo.myFnc(Param1 int , Param2 int)
some sql allows it some doesn't. If yours doesn't, maybe you could try something the could handle null as input
create function func
(
#in1 int,
#in2 int
)
returns int
as
begin
declare #count int
select #count = count(*)
from table
where
field1 = isnull(#in1, field1)
and field2 = isnull(#in2, field2)
return #count
end
go
so you could do something like
select func(null,9)

Related

Get return type of SQL Server function

In SQL Server, a function is defined as follows:
-- Transact-SQL Scalar Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { #parameter_name [ AS ][ type_schema_name. ] parameter_data_type
[ = default ] [ READONLY ] }
[ ,...n ]
]
)
RETURNS return_data_type
[ WITH <function_option> [ ,...n ] ]
[ AS ]
BEGIN
function_body
RETURN scalar_expression
END
[ ; ]
Where return_data_type can be text, a table (with a slightly different syntax), or almost any other data type.
Is it possible to retrieve the return data type without running the query?
I know it's possible to do using sp_describe_first_result_set, but this executes the query and looks at the response. Edit: I was wrong. It is done through static analysis, but has a number of limitations associated with it.
As mentioned in comments, you can use sp_describe_first_result_set.
Or you can use the query from the linked duplicate and extend it with INFORMATION_SCHEMA.ROUTINE_COLUMNS:
SELECT r.ROUTINE_NAME AS FunctionName,
r.DATA_TYPE AS FunctionReturnType,
rc.COLUMN_NAME AS ColumnName,
rc.DATA_TYPE AS ColumnType
FROM INFORMATION_SCHEMA.ROUTINES r
LEFT JOIN INFORMATION_SCHEMA.ROUTINE_COLUMNS rc ON rc.TABLE_NAME = r.ROUTINE_NAME
WHERE ROUTINE_TYPE = 'FUNCTION'
ORDER BY r.ROUTINE_NAME, rc.ORDINAL_POSITION;
That will give you the return information for both scalar-value functions and table-value functions, including schema information for the TVF result set.

Functions with returns 'table' has no begin...end?

If I ever add 'Begin' after 'As' It says incorrect syntax. It works just fine If I'm trying to return one value though.
Instead I should add 'return' after 'as' and open brackets ()
Why is that?
With one value as returns, I can do it fine:
CREATE FUNCTION MATHEE(#A int,#B int)
returns int
as
begin
DECLARE #C int
SET #C = #A + #B
return #C
end
With table as returns, I cant:
CREATE FUNCTION TOP_USERSs(#number int,#bob varchar(20))
RETURNS TABLE
AS
BEGIN
RETURN SELECT agent from Agents where agent = #bob and prime > #number
END
It says :
Incorrect syntax near 'BEGIN'.
It works fine using brackets and without begin..end though:
CREATE FUNCTION TOP_USERSs(#number int,#bob varchar(20))
RETURNS TABLE
AS
RETURN
(
SELECT agent from Agents where agent = #bob and prime > #number
)
RETURNS TABLE in an Inline User-Defined Function & these do not have function bodies
There is no function_body delimited by BEGIN and END.
For example if you added set #number += 1 before the RETURN this would also fail to parse.
RETURNS TABLE creates an inline table-valued function. It supposed to have a single select wrapped in return as its body:
CREATE FUNCTION TOP_USERSs(#number int,#bob varchar(20))
returns table
as return (
select ...
);
If you want the begin-end syntax, that is a multi-statement table-valued function, and you will then need to declare the table it returns:
CREATE FUNCTION TOP_USERSs(#number int,#bob varchar(20))
returns #result table (agent varchar(10) not null)
as
begin
insert into #result (agent) ... ;
...
return;
end;
You can declare fields of Return table as following code:
CREATE FUNCTION TOP_USERSs(#number int,#bob varchar(20))
RETURNS #Result TABLE ( Agent varchar(20) )
AS
BEGIN
Insert into #Result
SELECT agent from Agents where agent = #bob and prime > #number
RETURN
END
Per the documentation, there are two kinds of table-valued function, with different syntaxes:
-- Transact-SQL Inline Table-Valued Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { #parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
[ = default ] [ READONLY ] }
[ ,...n ]
]
)
RETURNS TABLE
[ WITH <function_option> [ ,...n ] ]
[ AS ]
RETURN [ ( ] select_stmt [ ) ]
[ ; ]
This is an inline TVF. As the syntax shows, it can include solely a RETURN followed by a SELECT. Nothing more, nothing less.
-- Transact-SQL Multi-Statement Table-Valued Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { #parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
[ = default ] [READONLY] }
[ ,...n ]
]
)
RETURNS #return_variable TABLE <table_type_definition>
[ WITH <function_option> [ ,...n ] ]
[ AS ]
BEGIN
function_body
RETURN
END
[ ; ]
This is a multi-statement TVF. As the name suggests, you can include multiple statements in the definition. But note that you must specify the schema of the returned table as part of the function definitions.

Using variables when calling sp_rename

I try to make a stored proc which will
Drop a primary key
Rename the column name where the primary key was set
Create the new primary key
I'm struggling with the point number 2.
I'm trying to rename the column with sp_rename with the parameters passed to the stored proc like this:
EXEC sp_rename '[' + #SCHEMA + '].[' + #TABLE + '].[ID]' , 'Id', 'COLUMN'
But this way I got this error:
Procedure or function 'sp_RENAME' expects parameter '#newname', which was not supplied.
How can I use sp_rename with parameters ?
Try like this
DECLARE #SCHEMA NVARCHAR(30)='your schema name'
DECLARE #TABLE NVARCHAR(30)='table Name'
DECLARE #OLD NVARCHAR(30) = '[' + #SCHEMA + '].[' + #TABLE + '].[ID]'
EXEC sp_rename #OLD, 'Id'
The problem isn't with sp_rename, per se, it's actually a problem with EXEC.
For each parameter you wish to pass, you may supply a value (a literal of some kind), a variable or the keyword DEFAULT. What you may not pass is an expression that computes a value.
[ { EXEC | EXECUTE } ]
{
[ #return_status = ]
{ module_name [ ;number ] | #module_name_var }
[ [ #parameter = ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
[ ,...n ]
[ WITH <execute_option> [ ,...n ] ]
}
[;]
All this means that, if you wish to compute something, you need to do it as separate statement(s), and store the result of the computation in a variable, before the EXEC, as shown in JaydipJ's answer.

SQL Server stored procedure with empty body

CREATE PROCEDURE syntax:
CREATE { PROC | PROCEDURE } [schema_name.] procedure_name [ ; number ]
[ { #parameter [ type_schema_name. ] data_type }
[ VARYING ] [ = default ] [ OUT | OUTPUT | [READONLY]
] [ ,...n ]
[ WITH <procedure_option> [ ,...n ] ]
[ FOR REPLICATION ]
AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] }
[;]
<sql_statement> ::=
{ [ BEGIN ] statements [ END ] }
[ ] (brackets) Optional syntax items. Do not type the brackets.
{ } (braces) Required syntax items. Do not type the braces.
And human readable form:
Let's try to write stored procedure with empty body:
CREATE PROC my_proc AS
-- please treat it as separate call, for example with different session
EXEC my_proc
is perfect valid syntax.
LiveDemo
So it looks like that sql_statement could be empty.
Now let's try the same with but this time with BEGIN/END block:
CREATE PROC my_proc AS
BEGIN
END
-- Incorrect syntax near 'END'.
LiveDemo2
Why is the first example valid? If sql_statement allows nothing then second example should work too or the doc is inaccurate.
EDIT
well, that's because in the first example it isn't an empty body, your sp will be: EXEC my_proc
The case was to show that I could call SP. But you could add GO or use EXEC:
CREATE PROC my_proc AS
GO
EXEC my_proc
or
EXEC('CREATE PROC my_proc AS')
EXEC my_proc
LiveDemo3
The syntax error is not related to the proper syntax for stored procs. It is the proper syntax for "BEGIN/END". BEGIN/END requires some SQL inside of it to be valid. The documentation for BEGIN/END shows this:
https://msdn.microsoft.com/en-us/library/ms190487.aspx
BEGIN
{
sql_statement | statement_block
}
END
The grammar in the CREATE PROC documentation is indeed not fully correct, as it says that sql_statement is required for "CREATE PROC", when it is actually not required.

SQL Server stored procedure parameter assignment

Why can I not use functions to directly assign stored procedure parameters?
e.g.
exec myStoredProc #firstParam = aFunctionThatReturnsAnAppropriateValue()
but I find I have to decalre a variable just to hold the value
declare #temp type = aFunctionThatReturnsAnAppropriateValue()
exec myStoredProc #firstParam = #temp
which seems redundant
Quoting EXECUTE (Transact-SQL):
Execute a stored procedure or function
[ { EXEC | EXECUTE } ]
{
[ #return_status = ]
{ module_name [ ;number ] | #module_name_var }
[ [ #parameter = ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
[ ,...n ]
[ WITH RECOMPILE ]
}
[;]
You can see that it explicitly says #variable or value. I guess this is a language limitation, as you can neither write a call to a function as a variable or as a value; it is executable code (an expression), and the short-hand assignment during variable declaration is just a misleading bonus.
EDIT: Compare the difference of description for DECLARE and EXECUTE:
For DECLARE
=value
Assigns a value to the variable in-line. The value can be a constant or an expression, but it must either match the variable
declaration type or be implicitly convertible to that type.
When looking through the page for EXECUTE, I do not see the mention of an expression. It seems to me that it would be handy, as I think you are trying to point out.