Tạo chuỗi ngẫu nhiên với T-SQL


95

Nếu bạn muốn tạo một chuỗi ký tự số giả bằng T-SQL, bạn sẽ làm như thế nào? Làm cách nào để bạn loại trừ các ký tự như ký hiệu đô la, dấu gạch ngang và dấu gạch chéo khỏi nó?

Câu trả lời:


40

Khi tạo dữ liệu ngẫu nhiên, đặc biệt để thử nghiệm, sẽ rất hữu ích để làm cho dữ liệu trở nên ngẫu nhiên, nhưng có thể tái tạo. Bí mật là sử dụng các hạt giống rõ ràng cho hàm ngẫu nhiên, để khi chạy thử nghiệm lại với cùng một hạt giống, nó lại tạo ra các chuỗi giống hệt nhau. Dưới đây là một ví dụ đơn giản về hàm tạo tên đối tượng theo cách có thể tái tạo:

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

Khi chạy các bài kiểm tra, trình gọi tạo ra một hạt giống ngẫu nhiên mà nó liên kết với quá trình chạy thử nghiệm (lưu nó trong bảng kết quả), sau đó chuyển cùng hạt giống, tương tự như sau:

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;  

Cập nhật 2016-02-17: Xem các nhận xét bên dưới, quy trình ban đầu có vấn đề trong cách nó nâng cao hạt giống ngẫu nhiên. Tôi đã cập nhật mã và cũng đã khắc phục sự cố từng người một được đề cập.


Lưu ý rằng việc gieo hạt lại trong ví dụ của tôi chủ yếu là để củng cố điểm. Trên thực tế, nó đủ để gieo RNG một lần mỗi phiên, miễn là sau đó chuỗi cuộc gọi là xác định.
Remus Rusanu

2
Tôi biết đây là chủ đề cũ, nhưng mã trả về chuỗi tương tự cho hạt giống 192.804 và 529.126
Davey

1
@RemusRusanu Tôi cũng muốn trả lời bình luận của
davey

Hạt giống tiến bộ với công thức @seed = rand(@seed+1)*2147483647. Đối với giá trị 529126, giá trị tiếp theo là 1230039262 và sau đó giá trị tiếp theo là 192804. trình tự tiếp tục giống nhau sau đó. Kết quả đầu ra phải khác nhau theo ký tự đầu tiên, nhưng không phải do lỗi SUBSTRING(..., 0, ...)riêng lẻ : trả về chuỗi trống cho chỉ mục 0 và đối với 529126, điều này 'ẩn' ký tự đầu tiên được tạo. Khắc phục là tính toán @dice = rand(@seed) * len(@specials)+1để làm cho các chỉ mục dựa trên 1.
Remus Rusanu

Vấn đề này nảy sinh từ thực tế là các chuỗi ngẫu nhiên, khi chúng đạt đến một giá trị chung, chúng sẽ tiến triển giống nhau. Nếu cần thiết, nó có thể tránh được bằng cách làm cho +1trong rand(@seed+1)được tự ngẫu nhiên và xác định từ chỉ hạt giống ban đầu. Bằng cách này, ngay cả khi chuỗi đạt cùng một giá trị, chúng sẽ phân kỳ ngay lập tức.
Remus Rusanu

201

Sử dụng một hướng dẫn

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

rất ngắn ...


7
+1, rất dễ dàng. Kết hợp với RIGHT / SUBSTRING để cắt ngắn nó đến độ dài cần thiết.
Johannes Rudolph

2
Tôi thích điều này - ngọt ngào và đơn giản. Mặc dù nó không có tính năng "dự đoán", nhưng nó hoạt động rất tốt cho việc tạo dữ liệu.
madhurtanwani

6
Đừng không sử dụng QUYỀN / substring để cắt xén một UUID vì nó sẽ không phải độc đáo và cũng không ngẫu nhiên do cách UUIDs được tạo ra!
ooxi

1
Điều này là tốt, nhưng nếu bạn sử dụng điều này, hãy đảm bảo rằng bạn đã đọc phần này: blog.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx - Lưu ý GUID là cách triển khai UUID của Microsoft, bất kể điểm là ooxi đã đề cập, bạn cần phải cẩn thận cách cắt UUID.
Clarence Liu

7
Các ký tự chữ cái trong NEWID () là hệ thập phân, vì vậy bạn chỉ nhận được AF, không phải phần còn lại của bảng chữ cái. nó đang hạn chế theo nghĩa đó.
Smoore 4

51

Tương tự như ví dụ đầu tiên, nhưng linh hoạt hơn:

-- 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

Tôi quên đề cập đến một trong những tính năng khác giúp điều này linh hoạt hơn. Bằng cách lặp lại các khối ký tự trong @CharPool, bạn có thể tăng tỷ trọng cho các ký tự nhất định để chúng có nhiều khả năng được chọn hơn.


1
+1 đó là một thói quen tốt, tôi đang sử dụng nó như một phần của quy trình được lưu trữ.
Marcello Miorelli

2
Giải pháp tốt. Thật không may, nó không hoạt động trong một udf. Vì một số lý do, nó gây ra lỗi này: "Sử dụng không hợp lệ toán tử hiệu quả bên 'rand' trong một hàm".
rdans

12
Có một lỗi trong hàm này trong lệnh gọi SUBSTRING (). Nó nên được CONVERT(int, RAND() * @PoolLength) + 1(lưu ý +1 được thêm vào). SUBSTRING trong T-SQL bắt đầu với chỉ mục 1, do đó, hàm này đôi khi thêm một chuỗi rỗng (khi chỉ mục bằng 0) và không bao giờ thêm ký tự cuối cùng từ @CharPool.
Dana Cartwright

@Dana Cartwright bạn có thể vui lòng giúp tôi với yêu cầu của tôi không .. điều gì sẽ xảy ra nếu tôi cần độ dài không đổi của số sê-ri bằng cách sử dụng Charpool ở trên như số sê-ri 10 chữ và số. Làm cách nào để chúng tôi thay đổi quy trình được lưu trữ. Trong giao diện người dùng, tôi sẽ cung cấp tổng số số sê-ri sẽ được tạo như 100 hoặc 200 bằng Charpool. Chiều dài tối thiểu của số serial sẽ là 10 và tối đa 14 (mà cũng được cung cấp như là tham số)
Prathap Gangireddy

@PrathapGangireddy xin đặt một câu hỏi, ý kiến với một người không phải là nơi thích hợp cho câu hỏi
Dana Cartwright

31

Sử dụng mã sau để trả về một chuỗi ngắn:

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

2
Chỉ trả về ký tự thập lục phân: 0-9 & AF
jumxozizi

19

Nếu bạn đang chạy SQL Server 2008 trở lên, bạn có thể sử dụng hàm mật mã mới crypt_gen_random () và sau đó sử dụng mã hóa base64 để biến nó thành một chuỗi. Điều này sẽ hoạt động cho tối đa 8000 ký tự.

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

16

Tôi không phải là chuyên gia về T-SQL, nhưng cách đơn giản nhất mà tôi đã sử dụng là như sau:

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

Điều này tạo ra hai ký tự (AZ, trong ascii 65-90).


11
select left(NEWID(),5)

Điều này sẽ trả về 5 ký tự bên trái nhất của chuỗi hướng dẫn

Example run
------------
11C89
9DB02

1
Mặc dù giải pháp này không tốt cho hệ thống sản xuất vì bạn sẽ dễ dàng nhận được các bản sao sau vài nghìn hoặc lâu hơn, nhưng nó khá hữu ích cho một cách nhanh chóng và dễ dàng để có được một chuỗi ngẫu nhiên trong khi gỡ lỗi hoặc kiểm tra thứ gì đó.
Ian1971

Tôi đã sử dụng điều này để tạo mật khẩu 4 chữ cái ngẫu nhiên cho khoảng 500 lần đăng nhập và điều này hoạt động hoàn hảo cho điều đó. Có cho dữ liệu lớn và các mục đích khác sử dụng nhiều ký tự hơn.
Hammad Khan

1
NEWID () không được coi là đủ ngẫu nhiên cho mật khẩu an toàn, vì vậy tùy thuộc vào yêu cầu của bạn, bạn cần phải cẩn thận. Với 5 ký tự, bạn nhận được một va chạm sau khoảng 1500 bản ghi. Với 4 ký tự, bạn có thể xảy ra va chạm ở bất kỳ đâu từ 55-800 bản ghi trong thử nghiệm của tôi.
Ian1971

@ Ian1971 cho mật khẩu tạm thời vẫn ok. Giả sử tôi cung cấp cho bạn mã pin 4 chữ cái cho thẻ ATM của bạn. Cùng một mã pin đó cũng có thể được cấp cho người dùng thứ 800 khác, nhưng khả năng bạn sẽ sử dụng thẻ của anh ấy bằng mật khẩu của bạn là rất khó xảy ra. Đó là một số ngẫu nhiên khá nhiều, có thể truy cập tạm thời.
Hammad Khan

6

Đây là một trình tạo số alpha ngẫu nhiên

print left(replace(newid(),'-',''),@length) //--@length is the length of random Num.

Chỉ trả về ký tự thập lục phân: 0-9 & AF
jumxozizi

5

Đối với một chữ cái ngẫu nhiên, bạn có thể sử dụng:

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

Một sự khác biệt quan trọng giữa việc sử dụng newid()so với rand()là nếu bạn trả về nhiều hàng, newid()được tính riêng cho từng hàng, trong khi rand()được tính một lần cho toàn bộ truy vấn.


4

Điều này phù hợp với tôi: Tôi chỉ cần tạo ba ký tự chữ và số ngẫu nhiên cho một ID, nhưng nó có thể hoạt động với bất kỳ độ dài nào lên đến 15 hoặc lâu hơn.

declare @DesiredLength as int = 3;
select substring(replace(newID(),'-',''),cast(RAND()*(31-@DesiredLength) as int),@DesiredLength);

Chỉ trả về ký tự thập lục phân: 0-9 & AF
jumxozizi

Vâng, tôi đoán chính xác của bạn. Nó không thực sự là "chữ và số" vì bạn không nhận được ký tự> "F".
Brian

3

Có rất nhiều câu trả lời hay nhưng cho đến nay không có câu trả lời nào cho phép nhóm ký tự có thể tùy chỉnh và hoạt động như một giá trị mặc định cho một cột. Tôi muốn có thể làm điều gì đó như thế này:

alter table MY_TABLE add MY_COLUMN char(20) not null
  default dbo.GenerateToken(crypt_gen_random(20))

Vì vậy, tôi đã nghĩ ra điều này. Hãy cẩn thận với số được mã hóa cứng 32 nếu bạn sửa đổi nó.

-- 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

2

Tôi nhận ra rằng đây là một câu hỏi cũ với nhiều câu trả lời hay. Tuy nhiên khi tôi tìm thấy điều này, tôi cũng tìm thấy một bài báo gần đây hơn trên TechNet của Saeid Hasani

T-SQL: Cách tạo mật khẩu ngẫu nhiên

Trong khi giải pháp tập trung vào mật khẩu, nó áp dụng cho trường hợp chung. Saeid làm việc thông qua các cân nhắc khác nhau để đi đến một giải pháp. Nó là rất hướng dẫn.

Một tập lệnh chứa tất cả các khối mã tạo thành bài viết có sẵn riêng biệt qua TechNet Gallery , nhưng tôi chắc chắn sẽ bắt đầu từ bài viết.


1

Tôi sử dụng quy trình mà tôi đã phát triển này chỉ đơn giản là đánh dấu các ô trống mà bạn muốn có thể hiển thị trong các biến đầu vào, bạn cũng có thể xác định độ dài. Hy vọng định dạng này tốt, tôi mới để ngăn xếp tràn.

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

1

Đôi khi chúng ta cần rất nhiều thứ ngẫu nhiên: tình yêu, lòng tốt, kỳ nghỉ, v.v. Tôi đã thu thập một vài bộ tạo ngẫu nhiên trong nhiều năm, và chúng là từ Pinal Dave và một câu trả lời stackoverflow tôi đã tìm thấy một lần. Giới thiệu bên dưới.

--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

1
Cảm ơn bạn đã đăng bộ sưu tập các trình tạo ngẫu nhiên tiện dụng
iiminov Ngày

1

Đây là câu trả lời mà tôi nghĩ ra hôm nay (vì tôi không thích bất kỳ câu trả lời hiện có nào đủ).

Cái này tạo ra một bảng tạm thời gồm các chuỗi ngẫu nhiên, dựa trên newid()nhưng cũng hỗ trợ một bộ ký tự tùy chỉnh (không chỉ 0-9 & AF), độ dài tùy chỉnh (tối đa 255, giới hạn được mã hóa cứng, nhưng có thể đã thay đổi) và một số bản ghi ngẫu nhiên tùy chỉnh.

Đây là mã nguồn (hy vọng các ý kiến ​​sẽ giúp ích):

/**
 * 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

Nó không phải là một thủ tục được lưu trữ, nhưng sẽ không khó để biến nó thành một thủ tục. Nó cũng không quá chậm (tôi mất ~ 0,3 giây để tạo ra 1.000 kết quả có độ dài 60, nhiều hơn mức mà cá nhân tôi cần), đó là một trong những mối quan tâm ban đầu của tôi từ tất cả các đột biến chuỗi mà tôi đang làm.

Điều rút ra chính ở đây là tôi không cố tạo trình tạo số ngẫu nhiên của riêng mình và bộ ký tự của tôi không bị giới hạn. Tôi chỉ đơn giản là đang sử dụng trình tạo ngẫu nhiên mà SQL có (tôi biết là có rand(), nhưng điều đó không tốt cho kết quả bảng). Hy vọng rằng cách tiếp cận này kết hợp hai loại câu trả lời ở đây, từ quá đơn giản (tức là chỉ newid()) và quá phức tạp (tức là thuật toán số ngẫu nhiên tùy chỉnh).

Nó cũng ngắn gọn (trừ các bình luận), và dễ hiểu (ít nhất là đối với tôi), luôn là một điểm cộng trong cuốn sách của tôi.

Tuy nhiên, phương pháp này không thể được thực hiện, vì vậy nó sẽ thực sự ngẫu nhiên mỗi lần và bạn sẽ không thể sao chép cùng một tập dữ liệu với bất kỳ phương tiện tin cậy nào. OP đã không liệt kê điều đó như một yêu cầu, nhưng tôi biết rằng một số người đang tìm kiếm điều đó.

Tôi biết tôi đến muộn bữa tiệc ở đây, nhưng hy vọng ai đó sẽ thấy điều này hữu ích.


0

Tôi đã xem qua bài đăng trên blog này trước tiên, sau đó đưa ra quy trình được lưu trữ sau cho quy trình này mà tôi đang sử dụng trong một dự án hiện tại (xin lỗi vì định dạng kỳ lạ):

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

Tôi đã thực hiện điều này trong SQL 2000 bằng cách tạo một bảng có các ký tự mà tôi muốn sử dụng, tạo một dạng xem chọn các ký tự từ bảng đó theo thứ tự newid (), rồi chọn 1 ký tự hàng đầu từ dạng xem đó.

CREATE VIEW dbo.vwCodeCharRandom
AS
SELECT TOP 100 PERCENT 
    CodeChar
FROM dbo.tblCharacter
ORDER BY 
    NEWID()

...

SELECT TOP 1 CodeChar FROM dbo.vwCodeCharRandom

Sau đó, bạn có thể chỉ cần kéo các ký tự từ chế độ xem và nối chúng khi cần thiết.

CHỈNH SỬA: Lấy cảm hứng từ phản ứng của Stephan ...

select top 1 RandomChar from tblRandomCharacters order by newid()

Không cần xem (thực tế là tôi không chắc tại sao mình lại làm như vậy - mã của vài năm trước). Bạn vẫn có thể chỉ định các ký tự bạn muốn sử dụng trong bảng.


0

Đây là một cái gì đó dựa trên Id mới.

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)

Chỉ trả về ký tự thập lục phân: 0-9 & AF
jumxozizi

0

Tôi nghĩ rằng tôi sẽ chia sẻ, hoặc trả lại cho cộng đồng ... Nó dựa trên ASCII, và giải pháp không hoàn hảo nhưng nó hoạt động khá tốt. Hãy tận hưởng, 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

tôi nhận ra rằng giải pháp của tôi KHÔNG phải là tạo ký tự ngẫu nhiên mà là sự xáo trộn các chuỗi có thể đoán trước được ... :)
Goran B.

0

Điều này sử dụng rand với một hạt giống như một trong những câu trả lời khác, nhưng không cần thiết phải cung cấp một hạt giống cho mọi cuộc gọi. Cung cấp nó trong cuộc gọi đầu tiên là đủ.

Đây là mã sửa đổi của tôi.

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

0

Trong SQL Server 2012+, chúng tôi có thể nối các mã nhị phân của một số (G) UID và sau đó thực hiện chuyển đổi base64 trên kết quả.

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
;

Nếu bạn cần chuỗi dài hơn (hoặc bạn thấy các =ký tự trong kết quả), bạn cần thêm nhiều + CAST(newid() as varbinary(max))chuỗi hơn trong lựa chọn phụ.


0

Vì vậy, tôi thích rất nhiều câu trả lời ở trên, nhưng tôi đang tìm kiếm thứ gì đó ngẫu nhiên hơn một chút về bản chất. Tôi cũng muốn có một cách để gọi ra các ký tự bị loại trừ một cách rõ ràng. Dưới đây là giải pháp của tôi sử dụng chế độ xem gọi hàm CRYPT_GEN_RANDOMlấy số ngẫu nhiên mật mã. Trong ví dụ của tôi, tôi chỉ chọn một số ngẫu nhiên có 8 byte. Xin lưu ý, bạn có thể tăng kích thước này và cũng có thể sử dụng tham số hạt giống của hàm nếu bạn muốn. Đây là liên kết đến tài liệu: 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];

Lý do tạo khung nhìn là vì CRYPT_GEN_RANDOMkhông thể gọi trực tiếp từ một hàm.

Từ đó, tôi đã tạo một hàm vô hướng chấp nhận độ dài và tham số chuỗi có thể chứa một chuỗi ký tự bị loại trừ được phân tách bằng dấu phẩy.

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

Dưới đây là một ví dụ về cách gọi hàm.

SELECT [dbo].[fn_GenerateRandomString](8,'!,@,#,$,%,&,?');

~ Chúc mừng


0

nó rất đơn giản. sử dụng nó và tận hưởng.

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;

0

Điều này sẽ tạo ra một chuỗi có độ dài 96 ký tự, từ phạm vi Base64 (uppers, lowers, số, + và /). Thêm 3 "NEWID ()" sẽ tăng chiều dài thêm 32, không có phần đệm 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

Nếu bạn đang áp dụng điều này cho một tập hợp, hãy đảm bảo giới thiệu một cái gì đó từ tập hợp đó để NEWID () được tính toán lại, nếu không, bạn sẽ nhận được cùng một giá trị mỗi lần:

  SELECT 
    U.UserName
    , LEFT(PseudoRandom.StringValue, LEN(U.Pwd)) AS FauxPwd
  FROM Users U
    CROSS APPLY (
        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())
                    +CONVERT(VARBINARY(8), NEWID())
                    +CONVERT(VARBINARY(8), U.UserID)  -- Causes a recomute of all NEWID() calls
                ,2) 
            AS XML).value('xs:base64Binary(xs:hexBinary(.))', 'VARCHAR(MAX)') AS StringValue
    ) PseudoRandom

0

Đối với SQL Server 2016 trở lên, đây là một biểu thức thực sự đơn giản và tương đối hiệu quả để tạo chuỗi ngẫu nhiên mã hóa có độ dài byte nhất định:

--Generates 36 bytes (48 characters) of base64 encoded random data
select r from OpenJson((select Crypt_Gen_Random(36) r for json path)) 
  with (r varchar(max))

Lưu ý rằng độ dài byte không giống với kích thước được mã hóa; sử dụng sau đây từ này bài viết để chuyển đổi:

Bytes = 3 * (LengthInCharacters / 4) - Padding

0

Dựa trên các câu trả lời hữu ích khác nhau trong bài viết này, tôi đã kết hợp một số tùy chọn mà tôi thích.

DECLARE @UserId BIGINT = 12345 -- a uniqueId in my system
SELECT LOWER(REPLACE(NEWID(),'-','')) + CONVERT(VARCHAR, @UserId)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.