我有一个列 ID 和 1000 个项目,其中一些被删除了id=90, id=127, id=326
我如何进行查询以查找那些可用的 ID,以便我可以将其重用于另一个项目?
它就像一个min(ID)
,但我只想找到不在我的数据库中的 id,所以如果我删除一个带有 的项目ID = 90
,下次我点击添加项目时,我会将其插入为id = 90
您可以使用此查询获取最小可用 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
您想要的结果。
不要重复使用 ID。您通常有足够多的可用 ID,因此您不必关心碎片。
例如,如果您重复使用 ID,来自搜索引擎的链接可能指向与搜索索引中的任何内容完全无关的内容 - 在这种情况下显示“未找到”错误要好得多。
尝试重用 ID 违反代理键的概念
代理键很好,因为它标识了记录本身,而不是现实生活中的某个对象。如果记录消失了,ID也消失了。
有经验的数据库开发人员不怕数字用完,因为他们知道需要多少个世纪才能耗尽长整数。
顺便说一句,您可能会在多线程环境中遇到锁定或违反唯一性问题,同时事务试图在 ID 序列中找到间隙。数据库服务器提供的自动增量 id 生成器通常在事务范围之外工作,因此可以生成良好的代理键。
进一步阅读:代理键
查询是这样的:
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;
如果这返回任何内容,则 1 的 ID 不是免费的,您应该使用他们的答案。但是如果 1 的 ID 是免费的,就使用它。
在我个人看来。与其从自动增量中删除行,不如将布尔列用于“已删除”或“已删除”,并在设置删除标志时为带有空白的行提供额外的安全性。
UPDATE table SET data=" ", removed = TRUE WHERE id = ##
(## 是实际的 id 顺便说一句)然后你可以
SELECT * FROM table WHERE removed = TRUE ORDER BY id ASC
这将使您的数据库性能更好,并为您节省服务器上的钱。更不用说确保不会发生令人讨厌的错误。
鉴于您的数据库足够小,正确的答案是根本不重用您的 id并确保它是一个自动递增的主键。该表包含一千条记录,因此您可以免费执行此操作。
但是,如果您有一个包含几百万条记录/更长 id 的表,您会发现接受的答案不会在合理的时间内完成。
接受的答案将正确地为您提供这些值中的最小值,但是,您付出的代价是不使用自动增量列,或者如果您有一个,则不使用自动增量列作为预期的实际 ID (像我一样,否则我不会在这里)。我受遗留应用程序的支配,如果 ID 不是正在使用的实际主键,并且是无缘无故地使用 logorithm 随机生成的,所以我需要一种方法来替换它,因为增加列范围是现在是一个极其昂贵的改变。
在这里,它在报告这些连接的最小值之前计算出整个 t1 和 t2 之间的整个连接。本质上,您只关心NULL
找到的第一个 t1,而不管它实际上是否是最小的。
因此,您将MIN
取出并添加 a LIMIT
of 1 。
编辑:由于它不是主键,您还需要检查不为空,因为主键字段不能为空
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,只是不能保证它始终是最小的。