【问题标题】:Random key generation using SQL Server使用 SQL Server 随机生成密钥
【发布时间】:2018-01-12 05:34:32
【问题描述】:

我正在使用以下函数生成 5 个字母的随机密钥,但它是所有字母和数字的组合。

但根据要求,我需要生成一个不包含字符 'o' 和 'I' 且不包含数字 '0' 和 '1' 的随机唯一密钥。

   DECLARE @automateKey VARCHAR(15)
   DECLARE @Length INT = 6
   DECLARE @Count INT = 2

   SET @Length = @Length + 1
   SET @Count = @Count + 1

   SELECT @automateKey =  
          (SELECT CAST((ABS(Checksum(NewId())) % 10) AS VARCHAR(1)) + 
                  CHAR(ascii('A')+(Abs(Checksum(NewId()))%25)) +
                  LEFT(newid(),@count) Random_Number)

   SELECT (@automateKey)

我不确定如何从随机密钥生成中转义那些特定的字符和数字

有人可以帮忙解决这个问题吗?非常感谢。

【问题讨论】:

  • 您可以检查最终字符串是否包含 0,1 或 O,L 中的任何一个,然后替换为其他一些字母
  • 您提到随机键而不是随机值。生成的密钥是否需要是唯一的(即没有重复)?解决方案将取决于该要求。
  • 是的,很抱歉忘记它应该是独一无二的......
  • 澄清一下:您希望代码生成一个由单个数字、一个大写字母和三个附加数字组成的随机字符串。数字 01 被禁止,字母 IO 也是如此。相对于以前发布的字符串的某些未指定列表,结果字符串必须是唯一的。并且代码必须在insert 语句中可用。这涵盖了一切吗? (从 0 到 7 的四个值,一个从 0 到 23 的值,映射到有效数字/字母的字符串。连接,检查if exists( ? ),根据需要重复。用户定义函数(UDF)?)

标签: sql sql-server tsql sql-server-2012 sql-server-2014


【解决方案1】:

使用RAND() 优于NEWID(),因为它本质上不是随机的。

DECLARE 
    @Chars varchar(100) = 'ABCDEFGHJKLMNPQRSTUVWXYZ', 
    @CharsAndNumbers varchar(100) = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'

SELECT 
    CONCAT
    (
        -- Numbers 2-9
        FLOOR(RAND() * 8 + 2),

        -- Any UPPER CASE character but not I,O
        SUBSTRING(@Chars, CONVERT(int, RAND() * LEN(@Chars) + 1), 1),

        -- Numbers 2-9 and Any UPPER CASE charcter but not I,O
        SUBSTRING(@CharsAndNumbers, CONVERT(int, (RAND() * LEN(@CharsAndNumbers)) + 1), 1),
        SUBSTRING(@CharsAndNumbers, CONVERT(int, (RAND() * LEN(@CharsAndNumbers)) + 1), 1),
        SUBSTRING(@CharsAndNumbers, CONVERT(int, (RAND() * LEN(@CharsAndNumbers)) + 1), 1)
    )

Testing SQL in StackExchange Data Explorer

【讨论】:

    【解决方案2】:

    我建议这样做:

    declare @chars varchar(255);
    set @chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZ23456789';
    
    declare @i int;
    set @i = 1;
    
    declare @automateKey = varchar(255);
    
    set @automatekey = '';
    
    while @i <= 5
    begin
        set @automateKey = @automateKey + substring(@chars, cast(rand() * len(@chars) + 1 as int), 1)
        set @i = @i + 1;
    end;
    

    此解决方案有两个主要组成部分。首先,所有有效字符都定义为字符串。其次,它使用while 循环来设置使用rand() 的值。

    rand() 在 SQL Server 中的行为方式很奇怪——当给定查询出现时,它只计算一次。因此,我通常不想在SELECT 语句中使用它。

    我应该补充一点,以下可以替换 WHILE 循环:

    set @automateKey = (substring(@chars, cast(rand() * len(@chars) + 1 as int), 1) +
                        substring(@chars, cast(rand() * len(@chars) + 1 as int), 1) +
                        substring(@chars, cast(rand() * len(@chars) + 1 as int), 1) +
                        substring(@chars, cast(rand() * len(@chars) + 1 as int), 1) +
                        substring(@chars, cast(rand() * len(@chars) + 1 as int), 1)
                       );
    

    【讨论】:

      【解决方案3】:

      您的钥匙似乎有 3 个部分:

      第一个字符是 0-10 的随机数,它是通过以下方式生成的:

      (Abs(Checksum(NewId()))%10)
      

      第二个字符是随机生成的字母:

      CHAR(ascii('A')+(Abs(Checksum(NewId()))%25))
      

      第三部分是三个字符,可以是字母或数字

      LEFT(newid(),@count)
      

      更改前两部分以消除不需要的字符并不难,但需要对第三部分进行一些更改。 相反,您可以保持原样,并添加到末尾的 while 循环以搜索和替换不需要的字符 - 0 和 1 带有随机数,O 和 L 带有随机字母:

      DECLARE @automateKey VARCHAR(15)
      DECLARE @Length INT = 6
      DECLARE @Count INT = 2
      
      SET @Length = @Length + 1
      SET @Count = @Count + 1
      --this seems unnecessary , why not just SET @Count = 3 ?
      
      SELECT @automateKey =  
            (SELECT CAST((ABS(Checksum(NewId())) % 10) AS VARCHAR(1)) + 
                    CHAR(ascii('A')+(Abs(Checksum(NewId()))%25)) +
                    LEFT(newid(),@count) Random_Number)
      
      WHILE (@automateKey LIKE '%0%' OR @automateKey LIKE '%1%')
      BEGIN
          SELECT @automateKey = REPLACE(@automateKey, '0', (Abs(Checksum(NewId()))%10))
          SELECT @automateKey = REPLACE(@automateKey, '1', (Abs(Checksum(NewId()))%10))
      END
      
      WHILE (@automateKey LIKE '%O%' OR @automateKey LIKE '%L%')
      BEGIN
          SELECT @automateKey = REPLACE(@automateKey, 'O', CHAR(ascii('A')+(Abs(Checksum(NewId()))%25)))
          SELECT @automateKey = REPLACE(@automateKey, 'L', CHAR(ascii('A')+(Abs(Checksum(NewId()))%25)))
      END
      
      SELECT @automateKey
      

      【讨论】:

      • 非常感谢您的支持,但是我怎样才能将这个作为输入值添加到插入脚本中,并且我只需要 5 个字符的随机生成密钥 ..
      • 和以前一样吗?在生成密钥和使用密钥之间只有两个额外的循环。
      猜你喜欢
      • 1970-01-01
      • 2016-08-15
      • 2018-09-10
      • 2015-09-27
      • 1970-01-01
      • 2012-11-15
      • 2014-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多