1

我从这个问题中获得了一些帮助,但仍然需要一些进一步的帮助。

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

因此,例如,假设我有序列

00, 01, 02,..., 09, 0A, 0B, 0C,..., 0Y, 0Z, 10, 11,...1Y, 1Z, 20, 21,..., 9Y, 9Z, I希望下一个 id 是 A0,

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

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

我希望我可以为所有这些分配一个数字 id,但此时表定义更为关键,所以我不允许更改它,所以我试图最大化我将拥有的可用 id有限的空间。

谢谢您的帮助。

4

2 回答 2

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
于 2015-03-23T22:45:51.593 回答
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
于 2015-03-25T14:46:07.007 回答