declare variable in a sql function - sql

I have a sql function and i need to declare few variables in that function. Please advise how can i achieve this.
For example i need to put -->
Declare #ClientResult TABLE(
RowIndex int identity(1,1),
SplitText varchar(50)
)
in the below function.
create FUNCTION [dbo].CLIENT_SHIPPINGREPORTDATA_Function_Test
(
#CLIENTPK_NEW TABLE,
#CGNEEPK TABLE
#type varchar(100)
)
RETURNS TABLE
AS
RETURN
SELECT distinct
OP_PartNum,
OP_PK
FROM Client_whsPallet pallet
I am using sql server 2005
Thanks

What you are after is a multi-statement table function
e.g.
CREATE FUNCTION dbo.fxnExample (#Param INTEGER)
RETURNS #Results TABLE(FieldA VARCHAR(50))
AS
BEGIN
INSERT #Results
SELECT SomeField
FROM Somewhere
WHERE ParamField = #Param
RETURN
END
This is different to your current function which is called an "inline table valued function" and you should be aware of the differences as this could cause performance issues if you switch to the multi-statement approach. My advice would be to try and use inline table valued functions wherever possible. I recommend you checking out these articles which go into detail:
Multi-statement Table Valued Function vs Inline Table Valued Function
Link
http://sqlbits.com/Agenda/event6/High_performance_functions/default.aspx

In SQL Server you can't declare variables inside of an inline table-Valued function. You'll need to create a multi-statement table valued function if you really need to declare variables in it. You would do something like this:
CREATE FUNCTION [dbo].CLIENT_SHIPPINGREPORTDATA_Function_Test
(
#CLIENTPK_NEW TABLE, #CGNEEPK TABLE #type varchar(100)
)
RETURNS #output TABLE (OP_PartNum int, OP_PK int)
AS BEGIN
Declare #ClientResult TABLE( RowIndex int identity(1,1), SplitText varchar(50) )
/* more code here */
RETURN
END
Not knowing what exactly it is you are trying to do, I would see if there is away around using a multi-statement function though as you will see performance decrease.

Compare these equivalent code samples. They show the syntax differences between inline and multistatement table-valued functions.
CREATE FUNCTION [dbo].Inline (#type varchar(100))
RETURNS TABLE
AS
RETURN
SELECT distinct name
FROM sysobjects
WHERE type = #type
GO
CREATE FUNCTION [dbo].Multistatement (#type varchar(100))
RETURNS #results TABLE (name sysname)
AS
BEGIN
INSERT #results (name)
SELECT distinct name
FROM sysobjects
WHERE type = #type
RETURN
END

As suggested by AdaTheDev you can create a multi-statement function for returning a table from a function.
Otherwise if you need to create a table inside the function you can create a new temporary table prefixing its name with an #
create table #TableNAme (FieldA Varchar(5))

Related

How a userdefined functions saved under Table valued function in sql server 2014

Im not sure whether im in right place to ask this question.
But I wonder How a function that i created fall under the table valued function? why cant it be inside scalar function?
I have the below function recorded in a Database.
IF OBJECT_ID (N'dbo.ufnGetTVP', N'FN') IS NOT NULL
DROP FUNCTION ufnGetTVP;
GO
CREATE FUNCTION dbo.ufnGetTVP(#input varchar(50))
returns #mt table (a nvarchar(60))
AS
-- Returns the stock level for the product.
BEGIN
declare #output varchar(1)
declare #len int=(select len(#input))
while(#len>0)
begin
set #output =substring(#input,0,2)
set #input=substring(#input,charindex(#output,#input)+2,len(#input))
SET #len=len(#input)
insert into #mt
Select #OUTPUT
end
return
END;
GO
if a function will be saved as TVF how a scalar function can created?
Please share your thoughts.
As I wrote in my comment - the difference between a Scalar function and a Table valued function is only the return type of the function.
A scalar valued function is a function that returns a scalar (or single) value such as int, varchar, bit etc`, while a table valued function is a function that returns a table.
The basic syntax of creating a scalar functions is the same as the one for creating a table function:
CREATE FUNCTION <name>
(
<parameters list>
)
RETURNS <scalar type>
AS
BEGIN
-- function code goes here
END;

Creating a Table valued Function if doesn't exist dynamically and altering it normally

I am working on creating a table-valued function but before creating it I would like to check if it exists and if it doesn't exist then create the function using dynamic script and then alter it normally.
IF NOT EXISTS
(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[region]')
AND OBJECTPROPERTY(id,N'IsTableFunction') = 1)
BEGIN
EXEC dbo.sp_executesql
#statement = N' CREATE FUNCTION [dbo].[region]()
RETURNS TABLE AS BEGIN RETURN ''A'' END'
GO
ALTER FUNCTION dbo.region(#dd datetime)
--
GO
But, above script threw me an error Incorrect syntax near the keyword 'RETURN'.
i think you have to write as follows:
CREATE FUNCTION [dbo].[region]()
RETURNS TABLE AS return ( select 'A')
and in case you want to return a variable table just to insert into it before returning it as a result, you can use the following,
CREATE FUNCTION [dbo].[region]()
RETURNS #table_buffer TABLE
(
TransDate datetime,
Company nvarchar(4),
RECID bigint
)
AS
begin
insert into #table_buffer select -- here you will complete it according to your need
return
end

Creating a stored procedure using variables

Is there any good way to do this, or am I just heading in the wrong direction? I would like to create a stored procedure inside an SQL script. I would like to have variables declared at the beginning of the script so that I can create the SPROCs to use in different contexts/servers.Here is what I would like to do (I know this obviously doesn't work, but I'm looking for any ideas of an alternative)..
DECLARE #golbalValue = 'SomeValue'
GO
CREATE PROCEDURE [dbo].[MyStoredProcedure](
AS
BEGIN
SELECT * FROM Mytable WHERE MyCol = #globalValue
END
GO
What you could do is use a scalar function for the variable
create function f ()
returns varchar(20)
as
begin
return 'some value'
end
go
then use it in your procedure
create proc p ()
as
begin
select *
from my_table
where col = f()
end
go
another possibility which is perhaps more appropriate is to use sqlcmd here's an example.
From what I understand, you need to create stored procedures with set value from your parameters. You don't want input parameters in the stored Procedures though. Second, you want to switch database contexts. So I think you'll need a tempTable for your parameters and some dynamic SQL. Try this out:
IF OBJECT_ID('tempdb..#globalParam') IS NOT NULL
DROP TABLE #globalParam;
IF OBJECT_ID('AdventureWorks2012.dbo.myTable') IS NOT NULL
DROP TABLE AdventureWorks2012.dbo.myTable
IF OBJECT_ID('Master..myTable') IS NOT NULL
DROP TABLE Master..mytable
--Create your data tables
SELECT 'SomeValue' AS col1 INTO AdventureWorks2012.dbo.myTable;
SELECT 1000 AS col1 INTO master.dbo.myTable;
CREATE TABLE #globalParam(
ParamName VARCHAR(100),
val SQL_VARIANT --SQL_Variant is designed to hold all data types.
);
--Here are your globalParams
DECLARE #globalParam1 VARCHAR(100) = 'SomeValue';
DECLARE #globalParam2 INT = 1000;
--Load your parameters into a table. Might have to cast some of your parameters to SQL_Variant
INSERT INTO #globalParam
VALUES ('globalParam1',#globalParam1),
('globalParam2',CAST(#globalParam2 AS sql_variant));
GO
--Switch database context
USE AdventureWorks2012
GO
--Variable to hold CREATE PROC
DECLARE #sql VARCHAR(MAX);
--Set #SQL with parameter value from #globalParam
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam1'
--Execute to create the stored procedure
EXEC(#sql)
--Execute it to see if it works
EXEC dbo.myStoredProc
--Switch context. Repeat same steps
USE master
GO
DECLARE #sql VARCHAR(MAX);
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam2'
EXEC(#sql)
EXEC dbo.myStoredProc
--Cleanup
DROP PROCEDURE dbo.myStoredProc;
USE AdventureWorks2012
GO
DROP PROCEDURE dbo.myStoredProc;
You cannot do what you want. T-SQL doesn't have the concept of global variables. One method is to store values in a "global" table and then reference them as needed. Something like:
create table GlobalParams (
name varchar(255) not null primary key,
value varchar(255) not null
);
create procedure . . .
begin
. . .
declare #value varchar(255);
select #value = value from Globalparams where name = 'name';
select *
from Mytable
where MyCol = #value;
. . .
end;
Note: this is a simplistic example that only allows variables whose type is a string.
You can also wrap the logic in a user-defined function, so the call looks like:
select *
from Mytable
where MyCol = udf_GlobalLookup('name');
It is rather rare to need global parameters that are shared among different stored procedures. Such a global context can be useful, at times, for complex systems. It is unlikely that you need all this machinery for a simple application. An alternative method, such as just passing the parameters in as arguments, is probably sufficient.

Unable to run stored procedure in OUTER APPLY [duplicate]

Why I can not use a stored procedure in OUTER APPLY block?
I need to get int value from the stored procedure dbo.GetTeacherId and use this in WHERE clause. Here my code:
USE [StudentsDb]
DECLARE #teacherIdOut int;
SELECT StudentLastName, StudentFirstName, StudentMiddleName, LessonName, Score, TLastName, TFirstName, TMiddleName
FROM Scores
JOIN Students
ON Scores.StudentId=Students.StudentId
JOIN Lessons
ON Scores.LessonId=Lessons.LessonId
OUTER APPLY
(
EXECUTE dbo.GetTeacherId 0, 0, #teacherId=#teacherIdOut -- here I get error
SELECT Teachers.TeacherLastName, Teachers.TeacherFirstName, Teachers.TeacherMiddleName
FROM Teachers
WHERE Teachers.TeacherId=#teacherIdOut
)T(TLastName, TFirstName, TMiddleName)
WHERE Score <=3
And is there any other way to get the value from the stored procedure?
Here my stored procedure dbo.GetTeacherId:
USE [StudentsDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetTeacherId] #lessonId int, #groupId int, #teacherId int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #teacherId=GroupTeachers.TeacherId
FROM GroupTeachers
WHERE GroupTeachers.LessonId=#lessonId AND GroupTeachers.GroupId=#groupId
END
Stored procedure is not designed for that kind of usage, as it can perform operations other then selecting data, it can work without returning data or it can return different set in different scenarios.
Unlike stored procedures, functions are exactly suited to be used inline with other queries.
You have two options:
A) Create a scalar function that will return only a TeacherID and use it in your WHERE
CREATE FUNCTION udfGetTeacherID
(
#lessonId int, #groupId int
)
RETURNS int
AS
BEGIN
DECLARE #teacherId INT;
SELECT #teacherId = GroupTeachers.TeacherId
FROM GroupTeachers
WHERE GroupTeachers.LessonId=#lessonId AND GroupTeachers.GroupId=#groupId;
RETURN #teacherId;
END
GO
B) Create table-valued function that can get you all the data needed and you can just join (apply) on it.
CREATE FUNCTION udfGetTeacherName
(
#lessonId int, #groupId int
)
RETURNS TABLE
AS
RETURN
(
SELECT t.TeacherLastName, t.TeacherFirstName, t.TeacherMiddleName
FROM Teachers t
INNER JOIN GroupTeachers g ON T.TeacherID = g.TeacherID
WHERE g.LessonId=#lessonId AND g.GroupId=#groupId
)
GO
Here is some reading:
Difference between Stored Procedure and Function in SQL Server

Defining several input variables in sql (server 2008) inline function

I want to modify my inline function so that it can handle two variables as input. With just one it worked just fine.
FUNCTION [dbo].[TBL_UDF_HowOften]
(
-- Add the parameters for the function here
#membername as varchar(15),
#tablename as varchar(15)
)
RETURNS #ergebnis TABLE
(
participated float,
percent float,
WonWen1 float,
WonWen2 float,
WonWen3 float
)
AS
BEGIN
DECLARE #wintimes float
DECLARE a lot of other stuff...
SELECT #wintimes = COUNT(DidWin)
FROM #tablename
WHERE DidWin = 1 AND membername = #membername
... and so on
Well, #membername is recognized but #tablename is marked with "Must declare the table variable "#tablename"."
You can't use a scalar variable as the table name in a 'from' clause. You would need to use dynamic sql, which I do not think can be done inside a function.