Для цикла и столбцов в PL / SQL - PullRequest
3 голосов
/ 26 октября 2011

Я новичок в PL / SQL.У меня проблема с циклом на этом языке.Я хотел бы сделать цикл следующим образом:

FOR nr IN 1..102 
LOOP
  DBMS_OUTPUT.PUT_LINE(nr);
  IF rec.column_||nr IS NULL
    THEN
    DBMS_OUTPUT.PUT_LINE('test');
  END IF;
END LOOP;

Я создал курсор.Как вы можете видеть, я хотел бы проверить все столбцы с именами столбца от column_1 до column_102.К сожалению ||Оператор не работает в этой ситуации.Знаете ли вы какое-нибудь решение моей проблемы?

1 Ответ

5 голосов
/ 26 октября 2011

Вы можете сделать это с dynamic PL / SQL . Используйте оператор EXECUTE IMMEDIATE для выполнения строкового аргумента в виде PL / SQL, который вы можете создать с помощью ||, как это и предполагалось в вопросе.

Пример:

BEGIN 
    FOR nr IN 1..102 
    LOOP
        DBMS_OUTPUT.PUT_LINE(nr);
        EXECUTE IMMEDIATE 
            'BEGIN ' || 
            'IF rec.column.' || nr ||' is null THEN ' ||
                'DBMS_OUTPUT.PUT_LINE(''test''); ' ||
            'END IF; ' || 
            'END; ';
    END LOOP;
END;

Или вы также можете присвоить rec.column.' || nr ||' is null переменной и сделать PUT_LINE за пределами EXECUTE IMMEDIATE:

ОБНОВЛЕНИЕ : Кажется, невозможно связать BOOLEAN переменные, поэтому я изменил пример для использования NUMBER.

ОБНОВЛЕНИЕ 2: Возможное повышение эффективности, хотя, возможно, не подходит в этом случае. Используйте константу VARCHAR для динамического SQL и передайте в nr переменную с привязкой. Это даже более эффективно, чем использование собственного SQL, если он находится в большом цикле. Я не думаю, что 'rec.column.:arg is null будет исполняться как 'rec.column.1 is null.

 DECLARE
    isnull NUMBER;
 BEGIN 
    FOR nr IN 1..102 
    LOOP
        DBMS_OUTPUT.PUT_LINE(nr);
        EXECUTE IMMEDIATE 
            'BEGIN ' || 
                'IF rec.column.' || nr ||' IS NULL THEN ' || 
                    ':x:=1; ' || 
                'ELSE ' ||
                    ':x:=0; ' ||
                'END IF; ' ||
            'END; ' 
            USING OUT isnull;
        IF isnull = 1 THEN 
            DBMS_OUTPUT.PUT_LINE('test');
        END IF;
    END LOOP;
END;

ОБНОВЛЕНИЕ 3 : Видя, что:

  • Невозможно получить доступ к rec внутри динамического оператора SQL, поскольку он не определен (выходит за рамки),

  • Кажется невозможным передать тип не-sql в качестве аргумента динамического оператора (запись, курсор)

Возможный обходной путь - связать некоторые столбцы идентификатора (тип SQL) с динамическим оператором и использовать предложение select, чтобы выяснить, является ли текущий столбец пустым:

DECLARE
        isnull NUMBER;
        rec_id NUMBER; -- Identifier of the fetched record
     BEGIN 
        rec_id := rec.id;
        FOR nr IN 1..102 
        LOOP
            DBMS_OUTPUT.PUT_LINE(nr);
            EXECUTE IMMEDIATE 
                'SELECT 1 FROM my_table WHERE id = :idarg ' ||
                   ' AND column_' || nr || ' IS NULL'
              INTO isnull USING rec_id;
            IF isnull = 1 THEN 
                DBMS_OUTPUT.PUT_LINE('test');
            END IF;
        END LOOP;
    END;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...