Хранимые процедуры MYSQL: декларация переменных и условные выражения

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

Я пытаюсь создать хранимую процедуру с помощью phpMyAdmin.

Я не могу найти здесь ошибки, ошибки sql настолько туманны...

CREATE PROCEDURE insertToonOneShot(IN locale CHAR(2), IN name VARCHAR(16), IN realm VARCHAR(24), IN faction CHAR(1), IN toon_level INT, IN class_name INT)
BEGIN
DECLARE @realmID INT;
DECLARE @classID INT;
DECLARE @toonID INT;
SET @realmID = SELECT id FROM realms WHERE realms.name = realm;
SET @classID = SELECT id FROM classes WHERE classes.name = class_name;
IF NOT @realmID IS NULL AND NOT @classID IS NULL AND @toonID IS NULL THEN
INSERT INTO 
toon (`locale`, `name`, `realm_id`, `faction`, `level`, `class_id`)
VALUES
(locale, name, @realmID, faction, toon_level, @classID);
END IF;
END;

Ошибка, которую я получаю прямо сейчас:

# 1064 - У вас есть ошибка в синтаксисе SQL; проверьте руководство, которое соответствует вашей версии сервера MySQL для правильного синтаксиса для использования рядом с @realmID INT; DECLARE @classID INT; DECLARE @toonID INT; SET @rea в строке 3

Возможно, одна из самых неприятных вещей, которые мне когда-либо приходилось делать...

Я видел много обучающих онлайн, которые показывают использование символа @в объявлении переменной, а другие не используют его, я даже видел некоторых, которые используют VAR вместо DECLARE. Что такое правильный синтаксис?...

Ответ 1

Это трюк:

CREATE PROCEDURE insertToonOneShot(IN locale CHAR(2), IN name VARCHAR(16), IN realm VARCHAR(24), IN faction CHAR(1), IN toon_level INT, IN class_name VARCHAR(12))
BEGIN
SELECT @realmID := id FROM realms WHERE realms.name = realm;
SELECT @classID := id FROM classes WHERE classes.name = class_name;
SELECT @toonID := id FROM toon WHERE toon.name = name AND toon.realm_id = @realmID;
IF NOT @realmID IS NULL AND NOT @classID IS NULL AND @toonID IS NULL
THEN 
INSERT INTO toon (`locale`, `name`, `class_id`, `realm_id`, `faction`, `level`)
VALUES (locale, name, @classID, @realmID, faction, toon_level);
END IF;
END;
//

По-видимому, заявления декларации не требовались... Кто бы мог знать?

Спасибо Гордону Линоффу за то, что он указал мне в правильном направлении.

Ответ 2

Когда у вас есть подзапрос, он должен иметь круглые скобки. Эти строки:

SET @realmID = SELECT id FROM realms WHERE realms.name = realm;
SET @classID = SELECT id FROM classes WHERE classes.name = class_name;

Должно быть:

SET @realmID = (SELECT id FROM realms WHERE realms.name = realm);
SET @classID = (SELECT id FROM classes WHERE classes.name = class_name);

Или, еще лучше, вам не нужен set:

SELECT @realmID := id FROM realms WHERE realms.name = realm;
SELECT @classID := id FROM classes WHERE classes.name = class_name;

Ответ 3

Старый вопрос, но я думаю, что стоит упомянуть, что он, кажется, путают переменные сеанса, которые имеют префикс @, с процедурными переменными, которые не являются.

Принятое решение разрешает ошибку, но может вводить проблемы, связанные с областью переменных, если переменная определена вне процедуры и затем используется внутри. Правильный способ разрешить это - использовать только процедурные переменные:

DELIMITER $$

CREATE PROCEDURE insertToonOneShot(
    IN locale CHAR(2),
    IN name VARCHAR(16),
    IN realm VARCHAR(24),
    IN faction CHAR(1),
    IN toon_level INT,
    IN class_name INT
)
BEGIN
    DECLARE realmID INT;
    DECLARE classID INT;

    SELECT id INTO realmID FROM realms WHERE realms.name = realm LIMIT 1;
    SELECT id INFO classID FROM classes WHERE classes.name = class_name LIMIT 1;
    IF realmID IS NOT NULL AND classID IS NOT NULL THEN
        INSERT INTO toon (`locale`, `name`, `realm_id`, `faction`, `level`, `class_id`)
        VALUES (locale, name, realmID, faction, toon_level, classID);
    END IF;
END$$

DELIMITER ;