Replacing frequently used complicated test in SQL Server Query with Function - sql

I have a test I have to use regularly in queries to see if a CPT billing code is a billable encounter. In the SQL query, the test looks like this:
where (pvp.code between '99201' and '99215'
or pvp.code between '99221' and '99239')
plus a whole bunch more ranges.
I tried to create a function by just plugging this in to the function, but I got an "incorrect syntax" error -- not a huge surprise, really.
CREATE FUNCTION IsEncounter
(
#code varchar(20)
)
RETURNS bit
AS
BEGIN
DECLARE #Result bit;
SELECT #Result = #code between '99201' and '99215'
or #code between '99221' and '99239';
-- Return the result of the function
RETURN #Result;
END
I suppose I can do something like
if (#code >= '99201' and #code <= '99215')
or (#code >= '99221' and #code <= '99239')
select #Result = 1
else
select #Result = 0;
but I'd like to know the cleanest way to do this. Thanks.

Something like this should work:
CREATE FUNCTION IsEncounter
(
#code varchar(20)
)
RETURNS bit
AS
BEGIN
DECLARE #Result bit
SET #Result = CASE WHEN (#code between '99201' and '99215') or (#code between '99221' and '99239') THEN 1 ELSE 0 END
RETURN #Result
END

I think you are almost right with your UDF. I think there is just a few syntax issues. Try the following:
CREATE FUNCTION IsEncounter
(
#code varchar(20)
)
RETURNS bit
AS
BEGIN
DECLARE #Result bit = 0
IF #code between '99201' and '99215' or #code between '99221' and '99239'
BEGIN
SET #Result = 1
END
RETURN #Result
END
Then your WHERE clause would simply be:
where dbo.IsEncounter(p.Code)=1

I'd move my ranges into a table and then do this:
CREATE FUNCTION IsEncounter ( #code VARCHAR(20) )
RETURNS BIT
AS
BEGIN
DECLARE #MatchedRanges SMALLINT ;
DECLARE #Result BIT ;
SELECT #MatchedRanges = COUNT(*)
FROM tblRangeWhiteList
WHERE #code BETWEEN RangeStart AND RangeEnd
IF #MatchedRanges > 0
SET #Result = 1
ELSE
SET #Result = 0
RETURN #Result
END

Related

SQL Server function to get output zero or not

I am stuck to get output from function that takes an input parameter and should return zero or not:
alter function dbo.ZERONOT(#input int)
returns varchar(30)
as
begin
declare #result varchar(30)
declare #result1 varchar(30)
select #input = P_PRICE
from Product_ID
if (#input > 0)
set #result = 'YES'
return #result
else
set #result1 = 'NO'
return #result1
end
I think you want this:
ALTER FUNCTION dbo.ZERONOT(#Input INT) --The input value stored here
-- The variable used to pass the value to the function and make some
-- operations based on it, do not change his value.
RETURNS VARCHAR(3)
AS
BEGIN
DECLARE #Result VARCHAR(3);
IF EXISTS (SELECT 1 FROM Products WHERE Product_ID = #Input)
--Or maybe the price because I don't think you have a table named Product_ID
SET #Result = 'Yes'
ELSE
SET #Result = 'No';
RETURN #Result
END
Don't forget to visit the documentation

SQL - parametrized procedure with multiple parameters as array

I have very simple procedure:
CREATE PROCEDURE [Report]
#statusValue varchar(200) = '%'
AS
BEGIN
SELECT * FROM SomeTable
WHERE Something LIKE UPPER(#statusValue)
END
I'd like to provide user set multiple statusValue. Because there is 6 levels of statusValue in my table, I'd like to provide user to define required statusValue into procedure parameters - something like array.
I don't know, how it exactly works - I'm very new in this area - but I'm supposing to have procedure like this one:
EXEC Report #statusValue = 'statusValue1|statusValue2|statusValue3'
Do you happen to know, how can I adjust my procedure to have required output. Many thanks in advance.
Use following user defined function to return values from delimited string (say pipe):
CREATE FUNCTION [dbo].[stringlist_to_table]
(#list varchar(8000),
#delimiter nchar(1) = N',')
RETURNS #tbl TABLE (value varchar(8000)) AS
BEGIN
DECLARE #pos int,
#tmpstr varchar(8000),
#tmpval varchar(8000);
SET #tmpstr = #list;
SET #pos = charindex(#delimiter , #tmpstr);
WHILE #pos > 0
BEGIN
SET #tmpval = ltrim(rtrim(left(#tmpstr, #pos - 1)))
INSERT #tbl (value) VALUES(#tmpval)
SET #tmpstr = substring(#tmpstr, #pos + 1, len(#tmpstr))
SET #pos = charindex(#delimiter, #tmpstr)
END
INSERT #tbl(value) VALUES (ltrim(rtrim(#tmpstr)));
RETURN
END
Now use the following procedure to get the required output:
CREATE PROCEDURE [Report]
#statusValue varchar(200) = '%'
AS
BEGIN
DECLARE #iterator INT = 1;
DECLARE #total INT = 1;
DECLARE #keyword VARCHAR(100) = '';
SELECT ROW_NUMBER() OVER (ORDER BY value) SNo, value keyword
INTO #temp
FROM dbo.stringlist_to_table(#statusValue, '|')
SELECT *
INTO #output
FROM SomeTable
WHERE 1 = 0;
SELECT #total = MAX(SNo), #iterator = MIN(Sno)
FROM #temp
WHILE (#iterator <= #total)
BEGIN
SELECT #keyword = '%' + keyword + '%'
FROM #temp
WHERE SNo = #iterator;
INSERT INTO #output
SELECT *
FROM SomeTable
WHERE Something LIKE #keyword
SET #iterator = #iterator + 1;
END
SELECT *
FROM #output;
DROP TABLE #output, #temp;
END
You need the split function in this case. As there is no way to handle what you need. Another approach to add many variables. But in your case it will be enough to create split function and use it to parse your string. Please find the split function below:
CREATE FUNCTION [dbo].[ufnSplitInlineStringToParameters] (
#list NVARCHAR(MAX)
,#delim NCHAR(1) = ','
)
RETURNS TABLE
AS
RETURN
WITH csvTbl(START, STOP) AS (
SELECT START = CONVERT(BIGINT, 1)
,STOP = CHARINDEX(#delim, #list + CONVERT(NVARCHAR(MAX), #delim))
UNION ALL
SELECT START = STOP + 1
,STOP = CHARINDEX(#delim, #list + CONVERT(NVARCHAR(MAX), #delim), STOP + 1)
FROM csvTbl
WHERE STOP > 0
)
SELECT LTRIM(RTRIM(CONVERT(NVARCHAR(4000), SUBSTRING(#list, START, CASE
WHEN STOP > 0
THEN STOP - START
ELSE 0
END)))) AS VALUE
FROM csvTbl
WHERE STOP > 0
GO
One of the simplest way to achieve this is using a custom type. Sample snippet as follows:
CREATE TYPE dbo.StatusList
AS TABLE
(
statusValue varchar(200)
);
GO
CREATE PROCEDURE [Report]
#statusValue AS dbo.StatusList READONLY
AS
BEGIN
SELECT * FROM SomeTable
WHERE Something IN (SELECT * FROM #statusValue)
END
GO
--EDIT---
If you are using SSMS, you can execute the procedure as follows:
DECLARE #status dbo.StatusList
INSERT INTO #status VALUES('Pending')
EXEC [Report] #status

SQL Server, horizontal concatenate Range of Dates

I would like to know the way I could concatenate between two dates in a calculated column horizontally, for example:
date_ini,date_end,result
2016-04-01,2016-04-05,2016-04-01|2016-04-02|2016-04-03|2016-04-04|2016-04-05
2016-04-03,2016-04-06,2016-04-03|2016-04-04|2016-04-05|2016-04-06
2016-04-05,2016-04-05,2016-04-05
2016-04-05,2016-04-06,2016-04-05|2016-04-06
The result is the column I would like to create
Thanks,
A function like this could do the trick. Please change the size of the return varchar to fit your needs.
CREATE FUNCTION dbo.date_concatenate(#start_date DATETIME, #end_date DATETIME)
RETURNS VARCHAR(255)
AS
BEGIN
DECLARE #result VARCHAR(255);
SET #result = '';
IF(#end_date < #start_date)
SET #result = 'Error: End Date can not be less than start date';
ELSE
BEGIN
WHILE (#start_date < #end_date)
BEGIN
SET #result = #result + CONVERT(varchar(10),#start_date,120) + '|'
SET #start_date = DATEADD(dd,1,#start_date)
END
END
SET #result = #result + CONVERT(varchar(10),#end_date,120)
RETURN #result
END

How to toggle case of Entire string in sql

I want to toggle case of entire string.
I am able to do for characters, not for string.
DECLARE #Char AS VARCHAR(1)
SET #Char='a'
IF ASCII(#Char)>=97 AND ASCII(#Char) <=122
PRINT UPPER(#Char)
IF ASCII(#Char)>=65 AND ASCII(#Char) <=90
PRINT LOWER(#Char)
How, I can change case for entire string?
For Ex. "AbCdE", I want to change it to "aBcDe".
You can do it by creating functions:
First make function for one character:
CREATE FUNCTION ToggleChar
(
#Char VARCHAR(1)
)
RETURNS VARCHAR(1)
AS
BEGIN
RETURN CHAR(ASCII(UPPER(#Char))+ASCII(LOWER(#Char))-ASCII(#Char))
END
Then, create function for string:
CREATE FUNCTION ToggleCase
(
#Str VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #ResultStr VARCHAR(MAX)
SET #ResultStr=''
WHILE ( #Str<>'')
BEGIN
SET #ResultStr=#ResultStr + [dbo].[ToggleChar](#Str)
SET #Str= SUBSTRING(#Str,2,LEN(#Str))
END
RETURN #ResultStr
END
Now, use this function to toggle string.
SELECT dbo.ToggleCase('AbCdE') AS ToggleString
Try this:
DECLARE #Name VARCHAR(10) = 'SaMplE'
DECLARE #Count INT = 1
WHILE #Count <= LEN(#Name)
BEGIN
SET #Name = STUFF(#Name, #Count, 1,
CASE
WHEN ASCII(SUBSTRING(#Name,#Count,1)) BETWEEN 97 AND 122 THEN
UPPER(SUBSTRING(#Name,#Count,1))
WHEN ASCII(SUBSTRING(#Name,#Count,1)) BETWEEN 65 AND 90 THEN
LOWER(SUBSTRING(#Name,#Count,1))
END)
SET #Count = #Count + 1
END
SELECT #Name

How to assign an exec result to a sql variable?

How do you assign the result of an exec call to a variable in SQL? I have a stored proc called up_GetBusinessDay, which returns a single date.
Can you do something like this:
exec #PreviousBusinessDay = dbo.up_GetBusinessDay #Date, -1
I always use the return value to pass back error status. If you need to pass back one value I'd use an output parameter.
sample stored procedure, with an OUTPUT parameter:
CREATE PROCEDURE YourStoredProcedure
(
#Param1 int
,#Param2 varchar(5)
,#Param3 datetime OUTPUT
)
AS
IF ISNULL(#Param1,0)>5
BEGIN
SET #Param3=GETDATE()
END
ELSE
BEGIN
SET #Param3='1/1/2010'
END
RETURN 0
GO
call to the stored procedure, with an OUTPUT parameter:
DECLARE #OutputParameter datetime
,#ReturnValue int
EXEC #ReturnValue=YourStoredProcedure 1,null, #OutputParameter OUTPUT
PRINT #ReturnValue
PRINT CONVERT(char(23),#OutputParameter ,121)
OUTPUT:
0
2010-01-01 00:00:00.000
This will work if you wish to simply return an integer:
DECLARE #ResultForPos INT
EXEC #ResultForPos = storedprocedureName 'InputParameter'
SELECT #ResultForPos
declare #EventId int
CREATE TABLE #EventId (EventId int)
insert into #EventId exec rptInputEventId
set #EventId = (select * from #EventId)
drop table #EventId
From the documentation (assuming that you use SQL-Server):
USE AdventureWorks;
GO
DECLARE #returnstatus nvarchar(15);
SET #returnstatus = NULL;
EXEC #returnstatus = dbo.ufnGetSalesOrderStatusText #Status = 2;
PRINT #returnstatus;
GO
So yes, it should work that way.
I had the same question. While there are good answers here I decided to create a table-valued function. With a table (or scalar) valued function you don't have to change your stored proc. I simply did a select from the table-valued function. Note that the parameter (MyParameter is optional).
CREATE FUNCTION [dbo].[MyDateFunction]
(#MyParameter varchar(max))
RETURNS TABLE
AS
RETURN
(
--- Query your table or view or whatever and select the results.
SELECT DateValue FROM MyTable WHERE ID = #MyParameter;
)
To assign to your variable you simply can do something like:
Declare #MyDate datetime;
SET #MyDate = (SELECT DateValue FROM MyDateFunction(#MyParameter));
You can also use a scalar valued function:
CREATE FUNCTION TestDateFunction()
RETURNS datetime
BEGIN
RETURN (SELECT GetDate());
END
Then you can simply do
Declare #MyDate datetime;
SET #MyDate = (Select dbo.TestDateFunction());
SELECT #MyDate;
Here is solution for dynamic queries.
For example if you have more tables with different suffix:
dbo.SOMETHINGTABLE_ONE, dbo.SOMETHINGTABLE_TWO
Code:
DECLARE #INDEX AS NVARCHAR(20)
DECLARE #CheckVALUE AS NVARCHAR(max) = 'SELECT COUNT(SOMETHING) FROM
dbo.SOMETHINGTABLE_'+#INDEX+''
DECLARE #tempTable Table (TempVALUE int)
DECLARE #RESULTVAL INT
INSERT INTO #tempTable
EXEC sp_executesql #CheckVALUE
SET #RESULTVAL = (SELECT * FROM #tempTable)
DELETE #tempTable
SELECT #RESULTVAL
You can use a Table Variable for that
Code:
DECLARE #PreviousBusinessDay DATETIME
DECLARE #Temp TABLE(BusinessDay DATETIME)
INSERT INTO #Temp EXEC dbo.up_GetBusinessDay #Date, -1
SET #PreviousBusinessDay = (SELECT * FROM #Temp)
SELECT #PreviousBusinessDay
https://www.sqlservertutorial.net/sql-server-user-defined-functions/sql-server-table-variables/