【问题标题】:Called MySQL Stored Procedure via PHP does not execute properly通过 PHP 调用的 MySQL 存储过程无法正确执行
【发布时间】:2019-05-18 02:54:46
【问题描述】:

这个问题让我很困惑,我希望解决方案是“你知道为什么这不起作用,不是吗?”回复类型。

这里是:我通过 PHP 调用 MySQL 存储过程:

$sql = "CALL sp_test;";
$mysqli->query($sql);

那里没问题。我知道存储过程被执行。

这是我为本示例条带化的存储过程,它仍然产生同样的问题。

DELIMITER \\
DROP PROCEDURE IF EXISTS sp_test\\

CREATE PROCEDURE sp_test()
DETERMINISTIC

BEGIN
DECLARE exit_loop TINYINT(1) DEFAULT 0;
DECLARE v_TableName VARCHAR(50); DECLARE v_ScanID INT(11); DECLARE v_ScanType TINYINT(4); 
    DECLARE v_TitleID INT(11); DECLARE v_VolumeNo INT(11); DECLARE v_IssueNo VARCHAR(10); DECLARE v_IssueDate INT(11); DECLARE v_FIDateUnknown TINYINT(4); DECLARE v_PureHavocScan TINYINT(4);

-- declare cursor for employee email
DECLARE storeroom_cursor CURSOR FOR SELECT TableName, ScanID, ScanType, FIDateUnknown, TitleID, VolumeNo, REPLACE(IssueNo, "\'", "") AS IssueNo, IssueDate FROM t_storeroom ts JOIN t_issueguide tig ON ts.TitleID = tig.ComicTitleID;

-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;

OPEN storeroom_cursor;

get_purehavoc: LOOP

    FETCH storeroom_cursor INTO v_TableName, v_ScanID, v_ScanType, v_FIDateUnknown, v_TitleID, v_VolumeNo, v_IssueNo, v_IssueDate;

    IF exit_loop = TRUE THEN 
        LEAVE get_purehavoc;
    END IF;

            CASE v_ScanType

                WHEN '1' AND v_FIDateUnknown = 0 THEN
                    SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND IssueDate = ", v_IssueDate, " AND DiggerExclusive = 1;");

                WHEN '1' AND v_FIDateUnknown = 1 THEN
                    SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND DiggerExclusive = 1;");

                -- WHEN '2' THEN
                    -- Do something

            END CASE;

            PREPARE statement FROM @sql_text;
            EXECUTE statement;  

            -- Setting the PureHavocScan variable to enter into the PREPARE STATEMENT.
            IF @RowCount = 0 THEN 
                SET @PureHavocScan = 1;
            ELSE                    
                SET @PureHavocScan = 0;
            END IF;

            SET @ScanID = v_ScanID;
            SET @TableName = v_TableName;

            -- SET @sql_text = concat("UPDATE t_storeroom SET PureHavocScan = ? WHERE TableName = ? AND ScanID = ? ");
            SET @sql_text = concat("UPDATE t_storeroom SET PureHavocScan = ", @PureHavocScan, " WHERE TableName = '", @TableName, "' AND ScanID = ", @ScanID, ";");
            PREPARE statement FROM @sql_text;
            EXECUTE statement;

END LOOP get_purehavoc;

DEALLOCATE PREPARE stmt;
CLOSE storeroom_cursor; 
END//
DELIMITER ;

当我在我的 MySQL 数据库管理工具(在我的例子中是 Navicat)中运行这个确切的存储过程时,存储过程 100% 按预期工作,并且所有应该更新的行都得到更新。

但是,当我通过 PHP 运行这个确切的存储过程时,只有 1(有时 2)行得到更新。

以完全相同的方式调用的其他存储过程可以正常工作。就这一个。与失败的唯一区别是 MySQL 命令是 UPDATE,而不是正常工作的 SELECTS 和 INSERTS。

我已经在这里工作了两天,并且已经用尽了所有“我的”知识。因此,如果有人能让我摆脱痛苦,我将不胜感激。

【问题讨论】:

  • 如何确定只有一(或有时是两)行得到更新?
  • CASE 语句不正确。
  • 小心更新您的光标正在迭代的表stackoverflow.com/questions/30365427/…
  • Ro Achterberg - 当我通过我的“数据库管理工具”运行相同的程序时,我收到了所有“预期”的结果(即 100 多行得到正确更新)。但是在执行 PHP CALL 命令之后,有问题的表只会更新“1”行。另一个“不同”表可能会更新“2”行。我使用了很多表,并且成功的未注明日期的行数永远不会超过“2”。我开始认为问题正在发生,因为我正在更新我正在迭代的表(正如 LUFC 所建议的那样。
  • lufc - 我调查了您的“迭代游标”建议(即 INSENSITIVE 和 ASENSITIVE 游标)。我什至尝试创建一个新的临时表并使用新信息对其进行更新,但它仍然以完全相同的方式失败。极好的!可以在每次迭代中更新的行只会更新自身,不会更新其他行。所以表不能以某种方式重新排序自己,就像更新正在迭代的表时可能发生的那样。必须有其他一些我在这里根本看不到的东西。不过感谢您的建议。

标签: php mysql stored-procedures


【解决方案1】:

CASE 声明不正确:

        CASE v_ScanType

            WHEN '1' AND v_FIDateUnknown = 0 THEN
                SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND IssueDate = ", v_IssueDate, " AND DiggerExclusive = 1;");

            WHEN '1' AND v_FIDateUnknown = 1 THEN
                SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND DiggerExclusive = 1;");

            -- WHEN '2' THEN
                -- Do something

        END CASE;

CASE <expression> WHEN <condition> THEN ...CASE WHEN (<expression>) = (<condition>) THEN ... 的快捷方式。因此,您的代码不是将v_ScanType'1''2' 进行比较,而是将其与('1' AND v_FIDateUnknown = 0) 进行比较。所以它只是将变量与TRUEFALSEv_FIDateUnknown 比较的结果进行比较。

你需要在没有快捷方式的情况下编写它。

        CASE

            WHEN v_ScanType = '1' AND v_FIDateUnknown = 0 THEN
                SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND IssueDate = ", v_IssueDate, " AND DiggerExclusive = 1;");

            WHEN v_ScanType = '1' AND v_FIDateUnknown = 1 THEN
                SET @sql_text = CONCAT("SELECT @RowCount := COUNT(*) FROM ", v_TableName, " WHERE ComicTitleID = ", v_TitleID, " AND VolumeNo = ", v_VolumeNo, " AND IssueNo = '", v_IssueNo, "' AND DiggerExclusive = 1;");

            -- WHEN v_ScanType = '2' THEN
                -- Do something

        END CASE;

我不确定为什么这只会在您从 PHP 调用该过程时导致它失败。也许这只是一个巧合。但是很难解释一个有如此明显错误的程序。

【讨论】:

  • 我按照 Barmar 的建议更改了 CASE 语句,但不幸的是,它仍然以完全相同的方式失败。不过感谢 CASE 的提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 2014-09-30
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-06
相关资源
最近更新 更多