Reputation: 2628
I have a client based system that is needing a sequential client number in the form of the following.
First client would get A001, and then each new client through to A999. Once it hits A999, it would continue to B001-B999, and so on until Z001-Z999, when it would reset to AA001-AA999 and so on through the alphabet.
Does anyone see a way of how this could be achieved?
Upvotes: 3
Views: 532
Reputation: 5403
This will give you the exact numbers you asked for from A001 to ZZ999. If you want more numbers than that you will need to add logic for a third letter, etc. Note that you aren't getting 1000 numbers per letter, which makes things slightly more awkward.
WITH Numbers AS (
SELECT 1 AS number
UNION ALL
SELECT number + 1 AS number FROM Numbers WHERE number < 701298)
SELECT
number,
CASE WHEN number > 25974 THEN CHAR(64 + (number - 1) / 25974) ELSE '' END --This is the first letter (optional)
+ CHAR(65 + ((number - 1) / 999) % 26) --This is the second letter
+ FORMAT(CASE WHEN number < 1000 THEN number ELSE CASE WHEN number % 999 = 0 THEN 999 ELSE number % 999 END END, 'd3') --This is the three digit number
AS client_id
FROM
Numbers
OPTION (MAXRECURSION 0);
The Numbers CTE is just to get a suitable number of numbers (1 - 701,298). Once I have them I need to find the boundaries when the second letter changes (every 999 numbers) or the first letter changes (every 26 * 999 = 25974 numbers). Note that the first letter is suppressed until needed.
This gives you 27 * 26 * 999 client ids (the first letter can be blank or A-Z = so 27 options, the second letter can be A-Z = 26 options, the number can be 001-999 = 999 options). That's a grand total of 701,298 client ids.
I would suggest either using an IDENTITY
column, or a SEQUENCE
to get the "internal" id (which would be a primary key candidate), and then use a function to calculate the client id from this number. That's safer for multiple users, etc. You could use a calculated column, but that's a pretty big overhead?
Upvotes: 2
Reputation: 4620
EXAMPLE from the comments: (may not be an answer, posted here just because it is long)
CREATE SEQUENCE Numbers
INCREMENT BY 1
MINVALUE 1
MAXVALUE 999
CYCLE
;
--DROP TABLE test_DL
Create table test_DL
(
VendorName varchar(50),
VendorId as LeadingCharacters + CAST(FORMAT(TailingNumbers,'000') as VARCHAR(10)),
LeadingCharacters VARCHAR(50),
TailingNumbers INT DEFAULT(NEXT VALUE FOR Numbers),
[Counter] INT IDENTITY(1,1)
)
--ALTER SEQUENCE Numbers RESTART WITH 1
DECLARE @CONTROL INT = 0
WHILE (@CONTROL < 250)
BEGIN
INSERT INTO test_DL (VendorName)
VALUES ('THIS'),('IS'),('AN'),('EXAMPLE')
SET @CONTROL = @CONTROL + 1
END
;
WITH CTE
AS
(
SELECT *, ROW_NUMBER()OVER(ORDER BY [Counter],TailingNumbers) as RowNumber
FROM test_DL
)
UPDATE CTE
SET LeadingCharacters = CASE WHEN RowNumber <= 999 THEN 'A' WHEN 999 < RowNumber AND RowNumber < 2* 999 THEN 'B' END --The MOST ANNOYING PART is here, you need to manually category all the possibles
SELECT * FROM test_DL --Run this to check the result
Above method will be very dumb for future updates. Just give you some ideas lol
Upvotes: 0
Reputation: 4005
I'd use simple integers as the key and a stored procedure (or calculated column) which translates to your desired format. I't essentially a numeric operation, check this SQL which calculates the format.
It does assume that you have no more than 2 letters in the beginning, so number of clients is under 26 * 26 * 1000.
select tmp.num as client_num, CONCAT(
CASE WHEN tmp.num < 26000 THEN '' ELSE CHAR(ASCII('A') - 1 + (tmp.num / 26000)) END,
CHAR (ASCII('A') + (tmp.num / 1000) % 26),
RIGHT('000'+CAST(tmp.num % 1000 AS VARCHAR(3)),3)) as client_id
from
(select 1 as 'num'
union
select 10
union
select 150
union
select 1000
union
select 25999
union
select 26000
union
select 27000
union
select 100000) tmp
Returns table:
+------------+-----------+
| client_num | client_id |
+------------+-----------+
| 1 | A001 |
| 10 | A010 |
| 150 | A150 |
| 1000 | B000 |
| 25999 | Z999 |
| 26000 | AA000 |
| 27000 | AB000 |
| 100000 | CW000 |
+------------+-----------+
Upvotes: 2