在表中生成介于1-999之间的唯一主键数字。

我有一个问题,我不确定如何优雅地解决它。

背景信息

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

  • 使用lua的math.random函数或可能是sqlite中的随机数生成器生成1到999之间的随机数(到目前为止,在我的测试中,lua的math.random总是返回相同的值...但这是一个不同的问题)
  • 做一个select语句,查看是否已经存在分配了这个数字的小部件...
  • 如果没有,创建新的小部件。
  • 否则重复这个过程,直到找到一个尚未使用的数字。

问题

我看到上面的逻辑存在两个问题:

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

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

点赞
用户2363469
用户2363469

你可以使用 SQL 创建一个主键,每次向数据库中添加一行,该主键都会自动增加一。

2013-05-08 18:04:15
用户2324286
用户2324286

创建一张表来存储键和 'used' 属性。

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

然后使用以下语句来查找一个新的键

select id
from KEYS
where used = 0
order by RANDOM()
limit 1
2013-05-08 18:15:16
用户427192
用户427192

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

例如,制作数字1-999的列表。使用Fisher-Yates 或等效方法(参见 C#中的随机列表,即使您不使用C#)洗牌该列表。

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

粗略的伪代码:

如果配置文件不包含索引列表
    创建包含数字1-999的列表
    使用Fisher-Yates洗牌该列表
    //列表现在看起来像0,97,251,3,...
    将列表写入配置文件
    设置“上次使用的索引”为0并写入配置文件
结束如果

使用此方法:

NextPK = myList[last-index-used]
last-index-used = last-index-used + 1
将“上次使用的索引”写入配置文件
2013-05-08 18:16:35
用户1442917
用户1442917

将下面翻译成中文并且保留原本的 markdown 格式

Generate your random numbers ahead of time and store them in a table; make sure the numbers are unique. Then when you need to get the next number, just check how many have already been assigned and get the next number from your table. So, instead of

- Generate a number between 1-999
- Check if it's already assigned
- Generate a new number, and so on.

do this:

- Generate array of 999 elements that have values 1-999 in some random order
- Your `GetNextId` function becomes `return ids[currentMaxId+1]`

To manage simultaneous requests, you need to have some resource that generates a proper sequence. The easiest is probably to use a key in your widget table as the index in the `ids` array. So, add a record to the `widgets` table first, get its key and then generate widget ID using `ids[key]`.

提前生成您的随机数并将其存储在一张表中,确保数字是唯一的。然后,在您需要获取下一个数字时,只需检查已分配的数字数量,并从您的表中获取下一个数字。因此,替代以下步骤:

  • 生成一个介于1-999之间的数字
  • 检查它是否已被分配
  • 生成一个新的数字,以此类推

执行以下步骤:

  • 生成拥有999个元素的数组,这些元素在某种随机顺序下具有值1-999
  • 您的GetNextId函数变成了return ids[currentMaxId+1]

为了管理同时请求,您需要拥有一些资源来生成适当的序列。最简单的方法可能是将您的widget表中的一个键用作ids数组中的索引。因此,首先向widgets表添加一条记录,获取其键,然后使用ids[key]生成widget ID。

2013-05-08 18:20:05
用户551343
用户551343

为了同时获取并标记一个 ID(在 Declan_K 的答案上进行扩展):

replace into random_sequence values ((select id from random_sequence where used=0 order by random()), 1);

select id from random_sequence where rowid = last_insert_rowid();

当你用完了“未使用”的序列表条目时,select 将返回“空白”

我使用 replace into,因为我看不到 update 有一个 last_insert_rowid() 的等效函数。

2013-05-08 21:07:44