如果您想使用T-SQL生成伪随机的字母数字字符串,您将如何做?您如何从中排除美元符号,破折号和斜线之类的字符?
生成随机数据(特别是用于测试时,使数据随机但可重现非常有用。秘诀是对随机函数使用显式种子,这样当再次使用相同种子运行测试时,它会再次产生完全相同的字符串。这是一个函数的简化示例,该函数以可重现的方式生成对象名称:
alter procedure usp_generateIdentifier
@minLen int = 1
, @maxLen int = 256
, @seed int output
, @string varchar(8000) output
as
begin
set nocount on;
declare @length int;
declare @alpha varchar(8000)
, @digit varchar(8000)
, @specials varchar(8000)
, @first varchar(8000)
declare @step bigint = rand(@seed) * 2147483647;
select @alpha = 'qwertyuiopasdfghjklzxcvbnm'
, @digit = '1234567890'
, @specials = '_@# '
select @first = @alpha + '_@';
set @seed = (rand((@seed+@step)%2147483647)*2147483647);
select @length = @minLen + rand(@seed) * (@maxLen-@minLen)
, @seed = (rand((@seed+@step)%2147483647)*2147483647);
declare @dice int;
select @dice = rand(@seed) * len(@first),
@seed = (rand((@seed+@step)%2147483647)*2147483647);
select @string = substring(@first, @dice, 1);
while 0 < @length
begin
select @dice = rand(@seed) * 100
, @seed = (rand((@seed+@step)%2147483647)*2147483647);
if (@dice < 10) -- 10% special chars
begin
select @dice = rand(@seed) * len(@specials)+1
, @seed = (rand((@seed+@step)%2147483647)*2147483647);
select @string = @string + substring(@specials, @dice, 1);
end
else if (@dice < 10+10) -- 10% digits
begin
select @dice = rand(@seed) * len(@digit)+1
, @seed = (rand((@seed+@step)%2147483647)*2147483647);
select @string = @string + substring(@digit, @dice, 1);
end
else -- rest 80% alpha
begin
declare @preseed int = @seed;
select @dice = rand(@seed) * len(@alpha)+1
, @seed = (rand((@seed+@step)%2147483647)*2147483647);
select @string = @string + substring(@alpha, @dice, 1);
end
select @length = @length - 1;
end
end
go
[运行测试时,调用者会生成一个随机种子,它将与测试运行相关联(将其保存在结果表中),然后将其传递给种子,类似于此:
declare @seed int;
declare @string varchar(256);
select @seed = 1234; -- saved start seed
exec usp_generateIdentifier
@seed = @seed output
, @string = @string output;
print @string;
exec usp_generateIdentifier
@seed = @seed output
, @string = @string output;
print @string;
exec usp_generateIdentifier
@seed = @seed output
, @string = @string output;
print @string;
[更新2016-02-17:请参见下面的评论,原始过程在推进随机种子的方式方面存在问题。我更新了代码,并修复了上述的问题。
对于一个随机字母,您可以使用:
我意识到这是一个古老的问题,答案很多。但是,当我发现此问题时,我也在Saeid Hasani的TechNet上找到了最近的文章
有很多好的答案,但是到目前为止,它们都没有一个允许自定义的字符池,并且无法用作列的默认值。我希望能够做这样的事情:
我使用我开发的此过程只是规定了要显示在输入变量中的字符,也可以定义长度。希望格式正确,我是堆栈溢出的新手。
这是我今天想出的一个(因为我对现有的答案不满意)。>>
这会根据newid()
生成一个随机字符串的临时表,但它还支持自定义字符集(因此不止是0-9和AF),自定义长度(最多255个,限制为-编码,但可以更改),以及自定义数量的随机记录。
我首先遇到了this blog post,然后针对当前项目使用了以下存储过程(对不起,格式化很奇怪):
CREATE PROCEDURE [dbo].[SpGenerateRandomString]
@sLength tinyint = 10,
@randomString varchar(50) OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE @counter tinyint
DECLARE @nextChar char(1)
SET @counter = 1
SET @randomString = ”
WHILE @counter <= @sLength
BEGIN
SELECT @nextChar = CHAR(48 + CONVERT(INT, (122-48+1)*RAND()))
IF ASCII(@nextChar) not in (58,59,60,61,62,63,64,91,92,93,94,95,96)
BEGIN
SELECT @randomString = @randomString + @nextChar
SET @counter = @counter + 1
END
END
END
我在SQL 2000中通过创建一个具有要使用的字符的表,创建一个视图来选择该表中的字符(按newid()排序,然后从该视图中选择前1个字符)来完成此操作。
CREATE VIEW dbo.vwCodeCharRandom
AS
SELECT TOP 100 PERCENT
CodeChar
FROM dbo.tblCharacter
ORDER BY
NEWID()
...
SELECT TOP 1 CodeChar FROM dbo.vwCodeCharRandom
这里有一些基于新ID的内容。
with list as
(
select 1 as id,newid() as val
union all
select id + 1,NEWID()
from list
where id + 1 < 10
)
select ID,val from list
option (maxrecursion 0)
我以为我会分享或回馈社区...它基于ASCII,解决方案虽然不完美,但效果很好。请享用,Goran B。
/*
-- predictable masking of ascii chars within a given decimal range
-- purpose:
-- i needed an alternative to hashing alg. or uniqueidentifier functions
-- because i wanted to be able to revert to original char set if possible ("if", the operative word)
-- notes: wrap below in a scalar function if desired (i.e. recommended)
-- by goran biljetina (2014-02-25)
*/
declare
@length int
,@position int
,@maskedString varchar(500)
,@inpString varchar(500)
,@offsetAsciiUp1 smallint
,@offsetAsciiDown1 smallint
,@ipOffset smallint
,@asciiHiBound smallint
,@asciiLoBound smallint
set @ipOffset=null
set @offsetAsciiUp1=1
set @offsetAsciiDown1=-1
set @asciiHiBound=126 --> up to and NOT including
set @asciiLoBound=31 --> up from and NOT including
SET @inpString = '{"config":"some string value", "boolAttr": true}'
SET @length = LEN(@inpString)
SET @position = 1
SET @maskedString = ''
--> MASK:
---------
WHILE (@position < @length+1) BEGIN
SELECT @maskedString = @maskedString +
ISNULL(
CASE
WHEN ASCII(SUBSTRING(@inpString,@position,1))>@asciiLoBound AND ASCII(SUBSTRING(@inpString,@position,1))<@asciiHiBound
THEN
CHAR(ASCII(SUBSTRING(@inpString,@position,1))+
(case when @ipOffset is null then
case when ASCII(SUBSTRING(@inpString,@position,1))%2=0 then @offsetAsciiUp1 else @offsetAsciiDown1 end
else @ipOffset end))
WHEN ASCII(SUBSTRING(@inpString,@position,1))<=@asciiLoBound
THEN '('+CONVERT(varchar,ASCII(SUBSTRING(@Inpstring,@position,1))+1000)+')' --> wrap for decode
WHEN ASCII(SUBSTRING(@inpString,@position,1))>=@asciiHiBound
THEN '('+CONVERT(varchar,ASCII(SUBSTRING(@inpString,@position,1))+1000)+')' --> wrap for decode
END
,'')
SELECT @position = @position + 1
END
select @MaskedString
SET @inpString = @maskedString
SET @length = LEN(@inpString)
SET @position = 1
SET @maskedString = ''
--> UNMASK (Limited to within ascii lo-hi bound):
-------------------------------------------------
WHILE (@position < @length+1) BEGIN
SELECT @maskedString = @maskedString +
ISNULL(
CASE
WHEN ASCII(SUBSTRING(@inpString,@position,1))>@asciiLoBound AND ASCII(SUBSTRING(@inpString,@position,1))<@asciiHiBound
THEN
CHAR(ASCII(SUBSTRING(@inpString,@position,1))+
(case when @ipOffset is null then
case when ASCII(SUBSTRING(@inpString,@position,1))%2=1 then @offsetAsciiDown1 else @offsetAsciiUp1 end
else @ipOffset*(-1) end))
ELSE ''
END
,'')
SELECT @position = @position + 1
END
select @maskedString
这与其他答案之一一样,将rand与种子一起使用,但是不必在每次调用时都提供种子。在第一个电话上提供就足够了。
这是我修改的代码。
使用向导
SELECT @randomString = CONVERT(varchar(255), NEWID())
非常短...
有时我们需要很多随机的东西:爱,友善,休假等。这些年来,我已经收集了一些随机生成器,它们来自Pinal Dave和我一次发现的stackoverflow答案。参考如下。
--Adapted from Pinal Dave; http://blog.sqlauthority.com/2007/04/29/sql-server-random-number-generator-script-sql-query/
SELECT
ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1 AS RandomInt
, CAST( (ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1)/7.0123 AS NUMERIC( 15,4)) AS RandomNumeric
, DATEADD( DAY, -1*(ABS( CAST( NEWID() AS BINARY( 6)) %1000) + 1), GETDATE()) AS RandomDate
--This line from http://stackoverflow.com/questions/15038311/sql-password-generator-8-characters-upper-and-lower-and-include-a-number
, CAST((ABS(CHECKSUM(NEWID()))%10) AS VARCHAR(1)) + CHAR(ASCII('a')+(ABS(CHECKSUM(NEWID()))%25)) + CHAR(ASCII('A')+(ABS(CHECKSUM(NEWID()))%25)) + LEFT(NEWID(),5) AS RandomChar
, ABS(CHECKSUM(NEWID()))%50000+1 AS RandomID
在SQL Server 2012+]中,我们可以连接某些(G)UID的二进制文件,然后对结果进行base64转换。SELECT
textLen.textLen
, left((
select CAST(newid() as varbinary(max)) + CAST(newid() as varbinary(max))
where textLen.textLen is not null /*force evaluation for each outer query row*/
FOR XML PATH(''), BINARY BASE64
),textLen.textLen) as randomText
FROM ( values (2),(4),(48) ) as textLen(textLen) --define lengths here
;
所以我喜欢上面的许多答案,但我一直在寻找自然界中随机性更高的东西。我还想要一种明确地指出排除字符的方法。下面是我的解决方案,其中使用了调用CRYPT_GEN_RANDOM
的视图以获取密码随机数。在我的示例中,我只选择了一个8字节的随机数。请注意,您可以增加此大小,也可以根据需要利用函数的种子参数。这是文档的链接:https://docs.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql
CREATE VIEW [dbo].[VW_CRYPT_GEN_RANDOM_8] AS SELECT CRYPT_GEN_RANDOM(8) as [value];
创建视图的原因是,无法直接从函数中调用
CRYPT_GEN_RANDOM
。
非常简单。请尽情使用。
CREATE VIEW [dbo].[vwGetNewId]
AS
SELECT NEWID() AS Id
Creat FUNCTION [dbo].[fnGenerateRandomString](@length INT = 8)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @result CHAR(2000);
DECLARE @String VARCHAR(2000);
SET @String = 'abcdefghijklmnopqrstuvwxyz' + --lower letters
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + --upper letters
'1234567890'; --number characters
SELECT @result =
(
SELECT TOP (@length)
SUBSTRING(@String, 1 + number, 1) AS [text()]
FROM master..spt_values
WHERE number < DATALENGTH(@String)
AND type = 'P'
ORDER BY
(
SELECT TOP 1 Id FROM dbo.vwGetNewId
) --instead of using newid()
FOR XML PATH('')
);
RETURN @result;
END;
这将产生一个长度为96个字符的字符串,其长度来自Base64范围(上,下,数字,+和/)。添加3个“ NEWID()”将使长度增加32,而没有Base64填充(=)。
SELECT
CAST(
CONVERT(NVARCHAR(MAX),
CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
+CONVERT(VARBINARY(8), NEWID())
,2)
AS XML).value('xs:base64Binary(xs:hexBinary(.))', 'VARCHAR(MAX)') AS StringValue
如果将它应用于集合,请确保从集合中引入一些东西,以便重新计算NEWID(),否则每次将获得相同的值:
类似于第一个示例,但具有更大的灵活性:
-- min_length = 8, max_length = 12
SET @Length = RAND() * 5 + 8
-- SET @Length = RAND() * (max_length - min_length + 1) + min_length
-- define allowable character explicitly - easy to read this way an easy to
-- omit easily confused chars like l (ell) and 1 (one) or 0 (zero) and O (oh)
SET @CharPool =
'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789.,-_!$@#%^&*'
SET @PoolLength = Len(@CharPool)
SET @LoopCount = 0
SET @RandomString = ''
WHILE (@LoopCount < @Length) BEGIN
SELECT @RandomString = @RandomString +
SUBSTRING(@Charpool, CONVERT(int, RAND() * @PoolLength), 1)
SELECT @LoopCount = @LoopCount + 1
END
我忘了提其他使它更加灵活的功能。通过在@CharPool中重复字符块,可以增加某些字符的权重,以便更有可能选择它们。
使用以下代码返回短字符串:
SELECT SUBSTRING(CONVERT(varchar(40), NEWID()),0,9)
如果运行的是SQL Server 2008或更高版本,则可以使用新的加密函数crypt_gen_random(),然后使用base64编码将其设置为字符串。这最多可以使用8000个字符。
declare @BinaryData varbinary(max)
, @CharacterData varchar(max)
, @Length int = 2048
set @BinaryData=crypt_gen_random (@Length)
set @CharacterData=cast('' as xml).value('xs:base64Binary(sql:variable("@BinaryData"))', 'varchar(max)')
print @CharacterData
我不是T-SQL方面的专家,但是我已经使用过的最简单的方法是这样的:
select char((rand()*25 + 65))+char((rand()*25 + 65))
这将生成两个字符(A-Z,ASCII 65-90中的字符。)。>>
select left(NEWID(),5)
这里是随机字母数字生成器
这对我有用:我只需要为ID生成三个随机的字母数字字符,但它就可以在不超过15个左右的任何长度下工作。