2009-08-24 4 views
63

Если вы хотите сгенерировать псевдослучайную буквенно-цифровую строку с использованием T-SQL, как бы вы это сделали? Как бы вы исключали из него символы, такие как знаки доллара, тире и косые черты?Создание случайных строк с T-SQL

ответ

26

При создании случайных данных, специально для тестирования, очень полезно сделать данные случайными, но воспроизводимыми. Секрет состоит в том, чтобы использовать явные семена для случайной функции, так что, когда тест снова запускается с тем же самым семенем, он снова воспроизводит точно такие же строки. Вот упрощенный пример функции, которая генерирует имена объектов воспроизводимым образом:

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 = '[email protected]# ' 
    select @first = @alpha + '[email protected]'; 

    set @seed = (rand((@[email protected])%2147483647)*2147483647); 

    select @length = @minLen + rand(@seed) * (@[email protected]) 
     , @seed = (rand((@[email protected])%2147483647)*2147483647); 

    declare @dice int; 
    select @dice = rand(@seed) * len(@first), 
     @seed = (rand((@[email protected])%2147483647)*2147483647); 
    select @string = substring(@first, @dice, 1); 

    while 0 < @length 
    begin 
     select @dice = rand(@seed) * 100 
      , @seed = (rand((@[email protected])%2147483647)*2147483647); 
     if (@dice < 10) -- 10% special chars 
     begin 
      select @dice = rand(@seed) * len(@specials)+1 
       , @seed = (rand((@[email protected])%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((@[email protected])%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((@[email protected])%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: Смотрите комментарии ниже, оригинальная процедура была проблема в том, как он продвинул случайное зерно. Я обновил код, а также исправил упомянутую проблему отдельно.

+0

Обратите внимание, что повторное посев в моем примере в основном иллюстрирует точку. На практике его достаточно, чтобы засеять RNG один раз за сеанс, пока последовательность вызовов детерминирована впоследствии. –

+2

Я знаю, что это старый поток, но код возвращает ту же строку для семян 192804 и 529126 – davey

+1

@RemusRusanu Мне также будет интересен ответ на комментарий пользователя davey –

0

я наткнулся 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 
0

Я сделал это в SQL Server 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() 

Нет необходимости в целях (на самом деле я не знаю, почему я сделал это - код от нескольких лет назад). Вы все равно можете указать символы, которые вы хотите использовать в таблице.

138

Использование GUID

SELECT @randomString = CONVERT(varchar(255), NEWID()) 

очень короткий ...

+6

+1, очень легко. Объедините с ПРАВОЙ/ПОДЪЕМНОЙ, чтобы усечь его до необходимой длины. –

+2

Мне это нравится - милый и простой. Хотя он не имеет функции «возможности поиска», отлично работает для генерации данных. – madhurtanwani

+0

+1 это замечательно. при использовании в сочетании с комментариями выше вы можете использовать для char (46) .. (guid/newid() length), а затем вручную применить функцию RTRIM() явно. – JBone

42

Аналогично первому примеру, но с большей гибкостью:

-- 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.,[email protected]#%^&*' 
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, вы можете увеличить взвешивание определенных символов, чтобы они были более вероятными.

+0

+1 Это хорошая рутина, я использую ее как часть хранимой процедуры. –

+0

большой скрипт полезности, спасибо – thetimmer

+0

Отличная рутина, будет использовать это в двух проектах, спасибо! – zukanta

24

Используйте следующий код, чтобы вернуть короткую строку:

SELECT SUBSTRING(CONVERT(varchar(40), NEWID()),0,9) 
+0

Возвращает только шестнадцатеричные символы: 0-9 и AF – jumxozizi

6

Здесь случайный буквенно-цифровой генератор

print left(replace(newid(),'-',''),@length) //[email protected] is the length of random Num. 
+0

Возвращает только шестнадцатеричные символы: 0-9 & AF – jumxozizi

0

Heres что-то основанное на Новом 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) 
+0

Возвращает только шестнадцатеричные символы: 0-9 & AF – jumxozizi

4

Это работает для меня: мне нужно, чтобы генерировать только три случайные буквенно-цифровые символы для идентификатора, но она может работать на любую длину до 15 или около того.

declare @DesiredLength as int = 3; 
select substring(replace(newID(),'-',''),cast(RAND()*([email protected]) as int),@DesiredLength); 
+0

Возвращает только шестнадцатеричные символы: 0-9 и AF – jumxozizi

+0

Да, я думаю, ваш верный. Это не верно «буквенно-цифровое», так как вы не получаете символов> «F». – Brian

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))<[email protected] 
     THEN '('+CONVERT(varchar,ASCII(SUBSTRING(@Inpstring,@position,1))+1000)+')' --> wrap for decode 
     WHEN ASCII(SUBSTRING(@inpString,@position,1))>[email protected] 
     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 
+0

Я действительно понимаю, что мое решение НЕ является случайным генерации символов, а скорее предсказуемым запутыванием строк ... :) –

13

Если вы работаете в 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 
8
select left(NEWID(),5) 

Это вернет 5 оставил большинство символов из строки Guid

Example run 
------------ 
11C89 
9DB02 
+1

Хотя это решение не подходит для производственной системы, так как вы получите довольно много дубликатов после нескольких тысяч или около того, это весьма полезен для быстрого и простого способа получения случайной строки при отладке или тестировании чего-либо. – Ian1971

+0

Я использовал это, чтобы создать случайный пароль из 4 букв для примерно 500 логинов, и это отлично подходит для этого. Да для больших данных и других целей используйте больше символов. –

+0

NEWID() не считается случайным для защищенных паролей, поэтому в зависимости от ваших требований вам нужно быть осторожными. С 5 символами вы получаете столкновение после 1500 записей. С 4 символами вы получаете столкновение в любом месте от 55-800 записей в моем тесте. – Ian1971

1

я понимаю, что это старый вопрос со многими прекрасными ответами. Однако, когда я нашел это я нашел более позднюю статью на веб-сайте TechNet по Саеид Хасани

T-SQL: How to Generate Random Passwords

Хотя решение фокусируется на пароли это относится к общему случаю. Саид работает по различным соображениям, чтобы прийти к решению. Это очень поучительно.

Сценарий, содержащий все блоки кода, составляющие статью, отдельно доступен через TechNet Gallery, но я определенно начну с статьи.

0

Это использует ранд с семенем, как и один из других ответов, но нет необходимости предоставлять семя при каждом вызове. Обеспечить его при первом вызове достаточно.

Это мой модифицированный код.

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 = '[email protected]#$&' 
    select @first = @alpha + '[email protected]'; 

    -- Establish our rand seed and store a new seed for next time 
    set @seed = (rand(@seed)*2147483647); 

    select @length = @minLen + rand() * (@[email protected]); 
    --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 
6

Я не эксперт в T-SQL, но самый простой способ я уже использовал это так:

select char((rand()*25 + 65))+char((rand()*25 + 65)) 

Это создает два полукокса (AZ, в ASCII 65-90) ,

0

Есть много хороших ответов, но до сих пор ни один из них не позволяет настраиваемый пул символов и работает как значение по умолчанию для столбца. Я хотел бы сделать что-то вроде этого:

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 = 'abcdefghijklmnopqrstuvwxyz'; 

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 
1

Я использую эту процедуру, я разработал просто stipluate в Charaters вы хотите, чтобы иметь возможность отображать во входных переменных, вы можете определить длину тоже. Надеюсь, что этот формат хорошо, я новичок в переполнении стека.

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) 
     = '',  
    @ALPHABET    VARCHAR(100) 
     ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 
    @SPECIALS    VARCHAR(50) 
     = '_=+-$£%^&*()"[email protected]~#:', 
    @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 
0

Иногда нам нужно много случайных вещей: любовь, доброта, отпуск и т. Д. Я собрал несколько случайных генераторов на протяжении многих лет, и это из 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.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 
0

В 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)) в подменю выберите.

0

Так что мне понравилось много ответов выше, но я искал нечто более случайное в природе. Я также хотел, чтобы явным образом вызывать исключенные символы. Ниже мое решение, используя представление, которое вызывает 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 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,'!,@,#,$,%,&,?'); 

~ Приветствия

1

Для одного случайного письма, вы можете использовать:

select substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
       (abs(checksum(newid())) % 26)+1, 1) 

Важное различие между использованием newid() против rand() является то, что если вы вернете несколько строк, newid() рассчитывается отдельно для каждая строка, а rand() вычисляется один раз для всего запроса.

Смежные вопросы