【问题标题】:Return data in the single set from stored procedure using CURSOR/LOOP使用 CURSOR/LOOP 从存储过程中返回单个集合中的数据
【发布时间】:2020-11-08 15:27:54
【问题描述】:

我想返回单个集合中的数据,但是我得到了 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');

【问题讨论】:

    标签: mysql cursor mysql-5.6


    【解决方案1】:

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

    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
    

    这将返回一个您所说的结果集。

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

    但我认为不可能像返回一个结果集一样返回由游标处理的行。当然,在游标循环的每次迭代中,SELECT d; 不可能做到这一点。正如您所发现的,这势必会为每行返回一个单独的结果集。

    一种解决方法虽然很尴尬,但在游标循环期间将行插入到临时表中。然后从临时表中选择作为最后一步。

    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

    【讨论】:

    • 逻辑会比较复杂,我举个小例子。
    • 哦...我应该在 DECLARE 之后创建临时表...这是我的另一个错误 :) 谢谢!
    • 是的,文档指出所有DECLARE 语句必须位于过程主体的顶部,在任何其他类型的语句之前。
    猜你喜欢
    • 2012-01-23
    • 2020-03-27
    • 2022-07-21
    • 2015-05-29
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    相关资源
    最近更新 更多