Опубликован: 25.09.2009 | Уровень: специалист | Доступ: свободно
Лекция 2:

PL/SQL в Oracle Forms. Управляющие структуры. Глобальные переменные и параметры

< Лекция 1 || Лекция 2: 123 || Лекция 3 >

Использование циклов

В ваших приложениях вам не раз придется исполнять какую-то группу операторов неоднократно. Повторять операторы можно двумя способами: указав конкретное число проходов в цикле или выполняя цикл до встречи с некоторым условием сравнения, пока условие не будет истинно. Поскольку Oracle Forms поддерживает PL/SQL, то, следовательно, и циклы в Forms будут такого же типа, как и в PL/SQL:

  • LOOP-EXIT ;
  • WHILE -LOOP ;
  • FOR-LOOP.

LOOP-EXIT - это один из самых простых циклов PL/SQL. Ключевое слово LOOP указывает на начало повторяемого программного блока, а END LOOP - на его конец. Ключевое слово EXIT, указываемое отдельно, означает, что цикл нужно прервать, а ключевое слово EXIT WHEN - что

предлагаемый оператор сравнения нужно проверить на необходимость завершения выполнения операторов.

Рассмотрим пример с применением такого цикла:

Declare
i number:=0; 
Begin
 LOOP i:=C_ount+1 
  insert into EXEM1 (SUM) values (i); 
  IF i=10 THEN EXIT; 
  end if; 
 end loop; 
end;

После выполнения этого цикла в таблицу EXEM1 будет вставлено 10 записей, причем здесь наглядно видно, что как только наше условие будет истинно, то есть значение счетчика i будет равным 10, - цикл прервется.

Теперь рассмотрим этот же пример, только с использованием оператора EXIT-WHEN:

Declare
i number:=0; 
Begin
LOOP i:=C_ount+1; 
 insert into EXEM1 (SUM) values (i);
 EXIT WHEN i=10; 
end loop; 
end;

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

WHILE -LOOP - цикл этого типа похож на цикл с условием LOOP-EXIT WHEN, разница заключается в том, что в WHILE -LOOP проверка условия выхода осуществляется в начале цикла. Если сравнивать два этих цикла, то по гибкости, конечно, выигрывает LOOP-EXIT, т. к. позволяет указывать условие EXIT в любом месте цикла, а если сравнивать по элегантности и краткости оформления кода, то WHILE -LOOP выигрывает.

Рассмотрим тот же самый пример, что и в предыдущем случае, только с использованием конструкции WHILE -LOOP:

Declare
i number:=0; 
Begin
 while i<=10 
  LOOP i:=C_ount+1; 
   insert into EXEM1 (SUM) values (i); 
  end loop; 
end;

В этом примере мы еще больше упростили наш цикл, т. к. не использовали оператор EXIT.

FOR_LOOP - этот цикл отличается от двух других, т. к. позволяет указать конкретное количество выполнений программы до ее прерывания. Данная циклическая конструкция состоит из счетчика и диапазона циркуляции цикла. Счетчик в операторах FOR -LOOP является встроенным и автоматически увеличивает значение на единицу. Диапазон циркуляции определяют нижняя и верхняя граница, причем границы должны иметь целочисленный тип. Нижняя граница диапазона циркуляции цикла может начинаться не только с единицы, но и с любого другого целого числа.

Для примера создадим таблицу EXEM1 с одним столбцом типа number - SUM, который содержит различные числовые значения. Теперь выполним цикл:

DECLARE
C_OUNT NUMBER;
BEGIN
 for i in 1..10 loop
  insert into EXEM1 (SUM)
  values (i);
  C_OUNT:=C_OUNT+i;
 end loop;
 SELECT C_OUNT INTO :block_name.item_name from DUAL;
end;

После выполнения этого цикла в таблицу EXEM1 будет вставлено 10 записей с значением от 1 до 10, а затем результат суммирования значений вставленных записей будет выведен в элемент формы :block_name.item_name. В рассмотренном нами цикле встроенным счетчиком будет переменная i, а диапазоном циркуляции будет интервал от 1 до 10, где 1 - это нижняя граница диапазона, а 10 - верхняя. Если рассмотреть пример, который мы приводили в двух предыдущих случаях, но с применением операторов FOR -LOOP, то вы увидите, что использование этой конструкции делает код элегантнее:

Declare
 i number:=0;
Begin
 for i in 1..10 LOOP  
  insert into EXEM1 (SUM) values (i);
 end loop; 
end;

FOR -LOOP также позволяет исполнять цикл в другом направлении с помощью оператора REVERSE, причем при изменении направления цикла вам не надо как-то иначе задавать границы диапазона, т. к. Oracle сделает это за вас:

Declare
 i number:=0;
Begin
 for i in REVERSE 1..10 LOOP
  insert into EXEM1 (SUM)
  values (i);
 end loop;
end;

Существуют также операторы FOR -LOOP для работы с курсорами, которые будут рассмотрены в разделе описания курсоров.

Oracle Forms позволяет создавать циклические конструкции любого уровня вложенности. Поэтому рассмотренные нами конструкции также могут быть вложенными.

Условное управление

Условным управлением называется оператор IF - THEN (если-то), который говорит о том, что при истинности условия (или наоборот, если оно ложно) нужно выполнить следующий программный блок.

Использование этого оператора позволяет разработчику структурировать код программы таким образом, что определенные операторы будут или не будут выполняться - это определяется достоверностью операции сравнения. Причем логика этой конструкции следующая: если (IF) сравнение истинно, то (THEN) выполнить следующее. В PL/SQL существуют еще две дополнительные конструкции ELSE (иначе) и ELSIF (иначе если). Логика оператора ELSE: "в противном случае сделать то, что указано в конструкции ELSE ", а логика оператора ELSIF: "в противном случае, если...". Оператор ELSIF позволяет вам исключить дополнительное вложение оператора IF внутрь конструкции ELSE, поэтому позволяет реализовать операцию взаимоисключения более четко. Приведем простой пример:

WHEN_NEW_FORM_INSTACE:
 BEGIN
  IF TO_CHAR (TO_DATE (SYSDATE, 'DAY')='SATURDAY' or 
     TO_CHAR (TO_DATE(SYSDATE, 'DAY')='SUNDAY'
  THEN
   set_block_property('Block1',update_allowed, property_false);
   set_block_property('Block1',insert_allowed, property_false);
   set_block_property('Block1',delete_allowed, property_false);
  ELSE
   message ('Сегодня '||
     TO_CHAR (SYSDATE,'DAY')||' удачного рабочегодня');
  end if;
 end;

В вышеприведенном примере перед запуском формы будет проверено, выходной день сегодня или рабочий: если условие истинно, то есть сегодня выходной, то запретить какие-либо операции, связанные с манипуляцией данными, если же условие ложно, то в строке состояния появится сообщение: "Сегодня понедельник, удачного рабочего дня". Теперь рассмотрим пример с использованием оператора ELSE:

Declare
 but_no Varchar2(1) := :System.Mouse_Button_Pressed ; 
Begin
 If but_no = '1' Then
  Message('Нажата левая кнопка'); 
 Else If LN$Btn = '2' Then
  Message('Нажата правая кнопка' ); End if ;
 End if;
End ;

Рассмотрим тот же случай, только с использованием оператора ELSIF:

Declare
 but_no Varchar2(1) := :System.Mouse_Button_Pressed ; 
Begin
 If but_no = '1' Then
  Message('Нажата левая кнопка');
 ELSIF LN$Btn = '2' Then
  Message('Нажата правая кнопка' );
 End if; 
End ;

Как видим, построенная конструкция IF-THEN с помощью оператора ELSIF менее громоздка и более понятна.

И в заключение рассмотрим пример, в котором используются как условные, так и итеративные операторы:

DECLARE OriPos number;
BEGIN
 OriPos := TO_NUMBER(:System.Trigger_Record); 
 First_Record; 
 LOOP
  IF (:System.Last_Record = 'TRUE') THEN 
   Go_Record ('OriPos'); 
   EXIT; 
  ELSE
   Next_Record;
  END IF;
 END LOOP;
END;

Последовательное управление

В PL/SQL существует оператор, который называется " метка " (label). Оператор GOTO - это последовательность символов, отмечающая некоторый исполняемый блок, который используется для выхода из условной структуры обработчика исключительных ситуаций или программного блока. Оператор GOTO дает возможность перейти с места его указания в программе непосредственно к метке.

LOOP
  IF (:System.Last_Record = 'TRUE') THEN goto first_rec; 
  ELSE Next_Record; 
  END IF; 
 END LOOP; 
 <<first_rec>> 
 First_record; 
END;

Ограничения на использование GOTO

Нельзя разместить метку перед неисполняемым оператором, например, перед IF, END LOOP и т. д. Если же вам все-таки необходимо разместить метку там, где нет исполняемого оператора, следует воспользоваться ключевым словом NULL, которое, как известно, не производит никаких действий, но при этом удовлетворяет требования, предъявляемые к меткам. Для примера возьмем часть из предыдущей программы:

LOOP
IF (:System.Last_Record = 'TRUE') THEN 
 goto first_rec;
 .......
 <<first_rec>> 
END;

Обратите внимание, что между меткой и оператором завершения ( end ) нет исполняемого оператора, поэтому такое объявление метки вызовет ошибку. Для того чтобы избежать этой ошибки, достаточно написать ключевое слово NULL:

LOOP
 IF (:System.Last_Record = 'TRUE') THEN 
  goto first_rec;
  .......
  <<first_rec>> 
  NULL; 
 END;

Оператор GOTO используется только для выхода из структуры, но не для входа в нее. Приведем пример такого объявления, все из того же программного блока:

goto first_rec; 
 LOOP
  IF (:System.Last_Record = 'TRUE') THEN 
   <<first_rec>> 
  ELSE
   Next_Record; 
  END IF; 
 END LOOP; 
 First_record; 
END;
Совет: старайтесь как можно более элегантней оформлять свой код с помощью вышеуказанных операторов для повышения читабельности вашей программы, чтобы ваш программный блок имел вид осмысленной структуры.
< Лекция 1 || Лекция 2: 123 || Лекция 3 >
Константин Лукин
Константин Лукин

ошибка: FRM47337  Tree node label can not be null

при выполнении скрипта

DECLARE
 Itree ITEM;
 top_node Ftree.Node;
 new_node Ftree.Node;
 i_value VARCHAR2(30);
BEGIN
 Itree := Find_Item('tree_block.tree_item ');
 new_node := Ftree.Add_Tree_Node(Itree, Ftree.ROOT_NODE,
   Ftree.PARENT_OFFSET, Ftree.LAST_CHILD,
   Ftree.EXPANDED_NODE, i_value, NULL, i_value);
END;

Юлия Малыгина
Юлия Малыгина
приведена функция скрытия URL отчета и ее применение, но применения так и нет
Жанбек Сарсенов
Жанбек Сарсенов
Россия, Москва, Московский Государственный Университет имени Ломоносова М.В., 2002