7

是否可以将准备好的语句的结果设置为变量?我试图创建下面的存储过程,但它失败:如何从准备好的语句中获得标量结果?

31行错误1064(42000):您的SQL语法错误;检查与你的MySQL服务器版本相对应的手册,在'stmt USING @m,@c,@a;

DROP PROCEDURE IF EXISTS deleteAction; 

DELIMITER $$ 
CREATE PROCEDURE deleteAction(
    IN modul CHAR(64), 
    IN controller CHAR(64), 
    IN actn CHAR(64)) 

MODIFIES SQL DATA 

BEGIN 

    PREPARE stmt FROM 'SELECT id 
         FROM actions 
         WHERE `module` = ? 
          AND `controller` = ? 
          AND `action` = ?'; 

    SET @m = modul; 
    SET @c = controller; 
    SET @a = actn; 

    SET @i = EXECUTE stmt USING @m, @c, @a; 

    DEALLOCATE PREPARE stmt; 

    DELETE FROM acl WHERE action_id = @i; 
    DELETE FROM actions WHERE id = @i; 

END 
$$ 
DELIMITER ; 

回答

6

它可能看起来很奇怪,但你可以变量直接在准备好的声明字符串赋值:

PREPARE stmt FROM 'SELECT @i := id FROM ...'; 

-- ... 

EXECUTE stmt USING @m, @c, @a; 

-- @i will hold the id returned from your query. 

测试用例:

CREATE TABLE actions (id int, a int); 

INSERT INTO actions VALUES (1, 100); 
INSERT INTO actions VALUES (2, 200); 
INSERT INTO actions VALUES (3, 300); 
INSERT INTO actions VALUES (4, 400); 
INSERT INTO actions VALUES (5, 500); 

DELIMITER $$ 
CREATE PROCEDURE myProc(
    IN p int 
) 

MODIFIES SQL DATA 

BEGIN 

    PREPARE stmt FROM 'SELECT @i := id FROM actions WHERE `a` = ?'; 

    SET @a = p; 

    EXECUTE stmt USING @a; 

    SELECT @i AS result; 

    DEALLOCATE PREPARE stmt; 

END 
$$ 
DELIMITER ; 

结果:

CALL myProc(400); 

+---------+ 
| result | 
+---------+ 
|  4 | 
+---------+ 
1 row in set (0.00 sec) 
+0

啊!当然!! – 2010-10-21 22:37:41

+0

我知道这个答案是非常古老的,但任何人都可以告诉我:当我使用这段代码并使用CALL myProc(600)时,它不返回空查询结果,而是返回最后一次“有效”调用。为什么是这样的,我该如何改变这一点?当我传递一个不在表中的值时,它应该将'result'返回为空。 – Meelah 2017-10-18 15:11:41

1

甚至不知道你为什么使用动态SQL在你的榜样 - 这似乎简单得多

drop procedure if exists deleteAction; 

delimiter # 

create procedure deleteAction 
(
in p_modul char(64), 
in p_controller char(64), 
in p_actn char(64) 
) 
begin 

declare v_id int unsigned default 0; 

    select id into v_id from actions where 
      module = p_modul and controller = p_controller and action = p_actn; 

    delete from acl where action_id = v_id; 
    delete from actions where id = v_id; 

    select v_id as result; 

end # 

delimiter ; 

call deleteAction('mod','ctrl','actn'); 
2

使用此代码

PREPARE stmt FROM 'SELECT ''a'' into @i' ; 

EXECUTE stmt; 

if(@i='a') then 
............ 
end if;