Pregunta

Me gustaría tener un activador para realizar la siguiente operación para registros insertados:

 # pseudocode
 if new.group_id is null
    set new.group_id = new.id
 else
    # don't touch it
 end

Más claramente: digamos que tengo una tabla con tres columnas: id clave principal, group_id int, value varchar.

Cuando inserto con group_id así:

INSERT INTO table(value, group_id) VALUES ('a', 10)

Me gustaría tener:

id | group_id | value
---+----------+------
 1 |       10 | a

pero cuando omito group_id :

INSERT INTO table(value) VALUES ('b')

debe establecerse automáticamente en el id de este registro:

id | group_id | value
---+----------+------
 2 |        2 | b

¿Es posible con un disparador? (Sé que puedo actualizar el registro después de insertarlo, pero tener el disparador sería mejor).

¿Fue útil?

Solución

No sé de ninguna manera de hacer esto en una declaración, incluso usando un disparador.

La solución de activación que @Lucky sugirió se vería así en MySQL:

CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
  SET NEW.group_id = COALESCE(NEW.group_id, NEW.id);
END

Sin embargo, hay un problema. En la fase ANTES DE INSERTAR , el valor id generado automáticamente todavía no se ha generado. Entonces, si group_id es nulo, el valor predeterminado es NEW.id que siempre es 0.

Pero si cambia este disparador para que se active durante la fase DESPUÉS DE INSERTAR , de modo que tenga acceso al valor generado de NEW.id , no podrá modificar la columna valores.

MySQL no admite expresiones para el DEFAULT de una columna, por lo que tampoco puede declarar este comportamiento en la definición de la tabla.

La única solución es hacer el INSERT , y luego inmediatamente hacer un UPDATE para cambiar el group_id si no está configurado.

INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a');
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID();

Otros consejos

Estoy respondiendo aquí, como en la respuesta aceptada Bill Karwin dice:

  

En la fase ANTES DE INSERTAR, el valor de ID generado automáticamente no ha sido   generado todavía. Entonces, si group_id es nulo, el valor predeterminado es NEW.id, que es   siempre 0.


Tengo una respuesta para ello: para OP (y los visitantes que vienen), aquí hay algunos puntos: No puede actualizar la tabla desde donde se invoca el desencadenador, para ello obtendrá el Error 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 actualizar la nueva fila Use el disparador ANTES DE INSERTAR EN , de esta manera puede actualizar todos los campos para la nueva fila, a los que se puede acceder a través del NUEVO operador, es decir,

set NEW.group_id = NEW.id

2. Obtenga el valor de auto_increment antes de insertar :

SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable'

Para resumir: el desencadenador SQL para 'd sería algo así:

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 ;

Esto funciona para mí

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 ;

Creo que esto funcionará para usted

Tengo dos tablas

test_b: a_id, value
test_c: a_id, value

Y aquí hay un disparador en la inserción de la prueba b. Comprueba si a_id es nulo y si lo es, inserta 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)

Este disparador debe hacer lo que le pediste.

   CREATE TRIGGER mytrigger BEFORE INSERT ON mytable
          IF new.group_id IS NULL
            SET new.group_id = new.id
          END IF
      END;

Se copia de un ejemplo muy similar en la documentación MYSQL página.

Un disparador parece excesivo en esta situación. Simplemente aplique un valor predeterminado.

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'
)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top