【问题标题】:Unique 6 digit number but not sequential for Customer ID (SQL)客户 ID (SQL) 的唯一 6 位数字但不连续
【发布时间】:2012-08-24 00:55:45
【问题描述】:

我们的 Customer 表有一个用于 ID 的 int Identity 列。这将发给客户,所以当他们打电话时,他们只需提供他们的 ID。

现在很明显,我们的竞争对手可以轻松地在我们的网站上注册两次,比如相隔一个月,然后就可以知道有多少人注册了。

因此,有没有一种很好的简单方法来创建我们可以提供给客户的“客户 ID”(在 SQL 或 c# 中): (a) 6 位数长 (b) 是独一无二的 (c) 不是顺序的(

提前致谢

【问题讨论】:

  • 必须是数字吗?还是可以是字母数字?
  • 这很酷,你有几个答案可以看看哪个应该有帮助。

标签: sql sql-server c#-4.0 random numbers


【解决方案1】:

如果您选择的增量不是 1000000 的因数,那么您可以取该数字的最后 6 位数字来提供 ID;即(IDENTITY (1,7)) % 1000000

但是您的竞争对手仍然可以通过几次连续注册找到增量,因此这并不能完全解决问题。

因此,您似乎想要一个完全随机的数字 - 为此,您必须在生成它时检查它是否已经存在,或者预先生成一个数字列表,对它们进行随机排序,然后选择创建新客户时的下一个。

如果您可以找到或创建适当的算法来创建足够短的输出,则需要考虑的另一个选项是某种形式的加密。

如果您采用较大的非因子增量路线,您可以随后重新排列数字的顺序以创建一个更随机的数字 - 例如;

declare @inc int , @loop int
declare @t table (i int, cn int, code varchar(4))

select @inc = 5173, @loop = 1
while @loop<=10000
begin
    insert @t (i, cn)
    select @loop, (@inc*@loop)%10000
    select @loop = @loop + 1
end

update @t 
set code = substring(convert(varchar(4),cn),2,1)
    + substring(convert(varchar(4),cn),4,1)
    + substring(convert(varchar(4),cn),3,1)
    + substring(convert(varchar(4),cn),1,1)

select code, count(*) from @t group by code having count(*)>1
select top 20 * from @t order by i 

根据您选择的数字,一些连续的项目之间会有相同的差异,但这个数字会有所不同。所以它不是加密安全的,但可能足以挫败除了最坚定的竞争对手之外的所有竞争对手。

您可以将上述内容转换为一个函数以运行标准 IDENTITY(1,1) id 字段

【讨论】:

    【解决方案2】:

    也许这很疯狂,但这是我预先生成客户编号的方法。

    这将生成许多您想要的唯一键非常快

    您显然可以将这些保存到真实表格中。

    这是下面的 SQLFiddlehttp://www.sqlfiddle.com/#!3/d41d8/3884

    DECLARE @tbl TABLE
    (
        ID INT IDENTITY(1,1),
        CustNo INT UNIQUE
    )
    
    DECLARE @Upper INT
    DECLARE @Lower INT
    DECLARE @NumberRequired INT
    
    SET @Lower = 100000 ---- The lowest random number allowed
    SET @Upper = 999999 ---- The highest random number allowed
    SET @NumberRequired = 1000 -- How many IDs do we want?
    
    WHILE (SELECT COUNT(*) FROM @tbl) < @NumberRequired
    BEGIN
        BEGIN TRY
            INSERT INTO @tbl SELECT (ROUND(((@Upper - @Lower -1) * RAND() + @Lower), 0))
        END TRY
        BEGIN CATCH
            -- If it goes wrong go round the loop again
        END CATCH
    END
    
    SELECT  *
    FROM    @tbl
    

    编辑:实际上这可能更快。它在我的开发机器上大约 30 秒内生成所有 900000 个可能的密钥,这对于一次性工作来说是可以的。

    DECLARE @tbl TABLE
    (
        ID INT
    )
    
    DECLARE @Upper INT
    DECLARE @Lower INT
    DECLARE @i INT;
    
    SET @Lower = 100000 ---- The lowest random number allowed
    SET @Upper = 999999 ---- The highest random number allowed
    
    SET @i = @Lower
    
    WHILE @i <= @Upper
    BEGIN
        INSERT INTO @tbl SELECT @i
        SET @i = @i + 1
    END
    
    SELECT  ID
    FROM    @tbl ORDER BY NEWID()
    

    【讨论】:

    • 很好,但随着剩余键数的减少,它会变得更慢。
    • 是的,这是真的!但肯定任何方法都会遇到这个问题,不是吗?在我工作的可怜的开发机器上,1000 个键(亚秒)非常快,10,000 个键不到 10 秒。如果 Dominic 担心人们看到顺序键,那么这可能足以预先生成?!尤其是因为这是一次性练习。
    【解决方案3】:

    您可以计算从标识列生成的列,并创建期望的唯一值。

    例如计算列如下:

    100000 + Identity_Column * 7 + 3

    【讨论】:

    • 标识列是唯一的,并且上面的计算列肯定是唯一的。
    【解决方案4】:

    如果 juts 使用用户注册时间戳怎么办。它不包含用户的计数信息和唯一性(例如,如果您不每秒注册用户)。例如,如果您在此查询中使用 10000,您可以每分钟注册用户并获得唯一的 9 个符号数字:

    select cast(cast(current_timestamp as float)*10000 as int)
    

    【讨论】:

    • 我认为 6 位数字不能提供足够大的数字范围,因此这适用于快速注册。
    【解决方案5】:

    您可以制作一个包含 2 列的表格,其中一列的值是 100.000 到 999.999,另一列带有标记是否已给出数字。让新客户随机分配此表中未分配的号码并将其标记为已分配。

    【讨论】:

    • 实际上是一个包含一列的表格并删除使用的数字也可以。您可以预先随机化表格。
    猜你喜欢
    • 2012-03-02
    • 1970-01-01
    • 2012-04-05
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2019-12-04
    相关资源
    最近更新 更多