Цикл по наборам результатов в MySQL - PullRequest
52 голосов
/ 17 ноября 2009

Я пытаюсь написать хранимую процедуру в 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

Хотя даже это несколько смутно для меня.

Для справки, хотя я не думаю, что это обязательно уместно, первоначальный запрос будет объединять четыре таблицы вместе, чтобы сформировать модель иерархических разрешений, а затем, основываясь на том, как высоко в цепочке находится конкретное разрешение, он получит дополнительная информация о детях, которым должно быть унаследовано это разрешение.

Ответы [ 2 ]

72 голосов
/ 17 ноября 2009

Что-то вроде этого должно сработать (однако, читайте после фрагмента для получения дополнительной информации)

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

Несколько вещей для рассмотрения ...

Относительно фрагмента выше:

  • может захотеть передать часть запроса в хранимую процедуру, в частности, критерии поиска, чтобы сделать ее более общей.
  • Если этот метод должен вызываться несколькими сеансами и т. Д., Возможно, потребуется передать идентификатор сеанса своего рода для создания уникального имени временной таблицы (на самом деле нет необходимости, поскольку разные сеансы не совместно используют одно и то же пространство имен временного файла; см. Комментарий Грубер, ниже)
  • Необходимо правильно указать несколько частей, таких как объявления переменных, запрос SELECT и т. Д.

В более общем смысле: пытается избежать необходимости курсора .

Я специально назвал переменную курсора curs [e], потому что курсоры - это смешанное благословение. Они могут помочь нам реализовать сложные бизнес-правила, которые может быть трудно выразить в декларативной форме SQL, но затем мы вынуждены использовать процедурную (императивную) форму SQL, которая является общей особенностью SQL, которая не очень удобна / выразительный, с программированием и зачастую менее эффективный с точки зрения производительности.

Может быть, вы можете рассмотреть выражение требуемой трансформации и фильтрации в контексте «простого» (декларативного) SQL-запроса.

4 голосов
/ 17 ноября 2009

Использовать курсоры.

При чтении документа курсор может считаться буферизованным читателем. Если вы думаете о каждой строке как о строке в документе, тогда вы читаете следующую строку, выполняете свои операции и затем перемещаете курсор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...