MySQL ON DUPLICATE KEY – última inserção id?

Eu tenho a seguinte consulta:

INSERT INTO table (a) VALUES (0) ON DUPLICATE KEY UPDATE a=1 

Eu quero o ID da inserção ou da atualização. Normalmente executo uma segunda consulta para obter isso, pois acredito que insert_id () retorna apenas o ID ‘inserido’ e não o ID atualizado.

Existe uma maneira de INSERT / UPDATE e recuperar o ID da linha sem executar duas consultas?

Confira esta página: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Na parte inferior da página, eles explicam como você pode tornar LAST_INSERT_ID significativo para atualizações, passando uma expressão para essa function MySQL.

Do exemplo da documentação do MySQL:

Se uma tabela contiver uma coluna AUTO_INCREMENT e INSERT … UPDATE inserir uma linha, a function LAST_INSERT_ID () retornará o valor AUTO_INCREMENT. Se a instrução atualiza uma linha, LAST_INSERT_ID () não é significativo. No entanto, você pode contornar isso usando LAST_INSERT_ID (expr). Suponha que id seja a coluna AUTO_INCREMENT. Para tornar LAST_INSERT_ID () significativo para atualizações, insira linhas da seguinte maneira:

 INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3; 

Para ser exato, se esta for a consulta original:

 INSERT INTO table (a) VALUES (0) ON DUPLICATE KEY UPDATE a=1 

e ‘id’ é a chave primária de incremento automático do que esta seria a solução de trabalho:

 INSERT INTO table (a) VALUES (0) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1 

Está tudo aqui: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Se uma tabela contiver uma coluna AUTO_INCREMENT e INSERT … UPDATE inserir uma linha, a function LAST_INSERT_ID () retornará o valor AUTO_INCREMENT. Se a instrução atualiza uma linha, LAST_INSERT_ID () não é significativo. No entanto, você pode contornar isso usando LAST_INSERT_ID (expr). Suponha que id seja a coluna AUTO_INCREMENT.

Você pode olhar para REPLACE, que é essencialmente uma exclusão / inserção se o registro existir. Mas isso alteraria o campo de incremento automático, se presente, o que poderia romper relacionamentos com outros dados.

Eu não sei qual é a sua versão do MySQL mas com o InnoDB, tem bug com autoinc

bug em 5.1.20 e corrigido em 5.1.23 http://bugs.mysql.com/bug.php?id=27405

bug em 5.1.31 e corrigido em 5.1.33 http://bugs.mysql.com/bug.php?id=42714

Vale a pena notar, e isso pode ser óbvio (mas eu vou dizer assim mesmo, por clareza aqui), que REPLACE vai acabar com a linha correspondente existente antes de inserir seus novos dados. ON DUPLICATE KEY UPDATE atualizará somente as colunas especificadas e preservará a linha.

Do manual :

REPLACE funciona exatamente como INSERT, exceto que se uma linha antiga na tabela tiver o mesmo valor de uma nova linha para uma PRIMARY KEY ou um índice UNIQUE, a linha antiga será excluída antes que a nova linha seja inserida.

As soluções existentes funcionam se você usar o incremento automático. Eu tenho uma situação em que o usuário pode definir um prefixo e deve reiniciar a seqüência em 3000. Devido a esse prefixo variado, não posso usar o incremento automático, o que torna last_insert_id vazio para inserções. Eu resolvi isso com o seguinte:

 INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1); SELECT LAST_INSERT_ID(); 

Se o prefixo existir, irá incrementá-lo e preencher last_insert_id. Se o prefixo não existir, ele inserirá o prefixo com o valor 3000 e preencherá last_insert_id com 3000.