Reputation: 600
I have a case to generate sequence ID but alphabet first then numeric ( A-Z
then 0-9
) I see the question
here and try the solution, but the solution always give me 0-9
first then A-Z
WITH seq AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY x.alpha + y.number + z.number ) AS Id,
CONVERT(nchar(3), x.alpha + y.number + z.number) AS Result
FROM
(
VALUES
('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9'),
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z')
) x(alpha) ,
(
VALUES
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'),
('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9')
) y(number),
(
VALUES
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9')
) z(number)
)
SELECT * FROM seq WHERE Id = (SELECT Id + 1 FROM seq WHERE Result = 'A1Z')
the Sequence what should generated is :
AAA,...,AAZ,AA1,...,AA9,ABA,...,ABZ,AB1,..,AB9,...999
sample when I hit the A1Z
the expected next value is A11
, but the solution I tried give me A21
, is the behavior of SQL is start by 0-9
then A-Z
, how to accomplish my requirement ?
Upvotes: 1
Views: 640
Reputation: 95574
Perhaps this is what you want? Numbers have lower value than letters in T-SQL, so when you order them then '9'
has a lower number than 'A'
. What you could do, however, is check if the value is a valid int
value or not, and then order the values that aren't first, and then by the character.
This gives you the following:
WITH Characters AS(
SELECT V.C
FROM (VALUES('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9'),
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z')) V(C)),
Sequences AS(
SELECT CONCAT(C1.C,C2.C,C3.C) AS Sequence,
ROW_NUMBER() OVER (ORDER BY TRY_CONVERT(int,C1.C), C1.C, TRY_CONVERT(int,C2.C), C2.C, TRY_CONVERT(int,C3.C), C3.C) AS RN
FROM Characters C1
CROSS JOIN Characters C2
CROSS JOIN Characters C3)
SELECT *
FROM Sequences;
You didn't state where 0
goes, so I assumed 'AAZ'
,'AA0'
, 'AA1'
...
Upvotes: 2
Reputation: 46219
You can try to use ASCII
function with a simple algorithm in ORDER BY
, judging the char whether number or letter. if the char is number need to add 43
because the gap between Z
(Capital letter) and 0
(first number) is 43, we need to add 43 to the number char to make sure the number is always behind letters.
WITH seq AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY IIF(x.alpha LIKE '[A-Z]', ASCII(x.alpha), ASCII(x.alpha) + 43),
IIF(y.number LIKE '[A-Z]', ASCII(y.number), ASCII(y.number) + 43),
IIF(z.number LIKE '[A-Z]', ASCII(z.number), ASCII(z.number) + 43)) AS Id,
CONVERT(nchar(3), x.alpha + y.number + z.number) AS Result
FROM
(
VALUES
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'),
('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9')
) x(alpha) ,
(
VALUES
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'),
('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9')
) y(number),
(
VALUES
('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'),
('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9')
) z(number)
)
SELECT * FROM seq WHERE Id = (SELECT Id + 1 FROM seq WHERE Result = 'A1Z');
Upvotes: 1