在MySQL中循环结果集

Der*_*sed 59 mysql loops stored-procedures cursor

我试图在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
}
Run Code Online (Sandbox Code Playgroud)

只是,我只想在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
Run Code Online (Sandbox Code Playgroud)

虽然在我看来这甚至有些朦胧.

作为参考,尽管我认为它不一定相关,但初始查询将连接四个表以形成层级权限模型,然后根据特定权限的链的高度,它将检索有关的其他信息.应该继承该许可的子女.

mjv*_*mjv 79

像这样的东西应该做的伎俩(但是,在片段后阅读更多信息)

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
Run Code Online (Sandbox Code Playgroud)

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

关于以上代码段:

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

更一般地说:试图避免需要游标.

我故意命名游标变量curs [e],因为游标是混合的祝福.它们可以帮助我们实现复杂的业务规则,这些规则可能难以用SQL的声明形式表达,但它然后使我们使用SQL的过程(命令式)形式,这是SQL的一般特性,它既不是非常友好/富有表现力,编程方面,而且往往效率低下.

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

  • 这个repeat-until循环还需要检查“IF not bDone”,因为它会在最后一条记录被命中后再执行一次。 (3认同)
  • FETCH curs INTO var1,, b; 这条线上的“b”是什么? (2认同)

Ali*_*vin 5

使用游标。

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