从CRYPT_GEN_RANDOM()中筛选出“特殊”字符

时间:2012-02-16 14:27:46

标签: sql-server-2008

SELECT CRYPT_GEN_RANDOM(4) as SAMPLEDATA

对于每个选择,上面的函数会生成一些字母数字的随机值,但有时它也会生成特殊字符,在这种情况下如何通过使用sql存储过程来避免使用特殊字符

2 个答案:

答案 0 :(得分:0)

CRYPT_GEN_RANDOM()生成的varbinary不能很好地转换为文本。

如果您只想要一个随机字母数字值,您可以使用NEWID()之类的GUID来获得相同的效果。

答案 1 :(得分:0)

借用@JNK的想法。假设你真的只使用字母数字,这种情况无关紧要,你需要的最长字符串是36个字符,你可以先创建一个视图:

CREATE VIEW dbo.RetrieveNewID
AS
    SELECT [NewID] = NEWID();
GO

然后创建此功能:

CREATE FUNCTION dbo.GenerateRandomNumbersLetters
(
    @NumberOfCharacters TINYINT
)
RETURNS VARCHAR(32)
AS
BEGIN
    RETURN 
    (
        SELECT LEFT(REPLACE([NewID], '-', ''), @NumberOfCharacters)
        FROM dbo.RetrieveNewID
    );
END
GO

我的结果:

SELECT r = dbo.GenerateRandomNumbersLetters(4);
SELECT r = dbo.GenerateRandomNumbersLetters(4);
SELECT r = dbo.GenerateRandomNumbersLetters(4);

r
----
EA93
9D32
B229

如果您在非常两种模式下执行此操作,这将是正常的。如果您尝试为集合生成此函数,则随着集合变大,效率会降低。例如:

SELECT r = dbo.GenerateRandomNumbersLetters(i) FROM
(
    SELECT i = 1 
    UNION ALL SELECT i = 2 
    UNION ALL SELECT i = 3
) AS x;

我不希望在大型数据集上表现得特别好。


现在,如果要在GUID(A-Z / 0-9)中使用可能的集合之外的字符,可以使用表格执行此操作。假设上面的视图相同,我们可以创建一个表,并用随机生成器可以使用的任何字符填充它(包括严格字母数字以外的字符,但仍然可以排除任何你不想要的“特殊”字符考虑)。

CREATE TABLE dbo.RandomCharacters
(
    Digit NVARCHAR(1) COLLATE Latin1_General_CS_AI PRIMARY KEY
);

;WITH x AS 
(
    SELECT TOP (200) i = ROW_NUMBER() OVER (ORDER BY [object_id])
    FROM sys.all_objects
    ORDER BY [object_id]
)
INSERT dbo.RandomCharacters 
SELECT NCHAR(i) FROM x
WHERE (i BETWEEN 65 AND 90)  -- A-Z
   OR (i BETWEEN 97 AND 122) -- a-z
   OR (i BETWEEN 48 AND 57)  -- 0-9
   OR (i IN (42, 126, 181)); -- *, ~, µ

现在,执行魔术的功能(同样这一切都取决于允许我们通过将其隐藏在视图中来引用函数中的NEWID()的技巧):

CREATE FUNCTION dbo.GenerateRandomCharacters
(
    @NumberOfCharacters TINYINT
)
RETURNS NVARCHAR(255)
AS
BEGIN
    RETURN
    (
        SELECT (SELECT x.Digit FROM (
            SELECT TOP (@NumberOfCharacters) r.Digit 
            FROM dbo.RandomCharacters AS r
            CROSS JOIN dbo.RetrieveNewID AS d
            ORDER BY CONVERT(VARBINARY(36), d.[NewID])
        ) AS x
        FOR XML PATH(''), TYPE).value('.[1]','nvarchar(max)')
    );
END
GO

我的结果:

SELECT r = dbo.GenerateRandomCharacters(4);
SELECT r = dbo.GenerateRandomCharacters(4);
SELECT r = dbo.GenerateRandomCharacters(4);

r 
----
H~1r
Dfn2
µHxF

在后一种解决方案中,不支持重复项。我也不希望在大型数据集上表现出色。但是你可以拥有超过32个字符。 : - )