MySQL Trigger para atualizar um campo para o valor do ID
Pergunta
Eu gostaria de ter um gatilho para executar a operação seguinte para registros inseridos:
# pseudocode
if new.group_id is null
set new.group_id = new.id
else
# don't touch it
end
Mais claramente: diga que tenho uma tabela com três colunas: id
chave primária, group_id
int, value
Varchar.
Quando eu insiro com group_id
Curtiu isso:
INSERT INTO table(value, group_id) VALUES ('a', 10)
Eu gostaria de ter:
id | group_id | value
---+----------+------
1 | 10 | a
Mas quando eu omito group_id
:
INSERT INTO table(value) VALUES ('b')
deve ser definido automaticamente para o id
deste registro:
id | group_id | value
---+----------+------
2 | 2 | b
É possível com um gatilho? (Eu sei que posso atualizar o registro depois de inserir, mas ter o gatilho seria melhor.)
Solução
Não conheço nenhuma maneira de fazer isso em uma declaração, mesmo usando um gatilho.
A solução de gatilho que @lucky sugeriu que seria assim em MySQL:
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
SET NEW.group_id = COALESCE(NEW.group_id, NEW.id);
END
No entanto, há um problema. No BEFORE INSERT
fase, a gerada automática id
O valor ainda não foi gerado. Então se group_id
é nulo, padroniza para NEW.id
que é sempre 0.
Mas se você mudar esse gatilho para disparar durante o AFTER INSERT
fase, então você tem acesso ao valor gerado de NEW.id
, você não pode modificar os valores da coluna.
MySQL não suporta expressões para o DEFAULT
de uma coluna, para que você não possa declarar esse comportamento na definição da tabela.
A única solução é fazer o INSERT
, e então imediatamente faça um UPDATE
Para mudar o group_id
Se não estiver definido.
INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a');
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID();
Outras dicas
Estou respondendo aqui, como na resposta aceita Bill Karwin estados:
Na fase anterior, o valor de ID gerado automaticamente ainda não foi gerado. Portanto, se Group_Id for nulo, ele padrão é o novo.id, que é sempre 0.
Eu tenho uma resposta para isso - para OP (e os visitantes que virão), aqui estão poucos pontos: você não pode atualizar a tabela de onde o gatilho é invocado, pois você ficar Erro 1442:
Error Code: 1442
Can't update table 'MyTable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
1. Para atualizar a nova linhaUsar BEFORE INSERT ON
Trigger, dessa maneira você pode atualizar todos os campos para a nova linha, que pode ser acessível através do novo operador, ou seja,
set NEW.group_id = NEW.id
2. Get Auto_INCrement Value antes da inserção:
SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable'
Para resumir - o gatilho SQL para 'D Be algo como seguinte:
DELIMITER //
DROP TRIGGER IF EXISTS MyTrigger//
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
IF new.group_id IS NULL
set @auto_id := (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='MyTable' AND TABLE_SCHEMA=DATABASE() );
set NEW.group_id = @auto_id;
ENF IF;
END;
//
DELIMITER ;
Isso funciona para mim
DELIMITER $$
CREATE TRIGGER `myTriggerNameHere`
BEFORE INSERT ON `table` FOR EACH ROW
BEGIN
SET NEW.group_id = IF(NEW.group_id IS NULL, LAST_INSERT_ID()+1, NEW.group_id);
END;
$$
DELIMITER ;
Eu acredito que isso vai funcionar para você
Eu tenho duas mesas
test_b: a_id, value
test_c: a_id, value
E aqui está um gatilho na inserção do teste b. Ele verifica se A_ID é nulo e se for insere 0
CREATE TRIGGER test_b AFTER INSERT ON test_b
FOR EACH ROW
INSERT INTO test_c (a_id, value) VALUES (IFNULL(NEW.a_id, 0),NEW.value)
Esse gatilho deve fazer o que você pediu.
CREATE TRIGGER mytrigger BEFORE INSERT ON mytable
IF new.group_id IS NULL
SET new.group_id = new.id
END IF
END;
É copiado de um exemplo muito semelhante no Documentação do MySQL página.
Um gatilho parece um exagero nessa situação. Basta aplicar um padrão.
CREATE TABLE `test` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`value` varchar(100) NOT NULL,
`group_id` TINYINT(3) UNSIGNED NOT NULL DEFAULT '2'
)