16

我查看了许多教程、手册和文档,但我仍然无法让它工作。

我正在尝试使用 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 附近使用的正确语法;声明@classID INT;声明@toonID INT;在第 3 行设置 @rea

可能是我不得不做的最令人沮丧的事情之一......

我在网上看到很多教程显示在变量声明中使用 @ 符号,还有一些没有使用它,我什至看到一些使用 VAR 而不是 DECLARE。什么是正确的语法?...

4

3 回答 3

15

老问题,但我认为值得一提的是,它似乎混淆了以 为前缀的会话变量和@没有的过程变量。

公认的解决方案解决了错误,但如果变量在过程外部定义然后在内部使用,则可能会引入与变量范围相关的问题。解决此问题的正确方法是仅使用过程变量:

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 INTO 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 ;
于 2016-01-15T19:33:30.620 回答
12

When you have a subquery, it needs to have parentheses. These lines:

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

Should be:

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

Or, better yet, you don't need the set:

SELECT @realmID := id FROM realms WHERE realms.name = realm;
SELECT @classID := id FROM classes WHERE classes.name = class_name;
于 2013-09-16T15:49:08.813 回答
10

这可以解决问题:

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;
//

显然不需要声明语句......谁会知道?

感谢 Gordon Linoff 为我指明了正确的方向。

于 2013-09-16T18:19:59.067 回答