Как заставить MySQL бросить условное исключение времени выполнения в SQL
Я пишу тест миграции, чтобы убедиться, что пользователь был создан миграцией. Если пользователь не существует, тест должен выдать ошибку. Сначала я думал, что могу просто использовать деление на нулевую ошибку, чтобы получить то, что я хотел:
SET SESSION sql_mode = 'error_for_division_by_zero';
SELECT 1/COUNT(*) FROM mysql.user WHERE user = 'foo';
однако это не вызывает ошибки, если foo
не существует. Оказывается, что error_for_division_by_zero
влияет только INSERT
и UPDATE
заявления.
тогда я подумал, может быть, я мог бы просто вызвать некоторую функцию с помощью неверное количество аргументов:
SELECT IF(COUNT(*) = 1, 1, date_format(1, 2, 3))
FROM mysql.user WHERE user = 'foo';
но это умирает, даже когда foo
существует, предположительно, потому, что анализатор замечает неправильное количество параметров.
я мог бы написать функция, которая эмулирует создание исключения, но я пытался избежать этого. Нет ли способа заставить MySQL условно бросать исключение времени выполнения?
3 ответов
это невозможно сделать без хранимой процедуры или функции, к сожалению. Однако я понял, как поддерживать функцию в моем приложении. Заимствование основной идеи процедуры из ответ, Я придумал это:
DELIMITER |
CREATE FUNCTION checkit(doit INTEGER, message VARCHAR(256)) RETURNS INTEGER DETERMINISTIC
BEGIN
IF doit IS NULL OR doit = 0 THEN
SIGNAL SQLSTATE 'ERR0R' SET MESSAGE_TEXT = message;
END IF;
RETURN doit;
END;
|
идея в том, что функция может использоваться в триггерах, таких как CHECK
ограничение или встроенные операторы SQL. Возвращаясь к моей первоначальной необходимости бросить ошибку, если пользователь не существует, я теперь использую этот запрос возвращает целое число. Если пользователь не существует, он выдает ошибку с сообщением, определенные там.
хотите также использовать функцию для ограничения проверки? Он пример (подражая ответ), С кончиком шляпы к @rouland-bouman:
CREATE TRIGGER mytabletriggerexample BEFORE INSERT FOR EACH ROW
BEGIN
SET @dummy := checkit(
NEW.important_value) >= (fancy * dancy * calculation),
'Your meaningful error message goes here'
);
END;
Я бы предпочел использовать DO
, а не установка фиктивной переменной, но ошибка MySQL предупреждает, что от работы, увы.
Давид
зачем вам нужна процедура? Вы можете сигнализировать изнутри функции (и вы все еще можете вызвать функцию в триггере)
delimiter go
create function f_raise(p_message_text varchar(255))
returns int
begin
signal sqlstate '45000' set message_text = p_message_text;
return null;
end;
go
select f_raise('bla');
go
ERROR 1644 (45000): bla
вы можете создать исключение без функции / процедуры, просто извлекая столбец из таблицы с несколькими строками. Обычно в базе данных уже есть таблица для этого, но здесь я включил временную таблицу для этой цели:
drop temporary table if exists t;
create temporary table t (
select ('a'));
insert into t values('b');
select * from t;
select case when
2*2 = 4
then 'OK'
else (select a from t)
end;
select case when
2*2 = 5
then 'OK'
else (select a from t)
end;