【问题标题】:randomly generating unique number between 1-999 for primary key in table为表中的主键随机生成 1-999 之间的唯一编号
【发布时间】:2013-05-03 01:43:23
【问题描述】:

我有一个问题,我不知道如何优雅地解决。

背景信息

我有一个小部件表。每个小部件都从一系列数字中分配了一个 ID,比如说 1-999。 1-999 的值在我的数据库中保存为名为“config”的表中的“lower_range”和“upper_range”。 当用户请求使用我的网络应用创建新小部件时,我需要能够执行以下操作:

  • 使用 lua 的 math.random 函数或 sqlite 中的随机数生成器生成 1 到 999 之间的随机数(到目前为止,在我的测试中,lua 的 math.random 总是返回相同的值...但这是一个不同的问题)
  • 执行一个选择语句以查看是否已经有一个分配了此编号的小部件...
  • 如果没有,请创建新的小部件。
  • 否则重复此过程,直到您获得当前未使用的号码。

问题

我看到上述逻辑的问题有两个:

  1. 该算法可能需要很长时间,因为我必须不断搜索,直到找到唯一值。
  2. 如何防止同时请求生成相同值的新小部件编号?

任何建议将不胜感激。 谢谢

【问题讨论】:

  • 为什么你的ID不能是一个系列?为什么它们必须是随机的?
  • 这是最终用户的要求。如果按顺序排列会容易很多。然后我可以跟踪配置表中的下一个可用数字。但他们想要随机。
  • 那么你可以使用 GUID 吗?如果你继续在同一台机器上生成它们,我认为你不会在宇宙热寂之前发生关键碰撞。它们不是数字,但嘿,问题解决了。

标签: sql sqlite lua


【解决方案1】:

提前生成随机数并将它们存储在表格中;确保数字是唯一的。然后,当您需要获取下一个数字时,只需检查已经分配了多少并从您的表格中获取下一个数字。所以,而不是

  • 生成一个介于 1-999 之间的数字
  • 检查是否已分配
  • 生成一个新号码,等等。

这样做:

  • 以某种随机顺序生成 999 个元素的数组,其值为 1-999
  • 您的GetNextId 函数变为return ids[currentMaxId+1]

要管理同时请求,您需要一些资源来生成正确的序列。最简单的可能是使用小部件表中的键作为ids 数组中的索引。因此,首先在widgets 表中添加一条记录,获取其键,然后使用ids[key] 生成小部件ID。

【讨论】:

    【解决方案2】:

    创建一个表来存储键和“使用”属性。

    CREATE TABLE KEYS
      ("id" INTEGER, "used" INTEGER)
    ;
    

    然后用下面的方法找到一个新的key

    select id
    from KEYS
    where used = 0
    order by RANDOM()
    limit 1
    

    【讨论】:

      【解决方案3】:

      不要生成随机数,只需从随机顺序的列表中选择数字即可。

      例如,制作一个 1 - 999 的数字列表。使用 Fisher-Yates 或等效项(即使您不使用 C#,也请参阅 Randomize a List in C#)随机播放该列表。

      现在您可以在列表中跟踪最近使用的索引。 (洗牌应该只发生一次,然后你存储并重复使用结果)。

      粗略的伪代码:

      If config-file does not contain list of indices
          create a list with numbers 1 - 999
          Use Fisher-Yates to shuffle that list
          // list now looks like 0, 97, 251, 3, ...
          Write the list to the config file
          Set 'last index used' to 0 and write to config file
      end if
      

      要使用它,

      NextPK = myList[last-index-used]
      last-index-used = last-index-used + 1
      write last-index-used to config file
      

      【讨论】:

      • 谢谢丹。我可能误读了,但你的答案和保罗库琴科斯差不多吗?只是想了解我的选择是什么......
      • 是的,它们几乎相同。我不确定为什么我不认为将索引列表存储在数据库中。如果它是一个选项,它可能会更容易实现。
      • 我很欣赏你的回答和提到 Fisher-yates shuffle。学到了新东西!再次感谢!
      【解决方案4】:

      同时获取和标记一个 ID(扩展 Declan_K 的答案):

      替换为 random_sequence 值 ((select id from random_sequence where used=0 order by random()), 1);

      从 random_sequence 中选择 id 其中 rowid = last_insert_rowid(); 6

      当您用完“未使用”的序列表条目时,选择将返回“空白”

      我使用 replace into 因为更新没有我可以看到的 last_insert_rowid() 等效项。

      【讨论】:

        【解决方案5】:

        你可以让sql创建一个主键,每次你向数据库添加一个ros时,主键就会增加一个。

        【讨论】:

        • OP 两次声明他的密钥必须是随机的。
        • 小部件 id 不仅仅是一个按顺序递增的 pk。它必须是一个预先定义的范围之间的数字,并且不能顺序分配。
        猜你喜欢
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-06
        • 2014-12-09
        • 1970-01-01
        相关资源
        最近更新 更多