#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. Оба триггера недопустимы. На таблицу, которая запускает триггер, нельзя ссылаться (для чтения или записи) внутри самого триггера. Вторая попытка запроса триггера была немного хуже, так как вы не можете ссылаться на ту же таблицу в подзапросе, который используется во внешнем запросе.