Могу ли я сравнить значения двух столбцов в триггере «перед вставкой»?

#mysql #sql

Вопрос:

Я пытаюсь создать триггер, при котором вставка останавливается, если разница между двумя значениями из двух разных таблиц составляет определенную величину.

У меня есть столик с людьми и столик с покупками.

 create table person(
    ssid                char(10),
    name                varchar(30),
    birthyear           year,
primary key (ssid)
)engine=innodb;

create table purchase(
    personssid          char(10),
    purchaseid          integer,
    yearpurchased       year,
    itemid              integer,
    itemname            varchar(20),
primary key(personssid, purchaseid),
foreign key(personssid) references person(ssid)
)engine=innodb;
 

То, что я пробовал до сих пор:

 delimiter //
create trigger age before insert on purchase
for each row begin
    if (((select distinct yearpurchased from purchase where personssid=new.personssid)
       -
       (select distinct birthyear from person where ssid=new.personssid)<18)) then
        signal sqlstate '45000' set message_text='people under 18 are not allowed to make purchases.';
    end if;
end//
delimiter ;
 

Код ошибки: 1242 — Подзапрос возвращает более 1 строки

 delimiter //
create trigger age before insert on purchase
for each row begin
    declare yearpurchased year;
    declare birthyear year;
    
    select yearpurchased from purchase where new.personssid in(select birthyear from person where ssid=new.personssid) into yearpurchased;
    select birthyear from person where new.personssid in(select yearpurchased from purchase where personssid=new.personssid) into birthyear;
    if (yearpurchased-birthyear<18)) then
        signal sqlstate '45000' set message_text='people under 18 are not allowed to make purchases.';
    end if;
end//
delimiter ;
 

Код ошибки: 1172 — Результат состоял из более чем одной строки

Поэтому то, что я пытаюсь сделать в своем триггере, — это предотвратить вставку в таблицу покупок, если вставляемому лицу меньше 18 лет.

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

Спасибо.

ИЗМЕНИТЬ: Решение:

 delimiter //
create trigger age before insert on purchase
for each row begin
    declare years year;
    select birthyear from person where ssid=new.personssid into years;
    if (new.yearpurchased-years<18) then
        signal sqlstate '45000' set message_text='people under 18 are not allowed to make purchases.';
    end if;
end//
delimiter ;
 

Комментарии:

1. SQL — это все о наборах. С помощью SELECT вы описываете набор строк из таблицы. То, как вы используете SELECT в своем коде, каждый набор должен содержать ровно один элемент. Но ваши избранные получают более одного элемента. Это подсказка о том, как решить вашу проблему.

2. Так ли это в обоих примерах?

3. ДА. Посмотри на это. dev.mysql.com/doc/refman/8.0/en/select-into.html Будьте терпеливы. Ты сам во всем разберешься. Но попробуйте разобраться в этом, запустив свой выбор в интерактивном режиме. Отладка сохраненного кода-это огромная боль в шее xxs.

4. Я попробовал альтернативный метод, и сейчас я не получаю никаких ошибок, но это не останавливает вставку. Я поместил новый код в исходное сообщение в качестве правки. Я не знаю, как прокомментировать код в комментариях. Это было слишком долго. Сейчас я смотрю на вашу ссылку, пытаясь понять, ха-ха.

5. Оба триггера недопустимы. На таблицу, которая запускает триггер, нельзя ссылаться (для чтения или записи) внутри самого триггера. Вторая попытка запроса триггера была немного хуже, так как вы не можете ссылаться на ту же таблицу в подзапросе, который используется во внешнем запросе.