【问题标题】:mysql find smallest + unique id availablemysql找到可用的最小+唯一ID
【发布时间】:2011-06-28 08:43:54
【问题描述】:

我有一个列 ID 和大约 1000 个项目,其中一些被删除,如 id=90, id=127, id=326

如何进行查询以查找那些可用的 id,以便我可以将其重用于另一个项目?

它就像 min(ID) 但我只想找到不在我的数据库中的 id,所以如果我删除带有 ID = 90 的项目,下次我点击添加项目时,我会将其插入为 @987654324 @

【问题讨论】:

    标签: php mysql unique min


    【解决方案1】:

    您可以使用此查询获得最小可用 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
    • @ThiefMaster,因为我们必须得到 NEXT 可用的 ID。 MIN 将给出最低的可用 ID,+1 将给出下一个。
    • 如果您的 id 从(例如)58 开始并且您想要知道 id 1 - 58 是免费的,则不起作用。所以它应该找到 57 作为最低可用数字。
    • 如果 ID 列可以为空,这可能会很慢。在这种情况下有什么帮助是将 t1.ID IS NOT NULL 添加到 WHERE 语句。
    • @shamittomar,如果id=1 没有被使用,您的查询将不会得到它。但有效!
    【解决方案2】:

    不要重复使用 ID。您通常有足够多的可用 ID,因此您不必关心碎片。

    例如,如果您重复使用 ID,来自搜索引擎的链接可能会指向与搜索索引中的任何内容完全无关的内容 - 在这种情况下显示“未找到”错误要好得多。

    【讨论】:

    • 谢谢,但事实并非如此,我需要知道如何获得那个 min+unique+unused id
    【解决方案3】:

    尝试重用 ID 违反代理键的概念

    代理键很好,因为它标识了记录本身,而不是现实生活中的某个对象。如果记录没有了,ID也没有了。

    经验丰富的数据库开发人员不怕数字用完,因为他们知道需要多少个世纪才能耗尽长整数。

    顺便说一句,您可能会在多线程环境中遇到锁定或违反唯一性问题,同时尝试在 ID 序列中查找间隙的事务。 DB 服务器提供的自动增量 id 生成器通常在事务范围之外工作,因此可以生成良好的代理键。

    延伸阅读:Surrogate keys

    【讨论】:

    • 每条记录都有自己的 id、自动增量和一切。我创建的这个 uniqueId 只是因为我的客户想要独一无二,但又不超过他添加的产品总数(它的另一个字段)。 .你们做了很多假设,但感谢您的投入,也许符合您所说的其他人可以从中受益......
    • 那么我建议不要删除记录,而是在某些字段中将它们标记为已删除。当您需要用新数据填充记录时,您会找到已删除 = true 的记录最小“id”并更新它。使用适当的事务隔离设置,数据库服务器将负责防止“脏读”,因此另一个线程不想更新相同的记录,认为它仍然被“删除”
    • 这是一个很好的补充答案,并为整个 SO 添加了权重和有用的信息。当我阅读这个问题时,我首先想到的是你为什么要这样做?这个问题没有具体说明原因——即使上面已经澄清了,它仍然没有什么意义。 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 来指定产品总数,则有问题
    • 这实际上不是问题的答案。答案应该假设提问者有正当理由去做他们所问的事情。这个答案正好相反。
    • 数百年的实践表明,重复使用 ID 没有正当理由
    【解决方案4】:

    查询是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
    

    【讨论】:

      【解决方案5】:

      请注意,如果最低 ID 是免费的,则 shamittomar 和 Haim Evgi 的答案将不起作用。要允许重新填充最低 ID,请预先检查它是否可用:

      SELECT TRUE FROM tablename WHERE ID = 1;

      如果返回任何内容,则 ID 1 不是免费的,您应该使用他们的答案。但是如果 1 的 ID 是免费的,就使用它。

      【讨论】:

        【解决方案6】:

        在我个人看来。与其从自动增量中删除行,不如将布尔列用于“已删除”或“已删除”,并在设置删除标志时为带有空白的行提供额外的安全性。

        UPDATE table SET data=" ", removed = TRUE WHERE id = ##
        

        (## 是实际的 id btw) 然后就可以了

        SELECT * FROM table WHERE removed = TRUE ORDER BY id ASC
        

        这将使您的数据库性能更好,并在服务器上节省您的资金。更不用说确保不会发生令人讨厌的错误。

        【讨论】:

          【解决方案7】:

          鉴于您的数据库足够小,正确的答案是根本不重用您的 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,但不能保证它始终是最小的。

          【讨论】:

            猜你喜欢
            • 2013-11-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-27
            相关资源
            最近更新 更多