SQL用于生成字母数字id中的下一个序列

时间:2015-03-23 22:05:13

标签: sql sql-server tsql sequencing

我从question获得了一些帮助,但仍需要一些帮助。

我需要能够生成下一个可用的2位字母数字代码。在你提出要求之前,我无法更改表格定义。我在T-SQL工作。

所以,例如,让我们说我有序列

00,01,02,...,09,0A,0B,0C,...,0Y,0Z,10,11,... 1Y,1Z,20,21,...,9Y, 9Z,我想下一个id为A0,

然后A1,A2,...,A9,AA,AB,AC,...,AZ,我想下一个id为B0,然后是B1等。

所以,简而言之,我想从00一直到ZZ,每次在该字段中查找MAX并分配一个大于最大值的新代码1。我会理解A>在图9中,第一列大于第二列,因此A0> 99和AA> A9。

我希望我可以为所有这些分配一个数字ID,但是表定义在这一点上更为重要,所以我不允许更改它,所以我试图最大化可用的ID我和#39;将在如此有限的空间内。

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

看看这个。对于ID而言,这是一个非常令人讨厌的问题。您已经有效地限制了自己使用2个字符的密钥的少量排列。如果使用ZZ并且此算法再次运行,您还有一个问题需要处理。我已将这些扩展为尽可能合乎逻辑的示范步骤,但可以根据需要自由缩小。

DECLARE @ExistingTable TABLE (ID CHAR(2))
INSERT INTO @ExistingTable (ID) VALUES ('5A'),('5B')

DECLARE @NewID CHAR(2)

;WITH
Ranks AS (
    SELECT '0' AS [Character] UNION SELECT '1' AS [Character] UNION SELECT '2' UNION SELECT '3' UNION SELECT '4' UNION SELECT '5' UNION SELECT '6' UNION
    SELECT '7' UNION SELECT '8' UNION SELECT '9' UNION SELECT 'A' UNION SELECT 'B'UNION
    SELECT 'C' UNION SELECT 'D' UNION SELECT 'E' UNION SELECT 'F' UNION SELECT 'G' UNION SELECT 'H' UNION
    SELECT 'I' UNION SELECT 'J' UNION SELECT 'K' UNION SELECT 'L' UNION SELECT 'M' UNION SELECT 'N' UNION
    SELECT 'O' UNION SELECT 'P' UNION SELECT 'Q' UNION SELECT 'R' UNION SELECT 'S' UNION SELECT 'T' UNION
    SELECT 'U' UNION SELECT 'V' UNION SELECT 'W' UNION SELECT 'X' UNION SELECT 'Y' UNION SELECT 'Z'
), Permutations AS (
    SELECT  SecondChar.[Character] + FirstChar.[Character] AS PermuteID
    FROM    Ranks AS FirstChar
            CROSS JOIN Ranks AS SecondChar
), PermutationsKeyed AS (
    SELECT  ROW_NUMBER() OVER (ORDER BY PermuteID ASC) AS PrimaryKeyHolder,
            PermuteID
    FROM    Permutations
), MaxPK AS (
    SELECT  MAX(Perm.PrimaryKeyHolder) + 1 AS MaxPK
    FROM    @ExistingTable AS E
            INNER JOIN PermutationsKeyed AS Perm ON (E.ID = Perm.PermuteID)
)
SELECT  @NewID = Perm.PermuteID
FROM    PermutationsKeyed AS Perm
        INNER JOIN MaxPK AS M ON (Perm.PrimaryKeyHolder = M.MaxPK)


SELECT @NewID

答案 1 :(得分:0)

我不确定你想要如何返回下一个值,但我认为这是一种简单有效的方法来获取所有价值。如果您还有其他需要,请告诉我。

DECLARE @values TABLE (val CHAR(1));
DECLARE @int        INT = 48,
        @letters    INT = 65;

IF OBJECT_ID('dbo.tbl_keys') IS NOT NULL
    DROP TABLE dbo.tbl_keys;

--This will hold the values so you can always reference them
CREATE TABLE dbo.tbl_Keys
(
    --Primary key will create a clustered index on rank_id by default
    rank_id INT PRIMARY KEY,
    ID_Code CHAR(2)
);
--Another index on ID_Code
CREATE NONCLUSTERED INDEX idx_ID_Code ON tbl_keys(ID_Code);

--This is how I get all your individual values
WHILE (SELECT COUNT(*) FROM @values) < 36
BEGIN
    IF(@int <= 57)
        INSERT INTO @values VALUES(CHAR(@int));

    INSERT INTO @values
    VALUES (CHAR(@letters))

    SET @int = @int + 1;
    SET @letters = @letters + 1;
END

--Insert all possible combinations and rank them
INSERT INTO tbl_Keys
    --ASCII is your best friend. It returns the ASCII code(numeric value) for characters
    SELECT  ROW_NUMBER() OVER (ORDER BY ASCII(A.val),ASCII(B.val)) AS rank_id,
            A.val + B.val ID
    FROM @values A
    CROSS JOIN @values B;

我提供了两种获取下一个ID_code的方式(阅读评论):

--Here's some dummy data
WITH CTE_DummyTable
AS
(
    SELECT '00' ID_Code
    UNION ALL
    SELECT '01'
    UNION ALL
    SELECT '02'
)


----Here's how to get the next value with the assumption there are no gaps in your data
--SELECT MIN(ID_Code) next_id_code
--FROM tbl_Keys
--WHERE ID_code > (SELECT MAX(id_code) FROM CTE_DummyTable)

--This one doesn't assume the gaps and returns the lowest available ID_code
SELECT MIN(ID_Code) next_id_code
FROM tbl_Keys
WHERE ID_code NOT IN (SELECT DISTINCT id_code FROM CTE_DummyTable)

注意:如果您想要在不改变排名的情况下轻易转换您的字母数字值,请尝试使用此功能。

SELECT  rank_id,
    ID_code,
    CAST(CONCAT(ASCII(LEFT(id_code,1)),ASCII(RIGHT(id_code,1))) AS INT) AS numeric_id_code
FROM tbl_Keys