代码之家  ›  专栏  ›  技术社区  ›  Dereleased

MySQL中的结果集循环

  •  44
  • Dereleased  · 技术社区  · 15 年前

    我尝试在MySQL中编写一个存储过程,它将执行一个稍微简单的select查询,然后循环结果,以决定是否执行其他查询、数据转换或完全丢弃数据。实际上,我想实现这一点:

    $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
    

    尽管这在我的脑海里有些模糊。

    作为参考,尽管我不认为它是必要的,但初始查询将把四个表连接在一起,形成一个层次权限模型,然后根据特定权限在链上的高度,它将检索有关该权限应继承到的子级的附加信息。

    2 回复  |  直到 9 年前
        1
  •  64
  •   mjv    9 年前

    类似这样的方法应该可以做到(不过,在代码片段后面阅读以获取更多信息)

    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
    

    有几件事要考虑…

    关于上面的片段:

    • 可能需要将查询的一部分传递给存储过程,特别是搜索条件,以使其更通用。
    • 如果此方法将由多个会话调用等,则可能需要传递排序的会话ID以创建唯一的临时表名(实际上不需要担心,因为不同的会话不共享相同的临时文件命名空间;请参阅下面的Gruber注释)
    • 需要正确指定一些部分,如变量声明、选择查询等。

    一般来说: 试图避免使用光标 .

    我故意将光标变量命名为curs[e],因为光标是好坏参半的。它们可以帮助我们实现复杂的业务规则,这些业务规则可能很难用SQL的声明形式来表达,但随后它使我们使用了SQL的过程(命令)形式,这是SQL的一个一般特性,它既不友好/表达,也不明智地编程,而且往往在性能方面效率较低。

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

        2
  •  3
  •   Flexo - Save the data dump sunny moon    9 年前

    使用游标。

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