Return 来自使用 CURSOR/LOOP 的存储过程的单个集合中的数据

Return data in the single set from stored procedure using CURSOR/LOOP

我想 return 单组数据,但是我在单行中得到 10 个不同的输出。我想在一组中有 10 行:

DROP TABLE IF EXISTS calendar;
DROP PROCEDURE IF EXISTS p_generate_snapshot;

CREATE TABLE calendar(date date);

INSERT INTO calendar(date) VALUES
('2020-11-01'),
('2020-11-02'),
('2020-11-03'),
('2020-11-04'),
('2020-11-05'),
('2020-11-06'),
('2020-11-07'),
('2020-11-08'),
('2020-11-09'),
('2020-11-10');

DELIMITER $$
CREATE PROCEDURE p_generate_snapshot(start_date date, end_date date)
BEGIN
  
   DECLARE d date;
   DECLARE done INT DEFAULT FALSE;

   DECLARE cursor_name CURSOR FOR SELECT * FROM calendar c WHERE date >= start_date AND date < end_date;
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
   OPEN cursor_name;
     fetch_loop: LOOP
       FETCH cursor_name INTO d;

       IF done THEN  
         LEAVE fetch_loop;
       END IF;

       SELECT d;
     
     END LOOP;
   CLOSE cursor_name;
END$$

DELIMITER ;

CALL p_generate_snapshot('20201101', '20201201');

不清楚为什么要为此使用游标。你的程序可以写成:

CREATE PROCEDURE p_generate_snapshot(start_date date, end_date date)
BEGIN  
   SELECT * FROM calendar c WHERE date >= start_date AND date < end_date;
END

这将 return 一个结果集,如您所说。

但您的示例可能已被简化,并且您需要执行其他步骤来处理游标获取的行。这将是使用游标的正当理由。

但我认为不可能 return 游标处理的行就好像它是一个结果集一样。当然,不可能在游标循环的每次迭代中都通过 SELECT d; 来完成。正如您所发现的那样,这必然会 return 每行一个单独的结果集。

一种解决方法是在游标循环期间将行插入到临时 table 中,尽管它很笨拙。然后 select 从温度 table 作为最后一步。

CREATE PROCEDURE p_generate_snapshot(start_date date, end_date date)
BEGIN
  
   DECLARE _d date;
   DECLARE done INT DEFAULT FALSE;

   DECLARE cursor_name CURSOR FOR SELECT date FROM calendar c WHERE date >= start_date AND date < end_date;
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

   CREATE TEMPORARY TABLE t (d DATE);

   OPEN cursor_name;
     fetch_loop: LOOP
       FETCH cursor_name INTO _d;

       IF done THEN  
         LEAVE fetch_loop;
       END IF;

       INSERT INTO t SET d = _d;
     
     END LOOP;
   CLOSE cursor_name;

   SELECT d FROM t;
   DROP TABLE t;
END

就此而言,我完全不知道您为什么要使用过程,而不仅仅是在客户端应用程序中使用 运行 那个 SELECT 语句。这将解决这两个问题——逐行处理,但仍将其视为单个查询结果。

我几乎从不使用 MySQL 中的存储过程。我发现它们确实比它们的价值更麻烦。我在这里发布了原因:https://www.quora.com/What-are-the-reasons-not-to-use-or-not-use-stored-procedures/answer/Bill-Karwin