Pregunta

Quiero hacer una columna en una relación imposible de modificar por razones de consistencia.

La historia de fondo es que tengo una relación: n donde la relación "conectación" tiene valores adicionales. No quiero que nadie pueda cambiar las ID de los socios de la relación.

Lo que se me ocurrió hasta ahora:

Crear un disparador que verifique si el nuevo valor es el mismo que el valor anterior. Pero no sé cómo negar la acción de actualización si la condición lo demuestra como verdadera.

Aquí está mi gatillo hasta ahora:

CREATE TRIGGER deny_nton_change BEFORE UPDATE ON Schueler_in_Klasse
FOR EACH ROW BEGIN
    IF NEW.Schueler_ID != OLD.Schueler_ID OR NEW.Klasse_ID != OLD.Klasse_ID THEN

    END IF;
END;
¿Fue útil?

Solución

En lugar de abortar la actualización, ¿solo anularla?

...
FOR EACH ROW BEGIN
    SET NEW.Schueler_ID = OLD.Schueler_ID;
    SET NEW.Klasse_ID = OLD.Klasse_ID;
END

Otros consejos

Una forma bastante agradable y limpia de abortar y devolver un mensaje de error legible es usar una señal:

Signal sqlState '45000' set Message_text = 'Schueler_id y Klasse_id no puede ser alterado!';

Asegúrese de que su versión MySQL admita esto, se introdujo en MySQL 5.5. En versiones anteriores, necesita hacks como insertar un campo no existente en una tabla no existente.

Como menciona GBN, sobrescribir los nuevos valores con los antiguos también es una buena opción.

De hecho, aprendí un enfoque de retroceso para abortar los desencadenantes. Es muy crudo, pero funciona porque el procesamiento de señales no se implementa en el lenguaje de procedimiento almacenado de MySQL. Se puede emular en el mejor de los casos.

Capítulo 11, páginas 254-256 del libro Programación de procedimientos almacenados de MySQL bajo el subtítulo 'Validación de datos con desencadenantes' sugiere hacer una selección de una cadena de caracteres en un entero ficticio (en términos de sintaxis, es correcto, pero muere en la ejecución [sin juego de palabras])::

CREATE TRIGGER deny_nton_change BEFORE UPDATE ON Schueler_in_Klasse 
FOR EACH ROW BEGIN
    DECLARE dummy INT; 
    IF NEW.Schueler_ID != OLD.Schueler_ID OR NEW.Klasse_ID != OLD.Klasse_ID THEN 
        SELECT 'Cannot Carry Out This Trigger Any Further'
        INTO dummy FROM table_you_know_does_not_exist WHERE 1=1 LIMIT 1;
    END IF; 
END; 

En realidad, es posible hacer esto perfectamente sin usar desencadenantes si está usando innodb.

Crea otra tabla con una sola columna. Esa columna debe tener una clave extranjera (de ahí el requisito innoDB en esta solución) que apunta a la columna inmutable de la tabla original en cuestión.

Ponga una restricción como "Restringir la actualización".

En resumen:

CREATE TABLE original (
     ....
     immutable_column ...
     INDEX index1(immutable_column)
     ....
) ENGINE=INNODB;

CREATE TABLE restricter (
     .....
     col1,
     INDEX index2(col1),
     FOREIGN KEY (col1) REFERENCES original (immutable_colum) ON UPDATE RESTRICT ON DELETE CASCADE
) ENGINE=INNODB;

Basado en una combinación de todas las respuestas, he leído, esto es lo que funcionó para mí:

delimiter $$ -- You may need this or not (in my visual client I need it, directly in console I don't)
create trigger deny_nton_change before update on surveys
for each row begin
    if new.Schueler_ID != old.Schueler_ID OR new.Klasse_ID != old.Klasse_ID then
      signal sqlstate '45000' set message_text = 'My own Error: Field is immutable';
    end if;
end$$
delimiter ; -- You may need this or not
Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top