【问题标题】:How to call a stored procedure within another stored procedure (PHP and mysqli)如何在另一个存储过程中调用一个存储过程(PHP 和 mysqli)
【发布时间】:2014-06-05 10:38:47
【问题描述】:

我正在努力在另一个存储过程中调用一个存储过程。就像现在存储过程永远不会将 SELECT 语句作为结果返回给 PHP 中的 mysqli 调用(但它在 MySQL 工作台中工作正常)。

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `new_bid`(IN bid_in decimal(6,2),
                                                      IN ticker_in varchar(5),
                                                      IN share_amount_in BIGINT)
BEGIN

    DECLARE company_id_var INT;
    DECLARE highest_bid BIT;
    DECLARE generated_bid_id BIGINT;

    SET company_id_var = (SELECT ID
                      FROM Companies
                      WHERE Ticker = ticker_in);

    -- Put the bid into the Bids table.
    INSERT INTO Bids(company_id,bid,share_amount)
    VALUES (company_id_var,bid_in,share_amount_in);

    SET generated_bid_id = LAST_INSERT_ID();

    CALL check_available_shares(bid_in,share_amount_in,generated_bid_id,@shares_left);

    -- Check if the bid is higher than the current highest bid.
    -- If so update the CurrentState table to have the new value.
    UPDATE CurrentState SET buyer = bid_in
                        WHERE ID = company_id_var
                        AND buyer < bid_in;

    IF (ROW_COUNT() = 1)
     THEN
     SELECT 1 AS highest_bid, @shares_left AS shares_left, CS.buyer, CS.seller, CS.last_price, CO.name,  CO.ticker
     FROM CurrentState CS, Companies CO
     WHERE CS.id = CO.id
     AND CO.ticker = ticker_in;
    ELSE
     SELECT 0 AS highest_bid, @shares_left AS shares_left, CS.buyer, CS.seller, CS.last_price, CO.name,  CO.ticker
     FROM CurrentState CS, Companies CO
     WHERE CS.id = CO.id
     AND CO.ticker = ticker_in;
    END IF;
END

如果我从这个存储过程中删除“CALL”函数,它将返回底部的 SELECT 语句之一,但如果我保留“CALL”函数,它不会返回任何内容。 我曾尝试使用 exec 并执行,但是当我尝试将过程保存在 MySQL 工作台中时,这只会给我语法错误。此问题与https://stackoverflow.com/questions/23193085/mysqli-does-not-return-any-results-but-stored-procedure-does 有关。 但似乎这个问题可能与mysqli如何处理存储过程的执行有关,因为当我在mySQL workbench中手动调用存储过程时它工作正常(?)

【问题讨论】:

    标签: php mysqli mysql-workbench


    【解决方案1】:

    在用头撞墙数小时后,我找到了解决方案。由于这个存储过程调用了另一个使用游标的存储过程,我不得不使用$mysqli-&gt;multi_query() 函数。以下是我的工作方式:

    new_bid 存储过程:

    -- --------------------------------------------------------------------------------
    -- Routine DDL
    -- Note: comments before and after the routine body will not be stored by the server
    -- --------------------------------------------------------------------------------
    DELIMITER $$
    
    CREATE DEFINER=`root`@`localhost` PROCEDURE `new_bid`(IN bid_in decimal(6,2),
                                                          IN ticker_in varchar(5),
                                                          IN share_amount_in BIGINT)
    BEGIN
    
        -- Store the company ID into a variable as this value will used more than once.
        DECLARE company_id_var INT;
        DECLARE ParamtoPass INT;
        DECLARE highest_bid BIT;
        DECLARE generated_bid_id BIGINT;
    
        SET company_id_var = (SELECT ID
                          FROM Companies
                          WHERE Ticker = ticker_in);
    
        -- Put the bid into the Bids table.
        INSERT INTO Bids(company_id,bid,share_amount)
        VALUES (company_id_var,bid_in,share_amount_in);
    
        SET generated_bid_id = LAST_INSERT_ID();
        -- EXECUTE check_available_shares bid_in, @share_amount_in,@generated_bid_id,@shares_left;
        CALL check_available_shares (bid_in,@share_amount_in,generated_bid_id,@shares_left);
    
        -- Check if the bid is higher than the current highest bid.
        -- If so update the CurrentState table to have the new value.
        UPDATE CurrentState SET buyer = bid_in
                            WHERE ID = company_id_var
                            AND buyer < bid_in;
    
        IF (ROW_COUNT() = 1)
         THEN
         SELECT 1 AS highest_bid, @shares_left AS shares_left, CS.buyer, CS.seller, CS.last_price, CO.name,  CO.ticker
         FROM CurrentState CS, Companies CO
         WHERE CS.id = CO.id
         AND CO.ticker = ticker_in;
        ELSE
         SELECT 0 AS highest_bid, @shares_left AS shares_left, CS.buyer, CS.seller, CS.last_price, CO.name,  CO.ticker
         FROM CurrentState CS, Companies CO
         WHERE CS.id = CO.id
         AND CO.ticker = ticker_in;
        END IF;
    END
    

    check_available_shares 程序:

    -- --------------------------------------------------------------------------------
    -- Routine DDL
    -- Note: comments before and after the routine body will not be stored by the server
    -- --------------------------------------------------------------------------------
    DELIMITER $$
    
    CREATE DEFINER=`root`@`localhost` PROCEDURE `check_available_shares`(IN bid_in decimal(6,2),
                                                                         IN share_amount_in int,
                                                                         IN bid_id bigint,
                                                                         OUT shares_left BIT)
    BEGIN
        DECLARE num_shares INT;
        DECLARE selling_id INT;
        DECLARE selling_price DECIMAL(6,2);
        DECLARE done INT DEFAULT FALSE;
    
        DECLARE cur CURSOR FOR SELECT share_amount,sell_price,ID
                               FROM ShareSell
                               WHERE sell_price <= bid_in
                               ORDER BY sell_price ASC, sell_timestamp ASC;
    
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    
        OPEN cur;   /* open cursor */
    
        read_loop: LOOP
            FETCH NEXT FROM cur
                       INTO num_shares, selling_price, selling_id;
    
            IF (done) THEN
                LEAVE read_loop;
            END IF;
    
            IF ((share_amount_in - num_shares) > 0) THEN
                SET share_amount_in = (share_amount_in - num_shares);
    
                DELETE FROM ShareSell
                       WHERE ID = selling_id;
            ELSEIF((share_amount_in - num_shares) < 0) THEN
                UPDATE ShareSell
                SET share_amount = (share_amount - share_amount_in)
                WHERE ID = selling_id;
    
                DELETE FROM Bids
                WHERE ID = bid_id;
    
                LEAVE read_loop;
            ELSE
                DELETE FROM ShareSell
                       WHERE ID = selling_id;
    
                DELETE FROM Bids
                       WHERE ID = bid_id;
            END IF;
    
            SELECT num_shares,selling_price;
        END LOOP;
    
        CLOSE cur;
    
        IF (share_amount_in > 0) THEN
            UPDATE Bids
            SET share_amount = share_amount_in
            WHERE ID = bid_id;
            SET shares_left = 1;
        ELSE
            SET shares_left = 0;
        END IF;
    END
    

    最后是 PHP 调用:

    $bid = 43.10;
    $ticker = "GOS";
    $share_amount = 1000;
    
    if ($mysqli->multi_query("CALL new_bid($bid,'$ticker',$share_amount)"))
    {
     if ($result = $mysqli->store_result())
     {
       while ($row = $result->fetch_assoc())
       {
         print_r($row);
       }
    
       $result->close();
     }
    }
    

    【讨论】:

      【解决方案2】:

      谢谢!这也正是我的问题。我也因一个完全相同的问题而崩溃(见PHP mysqli is NOT trapping some errors when calling stored procedure)。你的帖子帮我解决了问题!

      我也遇到过 PHP 调用 SP1 的情况,后者又调用 SP2,并且在 mysql 客户端中一切正常,但在被 PHP 调用时中断!事实上,我在 SP2 中也有一个 结果集 的 SELECT。我的问题症状和你的完全一样,我从来没有使用过multi_query()。

      我注意到您还在check_available_shares 中选择了一个“结果集*”(参见SELECT num_shares,selling_price; 行)。不知道为什么您有此行。如果您删除该行,我怀疑您应该能够执行@ 987654325@ 而不是 multi_query()。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-14
        • 2014-09-17
        • 2011-05-08
        • 1970-01-01
        • 2013-03-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多