【问题标题】:Looping Over Result Sets in MySQL在 MySQL 中循环遍历结果集
【发布时间】:2010-12-17 05:45:49
【问题描述】:

我正在尝试在 MySQL 中编写一个存储过程,它将执行一个简单的选择查询,然后循环遍历结果以确定是执行其他查询、数据转换还是完全丢弃数据。实际上,我想实现这个:

$result = mysql_query("SELECT something FROM somewhere WHERE some stuff");
while ($row = mysql_fetch_assoc($result)) {
    // check values of certain fields, decide to perform more queries, or not
    // tack it all into the returning result set
}

只有,我只想要在 MySQL 中,所以它可以作为一个过程来调用。我知道对于触发器,有 FOR EACH ROW ... 语法,但我找不到在 CREATE TRIGGER ... 语法之外使用的任何类似内容。我已经阅读了 MySQL 中的一些循环机制,但到目前为止,我所能想象的就是我将实现这样的东西:

SET @S = 1;
LOOP
    SELECT * FROM somewhere WHERE some_conditions LIMIT @S, 1
    -- IF NO RESULTS THEN
    LEAVE
    -- DO SOMETHING
    SET @S = @S + 1;
END LOOP

虽然这在我的脑海里有些模糊。

作为参考,虽然我认为它不一定相关,但初始查询会将四个表连接在一起以形成分层权限模型,然后根据特定权限链的高度,它会检索有关应继承该权限的子级的附加信息。

【问题讨论】:

标签: mysql loops stored-procedures database-cursor


【解决方案1】:

使用光标。

在阅读文档时,可以将光标视为缓冲阅读器。如果您将每一行视为文档中的一行,那么您将阅读下一行,执行您的操作,然后前进光标。

【讨论】:

    【解决方案2】:

    这样的事情应该可以解决问题(但是,请在 sn-p 之后阅读以获取更多信息)

    CREATE PROCEDURE GetFilteredData()
    BEGIN
      DECLARE bDone INT;
    
      DECLARE var1 CHAR(16);    -- or approriate type
      DECLARE Var2 INT;
      DECLARE Var3 VARCHAR(50);
    
      DECLARE curs CURSOR FOR  SELECT something FROM somewhere WHERE some stuff;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
    
      DROP TEMPORARY TABLE IF EXISTS tblResults;
      CREATE TEMPORARY TABLE IF NOT EXISTS tblResults  (
        --Fld1 type,
        --Fld2 type,
        --...
      );
    
      OPEN curs;
    
      SET bDone = 0;
      REPEAT
        FETCH curs INTO var1,, b;
    
        IF whatever_filtering_desired
           -- here for whatever_transformation_may_be_desired
           INSERT INTO tblResults VALUES (var1, var2, var3 ...);
        END IF;
      UNTIL bDone END REPEAT;
    
      CLOSE curs;
      SELECT * FROM tblResults;
    END
    

    需要考虑的一些事项...

    关于上面的sn-p:

    • 可能希望将部分查询传递给存储过程,尤其是搜索条件,以使其更通用。
    • 如果要由多个会话等调用此方法,可能需要传递一个排序的会话 ID 以创建唯一的临时表名称(实际上没有必要担心,因为不同的会话不共享相同的临时文件命名空间;请参阅评论格鲁伯,下)
    • 需要正确指定变量声明、SELECT 查询等一些部分

    更一般地说:尽量避免需要光标

    我特意将游标变量命名为 curs[e],因为游标是喜忧参半。它们可以帮助我们实现复杂的业务规则,这些规则可能很难用 SQL 的声明式形式表达,但它却让我们使用了 SQL 的过程(命令式)形式,这是 SQL 的一个通用特性,既不太友好/富有表现力、编程方面,但在性能方面通常效率较低。

    也许您可以考虑在“普通”(声明性)SQL 查询的上下文中表达所需的转换和过滤。

    【讨论】:

    • 所以这就是游标的用途...直到现在我才觉得它没有意义,因为我最近才开始使用过程、触发器等.这比我希望的更有帮助,非常感谢。
    • 很高兴我能帮上忙!再次,适度使用[光标]。所说的 SQL 是一个非常强大的集合代数,使用 DDL 和 DML(SQL 的“核心”功能),但对于命令式语言构造则较少。
    • 根据this answer,临时表不会在会话之间共享,因此您不需要处理唯一ID等。
    • 这个重复直到循环还需要检查“IF not bDone”,因为它会在命中最后一条记录后再执行一次。
    • FETCH curs INTO var1,, b;这条线上的“b”是什么?
    猜你喜欢
    • 2019-02-18
    • 2015-10-05
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    相关资源
    最近更新 更多