简体   繁体   English

如何在另一个存储过程(PHP和mysqli)中调用存储过程

[英]How to call a stored procedure within another stored procedure (PHP and mysqli)

I am struggling to call a stored procedure within another stored procedure. 我正在努力在另一个存储过程中调用存储过程。 Like it is now the stored procedure never return the SELECT statement back as a result to the mysqli call in PHP (but it works fine in MySQL workbench). 就像现在一样,存储过程从不将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

If I remove the "CALL" function from this stored procedure it returns one of the SELECT statement at the bottom, but if I keep the "CALL" function it does not return anything. 如果我从该存储过程中删除了“ CALL”函数,它将在底部返回SELECT语句之一,但是如果我保留了“ CALL”函数,它将不返回任何内容。 I have tried with exec and execute but that only gives me syntax error when I try to save the procedure within MySQL workbench. 我已经尝试使用exec和execute,但是当我尝试在MySQL工作台中保存过程时,这只会给我语法错误。 This problem is related to https://stackoverflow.com/questions/23193085/mysqli-does-not-return-any-results-but-stored-procedure-does . 该问题与https://stackoverflow.com/questions/23193085/mysqli-does-not-return-any-results-but-stored-procedure-does有关。 But it seems that that problem may be related to how mysqli handles the execution of the stored procedure since it works fine when I call the stored procedure manually in mySQL workbench(?) 但是似乎该问题可能与mysqli如何处理存储过程的执行有关,因为当我在mySQL workbench(?)中手动调用存储过程时,它可以正常工作

After hours of banging my head against a wall I found a solution. 在将我的头撞在墙上数小时之后,我找到了解决方案。 Since this stored procedure calls another stored procedure which uses a cursor I had to use the $mysqli->multi_query() function. 由于此存储过程调用了另一个使用游标的存储过程,因此我不得不使用$mysqli->multi_query()函数。 Here's how I got it working: 这是我的工作方式:

new_bid stored procedure: 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 procedure: 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

And finally the PHP call: 最后是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();
 }
}

Thanks! 谢谢! This was exactly my problem too. 这也是我的问题。 I too broke my head on an exact similar problem (see PHP mysqli is NOT trapping some errors when calling stored procedure ). 我也完全解决了一个类似的问题(请参阅PHP mysqli在调用存储过程时未捕获某些错误 )。 Your post helped me solve my problem! 您的帖子帮助我解决了我的问题!

I too had a case of PHP calling SP1, which in turn called SP2, and everything working fine in a mysql client but breaking when called by PHP! 我也有一个用PHP调用SP1的案例,该实例又调用了SP2,并且一切在mysql客户端中都可以正常工作,但是在被PHP调用时会中断! And indeed, I too had had a SELECT of a result set in SP2. 确实,我在SP2中也有一个结果集的SELECT。 And my problem symptoms were exactly identical to yours, and it never struck me to use multi_query() . 而且我的问题症状与您的症状完全相同,并且使用multi_query()从未使我multi_query()

I notice that you also SELECT a "result set* in check_available_shares (see line SELECT num_shares,selling_price; ). Not sure why you have this line. If you remove that line, I suspect you should be able to do a query() instead of multi_query() . 我注意到您还在check_available_shares选择了一个“结果集*”(请参见SELECT num_shares,selling_price;SELECT num_shares,selling_price; )不确定为什么要有此行。如果删除该行,我怀疑应该可以执行query() multi_query()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM