仅在自动递增id不等于6时插入(例如)?

时间:2014-04-09 22:50:32

标签: mysql sql sql-server-2008

我有一个包含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。

4 个答案:

答案 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
  • 插入ID = 7
  • 的数据
  • IDENTITY_INSERT设为OFF

您也可以使用以下方案:

  • 检查当前ID
  • 如果它是5,运行DBCC CHECKIDENT (Table, reseed, 6),它将重新设置表格,在这种情况下,您的下一个身份将是7

如果您在INSERT之后检查当前身份,可以使用SELECT @@IDENTITYSELECT SCOPE_IDENTITY()获得更好的结果(正如rcdmk在评论中指出的那样)

否则您只能使用selectSELECT 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