SQL Server Function - sql-server

What is wrong with this function... The function intends to remove the specified leading characters from a given string. I know there is a patindex base solution to this which however doesn't consider spaces and all zero entries... but I want to know what is wrong with this one...
If I input "00012345" it should out put me "12345" however the output I'm getting is "0001234".. Why?
The test data is:
DECLARE #result varchar(max)
EXEC #result = TrimLeadingChar '00012345'
PRINT #result
The function code is:
CREATE FUNCTION TrimLeadingChar
(
#st AS Varchar(max),
#trimChar AS Varchar(1) = "0"
)
RETURNS Varchar(max)
AS
BEGIN
DECLARE #index int
DECLARE #temp Varchar(1)
SET #index = 0
if LEN(RTRIM(LTRIM(#st))) <= 1
return #st;
While(#index < LEN(#st))
BEGIN
set #temp = substring(#st,#index,1)
if #temp = #trimChar
SET #index = #index + 1
else
Break;
END
Return substring(#st,#index, LEN(#st))
END
GO

set #temp = substring(#st,#index+1,1)
instead of
set #temp = substring(#st,#index,1)
UPDATE:
OR you should set #index = 1 at first
DECLARE #index int
DECLARE #temp Varchar(1)
SET #index = 1
then
set #temp = substring(#st,#index,1)

Just for the sake of other users: Here is the working and complete solution function for SQL Server:
CREATE FUNCTION TrimBothEndsAndRemoveLeadingChar
(
#st AS VARCHAR(MAX),
#trimChar AS VARCHAR(1) = "0"
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #index INT
DECLARE #temp VARCHAR(1)
IF #st IS NULL OR #trimChar IS NULL OR LEN(RTRIM(LTRIM(#st))) <= 0
RETURN #st
SET #st = LTRIM(RTRIM(#st))
SET #index = 1
WHILE(#index <= LEN(#st))
BEGIN
SET #temp = SUBSTRING(#st, #index, 1)
IF #temp = #trimChar
SET #index = #index + 1
ELSE
BREAK;
END
DECLARE #result VARCHAR(MAX)
IF #index = (LEN(#st) + 1)
SET #result = #st
ELSE
SET #result = SUBSTRING(#st, #index, LEN(#st) + 1)
RETURN #result
END
GO

Related

Return first five numbers form string within UDF

I am working on SQL Server (2005,2008 & 2012)
I wanna extract first five numbers from varchar column via using UDF
Input:
rrr123ddd4567ddd19828www2
123hhhsss124ss18762s
qq12349wsss12376ss
Output:
19828
18762
12349
My Trail is as following:
DECLARE
#myString VARCHAR(1000),
#temp VARCHAR(100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #myString = 'rrr123ddd4567ddd19828www2'
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #temp = Replace (#temp,',','''),(''')
Select #temp = '(''' + #temp + ''')'
Create table #temp
(
col1 varchar(100)
)
SET #ExecuteInsert = 'insert into #temp values ' + #temp
Execute sp_executesql #ExecuteInsert
select top 1 col1 from #temp
where LEN(col1) = 5
drop table #temp
-- Output >> 19828
The previous query is working well with string input , but I wanna using this code within UDF to could using it with columns.
if I used the previous query within UDF, the following error is raising:
Cannot access temporary tables from within a function.
EDIT
if I used Table variable , I get the next error:
Only functions and some extended stored procedures can be executed
from within a function.
any help will be greatly appreciated.
CREATE FUNCTION udfTest
(
-- Add the parameters for the function here
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE
#Result int,
#myString VARCHAR(1000),
#temp VARCHAR(100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #myString = 'rrr123ddd4567ddd19828www2'
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #temp = Replace (#temp,',','''),(''')
Select #temp = '(''' + #temp + ''')'
Declare #tempTable TABLE
(
col1 varchar(100)
)
insert into #tempTable SELECT #temp
select top 1 #Result=col1 from #tempTable
where LEN(col1) = 5
return #Result
END
GO
Here you are my answer of my question , hope helps others.
The objective is creating UDF function for using it with columns, not only fixed values.
The approach is using SplitString instead of sp_executesql
for splitting a comma separated string and loop it's values in table.
Demo:-
Create table DummyTable
( col1 varchar (100))
go
Insert into DummyTable values ('rrr123ddd4567ddd19828www2')
Insert into DummyTable values ('123hhhsss124ss18762s')
Insert into DummyTable values ('qq12349wsss12376ss')
go
/*
SplitString via Mudassar Khan
http://www.aspsnippets.com/Articles/Split-and-convert-Comma-Separated-Delimited-String-to-Table-in-SQL-Server.aspx
*/
Create FUNCTION SplitString
(
#Input NVARCHAR(MAX),
#Character CHAR(1)
)
RETURNS #Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#Input, LEN(#Input) - 1, LEN(#Input)) <> #Character
BEGIN
SET #Input = #Input + #Character
END
WHILE CHARINDEX(#Character, #Input) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Character, #Input)
INSERT INTO #Output(Item)
SELECT SUBSTRING(#Input, #StartIndex, #EndIndex - 1)
SET #Input = SUBSTRING(#Input, #EndIndex + 1, LEN(#Input))
END
RETURN
END
GO
-------------------------------------
-------------------------------------
-------------------------------------
/*
My Own Function
*/
Create FUNCTION udfGetFirstFiveNumbers
(
#myString VARCHAR(1000)
)
RETURNS varchar(100)
AS
BEGIN
DECLARE
#temp VARCHAR(100),
#result Varchar (100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #result = Item
FROM dbo.SplitString(#temp, ',')
where len(Item) = 5
return #result
END
GO
-- Test
select col1, dbo.udfGetFirstFiveNumbers(col1) as result
from DummyTable
Result:-

Conversion failed when converting the varchar value ',1,2,3' to data type int

This error results when attempting to use a comma delimited parameter in an IN condition
I'm passing a varchar parameter to a stored procedure that looks like this
,1,2,3
And I want to find out if it contains 1 (it doesn't always contain 1)
What's the easiest way to do that in TSQL ?
declare #Nums varchar(max)=',1,2,3'
if 1 in (#Nums) -- conversion error
BEGIN
select * from TestTable
END
You will need to use LIKE to see if the string contains the character 1. Note this will also match 12 or any string with the character '1' in it.
declare #Nums varchar(max)=',1,2,3'
if #Nums LIKE '%1%'
BEGIN
select * from TestTable
END
If you need to match the full number:
CREATE FUNCTION [dbo].[Split_String]
(
#ItemList NVARCHAR(4000),
#delimiter CHAR(1)
)
RETURNS #IDTable TABLE (Item VARCHAR(50))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(4000)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #tempItemList = REPLACE (#tempItemList, ' ', '')
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #IDTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
DECLARE #Nums VARCHAR(MAX) = ',1,2,3'
DECLARE #NumberTable TABLE (item INT)
INSERT INTO #NumberTable
SELECT TRY_CAST(Item AS INT)
FROM dbo.Split_String(#Nums, ',')
IF (SELECT 1 FROM #NumberTable WHERE item = 1) = 1
BEGIN
select * from TestTable
END
You can use CHARINDEX.
declare #Nums varchar(max)=',1,2,3'
IF CHARINDEX(',1,', #Nums+',') > 0
BEGIN
select * from TestTable
END

Transform text in SQL Server

I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here

Wrap text in SQL server using function

I googled a lot to wrap string with minimum defined length, but I am unable to get any solution.
I created my own function that can wrap text by given number of characters per line.
This post may help to others looking for same.
Function 1
Create FUNCTION [dbo].[fn_BraekTextInLines]
(
-- Add the parameters for the function here
#InString varchar(max),
#LineLength int
)
RETURNS nvarchar(max)
AS
BEGIN
if #LineLength <=0 or #LineLength> LEN(#InString)
return #InString
declare #tmp varchar(max)
declare #result varchar(max)
DECLARE #word varchar (max);
declare #addedInResult bit
DECLARE c CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR SELECT s FROM SplitMax(#InString,'');
OPEN c;
FETCH NEXT FROM c INTO #word;
--set #tmp =#word
WHILE ##FETCH_STATUS = 0
BEGIN
if LEN(#tmp + ' ' + #word) < #LineLength
begin
set #tmp = #tmp + ' ' + #word
set #addedInResult = 0
end
else
begin
set #result = isnull(#result, ' ') + CHAR(13) + RTRIM(LTRIM( #tmp))
set #tmp = #word
set #addedInResult = 1
end
FETCH NEXT FROM c INTO #word;
if ##FETCH_STATUS <> 0
begin
set #result = isnull(#result, ' ') + CHAR(13) + RTRIM(LTRIM( #tmp))
set #addedInResult = 1
end
END
CLOSE c;
DEALLOCATE c;
if #addedInResult=0
begin
set #result = isnull(#result, ' ') + CHAR(13) + RTRIM(LTRIM( #tmp))
end
return #result
END
Function 2
Create FUNCTION [dbo].[fn_WrapString]
(
-- Add the parameters for the function here
#InString varchar(max),
#LineLength int
)
RETURNS nvarchar(max)
AS
BEGIN
declare #result varchar(max)
declare #tmp varchar(max)
DECLARE #Line varchar (max);
DECLARE c CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR SELECT s FROM SplitMax(#InString,CHAR(13));
OPEN c;
FETCH NEXT FROM c INTO #Line;
WHILE ##FETCH_STATUS = 0
BEGIN
set #tmp = dbo.fn_BraekTextInLines(#Line,#LineLength)
set #result = isnull(#result,' ') + #tmp
FETCH NEXT FROM c INTO #Line;
END
CLOSE c;
DEALLOCATE c;
return Rtrim(Ltrim(#result))
END
Function 3
ALTER FUNCTION [dbo].[SplitMax](#String VARCHAR(max), #Delimiter CHAR(1))
RETURNS #temptable TABLE (s VARCHAR(max))
AS
BEGIN
DECLARE #idx INT
DECLARE #slice VARCHAR(max)
SELECT #idx = 1
IF len(#String)<1 OR #String IS NULL RETURN
while #idx!= 0
BEGIN
SET #idx = charindex(#Delimiter,#String)
IF #idx!=0
SET #slice = LEFT(#String,#idx - 1)
ELSE
SET #slice = #String
IF(len(#slice)>0)
INSERT INTO #temptable(s) VALUES(#slice)
SET #String = RIGHT(#String,len(#String) - #idx)
IF len(#String) = 0 break
END
RETURN
END
Calling Function fn_WrapString to wrap the text
declare #name varchar(max)
set #name = 'Ine was King of Wessex from 688 to 726. He was'+ CHAR(13) +'unable to retain the territorial gains of his predecessor, Cædwalla, who had brought much of southern England under his'
print dbo.fn_WrapString(#name,60)
Output :
Ine was King of Wessex from 688 to 726. He was
unable to retain the territorial gains of his predecessor,
Cædwalla, who had brought much of southern England under
his
I also created a short version for warping the text in T-Sql
CREATE FUNCTION [dbo].[WrapText]
(
#List NVARCHAR(MAX),
#length INT
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #result AS NVARCHAR(MAX);
SELECT #result = CASE
WHEN #result IS NULL THEN
SUBSTRING(#List, number.Number - #length + 1, #length)
ELSE
#result + CHAR(13) + CHAR(10) + SUBSTRING(#List, number.Number - #length + 1, #length)
END
FROM
(
SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects
) number
WHERE number.Number <= LEN(#List) + #length - 1
AND number.Number % #length = 0;
RETURN #result;
END;
Calling Function:
SELECT dbo.WrapText('abcdefghijklmnopqrstuvwxyz',5)
If you are coping the result from grid, it will not past with line breaks as explained here
https://stackoverflow.com/a/59189881/1606054

How to extract numeric values from a string in SQL Server

I have a string in a SQL Server table whose format is like this...
nvarchar int nvarchar int nvarchar
There are no obvious delimiters other than some chars are numeric and others are alpha.
How do I reference the second int value?
One way is to use the patindex function:
declare #s varchar(100)
declare #i1 int
declare #s2 varchar(100)
declare #i2 int
declare #s3 varchar(100)
declare #i3 int
declare #s4 varchar(100)
declare #i4 int
declare #secondInt int
set #s = 'alpha123beta3140gamma789'
set #i1 = PATINDEX('%[0-9]%', #s)
set #s2 = SUBSTRING(#s, #i1, 100)
set #i2 = PATINDEX('%[^0-9]%', #s2)
set #s3 = SUBSTRING(#s2, #i2, 100)
set #i3 = PATINDEX('%[0-9]%', #s3)
set #s4 = SUBSTRING(#s3, #i3, 100)
set #i4 = PATINDEX('%[^0-9]%', #s4)
set #secondInt = CAST(SUBSTRING(#s4, 1, #i4-1) as int)
select #s, #secondInt
I would personally write a CLR function and use the string SPLIT function.
Here is some code that I believe works:
Declare #Result Table
(
stringval varchar(100),
numvalue decimal(18,4)
)
Declare #Test varchar(100)
Declare #index int
Declare #char char(1)
Declare #currentVal varchar(100)
Declare #prevVal varchar(100)
Declare #currentType char(1)
Declare #nextType char(1)
Set #index = 0
Set #Test = 'a100.4bb110ccc2000'
Set #currentVal = ''
Set #currentType = 's'
While #index <= LEN(#Test)
Begin
Set #index = #index + 1
Set #char = SUBSTRING(#Test,#index,1)
Set #nextType = CASE WHEN PATINDEX('[^0-9.]', #char) > 0 then 's' else 'n' end
If #currentType <> #nextType
begin
if #currentType = 'n'
insert into #Result(stringval,numvalue) values(#prevVal,#currentVal)
Set #prevVal = #currentVal
set #currentVal = ''
set #currentType = #nextType
end
SEt #currentVal = #currentVal + #char
ENd
Select * FROM #Result
This article on using Regular Expressions with SQL Server may be helpful.
Regular Expressions Make Pattern Matching And Data Extraction Easier

Resources