T-SQL Alphanumeric Increment Function


While writing a T-SQL script I needed to be able to increment an alphanumeric number, and I wanted to keep it in T-SQL instead of going to some outside language and dealing with the mix. I searched a bit online to see if anyone had already done this, but all the solutions I found either didn’t work right, or weren’t as thorough as I would have liked. One solution tried to define the alpha portion of the string and the numeric portion and handling them as two separate strings converting the numeric portion, adding to it, and then padding it with zeros. It would work for the most part, but the example did not like the symbols I had in my string, and I did not feel like debugging someone else’s code that I was not quite fond of anyway.

So I built my own function. It increments alphabetic characters and numerical characters from a string and ignores anything else. I reverse the string and process it backwards so I can carry an increment forward to the next character processing it from right to left just like you would do with simple math on paper.

ALTER FUNCTION dbo.fn_USER_IncrementAlphaNumericString
(
@STRING VARCHAR(255)
)
/*****************************************************************
** Name : Sequential Alpha Numeric String Incrementer
**
** Description : This function will increment the given alpha
** numeric string in sequential order up to 255
** characters. (The length can be easily modified)
**
** Written By : Matt Johnson 3/19/2010
** Parameters : varchar string (255)
** Returns : varchar string (255)
**
*****************************************************************/
RETURNS varchar(255) AS
BEGIN
DECLARE @REV_STRING VARCHAR(255),
@POSITION INT,
@CURR_CHAR CHAR(1),
@CURR_CHAR_TYPE VARCHAR(20),
@NEW_CHAR CHAR(1),
@PREV_CHAR CHAR(1),
@PREV_CHAR_TYPE VARCHAR(20),
@NEW_STRING VARCHAR(255),
@INCR_CHAR BIT,
@DEBUG VARCHAR(4000),
@CR CHAR(1)

--SET INITIAL DEFAULTS FOR VARIABLES
SET @INCR_CHAR = 1
SET @POSITION = 1
SET @REV_STRING = REVERSE(@STRING)
SET @NEW_STRING = ''
SET @DEBUG = ''
SET @CR = CHAR(10)

SET @DEBUG = @DEBUG + '---- STRING: ' + @STRING + ' ----' + @CR + @CR

--LOOP THROUGH ALL CHARACTERS IN REVERSE ORDER
--REVERSE ORDER SO THAT WHEN A CHARACTER IS AT ITS
--MAX VALUE AND THAT VALUE NEEDS TO BE RESET AND THE
--INCREMENT CARRIED TO THE NEXT CHARACTER ITS SIMPLER
WHILE @POSITION <= LEN(@STRING) BEGIN

SET @DEBUG = @DEBUG + '---- POSITION: ' + CAST(@POSITION AS VARCHAR(50)) + ' --(' + CAST(@INCR_CHAR AS CHAR(1)) + ')--' + @CR

--GET THE CURRENT POSITION CHARACTER
SET @CURR_CHAR = SUBSTRING(@REV_STRING, @POSITION, 1)
SET @NEW_CHAR = @CURR_CHAR

--DETERMING CHARACTER TYPE
IF @CURR_CHAR LIKE '[0-9]' SET @CURR_CHAR_TYPE = 'NUMERIC'
ELSE IF @CURR_CHAR LIKE '[A-Z]' AND ASCII(@CURR_CHAR) >= 97 AND ASCII(@CURR_CHAR) <= 122 SET @CURR_CHAR_TYPE = 'LOWER ALPHA'
ELSE IF @CURR_CHAR LIKE '[A-Z]' AND ASCII(@CURR_CHAR) >= 65 AND ASCII(@CURR_CHAR) <= 90 SET @CURR_CHAR_TYPE = 'UPPER ALPHA'
ELSE SET @CURR_CHAR_TYPE = 'SYMBOL'

SET @DEBUG = @DEBUG + 'CURRENT_CHAR: ' + @CURR_CHAR + @CR
SET @DEBUG = @DEBUG + 'CURRENT_CHAR_TYPE: ' + @CURR_CHAR_TYPE + @CR

--CHECK INCREMENT BIT TO SEE IF WE NEED TO INCREMENT THIS CHARACTER
IF @INCR_CHAR = 1 BEGIN
--INCREMENT IS NEEDED

IF @CURR_CHAR_TYPE = 'NUMERIC' BEGIN
--PERFORM NUMERICAL INCREMENT TO THIS CHARACTER
IF @CURR_CHAR = '9' BEGIN
--CHARACTER IS AT ITS MAX SEQUENCABLE VALUE
--RESET THE SEQUENCE AND CARRY THE INCREMENT
--TO THE NEXT CHARACTER
SET @NEW_CHAR = '0'
END ELSE BEGIN
--CONVERT THE CHARACTER TO A NUMBER AND ADD 1 THEN CONVERT BACK TO A CHARACTER
SET @NEW_CHAR = CAST(CAST(@CURR_CHAR AS INT) + 1 AS CHAR(1))
--INCREMENT BIT IS SET TO 0 BECAUSE INCREMENT WAS COMPLETED
SET @INCR_CHAR = 0
END
--ADD NEW CHARACTER TO STRING BUILT IN REVERSE ORDER SO THAT
--THE FINAL RECONSTRUCTION IS IN THE ORIGINAL ORDER
SET @NEW_STRING = @NEW_CHAR + @NEW_STRING
END

ELSE IF @CURR_CHAR_TYPE = 'LOWER ALPHA' BEGIN
--PERFORM ALPHABETIC INCREMENT TO THIS CHARACTER
IF @CURR_CHAR = 'z' BEGIN
--CHARACTER IS AT ITS MAX SEQUENCABLE VALUE
--RESET THE SEQUENCE AND CARRY THE INCREMENT
--TO THE NEXT CHARACTER
SET @NEW_CHAR = 'a'
END ELSE BEGIN
--CONVERT THE CHARACTER TO AN ASCII NUMBER AND ADD 1 THEN CONVERT BACK TO A CHARACTER
SET @NEW_CHAR = CHAR(ASCII(@CURR_CHAR) + 1)
--INCREMENT BIT IS SET TO 0 BECAUSE INCREMENT WAS COMPLETED
SET @INCR_CHAR = 0
END
--ADD NEW CHARACTER TO STRING BUILT IN REVERSE ORDER SO THAT
--THE FINAL RECONSTRUCTION IS IN THE ORIGINAL ORDER
SET @NEW_STRING = @NEW_CHAR + @NEW_STRING
END

ELSE IF @CURR_CHAR_TYPE = 'UPPER ALPHA' BEGIN
--PERFORM ALPHABETIC INCREMENT TO THIS CHARACTER
IF @CURR_CHAR = 'Z' BEGIN
--CHARACTER IS AT ITS MAX SEQUENCABLE VALUE
--RESET THE SEQUENCE AND CARRY THE INCREMENT
--TO THE NEXT CHARACTER
SET @NEW_CHAR = 'A'
END ELSE BEGIN
--CONVERT THE CHARACTER TO AN ASCII NUMBER AND ADD 1 THEN CONVERT BACK TO A CHARACTER
SET @NEW_CHAR = CHAR(ASCII(@CURR_CHAR) + 1)
--INCREMENT BIT IS SET TO 0 BECAUSE INCREMENT WAS COMPLETED
SET @INCR_CHAR = 0
END
--ADD NEW CHARACTER TO STRING BUILT IN REVERSE ORDER SO THAT
--THE FINAL RECONSTRUCTION IS IN THE ORIGINAL ORDER
SET @NEW_STRING = @NEW_CHAR + @NEW_STRING
END

ELSE BEGIN
--IF INCREMENT IS NEEDED BUT CHARACTER TYPE IS NOT
--ABLE TO BE INCREMENTED SUCH AS A SYMBOL THEN WE
--WILL PASS ON THE CURRENT CHARCTER AND THE NEXT
--CHARACTER WILL ATTEMPT TO GET INCREMENTED (CARRY THE INCREMENT)
SET @NEW_STRING = @CURR_CHAR + @NEW_STRING
END
END ELSE BEGIN
--NO INCREMENT WAS NEEDED SO THE CURRENT CHARACTER IS PASSED ON
SET @NEW_STRING = @CURR_CHAR + @NEW_STRING
END

SET @DEBUG = @DEBUG + 'NEW_CHAR: ' + @NEW_CHAR + @CR
SET @DEBUG = @DEBUG + 'NEW_STRING: ' + @NEW_STRING + @CR
SET @DEBUG = @DEBUG + 'POST_INCR INCR_CHAR: ' + CAST(@INCR_CHAR AS CHAR(1)) + @CR

--ADD ADDITIONAL CHARACTER IF NEEDED
IF @POSITION = LEN(@STRING) AND @INCR_CHAR = 1 BEGIN
--WE ARE AT THE LAST POSITION AND AN INCREMENT STILL NEEDS TO BE
--PERFORMED, SO WE MUST ADD AN ADDITIONAL CHARACTER TO THE STRING SINCE
--ALL OTHER POSITIONS WERE NOT ABLE TO BE INCREMENTED OR WERE AT THEIR
--MAXIMUM SEQUENCE
IF @CURR_CHAR_TYPE = 'NUMERIC' SET @NEW_STRING = '1' + @NEW_STRING
ELSE IF @CURR_CHAR_TYPE = 'LOWER ALPHA' SET @NEW_STRING = 'a' + @NEW_STRING
ELSE IF @CURR_CHAR_TYPE = 'UPPER ALPHA' SET @NEW_STRING = 'A' + @NEW_STRING
ELSE SET @NEW_STRING = 'a' + @NEW_STRING

--IF THE NUMERIC OR ALPHA CHARACTER TYPES ARE NOT MATCHED WE DEFAULT TO
--ADDING A LOWER CASE ALPHA CHARACTER
END

SET @DEBUG = @DEBUG + 'POST_ADD NEW_STRING: ' + @NEW_STRING + @CR

--SET THE PREVIOUS CHARACTER AND TYPE FOR THE NEXT ITERATION OF THE LOOP
SET @PREV_CHAR = @CURR_CHAR
SET @PREV_CHAR_TYPE = @CURR_CHAR_TYPE

--INCREMENT THE POSITION SO THE NEXT ITERATION MOVES TO THE NEXT CHARACTER
SET @POSITION = @POSITION + 1
END

RETURN @NEW_STRING
END
GO

/* TESTING FUNCTION */
SELECT dbo.fn_USER_IncrementAlphaNumericString('A') [A],
dbo.fn_USER_IncrementAlphaNumericString('B') [B],
dbo.fn_USER_IncrementAlphaNumericString('0') [0],
dbo.fn_USER_IncrementAlphaNumericString('1') [1],
dbo.fn_USER_IncrementAlphaNumericString('9') [9],
dbo.fn_USER_IncrementAlphaNumericString('Z') [Z],
dbo.fn_USER_IncrementAlphaNumericString('a') [a],
dbo.fn_USER_IncrementAlphaNumericString('z') [z],
dbo.fn_USER_IncrementAlphaNumericString('99') [99],
dbo.fn_USER_IncrementAlphaNumericString('97') [97],
dbo.fn_USER_IncrementAlphaNumericString('278') [278],
dbo.fn_USER_IncrementAlphaNumericString('123') [123],
dbo.fn_USER_IncrementAlphaNumericString('A-9') [A-9],
dbo.fn_USER_IncrementAlphaNumericString('A9') [A9],
dbo.fn_USER_IncrementAlphaNumericString('-Zz9') [A9],
dbo.fn_USER_IncrementAlphaNumericString('z-2Z13') [z-2Z13],
dbo.fn_USER_IncrementAlphaNumericString('Aa-9999999') [Aa-9999999],
dbo.fn_USER_IncrementAlphaNumericString('Aa-99ZS999-') [Aa-99ZS999-]

  1. No comments yet.
(will not be published)