Increasing Alphanumeric value in user defined function - sql

I'm trying to code a user defined function under SQL Server 2005 that will increase integer part of alphanumeric value by one. For example, uf_AlphanumericIncrease ('A000299') should return 'A000300'. Here's what I've done so far;
ALTER FUNCTION uf_AlphaNumericIncrement
(
#ID varchar(10)
)
RETURNS VARCHAR(10) AS
BEGIN
DECLARE #RES varchar(10);
IF SUBSTRING(#ID,LEN(#ID),1)='9'
SET #RES=SUBSTRING(#ID,1,LEN(#ID)-2)+CAST (CAST(SUBSTRING(#ID,LEN(#ID)-1,1) AS smallint)+1 AS VARCHAR(10))+'0';
ELSE
SET #RES=SUBSTRING(#ID,1,LEN(#ID)-1)+CAST (CAST(SUBSTRING(#ID,LEN(#ID),1) AS smallint)+1 AS VARCHAR(10));
RETURN #RES;
END
But as you can see it only works for last digit. I need to get it under loop so it can work for A002999 and so on. Any ideas?
Edit: Given value might have alpha prefix longer than one character, or none at all.

Now works with any length of prefix and number part (well upto 20 each)
DECLARE #prefix varchar(20), #numberstr varchar(20), #number int, #Val varchar(40)
SELECT #Val = 'ABCD000006'
--SELECT #Val = 'A03'
SELECT #prefix = LEFT(#Val, PATINDEX ('%[0-9]%', #Val) -1)
SELECT #numberstr = SUBSTRING(#Val, PATINDEX ('%[0-9]%', #Val), 8000)
SELECT #number = CAST(#numberstr AS int) + 1
SELECT #prefix + RIGHT(REPLACE(SPACE(LEN(#numberstr)), ' ', '0') + CAST(#number AS varchar(20)), LEN(#numberstr))

CREATE FUNCTION dbo.uf_ANinc
(
#in varchar(10)
)
RETURNS varchar(10) AS
BEGIN
DECLARE #prefix varchar(10);
DECLARE #res varchar(10);
DECLARE #pad varchar(10);
DECLARE #num int;
DECLARE #start int;
SET #start = PATINDEX('%[0-9]%',#in);
SET #prefix = LEFT(#in, #start - 1 );
SET #num = CAST( RIGHT( #in, LEN(#in) - #start ) AS int ) + 1
SET #pad = REPLICATE( '0', 10 - LEN(#prefix) - CEILING(LOG(#num)/LOG(10)) );
SET #res = #prefix + #pad + CAST( #num AS varchar);
RETURN #res
END
GO
SELECT dbo.uf_ANinc('ABC000123');

Assuming that the alpha part of your alphanumeric is always only the first character, this should work.
EDIT: OK, if the alpha part varies in length this gets ugly pretty quickly for a UDF. This is just a quick-and-dirty solution, so it can probably be optimized a bit, but the logic should be sound.
EDIT AGAIN: patindex() ftw - I learned something new today ;-)
ALTER FUNCTION uf_AlphaNumericIncrement
(
#ID varchar(10)
)
RETURNS VARCHAR(10) AS
BEGIN
DECLARE #RES varchar(10);
DECLARE #num int;
DECLARE #prefix varchar(10);
set #prefix = left(#id, patindex('%[0-9]%', #id) -1)
set #num = cast(right(#id, len(#id) - len(#prefix)) as int) + 1
set #res = #prefix + replicate('0', len(#id) - len(#prefix) - len(#num)) + cast(#num as varchar(10))
RETURN #RES;
END

Related

format a wbs column in sql

How to split then format a wbs column to have a prefix of zeroes using SQL?
Example: 1.2.15 to 1.002.015
Sample WBS Column content:
- 1.1
- 1.1.1
- 1.1.2
- 1.1.3
- 1.2
Not the most beautiful code on Earth, but it does the trick:
DECLARE #STR VARCHAR(100) = '1.2.15'
DECLARE #FORMAT VARCHAR(10) = '000'
DECLARE #P1 VARCHAR(10)
DECLARE #P2 VARCHAR(10)
DECLARE #P3 VARCHAR(10)
DECLARE #P4 VARCHAR(10)
DECLARE #PARTS INT = 1 + LEN(#STR) - LEN(REPLACE(#STR, '.', ''))
SELECT #P1 = PARSENAME(#STR, #PARTS)
SELECT #P2 = PARSENAME(#STR, #PARTS - 1)
SELECT #P3 = PARSENAME(#STR, #PARTS - 2)
SELECT #P4 = PARSENAME(#STR, #PARTS - 3)
SELECT #P2 = FORMAT(CAST(#P2 AS INT), #FORMAT)
SELECT #P3 = FORMAT(CAST(#P3 AS INT), #FORMAT)
SELECT #P4 = FORMAT(CAST(#P4 AS INT), #FORMAT)
SELECT ISNULL(#P1, '') + ISNULL('.' + #P2, '') + ISNULL('.' + #P3, '') + ISNULL('.' + #P4, '')
-- Output is 1.002.015
The key is to use the PARSENAME function. It's intended for parsing a fully qualified SQL object name, but here we will use it for WBS. I first find the number of points to know how many parts it has, as that function's second parameter is the part counting from the end. That way I can get the main version in #P1, the next one in #P2, etc.
Then I do a trick to add leading zeroes, and finally I just concatenate the numbers, avoiding nulling the string if one of them is NULL.
Limitations:
Only up to 4 parts (can't use this for 1.2.15.6.3)
Must be valid, no spaces and no . at the end
Declare #wbs nvarchar(MAX)
Set #wbs ='1.1.12.123.1234.12345.123456.1234567.123456789.1234567890'
DECLARE #XML AS XML
DECLARE #delimiter AS CHAR(1) = '.' -- wbs character seperator
SET #XML = CAST(('<WBS>'+REPLACE(#wbs, #delimiter,'</WBS><WBS>')+'</WBS>') AS XML)
DECLARE #tempTable TABLE (ID INT IDENTITY(1, 1) primary key, WBS INT)
INSERT INTO #tempTable SELECT N.value('.', 'INT') AS ID FROM #XML.nodes('WBS') AS T(N)
DECLARE #formattedWbs varchar(MAX) = '',
#wbsSplit INT,
#id INT,
#skip bit = 1;
WHILE EXISTS (SELECT * FROM #tempTable)
BEGIN
SELECT TOP 1 #wbsSplit = WBS, #id = ID FROM #tempTable;
IF #skip = 1
BEGIN
SET #formattedWbs += #wbsSplit;
SET #skip = 0;
END
ELSE
BEGIN
SET #formattedWbs += '.' + FORMAT(#wbsSplit,'000#');
END
DELETE #tempTable Where ID = #id;
END
PRINT #formattedWbs;
CREATE FUNCTION GetFormattedWBS (#wbs VARCHAR(MAX))
RETURNS varchar(MAX)
BEGIN
SET #wbs += '.'
DECLARE #formattedwbs NVARCHAR(MAX);
SET #formattedwbs = '';
WHILE (CHARINDEX('.', #wbs) > 0)
BEGIN
DECLARE #wbsnode INT;
SET #wbsnode = SUBSTRING(#wbs, 1, CHARINDEX('.', #wbs) - 1);
SET #formattedwbs += FORMAT(#wbsnode,'00000#') + '.';
SET #wbs = SUBSTRING(#wbs, CHARINDEX('.', #wbs) + 1, len(#wbs));
END
SET #formattedwbs = SUBSTRING(#formattedWbs, 1, (len(#formattedWbs) - 1));
RETURN #formattedwbs
END

How to find a special characters in a string and replace it with a space in SQL?

I have contact_firstname column which has some special characters like (#,&,-,_, etc) in the data stored in that column. I want to first find all those special characters in each record and replace those characters with a space. I found a query on this website which helps identify the special characters but I am not sure how to find charindex of each special character in the below string and replace it with a space.
DECLARE #MyString VARCHAR(100)
SET #MyString = '!Char$Fox#'
IF (#MyString LIKE '%[^a-zA-Z0-9]%')
BEGIN
PRINT 'Contains "special" characters'
END
I think you have to loop, as Tab Alleman mentioned:
declare #MyString varchar(100) = '!Char$Fox#'
declare #i int = 0
declare #char varchar(1)
declare #len int = LEN(#MyString)
declare #result varchar(100) = ''
while #i < #len
begin
set #char = SUBSTRING(#MyString, #i, 1)
if #char like '%[^a-zA-Z0-9]%'
begin
set #char = ' '
end
set #result = #result + #char
set #i = #i + 1
end
select #result
You can also do this:
DECLARE #InvalidChars VARCHAR(100)
DECLARE #MyString VARCHAR(100)
SET #InvalidChars = '!$#'
SET #MyString = '!Char$Fox#'
;WITH CTE AS
(
SELECT SUBSTRING(#InvalidChars, 1, 1) AS [String], 1 AS [Start], 1 AS [Counter]
UNION ALL
SELECT SUBSTRING(#InvalidChars, [Start] + 1, 1) AS [String], [Start] + 1, [Counter] + 1
FROM CTE
WHERE [Counter] < LEN(#InvalidChars)
)
SELECT #MyString = REPLACE(#MyString, CTE.[String], ' ') FROM CTE
SELECT #MyString
Result:
Char Fox
This is a combination of solutions found here:
How to Replace Multiple Characters in SQL?
T-SQL: Opposite to string concatenation - how to split string into multiple records [duplicate]

How to insert data from String in table?

I have on table PersonDetail which contains NAME and AGE as column.
I am using one application which is taking all data as String by comma and pipe separated value like 'Acton,58|Nairi,20|Sara,14|Denny,52' (Format is same as given)
I want to insert that data into table(PersonDetail) but I don't know how can I separate it as a NAME and AGE.
Some one suggested me to create function which can separate the data, But i have no idea to do it.
Can any one give me suggestion??
Thanks in advance :)
you can create Multi-statement table value function to separate the data.
you just need to insert each NAME and AGE into table type variable and after inserting you should return that table as given below.
CREATE FUNCTION UDF_InsertDataFromString
(
#dataString VARCHAR(5000)
)
RETURNS #insertedData TABLE
(
NAME VARCHAR(30),
AGE INT
)
AS
BEGIN
DECLARE #pipeIndex INT,
#commaIndex INT,
#LENGTH INT,
#NAME VARCHAR(100),
#AGE INT
SELECT #LENGTH = LEN(RTRIM(LTRIM(#dataString))),
#dataString = RTRIM(LTRIM(#dataString))
WHILE (#LENGTH <> 0)
BEGIN
SELECT #LENGTH = LEN(#dataString),
#commaIndex = CHARINDEX(',', #dataString),
#pipeIndex = CHARINDEX('|', #dataString)
IF(#pipeIndex = 0) SET #pipeIndex = #LENGTH +1
SELECT #NAME = RTRIM(LTRIM(SUBSTRING(#dataString, 1, #commaIndex-1))),
#AGE = RTRIM(LTRIM(SUBSTRING(#dataString, #commaIndex+1, #pipeIndex-#commaIndex-1))),
#dataString = RTRIM(LTRIM(SUBSTRING(#dataString, #pipeIndex+1, #LENGTH-#commaIndex-1)))
INSERT INTO #insertedData(NAME, AGE)
VALUES(#NAME, #AGE)
SELECT #LENGTH = LEN(#dataString)
END
RETURN
END
Now you can use this function while inserting data from string, you just need to pass string as parameter in function as given below.
DECLARE #personDetail TABLE(NAME VARCHAR(30), AGE INT)
INSERT INTO #personDetail(NAME, AGE)
SELECT NAME, AGE
FROM dbo.UDF_InsertDataFromString('Acton,58|Nairi,20|Sara,14|Denny,52')
SELECT NAME, AGE
FROM #personDetail
use this split func
CREATE FUNCTION [dbo].[fnSplitString]
(
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE #start INT, #end INT
SELECT #start = 1, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1 BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
INSERT INTO #output (splitdata)
VALUES(SUBSTRING(#string, #start, #end - #start))
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
RETURN
END
and then use this query
DECLARE #x table ( id int identity(1,1)
, str varchar(50) )
DECLARE #str varchar(50)='Acton,58|Nairi,20|Sara,14|Denny,52'
INSERT INTO #x
SELECT *
FROM [dbo].[fnSplitString] (#str ,'|')
SELECT *
from #x
DECLARE #y int=(SELECT count(*)
FROM #x)
DECLARE #e varchar(50)
DECLARE #b varchar(50)
DECLARE #c varchar(50)
WHILE #y!=0
BEGIN
set #e =(SELECT str
FROM #x
where id=#y)
set #b =(substring(#e,1,(charindex(',',#e)-1)))
set #c = (substring(#e,(charindex(',',#e)+1),len(#e)-charindex(',',#e)))
INSERT INTO PersonDetail
SELECT distinct #b
, #c
FROM #x
SET #y=#y-1
END
yes you can create your own function.
just you need to apply different string function for that
https://msdn.microsoft.com/en-IN/library/ms181984.aspx

UDF to insert a text string in to each row of a table

I've been searching high and low for an answer and I can't seem to find anything that points me in the right direction.
I need to create a UDF that will extract each word of a text string and return a table with each word of the string in a separate row.
The UDF is only able to take in one variable '#mytext'.
We can assume that the text string is separated by a single space and may contain commas or periods.
For example, "don’t worry about failures, worry about the chances you miss when you don’t even try." would need to return a table with each word on a separate row of a column without the commas or periods present.
I'm figuring that the text string would need to be separated with a common value that could be used to separate each word for insert, but I could totally be wrong.
Any help with this would be really appreciated!
Based on what I've said so far, here is my far from complete code that I'm not too sure how to proceed with
create function [dbo].[textConverter]
(
#mytext nvarchar(max)
)
returns #text_string table
(
word nvarchar
)
as
begin
set #mytext = replace(#mytext, 'what needs to be changed', 'what it needs to be changed too')
--insert string to table
end
EDIT
I've checked out a couple of links and uncovered a little more information on this, I've now got this code. However it exits with an error. The example that was used in the article I found the code on used numbers in the insert so maybe this is the issue??
create function [dbo].[textConverter]
(
#mytext varchar(max)
)
returns #text_string table
(
word nvarchar
)
as
begin
--Change string to be seperated by commas
set #mytext = replace(#mytext, ' ', ',')
set #mytext = replace(#mytext, '.',',')
--Eliminate double commas
set #mytext = replace(#mytext, ',,', ',')
declare #name nvarchar(255)
declare #pos int
while CHARINDEX(',', #mytext) > 0
begin
select #pos = CHARINDEX(',', #mytext)
select #name = SUBSTRING(#mytext, 1, #pos-1)
insert into #text_string
select #name
select #mytext = SUBSTRING(#mytext, #pos+1, LEN(#mytext)-#pos)
end
insert into #text_string
select #mytext
return
end
--To use function
select * from dbo.textConverter('don’t worry about failures, worry about the chances you miss when you don’t even try.')
See the answer below, It is not in complete shape, but can be developed into a user defined function.
Declare #Sentence Varchar(max) = 'don’t worry about failures, worry about the chances you miss when you don’t even try.'
Set #Sentence = Replace(Replace(Replace(Replace(#Sentence,',',' '),'.',' '),' ',' '),' ',' ')
Declare #e int = (Select Len(#Sentence) - Len(Replace(#Sentence,' ','')))
Declare #s int = 1
Declare #Result Table(id int identity(1,1),Words varchar(max))
--Select #s,#e
While #s <= #e
begin
Insert into #Result
Select Left(#Sentence,Charindex(' ',#Sentence,1)-1)
Set #Sentence = Substring(#Sentence,Charindex(' ',#Sentence,1) + 1,Len(#Sentence) )
Set #s = #s + 1
End
Insert into #Result
Select #Sentence
Select * from #Result
Result
----+-----------
id |Words
----+-----------
1 |don’t
2 |worry
3 |about
4 |failures
5 |worry
6 |about
7 |the
8 |chances
9 |you
10 |miss
11 |when
12 |you
13 |don’t
14 |even
15 |try
----+-----------
I adapted some of the code from http://sqlperformance.com/2012/07/t-sql-queries/split-strings as my situation meant that the delimiter couldn't specified as input. I could only use on input and that was the text string. As such, the following worked for me:
create function [dbo].[textConverter]
(
#string nvarchar(max)
)
returns #output table(splitdata nvarchar(max)
)
begin
--Change string to be seperated by commas
set #string = replace(#string, ' ', ',')
set #string = replace(#string, '.',',')
--Eliminate double commas
set #string = replace(#string, ',,', ',')
declare #start int, #end int
select #start = 1, #end = charindex(',',#string)
while #start < len(#string) + 1
begin
if #end = 0
set #end = len(#string) + 1
insert into #output (splitdata)
values(substring(#string, #start, #end - #start))
set #start = #end + 1
set #end = charindex(',', #string, #start)
end
return
end

How to change case in string

My table has one column that contain strings like: ” HRM_APPLICATION_DELAY_IN”
I want to perform bellow operations on each row on this column
convert to lower case
remove underscore “_”
change case (convert to upper case) of the character after the underscore like: ” hrm_Application_Delay_In”
Need help for conversion. Thanks for advance
Here is a function to achieve it:
create function f_test
(
#a varchar(max)
)
returns varchar(max)
as
begin
set #a = lower(#a)
while #a LIKE '%\_%' ESCAPE '\'
begin
select #a = stuff(#a, v, 2, upper(substring(#a, v+1,1)))
from (select charindex('_', #a) v) a
end
return #a
end
Example:
select dbo.f_test( HRM_APPLICATION_DELAY_IN')
Result:
hrmApplicationDelayIn
To update your table here is an example how to write the syntax with the function:
UPDATE <yourtable>
SET <yourcolumn> = dbo.f_test(col)
WHERE <yourcolumn> LIKE '%\_%' ESCAPE '\'
For a variable this is overkill, but I'm using this to demonstrate a pattern
declare #str varchar(100) = 'HRM_APPLICATION_DELAY_IN';
;with c(one,last,rest) as (
select cast(lower(left(#str,1)) as varchar(max)),
left(#str,1), stuff(lower(#str),1,1,'')
union all
select one+case when last='_'
then upper(left(rest,1))
else left(rest,1) end,
left(rest,1), stuff(rest,1,1,'')
from c
where rest > ''
)
select max(one)
from c;
That can be extended to a column in a table
-- Sample table
declare #tbl table (
id int identity not null primary key clustered,
str varchar(100)
);
insert #tbl values
('HRM_APPLICATION_DELAY_IN'),
('HRM_APPLICATION_DELAY_OUT'),
('_HRM_APPLICATION_DELAY_OUT'),
(''),
(null),
('abc<de_fg>hi');
-- the query
;with c(id,one,last,rest) as (
select id,cast(lower(left(str,1)) as varchar(max)),
left(str,1), stuff(lower(str),1,1,'')
from #tbl
union all
select id,one+case when last='_'
then upper(left(rest,1))
else left(rest,1) end,
left(rest,1), stuff(rest,1,1,'')
from c
where rest > ''
)
select id,max(one)
from c
group by id
option (maxrecursion 0);
-- result
ID COLUMN_1
1 hrm_Application_Delay_In
2 hrm_Application_Delay_Out
3 _Hrm_Application_Delay_Out
4
5 (null)
6 abc<de_Fg>hi
select
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(lower('HRM_APPLICATION_DELAY_IN'),'_a','A'),'_b','B'),'_c','C'),'_d','D'),'_e','E'),'_f','F'),
'_g','G'),'_h','H'),'_i','I'),'_j','J'),'_k','K'),'_l','L'),
'_m','M'),'_n','N'),'_o','O'),'_p','P'),'_q','Q'),'_r','R'),
'_s','S'),'_t','T'),'_u','U'),'_v','V'),'_w','W'),'_x','X'),
'_y','Y'),'_z','Z'),'_','')
Bellow two steps can solve problem,as example i use sys.table.user can use any one
declare #Ret varchar(8000), #RetVal varchar(8000), #i int, #count int = 1;
declare #c varchar(10), #Text varchar(8000), #PrevCase varchar, #ModPrefix varchar(10);
DECLARE #FileDataTable TABLE(TableName varchar(200))
INSERT INTO #FileDataTable
select name FROM sys.tables where object_name(object_id) not like 'sys%' order by name
SET #ModPrefix = 'Pur'
DECLARE crsTablesTruncIns CURSOR
FOR select TableName FROM #FileDataTable
OPEN crsTablesTruncIns
FETCH NEXT FROM crsTablesTruncIns INTO #Text
WHILE ##FETCH_STATUS = 0
BEGIN
SET #RetVal = '';
select #i=1, #Ret = '';
while (#i <= len(#Text))
begin
SET #c = substring(#Text,#i,1)
--SET #Ret = #Ret + case when #Reset=1 then UPPER(#c) else LOWER(#c)
IF(#PrevCase = '_' OR #i = 1)
SET #Ret = UPPER(#c)
ELSE
SET #Ret = LOWER(#c)
--#Reset = case when #c like '[a-zA-Z]' then 0 else 1 end,
if(#c like '[a-zA-Z]')
SET #RetVal = #RetVal + #Ret
if(#c = '_')
SET #PrevCase = '_'
else
SET #PrevCase = ''
SET #i = #i +1
end
SET #RetVal = #ModPrefix + #RetVal
print cast(#count as varchar) + ' ' + #RetVal
SET #count = #count + 1
EXEC sp_RENAME #Text , #RetVal
SET #RetVal = ''
FETCH NEXT FROM crsTablesTruncIns INTO #Text
END
CLOSE crsTablesTruncIns
DEALLOCATE crsTablesTruncIns
I'd like to show you my nice and simple solution. It uses Tally function to split the string by pattern, in our case by underscope. For understanding Tally functions, read this article.
So, this is how my tally function looks like:
CREATE FUNCTION [dbo].[tvf_xt_tally_split](
#String NVARCHAR(max)
,#Delim CHAR(1))
RETURNS TABLE
as
return
(
WITH Tally AS (SELECT top (select isnull(LEN(#String),100)) n = ROW_NUMBER() OVER(ORDER BY [name]) from master.dbo.syscolumns)
(
SELECT LTRIM(RTRIM(SUBSTRING(#Delim + #String + #Delim,N+1,CHARINDEX(#Delim,#Delim + #String + #Delim,N+1)-N-1))) Value, N as Ix
FROM Tally
WHERE N < LEN(#Delim + #String + #Delim)
AND SUBSTRING(#Delim + #String + #Delim,N,1) = #Delim
)
)
This function returns a table, where each row represents part of string between #Delim (in our case between underscopes). Rest of the work is simple, just cobination of LEFT, RIGHT, LEN, UPPER and LOWER functions.
declare #string varchar(max)
set #string = ' HRM_APPLICATION_DELAY_IN'
-- convert to lower case
set #string = LOWER(#string)
declare #output varchar(max)
-- build string
select #output = coalesce(#output + '_','') +
UPPER(left(Value,1)) + RIGHT(Value, LEN(Value) - 1)
from dbo.tvf_xt_tally_split(#string, '_')
-- lower first char
select left(lower(#output),1) + RIGHT(#output, LEN(#output) - 1)