我有一个包含3个字段的表:Id(PK,AI),Name(varchar(36)),LName(varchar(36))。 我必须插入名称和姓氏,因为它的约束,Id会自动插入,
当达到6时,有没有办法跳转id自动增量值?
例如这样做7次:
Insert into table(Name,LName)值('name1','lname1')“并且如果它将是6,则将id跳转到7” 这样做可能听起来很愚蠢,但我有疑问。
同时跳转并且不记录ID 6。 仅记录,1-5,7,8,9等等
我想要实现的目标始于联盟:
Select * From TableNames
Union All
Select * From TableNames_general
在TableNames_general中,我指定了它的第一个值,这样当用户第一次看到该表时,它将显示我插入的记录。
问题出现在用户插入新记录时,如果插入的记录的Id与我插入的记录的ID相同,则会重复,这就是我想在用户插入一条记录时实现的原因最后一个插入ID已存在,只是跳过该记录。这是因为由于子表之间的关系,我必须有不同的ID。
答案 0 :(得分:1)
如果查询数据库以获取最后插入的ID,则可以通过在查询中使用参数来设置正确的ID来检查是否需要增加它。
答案 1 :(得分:1)
没有直接影响AUTO_INCREMENT的方法来跳过"跳过"特定值,或特定条件下的值。
我认为您必须在 AFTER INSERT
触发器中处理此问题。AFTER INSERT
触发器无法更新行的值刚插入,我不认为它可以对触发触发器的语句所影响的表进行任何修改。
BEFORE INSERT
触发器也无法正常工作,因为分配给AUTO_INCREMENT
列的值在BEFORE INSERT
触发器中不可用。
我不相信有一种方法可以让SQL Server IDENTITY
进入"跳过"特别值。
<强>更新强>
如果您需要&#34;独特&#34;两个表之间的id值,对MySQL来说是一个相当丑陋的解决方法:使用触发器和单独的表来滚动自己的auto_increment行为。不是使用AUTO_INCREMENT属性定义表,而是使用BEFORE INSERT
触发器来获取值。
如果提供了id
值,并且它大于虚拟auto_increment_seq表中auto_increment列的当前最大值,我们需要更新该行,或者插入一个新的。
粗略概述:
CREATE TABLE auto_increment_seq
(id INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=MyISAM;
DELIMITER $$
CREATE TRIGGER TableNames_bi
BEFORE INSERT ON TableNames
FOR EACH ROW
BEGIN
DECLARE li_new_id INT UNSIGNED;
IF ( NEW.id = 0 OR NEW.id IS NULL ) THEN
INSERT INTO auto_increment_seq (id) VALUES (NULL);
SELECT LAST_INSERT_ID() INTO li_new_id;
SET NEW.id = li_new_id;
ELSE
SELECT MAX(id) INTO li_max_seq FROM auto_increment_seq;
IF ( NEW.id > li_max_seq ) THEN
INSERT INTO auto_increment_seq (id) VALUES (NEW.id);
END IF;
END IF;
END$$
CREATE TRIGGER TableNames_ai
AFTER INSERT ON TableNames
FOR EACH ROW BEGIN
DECLARE li_max_seq INT UNSIGNED;
SELECT MAX(id) INTO li_max_seq FROM auto_increment_seq;
IF ( NEW.id > li_max_seq ) THEN
INSERT INTO auto_increment_seq (id) VALUES (NEW.id);
END IF;
END;
DELIMITER ;
表中的id列可以这样定义:
TableNames
( id INT UNSIGNED NOT NULL DEFAULT 0 PRIMARY KEY
COMMENT 'populated from auto_increment_seq.id'
, ...
您也可以为另一个表创建相同的触发器,因此这两个表实际上共享相同的auto_increment序列。 (效率和并发性低于Oracle SEQUENCE
对象所提供的。)
重要提示
这并不能确保表之间的id
值实际上保持唯一。那真的需要查询另一个表来查看id值是否存在;如果使用InnoDB引擎运行,在某些事务隔离级别的上下文中,我们可能会查询另一个表的陈旧情况(如在事务开始时的时间点一致)。
如果没有一些额外的(并发查杀)锁定,上面的方法概述会受到一个小小的机会窗口的影响。具有并发插入的条件...来自伪seq表的SELECT MAX(),后跟INSERT,允许另一个事务的小窗口也运行SELECT MAX(),并返回相同的值。我们所希望的最好的(我认为)是由于重复的密钥异常而引发的错误。
这种方法需要虚拟&#34; seq&#34;表使用MyISAM引擎,因此我们可以获得类似Oracle的AUTONOMOUS TRANSACTION行为;如果在REPEATABLE READ或SERIALIZABLE事务隔离级别的上下文中执行对实际表的插入,则seq表中的MAX(id)的读取将与事务开始时的快照一致,我们不会这样做。获取新插入(或更新)的值。
我们还需要考虑更新id值的UPDATE行的边缘情况;为了处理这种情况,我们还需要BEFORE / AFTER UPDATE触发器。
答案 2 :(得分:1)
如果您使用 MSSQL ,则可以执行以下操作:
在插入检查当前ID之前,如果它是5,则执行以下操作:
IDENTITY_INSERT
设为ON
IDENTITY_INSERT
设为OFF
您也可以使用以下方案:
DBCC CHECKIDENT (Table, reseed, 6)
,它将重新设置表格,在这种情况下,您的下一个身份将是7 如果您在INSERT之后检查当前身份,可以使用SELECT @@IDENTITY
或SELECT SCOPE_IDENTITY()
获得更好的结果(正如rcdmk在评论中指出的那样)
否则您只能使用select
:SELECT MAX(Id) FROM Table
答案 3 :(得分:1)
标识列为您生成值,并且最好保留这种方式,您可以在标识列中插入特定值,但最好单独使用它,让它为您生成值。
想象一下,您已在标识列中显式插入了一个值,然后在Identity列上为您生成相同的值,您将最终得到重复项。
如果您想在该列中输入,那么为什么还要打扰身份列?
这不是最好的做法,但你可以通过以下方式跳转到特定的数字:
MS SQL SERVER 2005及更高版本
-- Create test table
CREATE TABLE ID_TEST(ID INT IDENTITY(1,1), VALUE INT)
GO
-- Insert values
INSERT INTO ID_TEST (VALUE) VALUES
(1),(2),(3)
GO
-- Set idnentity insert on to insert values explicitly in identity column
SET IDENTITY_INSERT ID_TEST ON;
INSERT INTO ID_TEST (ID, VALUE) VALUES
(6, 6),(8,8),(9,9)
GO
-- Set identity insert off
SET IDENTITY_INSERT ID_TEST OFF;
GO
-- 1st reseed the value of identity column to any smallest value in your table
-- below I reseeded it to 0
DBCC CHECKIDENT ('ID_TEST', RESEED, 0);
-- execute the same commad without any seed value it will reset it to the
-- next highest idnetity value
DBCC CHECKIDENT ('ID_TEST', RESEED);
GO
-- final insert
INSERT INTO ID_TEST (VALUE) VALUES
(10)
GO
-- now select data from table and see the gap
SELECT * FROM ID_TEST