【问题标题】:AFTER INSERT Trigger for SQL Server to create unique random 8 character code?SQL Server 的 AFTER INSERT 触发器以创建唯一的随机 8 字符代码?
【发布时间】:2009-04-06 07:03:50
【问题描述】:

我从 Raymond Lewallen 为密码生成器编写的一些存储过程代码开始。我想创建一个触发器,每次插入新行(客户)时都会创建一个唯一的 8 个字符 ID。到目前为止我所拥有的:

    CREATE procedure dbo.AllAccessIDgenerator (
     
      @showID varchar(40)
      @accessID varchar(100) OUT
    )
    

    As
    

    Begin
       declare @codeLength int
       declare @characters varchar(100)
    
       declare @count int
       set @characters = ''
       set @codeLength = 8

    -- set A - Z (uppercase)
     
     set @count = 65
     
      while @count <=90
     
       begin
         
         set @characters = @characters + Cast(CHAR(@count) as char(1))
         
         set @count = @count + 1
     
       end
     end

    -- set 0-9
    set @count = 48  
     while @count <=57  
     begin  
      set @characters = @characters + Cast(CHAR(@count) as char(1))  
      set @count = @count + 1  
     end  
     end  
 
    set @count = 0  
    set @accessID = ''  

     while @count <= @codeLength
     
      begin
         
       set @accessID = @accessID + SUBSTRING(@characters,CAST(ABS(CHECKSUM(NEWID()))*RAND(@count) as int)%LEN(@characters)+1,1)
         
       set @count = @count + 1
     
      end
    
     end

    end
    
    GO

我如何 (a) 获取一个存储过程并使其成为 SQL Server 2008 中的触发器,以及 (b) 如果我需要测试唯一性,我该怎么做?

【问题讨论】:

  • 那么你真的需要一个唯一的、非顺序的标识符吗?

标签: sql sql-server triggers uniqueidentifier random


【解决方案1】:

根据您的要求,我会这样做

  1. 创建一个包含两列的密码表。密码和 IsUsed。
  2. 在密码列上创建唯一索引。
  3. 在此表中填写您需要的任意数量的项目。
  4. 在您的触发器中,获取第一个密码,其中 IsUsed = 0。
  5. 设置 IsUsed = 1。

显然,您应该对密码使用某种形式的加密或散列。 密码永远不应存储为纯文本。我建议你搜索一下密码保护方法。

编辑

  1. 我并不完全清楚您是否需要密码或只为您的客户提供唯一的 8 个字符 ID。如果您只需要唯一 ID,那么您当然应该忽略此解决方案的加密部分。
  2. 为了填充表,我会在一个临时表中生成 x 个 ID,并执行与该表不同的选择作为插入实际表的源。

【讨论】:

  • 该代码实际上不是用于主键或辅助键或密码的;应该解释一下。它作为产品的一部分被打印出来,每个客户都需要一个不同的产品。 A-Z + 0-9 中有 8 个字符,我猜有很多组合,基本上可以保证唯一性。
  • 我认为拥有客户 ID AAAAAAAAA 或 00000000 是不好的营销,这就是您使用 AllAccessIDGenerator 的原因。我的建议仍然有效。不过要小心生成包含错误语言的客户 ID。我不想要客户 ID“IAMIDIOT”。
【解决方案2】:

老实说,我建议在您的域层中执行此操作,而不是在数据库中。数据库中的域逻辑会使以后难以维护和部署。当然,您可以在数据库中设置约束等以防止无效的外键值等,但是唯一值的生成是一个业务规则,属于您系统的业务规则层(即域层/逻辑/对象)。

另外,以这种方式产生独特价值的原因是什么?身份列会更适合您的目的吗?您始终可以将标识列用作 8 字符填充值的一部分,这将确保唯一性。

【讨论】:

  • +1 身份列。如果唯一的要求是唯一性,那就可以了。
【解决方案3】:

我将添加一些关于为此使用触发器的建议。是的,可以使用触发器来执行此操作。 (与 Neil 不同,我认为这应该是一个数据库问题,因为所有记录都需要唯一性,而不仅仅是通过特定接口添加的记录。从数据完整性的角度来看,将这样的逻辑放在应用程序中是一个坏主意。Ata minumum make确保该文件具有唯一索引。)

但是,大多数缺乏经验的触发器开发人员认为触发器单独作用于每一行,并且不会将触发器设计为处理多行插入。你可能认为没有多行插入;大多数时候你会错的。在某些时候,您将要导入一组客户,触发器必须能够处理此问题。

现在使用您的 proc,它一次只能处理一条记录。这是一个巨大的缺陷,因为在触发器中处理它的唯一方法是使用游标或 while 循环。这非常慢,如果您需要一次添加大量客户,最终可能会锁定您的客户表数小时。

我认为 Lieven 创建一个可能的唯一密码池的想法是一个不错的想法,因为您可以在触发器中使用基于集合的逻辑来填充它。但要使其正常工作,您将需要三列(例如,用于获取接下来的 300 行的标识字段)。如果未使用的密码低于某个百分比,您还应该安排一个夜间作业以生成更多潜在密码。这样一来,事情就永远不会因为您意外用尽潜在密码而失败。

【讨论】:

  • 谢谢,我根本没有想到多行插入;我认为预先生成的 8 个字符串表的想法开始变得有意义。不过,我可能需要成千上万个这样的字符串。
  • 你能解释一下你的意思吗?关于多插入抓取行需要什么?
猜你喜欢
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 2010-09-29
相关资源
最近更新 更多