【发布时间】:2011-06-28 08:43:54
【问题描述】:
我有一个列 ID 和大约 1000 个项目,其中一些被删除,如 id=90, id=127, id=326
如何进行查询以查找那些可用的 id,以便我可以将其重用于另一个项目?
它就像 min(ID) 但我只想找到不在我的数据库中的 id,所以如果我删除带有 ID = 90 的项目,下次我点击添加项目时,我会将其插入为 @987654324 @
【问题讨论】:
我有一个列 ID 和大约 1000 个项目,其中一些被删除,如 id=90, id=127, id=326
如何进行查询以查找那些可用的 id,以便我可以将其重用于另一个项目?
它就像 min(ID) 但我只想找到不在我的数据库中的 id,所以如果我删除带有 ID = 90 的项目,下次我点击添加项目时,我会将其插入为 @987654324 @
【问题讨论】:
您可以使用此查询获得最小可用 ID:
SELECT MIN(t1.ID + 1) AS nextID
FROM tablename t1
LEFT JOIN tablename t2
ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL
它的作用是将表与自身连接并检查min+1 ID 是否为null。如果它为空,则该 ID 可用。假设您有 ID 所在的表:
1
2
5
6
然后,此查询将为您提供 3 的结果,这就是您想要的。
【讨论】:
MIN(idColumn)-1?
id=1 没有被使用,您的查询将不会得到它。但有效!
不要重复使用 ID。您通常有足够多的可用 ID,因此您不必关心碎片。
例如,如果您重复使用 ID,来自搜索引擎的链接可能会指向与搜索索引中的任何内容完全无关的内容 - 在这种情况下显示“未找到”错误要好得多。
【讨论】:
尝试重用 ID 违反代理键的概念
代理键很好,因为它标识了记录本身,而不是现实生活中的某个对象。如果记录没有了,ID也没有了。
经验丰富的数据库开发人员不怕数字用完,因为他们知道需要多少个世纪才能耗尽长整数。
顺便说一句,您可能会在多线程环境中遇到锁定或违反唯一性问题,同时尝试在 ID 序列中查找间隙的事务。 DB 服务器提供的自动增量 id 生成器通常在事务范围之外工作,因此可以生成良好的代理键。
延伸阅读:Surrogate keys
【讨论】:
this uniqueId im creating is just because my client wants to be unique but also that dont exceed the total of products he added (its another field) - 如果您使用 ids 来指定产品总数,则有问题
查询是like:
SELECT MIN(tableFoo.uniqueid + 1) AS nextID
FROM tableFoo
LEFT JOIN tableFoo tf1
ON tableFoo.uniqueid + 1 = tf1.uniqueid
WHERE tf1.uniqueid IS NULL
【讨论】:
请注意,如果最低 ID 是免费的,则 shamittomar 和 Haim Evgi 的答案将不起作用。要允许重新填充最低 ID,请预先检查它是否可用:
SELECT TRUE FROM tablename WHERE ID = 1;
如果返回任何内容,则 ID 1 不是免费的,您应该使用他们的答案。但是如果 1 的 ID 是免费的,就使用它。
【讨论】:
在我个人看来。与其从自动增量中删除行,不如将布尔列用于“已删除”或“已删除”,并在设置删除标志时为带有空白的行提供额外的安全性。
UPDATE table SET data=" ", removed = TRUE WHERE id = ##
(## 是实际的 id btw) 然后就可以了
SELECT * FROM table WHERE removed = TRUE ORDER BY id ASC
这将使您的数据库性能更好,并在服务器上节省您的资金。更不用说确保不会发生令人讨厌的错误。
【讨论】:
鉴于您的数据库足够小,正确的答案是根本不重用您的 ID,只需确保它是一个自动递增的主键。该表包含一千条记录,因此您可以免费执行此操作。
但是,如果您有一个几百万条记录/更长 id 的表,您会发现接受的答案不会在合理的时间内完成。
接受的答案将正确地为您提供这些值中的最小值,但是,您正在付出不使用自动增量列的代价,或者如果您有,则不使用自动增量列将列递增为预期的实际 ID(像我一样,否则我不会在这里)。我受遗留应用程序的支配,如果 ID 不是正在使用的实际主键,并且没有充分理由使用 logorithm 随机生成,所以我需要一种方法来替换它,因为增加列范围是现在是一个极其昂贵的改变。
在这里,它正在弄清楚整个
在报告这些连接的最小值之前,在整个 t1 和 t2 之间连接。本质上,您只关心找到的第一个NULL t1,而不管它实际上是否是最小的。
因此,您将取出MIN 并添加一个LIMIT 1。
edit : 由于它不是主键,因此您还需要检查不为空,因为主键字段不能为空
SELECT t1.ID + 1 AS nextID
FROM tablename t1
LEFT JOIN tablename t2
ON t1.ID + 1 = t2.ID
WHERE t2.ID IS NULL
AND t1.ID IS NOT NULL
LIMIT 1
这将始终为您提供一个您可以使用的 id,但不能保证它始终是最小的。
【讨论】: