MySQL Resetar Sequência AutoIncrement Sem Informar Próxima Sequência

-- first, remove auto-increment attribute if it still exists
ALTER TABLE `mytable` MODIFY COLUMN `id` INT(10) UNSIGNED;

-- second, add auto-increment attribute back
ALTER TABLE `mytable` MODIFY COLUMN `id` INT(10) UNSIGNED AUTO_INCREMENT;

Recentemente enfrentei um problema de deixar os cabelos em pé onde uma das tabelas acabou perdendo o atributo auto-increment durante uma operação de movimentação na nuvem.

Bom, o deixar os cabelos em pé foi por que demorei muito para descobrir a ocorrência deste evento de perda do atributo, porém a correção do schema é bastante simples.

Apesar do meu caso se tratar de uma tabela de pouca movimentação eu quis utilizar uma solução que encontrei durante minhas buscas. Achei esta solução bastante interessante pelo fato de não ser preciso atribuir o valor do auto-increment com um HARD SET utilizando o MAX VALUE da coluna id correntemente na tabela.

Ao invés disto, a operação consiste em remover o atributo auto-increment do campo e simplesmente adicioná-lo novamente. Durante esta operação o MySQL realiza um auto-reset atribuindo o valor correto de acordo com os dados existentes na tabela.

No meu caso o atributo auto-increment já tinha sido removido em outra operação, então foi só executar o segundo comando mesmo para adicionar o auto-increment de volta a coluna id.

Caso você queira simplesmente resetar a sequência auto-increment utilizando os comandos mais tradicionais você poderia utilizar, por exemplo, os comandos abaixo.

SELECT MAX(id)+1 INTO @next_id FROM `mytable`;

ALTER TABLE `mytable` AUTO_INCREMENT = @next_id;

Prontinho… Case Closed!

PHP Array Usando RESET para Extrair a Primeira Linha de um Array

$y[0] = [ 'col1' => 'A', 'col2' => 'B', 'col3' => 'C' ];
$y[1] = [ 'col1' => 'value1', 'col2' => 'value2', 'col3' => 'value3' ];
$y[2] = [ 'col1' => 'value4', 'col2' => 'value5', 'col3' => 'value6' ];
$y[3] = [ 'col1' => 'value7', 'col2' => 'value8', 'col3' => 'value9' ];

$header = reset($y);
var_dump($header);

// array(3) { 
//   ["col1"] => string(1) "A"
//   ["col2"] => string(1) "B"
//   ["col3"] => string(1) "C"
// }

Pode parecer uma tarefa super simples pegar o primeiro elemento de um array, e realmente é!!! Desde a semana passada o reset() é o meu jeito preferido de fazer isso.

Recentemente quando estive implementando a importação de um arquivo tipo planilha de dados naturalmente tive a necessidade de processar a primeira linha a qual continha o HEADER dos dados. Então me deparei com um código existente que me pareceu muito estranho a princípio, dá uma olhada nisso…

$mapped_headers = $this->map_headers(reset($spreadsheet_rows));

Para quem é familiar a este tipo de processamento sabe que estamos falando de um array bidimensional no melhor estilo linhas x colunas. O que eu não entendi foi aquele reset() ali na invocação do map_headers… que janho!!!

Como de praxe fui debugar e entender como a combinação funcionava… Para o meu espanto, somente agora eu entendi que o comando reset, além de resetar o ponteiro interno do array, retorna também o primeiro elemento do array.

Isto é fantástico!!! Eu sempre me perguntei por que o PHP não tinha um comando first() para pegar o primeiro elemento de um array já que temos o comando current() e o comando end().

Uma alternativa ao reset() seria inverter a array e usar o comando end(), mas acho que não tem necessidade de complicar o código com essa miscelânea pra atingir o mesmo resultado.

$r = array_reverse($y);
$header = end($r);
var_dump($header); 

// array(3) { 
//   ["col1"] => string(1) "A"
//   ["col2"] => string(1) "B"
//   ["col3"] => string(1) "C"
// }

Outra combinação possível seria combinar current() com reset(), mas também seria um desperdício já que o reset já faz o trabalho esperado.

reset($y);
$header = current($y);
var_dump($header); 

// array(3) { 
//   ["col1"] => string(1) "A"
//   ["col2"] => string(1) "B"
//   ["col3"] => string(1) "C"
// }

Outra alternativa segura de pegarmos o primeiro elemento da array seria fatiar o array com array_slice(), lembrando que este comando extrai o elemento como bidimensional preservando o índice da linha. Ainda assim teria que combinar com array_shift() ou array_pop() para pegar o primeiro elemento como array simples.

$first_row = array_slice($y, 0, 1);
var_dump($first_row); 

// array(1) {
//   [0]=>
//   array(3) {
//     ["col1"]=> string(1) "A"
//     ["col2"]=> string(1) "B"
//     ["col3"]=> string(1) "C"
//   }
// }

$header = array_shift($first_row);
var_dump($header); 

// array(3) { 
//   ["col1"] => string(1) "A"
//   ["col2"] => string(1) "B"
//   ["col3"] => string(1) "C"
// }

Pra finalizar uma última alternativa segura que podemos considerar seria utilizar array_values(). Sabemos que a primeira linha do array representam os headers não importa qual é a chave utilizada na indexação destas linhas. Então array_values() garante que o índice da primeira linha seja ZERO através do re-sequenciamento do array sem alterar a ordem de seus elementos.

$y['Z'] = [ 'col1' => 'A', 'col2' => 'B', 'col3' => 'C' ];
$y['X'] = [ 'col1' => 'value1', 'col2' => 'value2', 'col3' => 'value3' ];
$y['S'] = [ 'col1' => 'value4', 'col2' => 'value5', 'col3' => 'value6' ];
$y['J'] = [ 'col1' => 'value7', 'col2' => 'value8', 'col3' => 'value9' ];

$header = array_values($y)[0];
var_dump($header); 

// array(3) { 
//   ["col1"] => string(1) "A"
//   ["col2"] => string(1) "B"
//   ["col3"] => string(1) "C"
// }

Não exploramos outras alternativas como loop foreach() e for() mas nem precisa, com o PHP certamente encontraremos pelo menos mais meia dúzia de outras formas para atingir o mesmo resultado.

Agora convenhamos, o reset() arrasou!