Sql 如何获取表中第一个未使用的ID?

Sql 如何获取表中第一个未使用的ID?,sql,mysql,Sql,Mysql,我必须编写一个查询,其中我需要为数据库中未使用/未生成/不存在的特定记录分配一个ID(唯一键) 简而言之,我需要为特定记录生成一个id,并在打印屏幕上显示它 例如: ID Name 1 abc 2 def 5 ghi 身份证名称 1 abc 2 def 5 ghi 所以,问题是它应该返回ID=3,作为尚未生成的下一个立即数,在生成ID之后,我将把这些数据存储回数据库表 这不是一个硬件:我正在做一个项目,我有一个需要编写这个查询的需求,所以我需要一些帮助来实现这一点 因此,请指导我

我必须编写一个查询,其中我需要为数据库中未使用/未生成/不存在的特定记录分配一个
ID
(唯一键)

简而言之,我需要为特定记录生成一个
id
,并在打印屏幕上显示它

例如:

ID Name 1 abc 2 def 5 ghi 身份证名称 1 abc 2 def 5 ghi 所以,问题是它应该返回
ID=3
,作为尚未生成的下一个立即数,在生成
ID
之后,我将把这些数据存储回数据库表

这不是一个硬件:我正在做一个项目,我有一个需要编写这个查询的需求,所以我需要一些帮助来实现这一点

因此,请指导我如何进行此查询,或者如何实现此查询

谢谢

我无法添加评论,所以我在这里写评论。。 我正在使用MySQL作为数据库

我的步骤如下:-

1) 从未使用的数据库表中检索id

2) 由于他们是用户数(基于网站的项目),所以我不希望发生并发,因此,如果为一个用户生成一个ID,那么它应该锁定数据库,直到同一个用户收到该ID并存储该ID的记录。。之后,其他用户可以检索不存在的ID。。(主要要求)


我怎样才能在MySQL中实现所有这些,我也认为Quassnoi的答案是值得的,但它在MySQL中不起作用。。所以请解释一下这个查询,因为它对我来说是新的。。这个查询在MySQL中可以使用吗?

我将您的表命名为未使用的

SELECT  id
FROM    (
        SELECT  1 AS id
        ) q1
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    unused
        WHERE   id = 1
        )
UNION ALL
SELECT  *
FROM    (
        SELECT  id + 1
        FROM    unused t
        WHERE   NOT EXISTS
                (
                SELECT  1
                FROM    unused ti
                WHERE   ti.id = t.id + 1
                )
        ORDER BY
                id
        LIMIT 1
        ) q2
ORDER BY
        id
LIMIT 1
此查询由两部分组成

第一部分:

SELECT  *
FROM    (
        SELECT  1 AS id
        ) q
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    unused
        WHERE   id = 1
        )
如果表中没有具有此id的条目,则选择
1

第二部分:

SELECT  *
FROM    (
        SELECT  id + 1
        FROM    unused t
        WHERE   NOT EXISTS
                (
                SELECT  1
                FROM    unused ti
                WHERE   ti.id = t.id + 1
                )
        ORDER BY
                id
        LIMIT 1
        ) q2
选择表中没有下一个
id
的第一个
id


结果查询选择这两个值中的最小值。

取决于您所说的“下一个id”是什么意思以及它是如何生成的

如果您使用数据库中的序列或标识来生成id,则在您所呈现的情况下,“下一个id”可能不是3或4,而是6。您无法知道是否有id为3或4的值随后被删除。序列和身份不一定试图弥补差距;一旦它们消失了,你就不能再使用它们


因此,正确的做法是在数据库中创建一个序列或标识列,当您执行插入操作时,该列会自动递增,然后选择生成的值。

是否允许使用实用程序表?如果是这样,我将创建如下表:

CREATE TABLE number_helper (
    n INT NOT NULL
   ,PRIMARY KEY(n)
);
用所有正32位整数填充它(假设需要生成的id是正32位整数)

然后您可以这样选择:

SELECT MIN(h.n) as nextID
FROM my_table t
LEFT JOIN number_helper h ON h.n = t.ID
WHERE t.ID IS NULL
我还没有实际测试过,但它应该可以工作。

/*
/*
This is a query script I wrote to illustrate my method, and it was created to solve a Real World problem where we have multiple machines at multiple stores creating transfer transactions in their own databases,
that are then synced to other databases on the store (this happens often, so getting the Nth free entry for the Nth machine should work) where the transferid is the PK and then those are synced daily to a MainFrame where the maximum size of the key (which is the TransactionID and StoreID) is limited.  
*/

--- table variable declarations
/* list of used transaction ids (this is just for testing, it will be the view or table you are reading the transaction ids from when implemented)*/

DECLARE @SampleTransferIDSourceTable TABLE(TransferID INT)     

/* Here we insert the used transaction numbers*/

DECLARE @WorkTable TABLE (WorkTableID INT IDENTITY (1,1), TransferID INT) 

/*this is the same table as above with an extra column to help us identify the blocks of unused row numbers (modifying a table variable is not a good idea)*/

DECLARE @WorkTable2 TABLE (WorkTableID INT , TransferID INT, diff int)  

--- Machine ID declared

DECLARE @MachineID INT

-- MachineID set

SET @MachineID = 5

-- put in some rows with different sized blocks of missing rows.
-- comment out the inserts after two to the bottom to see how it handles no gaps or make 
-- the @MachineID very large to do the same.
-- comment out early rows to test how it handles starting gaps.

INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 1 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 2 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 4 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 5 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 6 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 9 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 10 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 20 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 21 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 24 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 25 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 30 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 31 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 33 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 39 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 40 )
INSERT @SampleTransferIDSourceTable ( TransferID ) VALUES ( 50 )

-- copy the transaction ids into a table with an identiy item.
-- When implemented add where clause before the order by to limit to the local StoreID
-- Zero row added so that it will find gaps before the lowest used row.

INSERT @WorkTable (TransferID)

SELECT 0

INSERT @WorkTable (TransferID)

SELECT TransferID FROM @SampleTransferIDSourceTable ORDER BY TransferID   

-- copy that table to the new table with the diff column 

INSERT @WorkTable2

SELECT WorkTableID,TransferID,TransferID - WorkTableID 

  FROM @WorkTable              

--- gives us the (MachineID)th unused ID or the (MachineID)th id beyond the highest id used.

IF EXISTS (

SELECT Top 1

       GapStart.TransferID  + @MachineID - (GapStart.diff + 1)

  FROM @WorkTable2 GapStart

 INNER JOIN @WorkTable2 GapEnd

    ON GapStart.WorkTableID = GapEnd.WorkTableID - 1

   AND GapStart.diff < GapEnd.diff

   AND gapEnd.diff >= (@MachineID - 1)

 ORDER BY GapStart.TransferID

 )

SELECT Top 1

       GapStart.TransferID  + @MachineID - (GapStart.diff + 1)

  FROM @WorkTable2 GapStart

 INNER JOIN @WorkTable2 GapEnd

    ON GapStart.WorkTableID = GapEnd.WorkTableID - 1

   AND GapStart.diff < GapEnd.diff

   AND gapEnd.diff >= (@MachineID - 1)

 ORDER BY GapStart.TransferID

ELSE 

SELECT MAX(TransferID) + @MachineID FROM @SampleTransferIDSourceTable
这是我为说明我的方法而编写的一个查询脚本,它的创建是为了解决现实世界中的一个问题,即我们在多个商店中有多台机器在它们自己的数据库中创建传输事务, 然后同步到存储上的其他数据库(这种情况经常发生,因此获取第n台机器的第n个免费条目应该可以工作),其中transferid是PK,然后每天同步到主机,在主机上,密钥的最大大小(即TransactionID和StoreID)是有限的。 */ ---表变量声明 /*已使用事务ID的列表(这仅用于测试,它将是您在实现时从中读取事务ID的视图或表)*/ 声明@SampleTransferIDSourceTable表(TransferID INT) /*在此,我们插入使用过的交易编号*/ 声明@WorkTable表(WorkTableID INT-IDENTITY(1,1),TransferID INT) /*这是与上面相同的表,有一个额外的列来帮助我们识别未使用的行号块(修改表变量不是一个好主意)*/ 声明@WorkTable2表(WorkTableID INT、TransferID INT、diff INT) ---已声明的计算机ID 声明@MachineID INT --机械设备 设置@MachineID=5 --放入一些缺少行的不同大小块的行。 --注释掉底部两个之后的插入,看看它是如何处理无间隙或闭合的 --@MachineID非常大,可以执行同样的操作。 --注释掉前面的行,以测试它如何处理起始间隙。 插入@SampleTransferIDSourceTable(TransferID)值(1) 插入@SampleTransferIDSourceTable(TransferID)值(2) 插入@SampleTransferIDSourceTable(TransferID)值(4) 插入@SampleTransferIDSourceTable(TransferID)值(5) 插入@SampleTransferIDSourceTable(TransferID)值(6) 插入@SampleTransferIDSourceTable(TransferID)值(9) 插入@SampleTransferIDSourceTable(TransferID)值(10) 插入@SampleTransferIDSourceTable(TransferID)值(20) 插入@SampleTransferIDSourceTable(TransferID)值(21) 插入@SampleTransferIDSourceTable(TransferID)值(24) 插入@SampleTransferIDSourceTable(TransferID)值(25) 插入@SampleTransferIDSourceTable(TransferID)值(30) 插入@SampleTransferIDSourceTable(TransferID)值(31) 插入@SampleTransferIDSourceTable(TransferID)值(33) 插入@SampleTransferIDSourceTable(TransferID)值(39) 插入@SampleTransferIDSourceTable(TransferID)值(40) 插入@SampleTransferIDSourceTable(TransferID)值(50) --将事务ID复制到具有标识项的表中。 --实现时,在order by之前添加where子句,以限制本地StoreID --添加零行,以便在使用最低的行之前找到间隙。 插入@WorkTable(TransferID) 选择0 插入@WorkTable(TransferID) 按TransferID从@SampleTransferIDSourceTable订单中选择TransferID --将该表复制到具有diff列的新表中 插入@WorkTable2 选择WorkTableID、TransferID、Tr
SELECT TOP 100
    T1.ID + 1 AS FREE_ID 
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T2.ID = T1.ID + 1
WHERE T2.ID IS NULL