Sql server 如何生成具有指定长度的随机字母数字唯一字符
问题描述如下:Sql server 如何生成具有指定长度的随机字母数字唯一字符,sql-server,tsql,Sql Server,Tsql,问题描述如下: 生成唯一的字母数字字符 字符长度应为32 唯一编号可以在当前时间内进行播种,以帮助生成编号的唯一性 字母表字符必须来自此池:abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz 样本输出:445rpxlKYPkj1pg4q8nAy7Ab91zxZ8v1 我可以使用Java来实现这一点,但如果您能在MS SQL或T-SQL上帮助我实现这一点,我将不胜感激。首先,您需要将字符串拆分为单独的行。然后,对随机排序执行选择和orderbyne
abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz
445rpxlKYPkj1pg4q8nAy7Ab91zxZ8v1
我可以使用Java来实现这一点,但如果您能在MS SQL或T-SQL上帮助我实现这一点,我将不胜感激。首先,您需要将字符串拆分为单独的行。然后,对随机排序执行
选择和orderbynewid()
。最后,对XML路径(“”)使用
将它们连接回:
DECLARE @str VARCHAR(100) = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
SELECT TOP(LEN(@str)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
)
SELECT (
SELECT TOP(32)
SUBSTRING(@str, N, 1)
FROM CteTally t
ORDER BY NEWID()
FOR XML PATH('')
) AS Result
以上是一个通用的随机字符串生成器。您可以修改它以满足您的需要。如果需求不会改变,您可以简单地使用:
DECLARE @str VARCHAR(100) = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
;WITH E1(N) AS( -- 52 Rows
SELECT 1 FROM( VALUES
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1)
)t(N)
),
CteTally(N) AS(
SELECT ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E1
)
SELECT (
SELECT TOP(32)
SUBSTRING(@str, N, 1)
FROM CteTally t
ORDER BY NEWID()
FOR XML PATH('')
) AS Result
首先,需要将字符串拆分为单独的行。然后,对随机排序执行选择和orderbynewid()
。最后,对XML路径(“”)使用
将它们连接回:
DECLARE @str VARCHAR(100) = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
SELECT TOP(LEN(@str)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
)
SELECT (
SELECT TOP(32)
SUBSTRING(@str, N, 1)
FROM CteTally t
ORDER BY NEWID()
FOR XML PATH('')
) AS Result
以上是一个通用的随机字符串生成器。您可以修改它以满足您的需要。如果需求不会改变,您可以简单地使用:
DECLARE @str VARCHAR(100) = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
;WITH E1(N) AS( -- 52 Rows
SELECT 1 FROM( VALUES
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1)
)t(N)
),
CteTally(N) AS(
SELECT ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E1
)
SELECT (
SELECT TOP(32)
SUBSTRING(@str, N, 1)
FROM CteTally t
ORDER BY NEWID()
FOR XML PATH('')
) AS Result
我使它足够通用,可以处理任何字符池和任何输出长度。其核心思想是获取一个随机的字节序列,并使用基本转换算法将一个长数字转换为一个新的表示形式,然后使用所需的字符作为其“数字”转换为字符串
对于您的特定场景,我们需要大约183位,或log2(52)x 32,以达到您所需的长度。使用newid()
将生成唯一的位序列,但一次只能生成128位,一系列值将简单地连接起来,直到有足够的位序列为止。然后有一个值可以操作,主循环本质上就是我们从小学学到的长除法。中间计算保留在varbinary
数组中,循环仅在获得足够的输出字符之前继续。每次迭代确定新基中的另一个低阶数字,这可以提前终止,因为它们不会改变。如果输出不使用至少一个newid()
,则该算法无法保证任何全局唯一性,因此请确保log2(len(pool))x输出长度至少为128
目标基数(最终是字符池的长度)不能超过256。通过设置@e
的128字节最大长度,我硬编码了一个限制。对于问题@e
只需要32字节长,可以根据需要向上或向下调整,也可以定义为varbinary(max)
。如果您需要更真实的随机性,您可以找到熵位的另一个来源,如crypt\u gen\u random()
。由于唯一性似乎是主要关注点,因此该答案符合该要求。顺便说一下,池中重复的角色自然会为碰撞打开大门
这是快速和通用的,可以很容易地包装在一个函数中。更健壮的实现将处理这些额外的检查
declare @characterPool varchar(256) =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
declare @outputLength int = 32;
declare @n int = 0; /* counter */
declare @numLoops int = ceiling(log(len(@characterPool)) / log(2) * @outputLength / 128)
declare @e varbinary(128) = 0x; /* entropy */
while @n < @numLoops
begin
set @e = cast(newid() as binary(16)); set @n += 1;
end
declare @b int; /* byte */
declare @d int; /* dividend */
declare @out varchar(128) = '';
declare @outputBase int = len(@characterPool);
declare @entropyBytes int = len(@e);
declare @m int = 0;
while @m < @outputLength
begin
set @b = 0; set @d = 0; set @n = 0;
while @n < @entropyBytes /* big-endian */
begin
set @b = (@b - @d * @outputBase) * 256 + cast(substring(@e, @n + 1, 1) as int);
set @d = @b / @outputBase;
set @e = cast(stuff(@e, @n + 1, 1, cast(@d as binary(1))) as varbinary(128));
set @n += 1;
end
set @out = substring(@characterPool, @b - @d * @outputBase + 1, 1) + @out;
set @m += 1;
end
select @out as "UniqueString"
我使它足够通用,可以处理任何字符池和任何输出长度。其核心思想是获取一个随机的字节序列,并使用基本转换算法将一个长数字转换为一个新的表示形式,然后使用所需的字符作为其“数字”转换为字符串
对于您的特定场景,我们需要大约183位,或log2(52)x 32,以达到您所需的长度。使用newid()
将生成唯一的位序列,但一次只能生成128位,一系列值将简单地连接起来,直到有足够的位序列为止。然后有一个值可以操作,主循环本质上就是我们从小学学到的长除法。中间计算保留在varbinary
数组中,循环仅在获得足够的输出字符之前继续。每次迭代确定新基中的另一个低阶数字,这可以提前终止,因为它们不会改变。如果输出不使用至少一个newid()
,则该算法无法保证任何全局唯一性,因此请确保log2(len(pool))x输出长度至少为128
目标基数(最终是字符池的长度)不能超过256。通过设置@e
的128字节最大长度,我硬编码了一个限制。对于问题@e
只需要32字节长,可以根据需要向上或向下调整,也可以定义为varbinary(max)
。如果您需要更真实的随机性,您可以找到熵位的另一个来源,如crypt\u gen\u random()
。由于唯一性似乎是主要关注点,因此该答案符合该要求。顺便说一下,池中重复的角色自然会为碰撞打开大门
这是快速和通用的,可以很容易地包装在一个函数中。更健壮的实现将处理这些额外的检查
declare @characterPool varchar(256) =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
declare @outputLength int = 32;
declare @n int = 0; /* counter */
declare @numLoops int = ceiling(log(len(@characterPool)) / log(2) * @outputLength / 128)
declare @e varbinary(128) = 0x; /* entropy */
while @n < @numLoops
begin
set @e = cast(newid() as binary(16)); set @n += 1;
end
declare @b int; /* byte */
declare @d int; /* dividend */
declare @out varchar(128) = '';
declare @outputBase int = len(@characterPool);
declare @entropyBytes int = len(@e);
declare @m int = 0;
while @m < @outputLength
begin
set @b = 0; set @d = 0; set @n = 0;
while @n < @entropyBytes /* big-endian */
begin
set @b = (@b - @d * @outputBase) * 256 + cast(substring(@e, @n + 1, 1) as int);
set @d = @b / @outputBase;
set @e = cast(stuff(@e, @n + 1, 1, cast(@d as binary(1))) as varbinary(128));
set @n += 1;
end
set @out = substring(@characterPool, @b - @d * @outputBase + 1, 1) + @out;
set @m += 1;
end
select @out as "UniqueString"
有一个函数可以生成给定数量的随机字节,最多8000个。无需在循环中调用NEWID
。@Vladimir我在关于唯一性的评论中提到了这一点。无论哪种方式,冲突的可能性都很低,但是使用newid()
的原因是为了保证128位是全局唯一的,不管这最终是一个真正的问题。我明白了。我没有仔细阅读这个问题。我没有考虑唯一性,我关注的是随机性。伟大的解决方案@shawnt00将尝试它。谢谢。有一个函数可以生成给定数量的随机字节,最多8000个。有