72

我正在尝试在 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

虽然这在我的脑海里有些朦胧。

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

4

2 回答 2

100

像这样的东西应该可以解决问题(但是,请阅读片段以获取更多信息)

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 的评论,如下)
  • 变量声明、SELECT 查询等一些部分需要正确指定

更一般地说:尽量避免需要一个 cursor

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

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

于 2009-11-16T22:31:56.643 回答
6

使用游标。

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

于 2009-11-16T22:31:05.090 回答