web-dev-qa-db-fra.com

Procédures stockées MYSQL: déclaration de variable et instructions conditionnelles

J'ai parcouru de nombreux tutoriels, manuels et documentations, mais je n'arrive toujours pas à faire fonctionner cela.

J'essaie de créer une procédure stockée à l'aide de phpMyAdmin.

Je n'arrive pas à trouver les erreurs ici, les erreurs sql sont si vagues ...

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;

L'erreur que je reçois en ce moment est:

# 1064 - Vous avez une erreur dans votre syntaxe SQL; consultez le manuel qui correspond à la version de votre serveur MySQL pour la bonne syntaxe à utiliser près de @realmID INT; DECLARE @classID INT; DECLARE @toonID INT; SET @rea à la ligne 3

Probablement l'une des choses les plus frustrantes que j'ai jamais eu à faire ...

J'ai vu de nombreux tutoriels en ligne qui montrent l'utilisation du symbole @ dans la déclaration de variable, et d'autres ne l'utilisant pas, j'en ai même vu certains qui utilisent VAR au lieu de DECLARE. Quelle est la bonne syntaxe? ...

12
Vigs

Cela fait l'affaire:

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

Apparemment, les déclarations de déclaration n'étaient pas nécessaires ... Qui aurait su?

Merci à Gordon Linoff de m'avoir pointé dans la bonne direction.

9
Vigs

Lorsque vous avez une sous-requête, elle doit avoir des parenthèses. Ces lignes:

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

Devrait être:

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

Ou, mieux encore, vous n'avez pas besoin du set:

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

Vieille question, mais je pense qu'il vaut la peine de mentionner qu'il semble être source de confusion pour les variables de session, qui sont préfixées par @, avec des variables procédurales, qui ne le sont pas.

La solution acceptée résout l'erreur, mais pourrait introduire des problèmes liés à la portée des variables, si une variable est définie en dehors de la procédure, puis utilisée à l'intérieur. La bonne façon de résoudre ce problème consiste à utiliser uniquement des variables procédurales:

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 ;
9
miken32