Use parameter as column name in table-valued function in SQL Server - sql-server

ALTER FUNCTION [dbo].[cycleplan_doctor_view]
(#Parameter1 INTEGER, #Group VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(SELECT *
FROM tbl_master_doctor
WHERE int_doctor_id IN (SELECT int_doctor_id
FROM tbl_master_MR
WHERE int_user_id = #Parameter1
AND #Group = 'Yes')
)
When I am passing a value for #Group, I am getting empty table. But when I replace the value of #Group with its value it is working correctly.
I think I am missing some basic thing here.

Related

How to add loops and compare in stored procedures SQL

I have the following set of number as a varchar and getting the input as an integer var.
#ProductId int
DECLARE #AllowedProductIds varchar(max)
SET #AllowedProductIds ='7002,7058,67,7000,7059,7038'
IF (#ProductId = (SELECT CAST(#AllowedProductIds AS INTEGER)
FROM dbo.SplitString(#AllowedProductIds, ',')))
BEGIN
SET #boolVariable = 1
END
I want to separate the varchar with a delimiter say in my case (,) and compare each one with the input and return the result from the boolean variable.
This is the following code that I have tried and I get an error:
Conversion failed when converting varchar to int
Can somebody please help me out how to do this?
Your cast call is not reading the returned column from the dbo.SplitString call, and instead is trying to evaluate the whole input string as an integer, which it is not.
I don't know the schema of the output of your SplitString function, but let's imagine that it returns something like this:
Input string: '12345,123,234,345'
Output table:
SplitStringItem
12345
123
234
345
Then your call should be:
if #ProductId IN
(
select cast(SplitStringItem AS INTEGER) from dbo.SplitString(#AllowedProductIds, ',')
)
Note the change to use the IN operator rather than the = operator, since you're trying to assess whether a single integer value is in a list of possible values.
As you're using SQL Server you can do this
declare #AllowedProductIds varchar(max), #ProductId int=67
set #AllowedProductIds ='7002,7058,67,7000,7059,7038'
if exists (select * from String_Split(#AllowedProductIds, ',') where Cast(value as int)=#ProductId )
print 'yay'
Or alternatively
declare #AllowedProductIds varchar(max), #ProductId int=67
set #AllowedProductIds ='7002,7058,67,7000,7059,7038'
if exists (select * from String_Split(#AllowedProductIds, ',') where value=Cast(#ProductId as varchar) )
print 'yay'
and
select #boolVariable=
case when exists (select * from String_Split(#AllowedProductIds, ',') where value=Cast(#ProductId as varchar) )
then 1 else 0 end
In SQL Server 2016 you can use string_split() function to do what you are trying to achieve.
Query:
DECLARE #ProductId int,#isHavingBoldAccess int
set #ProductId=7058
DECLARE #AllowedProductIds varchar(max)
SET #AllowedProductIds ='7002,7058,67,7000,7059,7038'
IF #ProductId in
(
select * from STRING_SPLIT(#AllowedProductIds, ',')
)
SET #isHavingBoldAccess = 1
print #isHavingBoldAccess
Output:
1
db<>fiddle here
You can Simplify your Code like this:
Also the above mentioned Error is resolved here.
If the #ProductId matches with the #AllowedProductIds String, the we can assign the Value as 1 else it will takes the default value for the variable #boolVariable. Here its default value is NULL.
DECLARE #AllowedProductIds VARCHAR(MAX),
#boolVariable INT,
#ProductId INT=67
SET #AllowedProductIds ='7002,7058,67,7000,7059,7038'
SELECT #boolVariable = 1
FROM String_Split(#AllowedProductIds, ',')
WHERE CAST(Value AS INTEGER) =#ProductId
SELECT #boolVariable

SQL server Function - Take column name as input parameter

I need to write a SQL function to return column specific values, so I am passing the column name as a parameter to SQL-function to return its corresponding value. Here is the sample function
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
RETURN (SELECT TOP 1.#columnName FROM TEST_TABLE )
END
GO
The above function seems to be straight forward, but it not working as expected.
And when I execute the function
SELECT dbo.GETDATETIME('DATETIMECOLUMNNAME')
I am getting this error:
Conversion failed when converting date and/or time from character string.
Can someone help me to identify the issue?
For that you need to write dynamic sql. But Functions won't support execute statement.
So you need to write multiple If conditions for each column.
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
IF (#columnName = 'ABC')
Begin
SELECT TOP 1 #RESULT = [ABC] FROM TEST_TABLE
END
ELSE IF (#columnName = 'DEF')
Begin
SELECT TOP 1 #RESULT = [DEF] FROM TEST_TABLE
END
ELSE IF (#columnName = 'GHI')
Begin
SELECT TOP 1 #RESULT = [GHI] FROM TEST_TABLE
END
RETURN #RESULT
END
GO
Edit 2:
If your column always return Datetime, then you can do like below.
CREATE TABLE A_DUM (ID INT, STARTDATE DATETIME, ENDDATE DATETIME, MIDDLEDATE DATETIME)
INSERT INTO A_DUM
SELECT 1, '2019-07-24 11:35:58.910', '2019-07-28 11:35:58.910', '2019-07-26 11:35:58.910'
UNION ALL
SELECT 2, '2019-07-29 11:35:58.910', '2019-08-01 11:35:58.910', '2019-07-24 11:35:58.910'
And your function like below
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
SELECT TOP 1 #RESULT = CAST(PROP AS DATETIME)
FROM A_DUM
UNPIVOT
(
PROP FOR VAL IN (STARTDATE, ENDDATE,MIDDLEDATE)
)UP
WHERE VAL = #columnName
RETURN #RESULT
END
GO
There's a workaround to this, similar to #Shakeer's answer - if you are attempting to GROUP BY or perform a WHERE on a column name, then you can just use a CASE statement to create a clause to match on specific column names (if you know them).
Obviously this doesn't work very well if you have many columns to hard-code, but at least it's a way to achieve the general idea.
E.g. with WHERE clause:
WHERE
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnCondition
WHEN #columnname = 'SecondColumn' THEN SecondColumnCondition
ELSE SomeOtherColumnCondition
END)
Or with GROUP BY:
GROUP BY
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnGroup
WHEN #columnname = 'SecondColumn' THEN SecondColumnGroup
ELSE SomeOtherColumnGroup
END)
No you cannot use dynamic sql in functions in SQL. Please check this link for more info link.
So it is not possible to achieve this by any function, yes you may use stored procedures with output parameter for same.
You may find this link for reference link.

Create function with conditional calculation

I tried to create a function with a conditional calculation before the RETURN statement, but SSMS states that there is an incorrect syntax near 'BEGIN IF #param2 IS NULL' and I can't figure out what is wrong with this code:
CREATE FUNCTION ConditionalFunction
(
#input1 VARCHAR(20),
#input2 VARCHAR(20)
)
RETURNS TABLE
AS BEGIN
IF #input2 IS NULL
BEGIN
SET #input2 = field
FROM table1
WHERE filter = #input1
END
RETURN
(
SELECT field1, field2
FROM table2
WHERE filter1 = #input1
AND filter2 = #input2
)
END
My goal is to be able to call it either
ConditionalFunction('Foo',NULL)
or
ConditionalFunction('Foo','Bar')
In a way that the first call will make it detect a default value for #input2 based on #input1.
I wrote this code based on this answer.
This is SQL Server 13. Could you please tell me if there is anything I can do to make it compile?
N.B: I obviously replaced real names with generics, but the code structure remains the same
Try this, but change the #Data table types to your data types:
CREATE FUNCTION ConditionalFunction
(
#input1 VARCHAR(20),
#input2 VARCHAR(20)
)
RETURNS #Data TABLE
(
field1 VARCHAR(12)
,field2 VARCHAR(12)
)
AS
BEGIN
IF #input2 IS NULL
BEGIN
SET #input2 = field
FROM table1
WHERE filter = #input1
END
INSERT INTO #Data
SELECT field1, field2
FROM table2
WHERE filter1 = #input1
AND filter2 = #input2
RETURN;
END
There are several types of functions in SQL:
scalar return only one value
inline - returns a table (it is like view with parameters)
table-valued - returns a table
Your syntax looks like you need a inline function, but should contain only one SELECT statement returning the data. So, you need to create a table-valued function.

Passing Delimited values to SQL Server stored procedure for IN operator. How?

I need to pass the parameter (#name) as string 'Alex','david','crowner' to the query in a stored procedure.
The query in the stored procedure looks like this:
select *
from employees
where name in (#name)
The value for #name parameter that would be passed would be something like
'Alex','david','crowner'
How could I handle this in my stored procedure to find the names in a table with IN operator?
In SQL Server 2008 and later, you can use a table valued parameter. In the database, you have to create a table type. For example:
-- Drop old example definitions
if exists (select * from sys.procedures where name = 'TestProcedure')
drop procedure TestProcedure
if exists (select * from sys.types where name = 'TestTableType')
drop type TestTableType
if exists (select * from sys.tables where name = 'TestTable')
drop table TestTable
go
-- Create example table, type and procedure
create table TestTable (id int identity, name varchar(50))
create type TestTableType as table (name varchar(50))
go
insert TestTable values ('Bill'), ('George'), ('Barrack')
go
create procedure dbo.TestProcedure
#List TestTableType readonly
as
select *
from TestTable
where name in
(
select name
from #List
)
go
In C#, you can pass a DataTable as a table-valued parameter:
var listTable = new DataTable();
listTable.Columns.Add("Name", typeof(string));
listTable.Rows.Add("Bill");
listTable.Rows.Add("George");
var listParameter = new SqlParameter();
listParameter.ParameterName = "#List";
listParameter.Value = listTable;
using (var con = new SqlConnection("Server=localhost;Database=test;" +
"User Id=testuser;Password=testpassword;"))
{
var com = con.CreateCommand();
com.CommandText = "dbo.TestProcedure";
com.CommandType = CommandType.StoredProcedure;
com.Parameters.Add(listParameter);
con.Open();
using (var read = com.ExecuteReader())
{
while (read.Read())
Console.WriteLine(read["name"]);
}
}
The amount and complexity of code required for even a single table-valued parameter is no complement for the SQL Server designers.
you can pass in a single string to the parameter and inside the body of the stored proc use function(s) like charindex and substring and replace to do what you want
After some research I stumbled over a Code Project thread which was the key to solve the problem. With the help of the above thread I wrote the following stored procedure:
CREATE PROCEDURE [dbo].[myWorkingProcedure]
#inputList nvarchar(MAX)
AS
DECLARE #SetPoint INT
DECLARE #VALUE nvarchar(50)
CREATE TABLE #tempTab (id nvarchar(50) not null)
BEGIN
SET NOCOUNT ON;
WHILE PATINDEX('%,%',#inputList) > 0 <-- Drive loop while commata exist in the input string
BEGIN
SELECT #SetPoint = PATINDEX('%,%',#inputList) <-- Determine position of next comma
SELECT #VALUE = LEFT(#inputList , #SetPoint - 1) <-- copy everything from the left into buffer
SELECT #idList = STUFF(#inputList, 1, #SetPoint, '') <-- throw away the stuff you copied
INSERT INTO #tempTab (id) VALUES (#VALUE) <-- put value in buffer table
END
INSERT INTO #tempTab (id) VALUES (#inputList) <-- insert last value in the input list to buffer
BEGIN
SELECT * FROM myTable
WHERE myColumn IN (SELECT id FROM #tempTab) <-- Do the select
DROP TABLE #tempTab <-- throw buffer table away
END
END
GO

'Where in' T-SQL implementation

I have a stored procedure that take many input parameters including an #userID.
Now, in the core of the SP I select from a view using the following Where close :
Where userID = #userID
This works fine. Now I want to pass multiple users to be able wo query it like this :
where userID in (1,2,...)
How can I pass the value 1,2 from one input parameter ?
Thanks
Create a function split:
create FUNCTION [dbo].[Split]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(2000)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
--select Value from dbo.Split('item1, item2, item3',',')
END
GO
And call the function with #PASS and use it inside a cursor.
Arrays and Lists in SQL Server
Create an input parameter which is a table varaible and send in the array as a table that you join to instead of using in. Read about this in BOL as it can be a little tricky to set up.

Resources