SQL Server Scalar variable in Inline table valued function - sql-server

I have a multi statement table valued function which I would like to change to an inline table valued function for optimization purposes ( I don't really know if that will be an optimization but I want to try that anyway ). My problem is that I have a scalar variable which I don't know how to put in my WITH statement.
Code example:
CREATE FUNCTION [dbo].[function]()
RETURNS
#return_table table (id INT,value NVARCHAR(500))
AS
BEGIN
DECLARE #tmp_table TABLE(id INT, value VARCHAR(500))
DECLARE #variable BIGINT
INSERT INTO #tmp_table [...insert code...]
SET #variable = (SELECT MAX(id) FROM #tmp_table)
INSERT INTO #return_table SELECT id,value FROM #tmp_table WHERE id = #variable
RETURN
This code is an example, the actual function is more complex but the problem is exactly the same
I could easily change this to a single WITH statement like this:
CREATE FUNCTION [dbo].[function]()
RETURNS TABLE
AS
RETURN
(
WITH tmp_table AS (
SELECT [...Select Code...]
)
SELECT id,value FROM tmp_table
WHERE id = [variable]
);
GO
My problem lies into the [variable] which I don't know how to put into the query. Also, the variable is used more than once in my function so I'd rather not just replace it with the query.
I also tried this approach:
CREATE FUNCTION [dbo].[function]()
RETURNS TABLE
AS
RETURN
(
WITH tmp_table AS (
SELECT [...Select Code...]
), variable = (SELECT MAX(id) value FROM tmp_table)
SELECT id,value FROM tmp_table
WHERE id = (SELECT TOP 1 value FROM variable)
);
GO
But is seems like it made the function way slower.
Thank you.

Just try
WITH tmp_table AS (
SELECT [...Select Code...]
)
SELECT id,value FROM tmp_table WHERE id = (SELECT MAX(id) FROM tmp_table)
I would actually just change it to
SELECT TOP 1 *
FROm [whatever]
ORDER BY id DESC

Related

using NEWID() inside a function - as variable - but getting the same value every time

I'm using NEWID() inside a function.
this is my function:
CREATE FUNCTION dbo.myFunc (#newid NVARCHAR(50))
RETURNS int
AS BEGIN
declare #rndValue int
set #rndValue = (SELECT top 1 * FROM #temp ORDER BY lower(#newid))
RETURN #rndValue
END
i have #temp with values: '1','2','3'
i want to random from this table using this function.
i called this function like this:
dbo.myFunc (NEWID())
but i'm getting every time the same value ('1')
where is my error?
The function isn't using NEWID(). It's using the value of a string parameter named #newid
If you want to select a random row, use ORDER BY NEWID(). This generates a new non-sequential GUID for every row and orders the rows by it, effectively producing a random ordering, eg :
set #rndValue = (SELECT top 1 * FROM #temp ORDER BY newid())
The original query orders rows by a constant and thus has no effect. It's no different than using
set #rndValue = (SELECT top 1 * FROM #temp ORDER BY 'potato')
If you check the query's execution plan you'll see there's no SORT operation. The query optimizer simply removes the ineffective ORDER BY clause.
Finally, NEWID() produces a GUID, not a string. That's a 128-bit binary value. Using LOWER() serves no purpose
What you are doing looks strange, but if you need it in this format use the code below:
CREATE VIEW dbo.GetGUID
AS
SELECT NEWID() AS [NewID]
GO
CREATE TABLE dbo.temp
(
id int
);
GO
INSERT INTO dbo.temp
VALUES (1), (2), (3);
GO
CREATE FUNCTION dbo.myFunc ()
RETURNS int
AS BEGIN
declare #rndValue int
set #rndValue = (SELECT top 1 id FROM dbo.temp CROSS APPLY dbo.GetGUID ORDER BY [NewID])
RETURN #rndValue
END
GO
SELECT dbo.myFunc()
SELECT dbo.myFunc()
SELECT dbo.myFunc()
SELECT dbo.myFunc()
SELECT dbo.myFunc()
SELECT dbo.myFunc()
Basically, if you need to have NEWID() in function you need to use the view hack.
CREATE FUNCTION dbo.myFunc (#newid NVARCHAR(50))
RETURNS int
AS BEGIN
declare #rndValue int
set #rndValue = (SELECT top 1 * FROM #temp ORDER BY #newid)
RETURN #rndValue
END

How to store the result of an select statement into a variable in sql server stored procedure

I have a condition like this:
IF #aaa = 'high'
set #bbb = select * from table1
else
set #bbb = select * from table2
I am going to use this variable (#bbb) throughout my stored procedure
is this possible to save a table into a variable?
I tried using temporary table but i am not able to assign it twice.
IF #aaa = 'high'
set #bbb = select * into #temp from table1
else
set #bbb = select * into #temp from table2
it shows #temp is already declared.
No, It is not work like that. You can declare a table variable and insert into inside it.
DECLARE #bbbTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
insert into #bbbTable (Id,SampleColumn)
select Id,SampleColumn from table1
If the table1 and table2 are completely different tables, you should declare two different table variable;
DECLARE #bbbTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
DECLARE #aaaTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
IF #aaa = 'high'
insert into #bbbTable (Id,SampleColumn)
select Id,SampleColumn from table1
else
insert into #aaaTable (Id,SampleColumn)
select Id,SampleColumn from table2
You cant insert into a variable more than 1 value.
you can use Table Variable to reach your answer like this:
DELCARE #TableResult AS TABLE (Column1 INT, Column2 INT)
IF #aaa = 'high'
BEGIN
INSERT INTO #TableResult (Column1,Column2)
SELECT Column1FromTable, Column2FromTable
FROM table1
END
ELSE
BEGIN
INSERT INTO #TableResult (Column1,Column2)
SELECT Column1FromTable, Column2FromTable
FROM table2
END
Of course you can declare more than 2 columns.
You can store only 1 Column/Row to a variable.So you can't say *.
Suppose I want to store the value of Column1 from TableA to a variable, I can use this
SELECT #MyVariable = Column1 FROM TableA
But I Can't Say
SELECT #MyVariable = * FROM TableA
Even if there is only 1 column in the Table TableA.
Also If there is more than 1 record returned by the Select condition, then it will assign the First value to the Variable.
Or What you need is to store the entire Rows, you can Either use a Temporary table or a table variable.
Temporary Table
SELECT * INTO #Temp FROM TableA
Table Variable
DECLARE #MyVarTable TABLE
(
Column1 VARCHAR(50),
Column2 VARCHAR(50)
)
INSERT INTO #MyVarTable
(
Column1 ,
Column2
)
SELECT
Column1 ,
Column2
From MyTable
This Temporary Table and Table variable can be accessed in the same way you access the normal table using SELECT/UPDATE/DELETE Queries. Except :
Temporary tables are created for each session and automatically dropped when the session ends or the Query window is Closed
Table Variables exists only when you execute the Query. So before using the table variable in a query you need to declare the same

TSQL use joined table data as function parameters

Can anybody briefly explain why it is not possible to use values of the table as parameters for the joined function?
;CREATE FUNCTION "foo" ( #id INT )
RETURNS #result TABLE
(
"value" INT
)
AS
BEGIN
INSERT INTO #result SELECT #id * 2
RETURN
END;
;WITH "cte" AS
(
SELECT "id" = 1
UNION ALL
SELECT 2
)
SELECT
*
FROM
cte
, "foo"(cte."id")
The last line throws an error ( ~ cte."id" can not be bound ).
It doesn't matter if it's a cte or table.
Joining result sets coming out from table valued function is done by using CROSS APPLY.

Table variable error: Must declare the scalar variable "#temp"

I am trying to achieve:
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1 <--- ERROR AT #TEMP.ID
But I'm getting the following error:
Must declare the scalar variable "#temp".
What am I doing wrong?
A table alias cannot start with a #. So, give #Temp another alias (or leave out the two-part naming altogether):
SELECT *
FROM #TEMP t
WHERE t.ID = 1;
Also, a single equals sign is traditionally used in SQL for a comparison.
Either use an Allias in the table like T and use T.ID, or use just the column name.
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE ID = 1
There is one another method of temp table
create table #TempTable (
ID int,
name varchar(max)
)
insert into #TempTable (ID,name)
Select ID,Name
from Table
SELECT *
FROM #TempTable
WHERE ID = 1
Make Sure You are selecting the right database.
If you bracket the # you can use it directly
declare #TEMP table (ID int, Name varchar(max))
insert into #temp values (1,'one'), (2,'two')
SELECT * FROM #TEMP
WHERE [#TEMP].[ID] = 1
You should use hash (#) tables, That you actually looking for because variables value will remain till that execution only.
e.g. -
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
When above two and below two statements execute separately.
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1
The error will show because the value of variable lost when you execute the batch of query second time.
It definitely gives o/p when you run an entire block of code.
The hash table is the best possible option for storing and retrieving the temporary value. It last long till the parent session is alive.
try the following query:
SELECT ID,
Name
INTO #tempTable
FROM Table
SELECT *
FROM #tempTable
WHERE ID = 1
It doesn't need to declare table.
You could stil use #TEMP if you quote the identifier "#TEMP":
declare #TEMP table (ID int, Name varchar(max));
insert into #temp SELECT 1 AS ID, 'a' Name;
SELECT * FROM #TEMP WHERE "#TEMP".ID = 1 ;
db<>fiddle demo
You've declared #TEMP but in your insert statement used #temp. Case sensitive variable names.
Change #temp to #TEMP

Declare variable in table valued function

How can I declare a variable in a table valued function? (like in my title)
There are two flavors of table valued functions. One that is just a select statement and one that can have more rows than just a select statement.
This can not have a variable:
create function Func() returns table
as
return
select 10 as ColName
You have to do like this instead:
create function Func()
returns #T table(ColName int)
as
begin
declare #Var int
set #Var = 10
insert into #T(ColName) values (#Var)
return
end
In SQL Server:
It's not a very nice solution, but if you have a valid reason for needing to use an inline TVF instead of a MSTVF and cannot pass the variable into the TVF as a parameter, but can obtain it using a SELECT statement, you can use a CTE to access the value as follows:
CREATE FUNCTION func()
RETURNS TABLE
AS
RETURN
(
-- Create a CTE table containing just the required value
WITH cte_myVar AS
(SELECT <statement to select variable>) col1
-- Use the value by selecting it from the CTE table
SELECT * FROM table1 t1
WHERE t1.col1 = (SELECT col1 FROM cte_myVar)
)

Resources