Você pode acessar o valor de incremento automático no MySQL dentro de uma declaração?

Eu tenho um database MySQL que contém uma tabela de usuários. A chave primária da tabela é ‘userid’, que é configurada para ser um campo de incremento automático.

O que eu gostaria de fazer ao inserir um novo usuário na tabela é usar o mesmo valor que o incremento automático está criando no campo ‘userid’ em um campo diferente, ‘default_assignment’.

por exemplo

Eu gostaria de uma declaração como esta:

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

então eu crio o usuário ‘Barry’, o ‘userid’ é gerado como sendo 16 (por exemplo), mas eu também quero que o ‘default_assignment’ tenha o mesmo valor de 16.

Existe alguma maneira de conseguir isso, por favor?

Obrigado!

Atualizar:

Obrigado pelas respostas. O campo default_assignment não é redundante. O default_assigment pode referenciar qualquer usuário dentro da tabela de usuários. Ao criar um usuário eu já tenho um formulário que permite a seleção de outro usuário como default_assignment, no entanto há casos em que ele precisa ser configurado para o mesmo usuário, daí minha pergunta.

Atualizar:

Ok, eu tentei a sugestão de gatilhos de atualização, mas ainda não consigo fazer isso funcionar. Aqui está o gatilho que eu criei:

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

Ao inserir um novo usuário, o default_assignment é sempre definido como 0.

Se eu definir manualmente o ID do usuário, a default_assignment será definida como userid.

Portanto, o processo de geração de atribuição automática ocorre claramente após o acionamento entrar em vigor.

não há necessidade de criar outra tabela, e max () terá problemas de acordo com o valor auto_increment da tabela, faça o seguinte:

 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 

Eu declaro a variável next_id porque normalmente ela será usada de alguma outra maneira (*), mas você poderia fazer straight newfield = (selecionar …)

 (*) 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 ) ) ); 

tente isso

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

vendo que last_insert_id() não funcionaria nesse caso, sim, o trigger seria a única maneira de conseguir isso.

Eu me pergunto: O que você precisa para essa funcionalidade? Por que você armazena o id dos usuários duas vezes? Pessoalmente, eu não gosto de armazenar dados redundantes como este e eu provavelmente resolveria isso no código do aplicativo, fazendo com que a coluna de default_assignment NULL e usando o id de usuário no código do meu aplicativo se default_assignment fosse NULL.

Na verdade, eu apenas tentei fazer a mesma coisa que foi sugerida acima. Mas parece que o Mysql não gera o ID inserido antes que a linha seja realmente confirmada. Então NEW.userid sempre retornará 0 em um trigger Before insert.

O acima também não funcionará a menos que seja um gatilho BEFORE INSERT, já que você não pode atualizar valores em uma consulta AFTER INSERT.

De um fórum do Mysql Post Parece que a única maneira de lidar com isso é usando uma tabela adicional como uma seqüência. Para que seu gatilho possa puxar os valores de uma fonte externa.

 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 

Este foi copiado de forums.mysql.com/read.php?99,186171,186241#msg-186241 mas não estou autorizado a postar links ainda.

O único que achei que resolveria esse problema sem uma tabela extra seria calcular o próximo número e colocá-lo nos campos necessários.

 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; 

Basicamente, a solução é como o Resegue disse.
Mas se você quiser em uma declaração, você usará uma das maneiras abaixo:

1. Uma declaração longa:

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

ou para texto com número:

 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))) 

parece mais claro em 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. Usando a function: (ainda não testado)

 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']; } 

Você pode fazer isso de forma confiável usando uma subconsulta simples:

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

Eu testei a ideia de trigger acima com 10 threads simultâneas fazendo inserções e consegui mais de 1000 casos de 2 ou 3 duplicatas depois de ~ 25k inseridos.

 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 

Eu usei 10 de:

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

E executei a última consulta para procurar por duplicatas

Exemplo de saída: ‘3’, ‘4217’ ‘3’, ‘13491’ ‘2’, ‘10037’ ‘2’, ‘14658’ ‘2’, ‘5080’ ‘2’, ‘14201’ …

Nota ‘LOCK IN SHARE MODE’ não alterou nada. Com e sem deu duplicatas em aproximadamente a mesma taxa. Parece que o MySQL AUTO_INCREMENT não funciona como next_val () do Postgres e NÃO é seguro para simultaneidade.

Eu sei que este post é de 2010, mas não consegui encontrar uma boa solução. Eu resolvi isso criando uma tabela separada que contém os contadores. Quando eu preciso gerar um identificador exclusivo para uma coluna eu apenas chamo um proc Stored:

 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 

A instrução ‘para atualização’ bloqueia a linha na tabela de contadores. Isso evita duplicatas sendo feitas por vários segmentos.

    Intereting Posts