Генерация случайных строк с помощью T-SQL
Если бы вы хотели создать псевдослучайную буквенно-цифровую строку с помощью T-SQL, как бы вы это сделали? Как бы вы исключили из него такие символы, как знаки доллара, тире и косые черты?
23 ответа:
при генерации случайных данных, специально для теста, очень полезно сделать данные случайными, но воспроизводимыми. Секрет заключается в том, чтобы использовать явные семена для случайной функции, чтобы при повторном запуске теста с тем же семенем он снова создавал точно такие же строки. Вот упрощенный пример функции, которая генерирует имена объектов воспроизводимым образом:
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: см. комментарии ниже, оригинальная процедура имела проблему в том, как она продвигала случайное семя. Я обновил код, а также исправил упомянутую проблему off-by-one.
похоже на первый пример, но с большей гибкостью:
-- 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).
вот случайный алфавитно-цифровой генератор
print left(replace(newid(),'-',''),@length) //--@length is the length of random Num.
это сработало для меня: мне нужно было создать всего три случайных буквенно-цифровых символа для идентификатора, но он мог работать для любой длины до 15 или около того.
declare @DesiredLength as int = 3; select substring(replace(newID(),'-',''),cast(RAND()*(31-@DesiredLength) as int),@DesiredLength);
для одной случайной буквы, вы можете использовать:
select substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ', (abs(checksum(newid())) % 26)+1, 1)важное различие между использованием
newid()иrand()это если вы возвращаете несколько строк,newid()рассчитывается отдельно для каждой строки, аrand()вычисляется один раз для всего запроса.
Я понимаю, что это старый вопрос со многими прекрасными ответами. Однако, когда я нашел это, я также нашел более свежую статью о TechNet от Saeid Hasani
T-SQL: как генерировать случайные пароли
в то время как решение фокусируется на паролях, оно применяется к общему случаю. Сейед работает через различные соображения, чтобы прийти к решению. Это очень поучительно.
скрипт, содержащий все блоки кода в статье отдельно доступны через Галерея TechNet, но я бы определенно начал со статьи.
Я использую эту процедуру, которую я разработал, просто стиплирую символы, которые вы хотите отображать во входных переменных, вы также можете определить длину. Надеюсь, что это форматы хорошо, я новичок в переполнении стека.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND object_id = OBJECT_ID(N'GenerateARandomString')) DROP PROCEDURE GenerateARandomString GO CREATE PROCEDURE GenerateARandomString ( @DESIREDLENGTH INTEGER = 100, @NUMBERS VARCHAR(50) = '0123456789', @ALPHABET VARCHAR(100) ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', @SPECIALS VARCHAR(50) = '_=+-$£%^&*()"!@~#:', @RANDOMSTRING VARCHAR(8000) OUT ) AS BEGIN -- Author David Riley -- Version 1.0 -- You could alter to one big string .e.e numebrs , alpha special etc -- added for more felxibility in case I want to extend i.e put logic in for 3 numbers, 2 pecials 3 numbers etc -- for now just randomly pick one of them DECLARE @SWAP VARCHAR(8000); -- Will be used as a tempoary buffer DECLARE @SELECTOR INTEGER = 0; DECLARE @CURRENTLENGHT INTEGER = 0; WHILE @CURRENTLENGHT < @DESIREDLENGTH BEGIN -- Do we want a number, special character or Alphabet Randonly decide? SET @SELECTOR = CAST(ABS(CHECKSUM(NEWID())) % 3 AS INTEGER); -- Always three 1 number , 2 alphaBET , 3 special; IF @SELECTOR = 0 BEGIN SET @SELECTOR = 3 END; -- SET SWAP VARIABLE AS DESIRED SELECT @SWAP = CASE WHEN @SELECTOR = 1 THEN @NUMBERS WHEN @SELECTOR = 2 THEN @ALPHABET ELSE @SPECIALS END; -- MAKE THE SELECTION SET @SELECTOR = CAST(ABS(CHECKSUM(NEWID())) % LEN(@SWAP) AS INTEGER); IF @SELECTOR = 0 BEGIN SET @SELECTOR = LEN(@SWAP) END; SET @RANDOMSTRING = ISNULL(@RANDOMSTRING,'') + SUBSTRING(@SWAP,@SELECTOR,1); SET @CURRENTLENGHT = LEN(@RANDOMSTRING); END; END; GO DECLARE @RANDOMSTRING VARCHAR(8000) EXEC GenerateARandomString @RANDOMSTRING = @RANDOMSTRING OUT SELECT @RANDOMSTRING
это очень просто.используйте его и наслаждайтесь.
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;
я наткнулся на этот блог во-первых, затем придумал следующую хранимую процедуру для этого, которую я использую в текущем проекте (извините за странное форматирование):
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затем вы можете просто вытащить символы из представления и объединить их по мере необходимости.
EDIT: вдохновленный ответом Стефана...
select top 1 RandomChar from tblRandomCharacters order by newid()нет необходимости в представлении (на самом деле я не уверен, почему я это сделал-код из нескольких лет назад). Вы можете указать символы, которые вы хотите использовать в таблице.
вот что-то на основе нового 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, и решение не идеально, но оно работает довольно хорошо. Наслаждаться, Горан Б.
/* -- 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 с семенем, как один из других ответов, но не обязательно предоставлять семя при каждом вызове. Достаточно предоставить его по первому звонку.
Это мой измененный код.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND object_id = OBJECT_ID(N'usp_generateIdentifier')) DROP PROCEDURE usp_generateIdentifier GO create 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) select @alpha = 'qwertyuiopasdfghjklzxcvbnm' , @digit = '1234567890' , @specials = '_@#$&' select @first = @alpha + '_@'; -- Establish our rand seed and store a new seed for next time set @seed = (rand(@seed)*2147483647); select @length = @minLen + rand() * (@maxLen-@minLen); --print @length declare @dice int; select @dice = rand() * len(@first); select @string = substring(@first, @dice, 1); while 0 < @length begin select @dice = rand() * 100; if (@dice < 10) -- 10% special chars begin select @dice = rand() * len(@specials)+1; select @string = @string + substring(@specials, @dice, 1); end else if (@dice < 10+10) -- 10% digits begin select @dice = rand() * len(@digit)+1; select @string = @string + substring(@digit, @dice, 1); end else -- rest 80% alpha begin select @dice = rand() * len(@alpha)+1; select @string = @string + substring(@alpha, @dice, 1); end select @length = @length - 1; end end go
есть много хороших ответов, но до сих пор ни один из них не позволяет настраиваемый пул символов и работать в качестве значения по умолчанию для столбца. Я хотел быть в состоянии сделать что-то вроде этого:
alter table MY_TABLE add MY_COLUMN char(20) not null default dbo.GenerateToken(crypt_gen_random(20))вот я и придумал это. Остерегайтесь жестко закодированного числа 32, Если вы измените его.
-- Converts a varbinary of length N into a varchar of length N. -- Recommend passing in the result of CRYPT_GEN_RANDOM(N). create function GenerateToken(@randomBytes varbinary(max)) returns varchar(max) as begin -- Limit to 32 chars to get an even distribution (because 32 divides 256) with easy math. declare @allowedChars char(32); set @allowedChars = 'abcdefghijklmnopqrstuvwxyz012345'; declare @oneByte tinyint; declare @oneChar char(1); declare @index int; declare @token varchar(max); set @index = 0; set @token = ''; while @index < datalength(@randomBytes) begin -- Get next byte, use it to index into @allowedChars, and append to @token. -- Note: substring is 1-based. set @index = @index + 1; select @oneByte = convert(tinyint, substring(@randomBytes, @index, 1)); select @oneChar = substring(@allowedChars, 1 + (@oneByte % 32), 1); -- 32 is the number of @allowedChars select @token = @token + @oneChar; end return @token; end
иногда нам нужно много случайных вещей: любви, доброты, отдыха и т. д. За эти годы я собрал несколько случайных генераторов, и это от 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)UIDs, а затем сделать 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 ;Если вам нужны более длинные строки (или вы видите
=символы в результате) вам нужно добавить больше+ CAST(newid() as varbinary(max))в подрубрике выберите.
так что мне понравилось много ответов выше, но я искал что-то, что было немного более случайным по своей природе. Я также хотел, чтобы способ явно вызвать исключенные символы. Ниже мое решение с помощью представления, которое вызывает
CRYPT_GEN_RANDOMчтобы получить криптографическое случайное число. В моем примере, я выбрал случайное число, которое было 8 байт. Обратите внимание, что вы можете увеличить этот размер, а также использовать параметр seed функции, если хотите. Вот ссылка на документацию: https://docs.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sqlCREATE VIEW [dbo].[VW_CRYPT_GEN_RANDOM_8] AS SELECT CRYPT_GEN_RANDOM(8) as [value];причина создания представления заключается в том, что
CRYPT_GEN_RANDOMне может быть вызван непосредственно из функции.оттуда я создал скалярную функцию, которая принимает длину и строковый параметр, который может содержать строку с разделителями-запятыми исключенных символов.
CREATE FUNCTION [dbo].[fn_GenerateRandomString] ( @length INT, @excludedCharacters VARCHAR(200) --Comma delimited string of excluded characters ) RETURNS VARCHAR(Max) BEGIN DECLARE @returnValue VARCHAR(Max) = '' , @asciiValue INT , @currentCharacter CHAR; --Optional concept, you can add default excluded characters SET @excludedCharacters = CONCAT(@excludedCharacters,',^,*,(,),-,_,=,+,[,{,],},\,|,;,:,'',",<,.,>,/,`,~'); --Table of excluded characters DECLARE @excludedCharactersTable table([asciiValue] INT); --Insert comma INSERT INTO @excludedCharactersTable SELECT 44; --Stores the ascii value of the excluded characters in the table INSERT INTO @excludedCharactersTable SELECT ASCII(TRIM(value)) FROM STRING_SPLIT(@excludedCharacters, ',') WHERE LEN(TRIM(value)) = 1; --Keep looping until the return string is filled WHILE(LEN(@returnValue) < @length) BEGIN --Get a truly random integer values from 33-126 SET @asciiValue = (SELECT TOP 1 (ABS(CONVERT(INT, [value])) % 94) + 33 FROM [dbo].[VW_CRYPT_GEN_RANDOM_8]); --If the random integer value is not in the excluded characters table then append to the return string IF(NOT EXISTS(SELECT * FROM @excludedCharactersTable WHERE [asciiValue] = @asciiValue)) BEGIN SET @returnValue = @returnValue + CHAR(@asciiValue); END END RETURN(@returnValue); ENDНиже приведен пример того, как вызвать функция.
SELECT [dbo].[fn_GenerateRandomString](8,'!,@,#,$,%,&,?');~Ура
вот один я придумал сегодня (потому что мне не понравился ни один из существующих ответов достаточно).
этот генерирует временную таблицу случайных строк, основанную на
newid(), но также поддерживает пользовательский набор символов (так что больше, чем просто 0-9 & A-F), пользовательскую длину (до 255, предел жестко закодирован, но может быть изменен) и пользовательское количество случайных записей.вот исходный код (надеюсь, комментарии помогут):
/** * First, we're going to define the random parameters for this * snippet. Changing these variables will alter the entire * outcome of this script. Try not to break everything. * * @var {int} count The number of random values to generate. * @var {int} length The length of each random value. * @var {char(62)} charset The characters that may appear within a random value. */ -- Define the parameters declare @count int = 10 declare @length int = 60 declare @charset char(62) = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' /** * We're going to define our random table to be twice the maximum * length (255 * 2 = 510). It's twice because we will be using * the newid() method, which produces hex guids. More later. */ -- Create the random table declare @random table ( value nvarchar(510) ) /** * We'll use two characters from newid() to make one character in * the random value. Each newid() provides us 32 hex characters, * so we'll have to make multiple calls depending on length. */ -- Determine how many "newid()" calls we'll need per random value declare @iterations int = ceiling(@length * 2 / 32.0) /** * Before we start making multiple calls to "newid", we need to * start with an initial value. Since we know that we need at * least one call, we will go ahead and satisfy the count. */ -- Iterate up to the count declare @i int = 0 while @i < @count begin set @i = @i + 1 -- Insert a new set of 32 hex characters for each record, limiting to @length * 2 insert into @random select substring(replace(newid(), '-', ''), 1, @length * 2) end -- Now fill the remaining the remaining length using a series of update clauses set @i = 0 while @i < @iterations begin set @i = @i + 1 -- Append to the original value, limit @length * 2 update @random set value = substring(value + replace(newid(), '-', ''), 1, @length * 2) end /** * Now that we have our base random values, we can convert them * into the final random values. We'll do this by taking two * hex characters, and mapping then to one charset value. */ -- Convert the base random values to charset random values set @i = 0 while @i < @length begin set @i = @i + 1 /** * Explaining what's actually going on here is a bit complex. I'll * do my best to break it down step by step. Hopefully you'll be * able to follow along. If not, then wise up and come back. */ -- Perform the update update @random set value = /** * Everything we're doing here is in a loop. The @i variable marks * what character of the final result we're assigning. We will * start off by taking everything we've already done first. */ -- Take the part of the string up to the current index substring(value, 1, @i - 1) + /** * Now we're going to convert the two hex values after the index, * and convert them to a single charset value. We can do this * with a bit of math and conversions, so function away! */ -- Replace the current two hex values with one charset value substring(@charset, convert(int, convert(varbinary(1), substring(value, @i, 2), 2)) * (len(@charset) - 1) / 255 + 1, 1) + -- (1) -------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------- -- (2) ---------------------------------^^^^^^^^^^^^^^^^^^^^^^11111111111111111111111^^^^------------------------------------- -- (3) --------------------^^^^^^^^^^^^^2222222222222222222222222222222222222222222222222^------------------------------------ -- (4) --------------------333333333333333333333333333333333333333333333333333333333333333---^^^^^^^^^^^^^^^^^^^^^^^^^-------- -- (5) --------------------333333333333333333333333333333333333333333333333333333333333333^^^4444444444444444444444444-------- -- (6) --------------------5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555^^^^---- -- (7) ^^^^^^^^^^^^^^^^^^^^66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666^^^^ /** * (1) - Determine the two hex characters that we'll be converting (ex: 0F, AB, 3C, etc.) * (2) - Convert those two hex characters to a a proper hexadecimal (ex: 0x0F, 0xAB, 0x3C, etc.) * (3) - Convert the hexadecimals to integers (ex: 15, 171, 60) * (4) - Determine the conversion ratio between the length of @charset and the range of hexadecimals (255) * (5) - Multiply the integer from (3) with the conversion ratio from (4) to get a value between 0 and (len(@charset) - 1) * (6) - Add 1 to the offset from (5) to get a value between 1 and len(@charset), since strings start at 1 in SQL * (7) - Use the offset from (6) and grab a single character from @subset */ /** * All that is left is to add in everything we have left to do. * We will eventually process the entire string, but we will * take things one step at a time. Round and round we go! */ -- Append everything we have left to do substring(value, 2 + @i, len(value)) end -- Select the results select value from @randomэто не хранится процедура, но превратить ее в таковую будет не так уж сложно. Это также не ужасно медленно (мне потребовалось ~0,3 секунды, чтобы сгенерировать 1000 результатов длины 60, что больше, чем мне когда-либо понадобится лично), что было одной из моих первоначальных проблем от всей мутации строки, которую я делаю.
основной вывод здесь заключается в том, что я не пытаюсь создать свой собственный генератор случайных чисел, и мой набор символов не ограничено. Я просто использую генератор случайных чисел, который имеет SQL (я знаю, что есть
rand(), но это не очень хорошо для результатов таблицы). Надеюсь, этот подход женится на двух видах ответов здесь, от чрезмерно простых (т. е. простоnewid()) и чрезмерно сложный (т. е. пользовательский алгоритм случайных чисел).Это короткие (без комментариев), и легко понять (по крайней мере для меня), что всегда является плюсом в моей книге.
однако этот метод не может быть засеян, поэтому он будет действительно случайным каждый раз, и вы не сможете воспроизвести один и тот же набор данные с любыми средствами надежности. ОП не перечислял это как требование, но я знаю, что некоторые люди ищут такие вещи.
Я знаю, что я опоздала на вечеринку здесь, но, надеюсь, кто-то найдет это полезным.