【问题标题】:PREPARED STATEMENT in a WHILE loopWHILE 循环中的准备好的语句
【发布时间】:2012-07-07 20:21:33
【问题描述】:

我有一个表autos 有一个列name,我想检查表中的前5 行,如果name 的值是"toyota",在表mytable 中写“是”,否则写“不”。 我写了存储过程,但是mysqli_error() 在行中返回错误,我有EXECUTE ...

如果在WHEN 中我写的不是PREPARED STATEMENT,而是直接查询,则程序有效。 请查看我的代码并告诉我,哪里出错了?

CREATE PROCEDURE proc_auto()
BEGIN

DECLARE start INT;
SET start = 0;
PREPARE stmt FROM  ' SELECT name FROM autos ORDER BY id LIMIT ?,1 ';

WHILE start < 5 DO

    CASE 
        WHEN (EXECUTE stmt USING @start ) = 'toyota'
            THEN INSERT INTO mytable (log)  VALUES('yes');
        ELSE 
           INSERT INTO mytable (log)  VALUES('no');
    END CASE;
    SET start = start + 1;

END WHILE;
END;

【问题讨论】:

  • 14 个问题,没有一个被接受的答案。我不会写答案。见how-it-works
  • 你用的是什么版本的 MySQL?
  • 一切都明白了,我不知道这个服务,我不偷懒说“谢谢”:)
  • 距您上次发表评论已有两年时间,但仍然没有被接受的答案? :|

标签: mysql stored-procedures while-loop prepared-statement


【解决方案1】:

(关于EXECUTE 的建议被删除,因为它不正确且可能令人困惑。)

您尝试使用存储过程解决的问题实际上可以在没有它的情况下解决,使用完全不同的方法:只需使用单个 INSERT ... SELECT 语句代替:

INSERT INTO mytable (log)
SELECT
  CASE name
    WHEN 'toyota' THEN 'yes'
    ELSE 'no'
  END
FROM autos
ORDER BY id
LIMIT 5

也就是说,上述语句的作用与您的存储过程相同:它从autos 检索前5 行并将5 行插入mytable。根据name 的值,它会生成yeses 或nos。

【讨论】:

  • EXECUTE stmt USING start 帮不了我,当然感谢您的变体,INSERT ... SELECT 语句非常简单,但我想要了解如何在循环 WHILE 中使用 PREPARED STATEMENT 并在此写入存储过程:)
  • 哦,我明白了。也许你当时不应该接受我的回答。请考虑不接受它,然后使用您在执行存储过程时收到的实际错误消息更新您的问题。我无法真正回答您的直接问题,但也许其他人可以。但是,请再次确保您不接受我的回答,否则如果人们看到您的问题已被接受,他们可能没有足够的兴趣来查看您的问题。 (要不接受答案,只需点击旁边的绿色复选标志。)
  • 无论出于何种原因,EXECUTE 函数只能接受以@ 字符为前缀的变量,因此EXECUTE stmt USING start 将失败。
  • @RossSmithII。谢谢。我想知道是不是你否决了我的回答。您认为(如果不是您,则“可能”)有什么特别错误的地方值得一票否决?
  • 建议一些实际上不起作用的东西 (EXECUTE ... start) 会让人们感到困惑。您的其余答案很有帮助,因此请删除第一个建议。
【解决方案2】:

Andriy M 的INSERT 语句是最优雅的解决方案,但如果您仍想使用过程,这将起作用:

CREATE PROCEDURE proc_auto()
BEGIN
    DECLARE start INT DEFAULT 0;

    PREPARE stmt FROM 
        'SELECT name INTO @name FROM autos ORDER BY id LIMIT ?,1';

    WHILE start < 5 DO
        SET @start = start;
        EXECUTE stmt USING @start;
        IF @name = 'toyota' THEN
            INSERT INTO mytable (log)  VALUES('yes');
        ELSE 
            INSERT INTO mytable (log)  VALUES('no');
        END IF;
        SET start = start + 1;
    END WHILE;
END;

但是,在这种情况下,使用 CURSOR 会产生更好的性能:

CREATE PROCEDURE proc_auto()
BEGIN
    DECLARE start INT DEFAULT 0;
    DECLARE b_not_found BOOL DEFAULT FALSE;

    DECLARE cur CURSOR FOR
        'SELECT name FROM autos ORDER BY id LIMIT 5';

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET b_not_found = TRUE;

    OPEN cur;

    loop1: WHILE start < 5 DO
        FETCH cur INTO @name;
        IF b_not_found THEN
            LEAVE loop1;
        END IF;

        IF @name = 'toyota' THEN
            INSERT INTO mytable (log)  VALUES('yes');
        ELSE 
            INSERT INTO mytable (log)  VALUES('no');
        END IF;
        SET start = start + 1;
    END WHILE;

    CLOSE cur;
END;

【讨论】:

    猜你喜欢
    • 2010-10-05
    • 2018-08-29
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多