TSQL use joined table data as function parameters - sql-server

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.

Related

How can i search for the same input parameter

My input parameter is :
exec [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER] N'2040,2041,2044,2047,2048'
I need to search in a data base where i have to search in those inputs like this
Product IN ('2040','2041','2044','2047','204048')
How can i convert the input parameter to put it inside the " Product" search one at a time
UPDATE
I need to split the input to be list of strings to be able to search in them
You can use a dynamic query and pass the IDs in the query directly but this option is vulnerable to SQL Injection. Therefore, you should split up the IDs first and then join it with your actual table. Your procedure should be like this:
CREATE PROCEDURE [MULTI_VALUED_USER_INPUT_PARAMETER] #Ids NVARCHAR(1000)
AS
--DECLARE #Ids NVARCHAR(1000) = N'2040,2041,2044,2047,2048'
;WITH CTE
AS(
SELECT CAST('<N>' + REPLACE(#Ids,',','</N><N>') + '</N>' AS XML) [XMLids]
)
SELECT T.a.value('.', 'INT') AS ID,yt.*
FROM CTE
CROSS APPLY CTE.XMLids.nodes('/N') AS T(a)
INNER JOIN dbo.YourTable yt
ON T.a.value('.', 'INT') = yt.Product
NOTE: I assumed that the IDs are INT by default, if not, please update the code. You can replace the JOIN with IN clause easily if required.
you are passing a string like this
N'2040,2041,2044,2047,2048'
and you are expecting it to be parsed as comma seperated values..so you need to parse the input first..
you could use split string available from here and do the parse like below in your proc..
select * from split_String(#String,',')
and pass the above input in the place where you are passing string in stored proc
split string source code:
CREATE FUNCTION dbo.SplitStrings_Numbers
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = SUBSTRING(#List, Number,
CHARINDEX(#Delimiter, #List + #Delimiter, Number) - Number)
FROM dbo.Numbers
WHERE Number <= CONVERT(INT, LEN(#List))
AND SUBSTRING(#Delimiter + #List, Number, LEN(#Delimiter)) = #Delimiter
);
GO
Numbers table :
CREATE TABLE Numbers
(
Number INT NOT NULL,
CONSTRAINT PK_Numbers
PRIMARY KEY CLUSTERED (Number)
WITH FILLFACTOR = 100
)
INSERT INTO Numbers
SELECT
(a.Number * 256) + b.Number AS Number
FROM
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) a (Number),
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) b (Number)
GO
What I understood is that you want to execute that store procedure with different parameters, which have to be included in the IN clause you wrote.
You can do this:
DECLARE #Product INT = 0
-- Iterate over all products
WHILE ( 1 = 1)
BEGIN
-- Get next productID
--Since you didn't show us how is your product tables I had to make up a little,
SELECT TOP 1 #Product = Product
FROM Products
WHERE Product > #Product
ORDER BY Product
-- Exit loop if no more products
IF ##ROWCOUNT = 0 BREAK;
-- call your sproc
EXEC [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER] #Product
END

SQL Adding Function

I'm trying to write a function that adds values that are selected from two different tables. I need the SUM of one column for a specific id in table 1, added to the SUM of a column for a specific id in table 2.
CREATE FUNCTION dbo.getSum(#id varchar(9)) --Our IDs are strings of length 9
RETURNS integer --I've also tried decimal(x,x) and int
AS
BEGIN
DECLARE #total as integer; -- same here with decimal and int
SELECT #total =
(
(select SUM(Amount)
from table1
where id = #id)
+
(select SUM(amount)
from table2
where id = #id)
);
RETURN #total;
END;
I get several types of errors when I try to create this function, like incorrect syntax near 'integer', Must declare the scalar variable "#total"., and Incorrect syntax near 'END'.
I've tried several variations and looked at several SO questions, but haven't found one that's fixed this issue for me yet. This is on SQL Server.
As previously mentioned the cause of your error is you did not define a datatype for your inbound parameter.
I would suggest a bit of a departure from the current structure. Instead of a scalar function I would use an inline table valued function. Something along these lines.
CREATE FUNCTION dbo.getSum(#id int)
RETURNS table
AS RETURN
SELECT SUM(MyAmount)
from
(
select SUM(Amount) as MyAmount
from table1
where id = #id
UNION ALL
select SUM(amount)
from table2
where id = #id
) x;
Looks like you are missing the parameter type in the function definiton
Try with the following
CREATE FUNCTION dbo.getSum(#id int)
RETURNS integer --I've also tried decimal(x,x)
AS
BEGIN
DECLARE #total as integer; -- same here with decimal
SELECT #total =
(
(select SUM(Amount)
from table1
where id = #id)
+
(select SUM(amount)
from table2
where id = #id)
);
RETURN #total;
END;
I think you need to declare the type of the parameter
CREATE FUNCTION dbo.getSum(#id int)
Your data types should be INT and there are general syntax errors... see below.
CREATE FUNCTION dbo.getSum(#id AS INT) -- Declare your paramater AS (datatype)
RETURNS INT -- No need for AS here, just start your block
BEGIN
DECLARE #total AS INT;
SELECT #total =
(
(select SUM(Amount)
from TableOne
where id = #id)
+
(select SUM(amount)
from TableTwo
where id = #id)
);
RETURN #total;
END;

how to use same column names with different data types in subquery in sqlserver

I have a query:
select *
from proformaentry
where cast(tcmno as varchar) not in(
select tcmno from contreceipt
)
I want to list all tcmno from proformaentry table which is not in the table contreceipt. In proformaentry table, tcmno is int datatype but in contreceipt, it is varchar type. So I used above query, but it is not returning any rows.
Actually there are some tcmno in proformaentry table which is not present in contreceipt.
Hope I can get the correct query to retrieve the rows from here.
I'm guessing contrecipt.tcmo is NULLABLE. NOT IN clause is the same as nested AND <> clauses. Example:
declare #tbl table(n int)
insert into #tbl values (1), (2), (3)
select * from #tbl where not n in(4, 5, 6, null)
The above query will not return any rows. If you transform the NOT IN, it'll be:
select * from #tbl where n <> 4 and n <> 5 and n <> 6 and n <> null
And since n <> null is FALSE, for the purpose of a WHERE clause, the NOT IN resulted to FALSE. In order to achieve the desired result, you can use NOT EXISTS:
select *
from proformaentry p
where not exists(
select 1 from contreceipt where tcmno = cast(p.tcmno as varchar(20))
)

SQL Server Scalar variable in Inline table valued function

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

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