MySQL триггер не проверяет переменную правильно - PullRequest
0 голосов
/ 14 января 2019

Я новичок в триггерах MySQL и хотел бы предотвратить сохранение записей в базе данных, если они недействительны. В этом случае я хотел бы проверить, больше ли год модуля, чем количество лет в курсе.

Вот моя процедура (выполняется перед вставкой).

SELECT num_of_years INTO @num_years FROM courses WHERE courses.course_id = NEW.course_id;

IF NEW.course_year > @num_years THEN
UPDATE `Error: invalid_id_test` SET x=1;
END;

Почему это разрешает ввод любого учебного года и как мне его решить?

1 Ответ

0 голосов
/ 14 января 2019

Редактировать: Исправлен ответ, теперь я лучше понимаю проблему.

Вот тест.

create table courses (
  course_id int primary key,
  num_of_years tinyint unsigned default 1
);

create table modules (
  module_id int primary key,
  course_id int,
  course_year tinyint unsigned
);

delimiter ;;
create trigger t before insert on modules for each row 
begin 
  declare num_years tinyint unsigned; 
  select num_of_years into num_years from courses where course_id = NEW.course_id; 
  if NEW.course_year > num_years then 
    signal sqlstate '45000' 
      set message_text = 'course_year is larger than the course length'; 
  end if; 
end;;
delimiter ;

Этот вид работ:

insert into courses set course_id=1, num_of_years=3;

insert into modules values set module_id=1, course_id1, course_year=4;
ERROR 1644 (45000): course_year is larger than the course length

Но это не помешает INSERT, если courses.num_of_years имеет значение NULL.

insert into courses set course_id=2, num_of_years=NULL;

insert into modules set module_id=2, course_id=2, course_year=99;
Query OK, 1 row affected (0.01 sec)

Причина в том, что переменная в триггере имеет значение NULL, поэтому NEW.course_year > num_years равно не верно и исключение не выдается.

Чтобы это исправить, проверьте NULL.

delimiter ;;
create trigger t before insert on modules for each row 
begin 
  declare num_years tinyint unsigned; 
  select num_of_years into num_years from courses where course_id = NEW.course_id; 
  if num_years is NULL or NEW.course_year > num_years then 
    signal sqlstate '45000' 
      set message_text = 'course_year is larger than the course length'; 
  end if; 
end;;
delimiter ;

insert into modules set module_id=2, course_id=2, course_year=99;
ERROR 1644 (45000): course_year is larger than the course length

Это также выдает ошибку, если вы пытаетесь вставить модуль для course_id, который не найден. Опять же, это сделает Num_years NULL, поэтому нам нужна проверка для этого в нашем триггере.

insert into modules set module_id=2, course_id=5, course_year=99;
ERROR 1644 (45000): course_year is larger than the course length
...