SQL Server user-defined-function using WITH, IF together - sql-server

I need to create a scalar-valued user defined function in SQL Server. I need to have with clause to store some intermediary tables which will produce the final return result. I also need IF .. ELSE because depending on the input parameter the query to the resutl is different. However, I can't write the code without error combinaing these two elements together. My function would be like this:
CREATE FUNCTION [dbo].[getMyValue](
#inputType int
)
RETURNS float
AS
BEGIN
DECLARE #result float
;
WITH tempTable AS
(
SELECT * from TableA
)
;
IF inputType = 1
set #result = select sum(t.result1) from tempTable
else
selecset #result = select sum(t.result2) from tempTable
return #result
END
GO
But now it complains incorrect syntax near 'if'. If I remove the with clause (and query against some actual table) it compiles, or if I remove IF statements it also compiles. So how can I make them work together?

You cannot use IF like this in the context of an SQL query. Try using the following instead:
DECLARE #result float, #result1 float, #result2 float
WITH tempTable AS
(
SELECT * from TableA
)
SELECT #result1 = sum(case when #inputType = 1 then t.result1 else 0 end),
#result2 = sum(case when #inputType = 2 then t.result2 else 0 end)
FROM tempTable
IF #inputType = 1
SET #result = #result1
ELSE
SET #result = #result2
RETURN #result

Related

How do I use WHILE loop in CASE statement in SQL

In 'CASE' statement in SQL we use a bool condition and get a TRUE or FALSE result. In this situation I have to use non-bool unlimited condition. But I can't...
ALTER proc [dbo].[sp_StudentList](#CreatedBy nvarchar(max))
as
begin
declare #LikedBy nvarchar(max) = (Select LikedBy from LikeStatus)
declare #TeacherRequestID int = (Select TeacherRequestID from LikeStatus where LikedBy=#CreatedBy)
declare #UserName nvarchar(max) = #CreatedBy
declare #i int = 1
declare #NumberOfRows int = (select count(*) from TeacherRequest)
select SP.StuThana, SP.StuDist, TR.StudentName,TR.StudentCode, TR.Class, TR.Subject, TR.StuGroup,TR.StuRelation, TR.Institute,TR.Status, TR.LikeStatus,
**CASE
WHEN
WHILE(#i <= #NumberOfRows)
BEGIN
#TeacherRequestID = TR.ID THEN 'Liked' Else 'Like'
set #i = #i + 1
END
END as LikeFlag**
from StudentsProfile SP join TeacherRequest TR on SP.CreatedBy=TR.CreatedBy
--sp_StudentList 'teacher1#gmail.com'
end
The technical answer to your question as posed in your title is that you can't.
declare #i int = 5;
select case when (while #i > 0 begin set #i = #i - 1 end) then 1 else 0 end;
-- Incorrect syntax near the keyword 'while'
Is your intention to just determine whether a student listed in a row likes the associated teacher? If so, then you're looking for whether an entry exists in another table, not how often it occurs. And I would tie it to sp.createdBy, not #createdBy.
select // ...,
likeFlag =
case when exists (
select 0
from likeStatus ls
where ls.likedBy = sp.createdBy
and ls.TeacherRequestId = tr.id
) then 'Liked'
else 'Like'
end
from studentsProfile sp
join teacherRequest tr on sp.createdBy = tr.createdBy
If for some reason you really only need 'Liked' based on #createdBy, then change ls.likedBy = sp.createdBy to ls.likedBy = #createdBy, but I don't see a strong use case for that.

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.

Issue with Returning Results SQL

DECLARE #ReturnValue INT
DECLARE #Field1 VARCHAR(50)
SET #Field1 = (SELECT Field1
FROM [Workflow Creation].[dbo].[ssFields]
WHERE Field1 = 'Gary')
IF #Field1 = 'Gary' OR #Field1 = 'Sarah'
SET #ReturnValue = '1'
ELSE
SET #ReturnValue = '0';
Essentially I want to Return a value and then set that value. I am working with program, that is very touchy feely on what it returns. So I get this error in SQL Management Studio:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Below is what I had before, it would return results, but the program would not take the results and properly assign it where i needed these files to go.
SELECT
CAST(CASE
WHEN Field1 = 'Gary' OR Field1 = 'Sarah'
THEN 1
ELSE 0
END AS BIT) AS [ReturnValue],
*
FROM
[Workflow Creation].[dbo].[ssfields];
Thanks,
JimmyDean
Your problem are these lines:
DECLARE #Field1 VARCHAR(50)
SET #Field1 = (SELECT Field1
FROM [Workflow Creation].[dbo].[ssFields]
WHERE Field1 = 'Gary')
#Field1 is a VARCHAR value (not a TABLE variable) and your select is returning multiple rows because in table ssFields there is more than 1 row with Field1 = 'Gary'. This is why you get the error message:
Subquery returned more than 1 value
To fix this you can use a TOP 1 inside the SELECT. This will always return either 0 or 1 row (and never more) and this message won't pop.
DECLARE #Field1 VARCHAR(50)
SET #Field1 = (SELECT TOP 1 Field1 -- Here
FROM [Workflow Creation].[dbo].[ssFields]
WHERE Field1 = 'Gary')
However, I believe that this is actually what you are looking for:
DECLARE #ReturnValue INT
DECLARE #Field1 VARCHAR(50) = 'Gary'
IF EXISTS ( SELECT 'the searched field exists!!'
FROM [Workflow Creation].[dbo].[ssFields]
WHERE Field1 = #Field1)
BEGIN
SET #ReturnValue = 1 -- Don't use literals if it's a number!
END
ELSE
BEGIN
SET #ReturnValue = 0 -- Don't use literals if it's a number!
END
the reason why you're getting that error is because you can only assign one item to your #Field1 variable. SQL Server thinks you're trying to assign multiple nvarchars to the same #Field1 variable. Here's how to fix your query:
DECLARE #ReturnValue INT
DECLARE #Field1 VARCHAR(50)
SET #Field1 = (SELECT TOP 1 Field1
FROM YourTable
WHERE Field1 = 'Gary')
IF #Field1 = 'Gary' OR #Field1 = 'Sarah'
SET #ReturnValue = '1'
ELSE
SET #ReturnValue = '0';
SELECT #ReturnValue --will be 1
When you use SELECT TOP 1 Field1 FROM YourTable you are explicitly telling SQL Server to take the top record returned and assign the Column result for Field1 to your variable #Field1.
If you have multiple results you want to capture then a temp table could do it:
CREATE TABLE #Field1s (
Id INT PRIMARY KEY IDENTITY (1,1),
IsGaryOrSarah BIT NOT NULL
)
INSERT INTO #Field1s
SELECT CASE WHEN Field1 = 'Gary' THEN 1
WHEN Field1 = 'Sarah' THEN 1
ELSE 0 END
FROM YourTable
SELECT * FROM #Field1s
However if the intent is to do some operation based on the result as part of a workflow then you would almost certainly want to do that from application code. You would query the table from the application and you can more easily implement a conditional logic workflow using a language designed for that task.

T-SQL different result between code in stored and same code in query pane

I'm working on a procedure that should return a o or a 1, depending on result from parameter calculation (parameters used to interrogate 2 tables in a database).
When I excute that code in a query pane, it gives me the results i'm expecting.
code looks like:
SELECT TOP 1 state, updDate INTO #history
FROM [xxx].[dbo].[ImportHystory] WHERE (db = 'EB') ORDER BY addDate DESC;
IF (SELECT state FROM #history) = 'O'
BEGIN
SELECT TOP 1 * INTO #process_status
FROM yyy.dbo.process_status WHERE KeyName = 'eb-importer';
IF(SELECT s.EndDate FROM #process_status s) IS NOT NULL
IF (SELECT s.EndDate FROM #process_status s) > (SELECT h.updDate FROM #history h)
BEGIN
IF (SELECT MessageLog from #process_status) IS NOT NULL SELECT 1;
ELSE SELECT 0;
END
ELSE
SELECT 1;
ELSE
SELECT 1;
END
ELSE
SELECT 0
I'm in the situation where EndDate from #process_status is null, so the execution returns 1.
Once i put the SAME code in a SP, and pass 'EB' and 'eb-importer' as parameters, it returns 0.
And I exec the procedure with the data from the table right in front of me, so i know for sure that result is wrong.
Inside the procedure:
ALTER PROCEDURE [dbo].[can_start_import] (#keyName varchar, #db varchar, #result bit output)
DECLARE #result bit;
and replace every
SELECT {0|1}
with
SELECT #result = {0|1}
Executed from the Query pane:
DECLARE #result bit;
EXEC [dbo].[can_start_import] #KeyName = 'eb-importer', #db = 'EB', #result = #result OUTPUT
SELECT #result AS N'#result'
Why does this happen?
You are doing a top(1) query without an order by. That means SQL Server can pick any row from table1 that matches the where clause.
If you want to guarantee that the result is the same every time you execute that code you need an order by statement that unambiguously orders the rows.
So, apparently 2 things needed to be done:
set the length of the varchar parameter with a higher length,
filter with ' like ' instead of ' = ' for god knows what reason
Now it work as i expected to do, but i still don't get the different results between the query pane and the procedure if i use the equal...

Use if, else in function in sql query

I use the below query,but throws an error:
CREATE FUNCTION getCustomerPaymentFunc (#customerCode bigint )
RETURNS bigint AS BEGIN
RETURN
( if(select coun from getCustomerPaymentCount (#customerCode))=0)
select 0 as price
else
(select SUM(price) as code
from PaymentLog
where customerCode=#customerCode)
) END
I Use below Two but says:
select statement included within a function cannot return data to client
CREATE FUNCTION getCustomerPaymentFunc (#customerCode bigint )
RETURNS bigint AS BEGIN
RETURN
(
SELECT CASE WHEN (select coun from getCustomerPaymentCount(#customerCode))=0
THEN 0 ELSE 1 END as
(select SUM(price) as code from PaymentLog
where customerCode=#customerCode)
) END
It looks like your intention is to have the function return the sum of price in the PaymentLog table for a given customerCode, or return 0 if the customerCode doesn't exist. If this is correct you could do this:
CREATE FUNCTION getCustomerPaymentFunc (#customerCode bigint) RETURNS bigint AS
BEGIN
DECLARE #result bigint
SET #result= (SELECT ISNULL(SUM(price), 0) FROM PaymentLog WHERE customerCode = #customerCode)
RETURN #result
END
If thecustomerCodedoesn't exist in thePaymentLogtable theSUM()function will returnNULLand you can use either theCOALESCEor theISNULLfunction to replace the NULLvalue with 0.
See MSDN: COALESCE and ISNULL

Resources