你能在一个语句中访问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计数器表中的行。 这避免了由多个线程所做的重复。