你能在一个语句中访问MySQL中的自动增量值吗?

我有一个包含用户表的MySQL数据库。 该表的主键是“userid”,它被设置为一个自动增量字段。

我想要做的是当我插入一个新的用户到表中是使用相同的值,自动增量创build在'userid'字段在不同的领域,'default_assignment'。

例如

我想要一个像这样的陈述:

INSERT INTO users ('username','default_assignment') VALUES ('barry', value_of_auto_increment_field()) 

所以我创build用户'Barry','userid'生成为16(例如),但我也希望'default_assignment'具有相同的值16。

有什么办法可以实现这个吗?

谢谢!

更新:

感谢您的答复。 default_assignment字段不是多余的。 default_assigment可以引用用户表中的任何用户。 创build用户时,我已经有一个表单,允许select另一个用户作为default_assignment,但有些情况下,它需要设置为同一个用户,因此我的问题。

更新:

好吧,我已经尝试了更新触发器的build议,但仍然无法得到这个工作。 这是我创build的触发器:

 CREATE TRIGGER default_assignment_self BEFORE INSERT ON `users` FOR EACH ROW BEGIN SET NEW.default_assignment = NEW.userid; END; 

插入新用户时,default_assignment始终设置为0。

如果我手动设置用户ID然后default_assignment确实设置为用户ID。

因此,在触发生效后,自动分配生成过程就会清楚地发生。

没有必要创build另一个表,并且max()将根据表的auto_increment值产生问题,请执行以下操作:

 CREATE TRIGGER trigger_name BEFORE INSERT ON tbl FOR EACH ROW BEGIN DECLARE next_id INT; SET next_id = (SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='tbl'); SET NEW.field=next_id; END 

我声明next_idvariables,因为通常它会以其他方式(*)使用,但你可以直接new.field =(select …)

 (*) To auto-name an image: SET NEW.field = CONCAT('image_', next_id, '.gif'); (*) To create a hash: SET NEW.field = CONCAT( MD5( next_id ) , MD5( FLOOR( RAND( ) *10000000 ) ) ); 

尝试这个

 INSERT INTO users (default_assignment) VALUES (LAST_INSERT_ID()+1); 

看到last_insert_id()在这种情况下不起作用,是的,触发器将是唯一的方法来完成。

我确实问自己:你需要什么function? 为什么你存储用户id两次? 就个人而言,我不喜欢存储这样的冗余数据,我可能会解决这个在应用程序代码通过使不祥的default_assignment列NULL,并在我的应用程序代码中使用用户ID如果default_assignment为NULL。

其实我只是试着去做同样的事情。 但似乎Mysql doesent在实际获取提交之前生成插入的ID。 所以NEW.userid将在一个Before insert触发器中总是返回0。

上述也不会工作,除非它是一个BEFORE INSERT触发器,因为你不能更新AFTER INSERT查询中的值。

从一个Mysql论坛post似乎处理这个唯一的方法是使用一个额外的表作为一个序列。 所以你的触发器可以从外部源拉入值。

 CREATE TABLE `lritstsequence` ( `idsequence` int(11) NOT NULL auto_increment, PRIMARY KEY (`idsequence`) ) ENGINE=InnoDB; CREATE TABLE `lritst` ( `id` int(10) unsigned NOT NULL auto_increment, `bp_nr` decimal(10,0) default '0', `descr` varchar(128) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `dir1` (`bp_nr`) ) ENGINE=InnoDB; DELIMITER $$ DROP TRIGGER /*!50032 IF EXISTS */ `lritst_bi_set_bp_nr`$$ CREATE TRIGGER `lritst_bi_set_bp_nr` BEFORE INSERT ON `lritst` FOR EACH ROW BEGIN DECLARE secuencia INT; INSERT INTO lritstsequence (idsequence) VALUES (NULL); SET secuencia = LAST_INSERT_ID(); SET NEW.id = secuencia; SET NEW.bp_nr = secuencia; END;$$ DELIMITER ; INSERT INTO lritst (descr) VALUES ('test1'); INSERT INTO lritst (descr) VALUES ('test2'); INSERT INTO lritst (descr) VALUES ('test3'); SELECT * FROM lritst; Result: id bp_nr descr ------ ------ ------ 1 1 test1 2 2 test2 3 3 test3 

这是从forums.mysql.com/read.php?99,186171,186241#msg-186241复制,但我不允许张贴链接。

唯一的我发现,将解决这个问题没有一个额外的表将是计算自己的下一个数字,把它放在所需的领域。

 CREATE TABLE `Temp` ( `id` int(11) NOT NULL auto_increment, `value` varchar(255) , PRIMARY KEY (`idsequence`) ) ENGINE=InnoDB; CREATE TRIGGER temp_before_insert BEFORE INSERT ON `Temp` FOR EACH ROW BEGIN DECLARE m INT; SELECT IFNULL(MAX(id), 0) + 1 INTO m FROM Temp; SET NEW.value = m; -- NOT NEEDED but to be save that no other record can be inserted in the meanwhile SET NEW.id = m; END; 

基本上,解决scheme就像Resegue说的。
但是如果你想在一个声明中使用,你可以使用下面的方法之一:

1.长话:

 INSERT INTO `t_name`(field) VALUES((SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t_name')) 

或用于编号为的文本:

 INSERT INTO `t_name`(field) VALUES(CONCAT('Item No. ',CONVERT((SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t_name') USING utf8))) 

它在PHP中看起来更清楚:

 $pre_name='Item No. '; $auto_inc_id_qry = "(SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='$table')"; $new_name_qry = "CONCAT('$pre_name',CONVERT($auto_inc_id_qry USING utf8))"; mysql_query("INSERT INTO `$table`(title) VALUES($new_name_qry)"); 

2.使用function:(尚未testing)

 CREATE FUNCTION next_auto_inc(table TINYTEXT) RETURNS INT BEGIN DECLARE next_id INT; SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=table INTO next_id; RETURN next_id; END INSERT INTO users ('username','default_assignment') VALUES ('barry', next_auto_inc('users')) 
 $ret = $mysqli->query("SELECT Auto_increment FROM information_schema.tables WHERE table_schema = DATABASE() ");l while ($row = mysqli_fetch_array($ret)) { $user_id=$row['Auto_increment']; } 

你可以使用一个简单的子查询可靠地做到这一点:

 INSERT INTO users ('username','default_assignment') SELECT 'barry', Auto_increment FROM information_schema.tables WHERE TABLE_NAME='users' 

我用10个并发线程做了插入testing了上面的触发器想法,插入了〜25k之后,我得到了超过1000个2或3个副本。

 DROP TABLE IF EXISTS test_table CASCADE; CREATE TABLE `test_table` ( `id` INT NOT NULL AUTO_INCREMENT, `update_me` VARCHAR(36), `otherdata` VARCHAR(36) NOT NULL, PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8 COMMENT 'test table for trigger testing'; delimiter $$ DROP TRIGGER IF EXISTS setnum_test_table; $$ CREATE TRIGGER setnum_test_table BEFORE INSERT ON test_table FOR EACH ROW -- SET OLD.update_me = CONCAT(NEW.id, 'xyz'); BEGIN DECLARE next_id INT; SET next_id = (SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='test_table' LOCK IN SHARE MODE ); -- SET NEW.update_me = CONCAT(next_id, 'qrst'); SET NEW.update_me = next_id; END $$ delimiter ; -- SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='test_table' INSERT INTO test_table (otherdata) VALUES ('hi mom2'); SELECT count(*) FROM test_table; SELECT * FROM test_table; -- select count(*) from ( select * from ( SELECT count(*) as cnt ,update_me FROM test_table group by update_me) q1 where cnt > 1 order by cnt desc 

我用了10个:

 while true ; do echo "INSERT INTO test_table (otherdata) VALUES ('hi mom2');" | mysql --user xyz testdb ; done & 

然后运行最后一个查询来查看重复项

示例输出:“3”,“4217”,“3”,“13491”,“2”,“10037”,“14658”,“2”,“5080”,“14201”…

注意“分享模式locking”没有改变任何东西。 有和没有以大致相同的速度给出重复。 看起来MySQL AUTO_INCREMENT不像Postgres的next_val()那样工作,并且不是并发安全的。

我知道这个post是从2010年,但我找不到一个好的解决scheme。 我已经通过创build一个单独的表来保存计数器来解决这个问题。 当我需要为列生成一个唯一的标识符时,我只需要调用一个Stored proc:

 CREATE DEFINER=`root`@`localhost` PROCEDURE `IncrementCounter`(in id varchar(255)) BEGIN declare x int; -- begin; start transaction; -- Get the last counter (=teller) and mark record for update. select Counter+1 from tabel.Counter where CounterId=id into x for update; -- check if given counter exists and increment value, otherwise create it. if x is null then set x = 1; insert into tabel.Counters(CounterId, Counter) values(id, x); else update tabel.Counters set Counter = x where CounterId = id; end if; -- select the new value and commit the transaction select x; commit; END 

“for update”语句locking计数器表中的行。 这避免了由多个线程所做的重复。