Mysql

除非 Select 語句為所有游標行返回結果,否則 Cursor 中的附加 Select 語句將終止循環

  • January 18, 2020

我有一個名為“held_toys”的簡單數據庫(持有的玩具是尚未出售的玩具),它由玩具的主鍵和外鍵組成。我有第二個表,名為“toys_on_sale”,它也只包含一個主鍵和一個玩具的外鍵。

我需要使用游標遍歷所有holded_toys,將尚未發售的Toys 插入到toys_on_sale 表中,並從holded_toys 中刪除任何已經發售的Toys。

在調試我的游標時,我注意到 LOOP 只會迭代一次,除非在 toys_on_sale 表中找到了held_toys 中的玩具(通過玩具 ID)。因此問題必須歸結為在我的循環中有以下 SELECT 語句:

DROP PROCEDURE IF EXISTS sp_Toys_On_Sale
$$
CREATE PROCEDURE `sp_Toys_On_Sale`(inToyIds text)
begin

DECLARE finished INTEGER DEFAULT 0; 
DECLARE heldId BIGINT;
DECLARE heldToyId BIGINT;
DECLARE existingSaleId BIGINT;

DECLARE curHeldToys
   CURSOR FOR
       select ht.ID, ht.TOY_ID
       from held_toys as ht
       where find_in_set(ht.TOY_ID,inToyIds);

   DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;

   OPEN curHeldToys;

   getHeldToys: LOOP

       SET existingSaleId = 0;

       FETCH curHeldToys INTO heldId, heldToyId;
       IF finished = 1 THEN
           LEAVE getHeldToys;
       END IF;

       #LOOP only runs once if heldToyId is not found (even though there are 500 records in held_toy), I want the loop to continue regardless if the select below returns no results
       select
           tos.ID
       from toys_on_sale tos
       where tos.TOY_ID = heldToyId INTO existingSaleId;

       IF existingSaleId > 0 THEN
           DELETE FROM held_toys WHERE ID = heldId;

       ELSE
           INSERT INTO toys_on_sale (TOY_ID) VALUES (heldToyId);

       END IF;

       DELETE FROM held_toys WHERE ID = heldId;

   END LOOP getHeldToys;
   CLOSE curHeldToys;


end
$$

我知道問題出在:

#LOOP only runs once if heldToyId is not found (even though there are 500 records in held_toy), I want the loop to continue regardless if the select below returns no results
       select
           tos.ID
       from toys_on_sale tos
       where tos.TOY_ID = heldToyId INTO existingSaleId;

但是我缺乏如何將這樣的 SELECT 嵌入到 CURSOR 中的知識,如果它返回零結果,則可以忽略它。而不是導致 CURSOR 停止循環..

任何幫助表示讚賞!

我做了一些研究,並找到了關於這種情況的官方指導。懷疑是 SELECT INTO 查詢導致的問題,這是因為它在第一個 BEGIN 和 END 語句的範圍內,該語句聲明了以下 HANDLER:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;

因此,當 SELECT INTO 沒有找到任何行時,finished 設置為 1,這是導致循環停止的條件。因此,要解決此問題,必須將 SELECT INTO 限定在其自己的 BEGIN 和 END 語句中,以允許將另一個 HANDLER 聲明為基本上忽略 NOT FOUND 條件。這應該是這樣的:

BEGIN 

       DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 0;

        select
           tos.ID
       from toys_on_sale tos
       where tos.TOY_ID = heldToyId INTO existingSaleId;

END;

現在,如果 SELECT INTO 語句沒有找到任何行,它將簡單地將完成設置為 0,這不會執行任何操作,因為只有在完成為 1 時循環才會終止。幸運的是,我們在另一個 BEGIN 和 END 語句中聲明的變數仍在此範圍內SELECT INTO 語句,我們可以按預期獲取這些 Id。

引用自:https://dba.stackexchange.com/questions/257684