【问题标题】:Generate unique random integer in database column在数据库列中生成唯一的随机整数
【发布时间】:2011-03-18 03:25:03
【问题描述】:

我的应用程序创建的优惠券每张都需要一个唯一的条形码编号。此数字必须是正整数,并且必须介于 6 到 12 位之间。这个数字代表一个唯一的优惠券,所以这个数字必须是唯一的。我不能简单地将条形码编号加 1,因为这样会让黑客很容易猜到其他优惠券条形码。

如果我有一张优惠券db表,如何生成这个随机条码号并保证唯一性?

【问题讨论】:

  • 回答问题的第二部分,似乎只能通过对优惠券表的数字进行测试才能保证唯一性。
  • 唯一性必须通过唯一索引来保证,插入例程必须考虑到可能的唯一性违规重新生成优惠券编号并重试。使用@Richard 提出的解决方案,碰撞概率将非常低,因为 UID 设计得非常好。

标签: sql sql-server database tsql math


【解决方案1】:

这将为您提供最多 12 位的随机数,并且很少发生冲突。

select -convert(bigint, convert(varbinary(max), newid())) % 1000000000000

您需要测试并忽略冲突,并丢弃最终少于 6 位的数字。


编辑

要首先使用最低长度,您将无法使用真正的随机数生成器。这是因为一旦达到 6 位范围的 95%,冲突就会非常高,以至于程序会花费所有时间尝试和重试以获取尚未使用的唯一编号。一旦你只剩下一个数字,程序可以永远等待并且永远不会“生成”那个数字。因此,要实现“首先实现最低长度”,您实际上必须将所有数字生成到一个表中,然后随机生成行号 (order by len(num), newid()),然后按顺序将它们绘制出来。

要将 0 填充到 12 位,请使用

select right('000000000000'
      +right(-convert(bigint, convert(varbinary(max), newid())),12),12)

【讨论】:

  • +1 是一个很好的解决方案,对如何生成 newid 有所了解,我认为 OP 不太可能有一个少于 6 位的数字。您可以通过将 100000 添加到任何值来防止这种情况,这反过来又很少会生成 13 位数字,这不太可能经常发生。在 1e11 而不是 1e12 上应用模块操作也可以防止这种情况,减少可能的范围但增加碰撞机会。
  • 如果我想要一个允许 0 填充数字前面的代码,例如 000243530981,该怎么办?
  • 另外,可以说 6-12 位的长度是可以接受的,但我更愿意先用尽可能的最低长度。您将如何处理,您会在插入代码中使用逻辑,还是更改上面的 SQL 语句?
  • 另一种最低优先的方法是说最低优先并使用上面的变体,您首先尝试使用 6 位随机数,如果您点击现有数字,则增加长度并尝试再次。 (您也可以在增加长度之前对相同的长度进行多次重试。
【解决方案2】:

可能听起来很蹩脚,但根据您需要的值的数量,您可以对列设置唯一约束,并使用随机数(6-12 位)更新每一行并循环直到它没有失败。 12 位是很多值,所以你可能不会遇到很多冲突。

【讨论】:

    猜你喜欢
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 2016-07-03
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    相关资源
    最近更新 更多