Как заставить 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;

см. также: https://dba.stackexchange.com/questions/78594/how-to-conditionally-raise-an-error-in-mysql-without-stored-procedure