Генерация случайных строк с помощью 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()
) и чрезмерно сложный (т. е. пользовательский алгоритм случайных чисел).Это короткие (без комментариев), и легко понять (по крайней мере для меня), что всегда является плюсом в моей книге.
однако этот метод не может быть засеян, поэтому он будет действительно случайным каждый раз, и вы не сможете воспроизвести один и тот же набор данные с любыми средствами надежности. ОП не перечислял это как требование, но я знаю, что некоторые люди ищут такие вещи.
Я знаю, что я опоздала на вечеринку здесь, но, надеюсь, кто-то найдет это полезным.