CREATE OR REPLACE PROCEDURE TESTPRM(NUM IN NUMBER)

IS

in_COMP VARCHAR2(50);

BEGIN

SELECT COMPANY INTO in_COMP FROM customers

WHERE customers. CUST_NUM = NUM;

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line(in_COMP);

END TESTPRM;

/

Получаем после компиляции:

SQL> CREATE OR REPLACE PROCEDURE TESTPRM(NUM IN NUMBER)

2 IS

3

4 in_COMP VARCHAR2(50);

5

6 BEGIN

7

8 SELECT COMPANY INTO in_COMP FROM customers

9 WHERE customers. CUST_NUM = NUM;

10

11 DBMS_OUTPUT. enable;

12 DBMS_OUTPUT. put_line(in_COMP);

13

14 END TESTPRM;

15 /

Процедура создана.

Здесь, я применил параметр NUM с типом NUMBER. IN в данном случае определяет, что параметр является входным. Что так же справедливо и по умолчанию. То есть, если параметр имеет только тип IN, то предикат IN можно не указывать. Так же напомню, что NUM является формальным параметром функции (formal parameters). А вот входное значение функции является фактическим параметром (actual parameters). Формальный параметр NUM, является только вместилищем для фактически передаваемого параметра и все операции производятся с формальным параметром (в программировании, если я правильно помню, это называется передача параметра в процедуру по значению).

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

НЕ нашли? Не то? Что вы ищете?

Что, собственно я и говорил выше. Вернемся к нашей процедуре, она содержит, один оператор SELECT (уже что-то полезное!), который выбирает одну запись из таблицы customers, в данном случае заказчика по его номеру. Для примера вызовем ее из анонимного блока предварительно определив и передав ей параметр:

SET SERVEROUTPUT ON

DECLARE

BEGIN

TESTPRM(2112);

END;

/

Получаем после вызова:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 BEGIN

4

5 TESTPRM(2112);

6

7 END;

8 /

Апельсин

Процедура PL/SQL успешно завершена.

Вот такой "желтый и круглый" заказчик! :) Ясно видно, как сработал оператор SELECT и функция TESTPRM вывела результат. При этом фактический параметр, был передан и не изменялся. А теперь попробуем написать более сложную процедуру:

CREATE OR REPLACE PROCEDURE TESTOUT(NUM IN NUMBER, DT OUT VARCHAR2)

IS

BEGIN

SELECT COMPANY INTO DT FROM customers

WHERE customers. CUST_NUM = NUM;

END TESTOUT;

/

Получаем после компиляции:

SQL> CREATE OR REPLACE PROCEDURE TESTOUT(NUM IN NUMBER, DT OUT VARCHAR2)

2 IS

3

4 BEGIN

5

6 SELECT COMPANY INTO DT FROM customers

7 WHERE customers. CUST_NUM = NUM;

8

9 END TESTOUT;

10 /

Процедура создана.

Рассмотрим параметры более внимательно, про первый мы уже все знаем, а вот второй DT определен как OUT и имеет тип VARCHAR2. Что это значит? А, вот что. DT выходной параметр и принимает значение из самой процедуры на возврат, т. е.

OUT - Любое значение имеющее фактический параметр при вызове процедуры игнорируется. Внутри процедуры формальный параметр рассматривается как параметр только для записи - ему можно присвоить значение, но считать из него значение нельзя. (!) Когда процедура завершается и управление передается в вызывающую среду, содержимое формального параметра присваивается фактическому параметру.

Вот так работает тип OUT. Давайте определим анонимный блок и посмотрим, что же получается:

DECLARE

FRDT VARCHAR2(100);

BEGIN

FRDT := 'HELLO';

TESTOUT(2103, FRDT);

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line('CUSTOMER '||FRDT);

END;

/

Получаем:

SQL> DECLARE

2

3 FRDT VARCHAR2(100);

4

5 BEGIN

6

7 FRDT := 'HELLO';

8

9 TESTOUT(2103, FRDT);

10

11 DBMS_OUTPUT. enable;

12 DBMS_OUTPUT. put_line('CUSTOMER '||FRDT);

13

14 END;

15 /

CUSTOMER Крупное предприятие

Процедура PL/SQL успешно завершена.

Заметили, что значение HELLO не появилось? Естественно, так как параметр DT функции TESTOUT является выходным. Если сказать честно, то лично меня такой тип возврата данных из процедуры немного шокирует, так как в классическом программировании такое применяется по моему редко, хотя я и могу ошибаться. Но, тем не менее может быть в каком-то случае такой вызов вполне оправдан! Можете пока поработать со всем этим. :)

Шаг 90 - PL/SQL - Процедуры и их параметры II

Идем дальше по пути познания процедур. Итак, мы с вами рассмотрели тип передаваемых параметров - IN и OUT. Существует еще один тип параметров процедур, а именно как вы уже, наверное, догадываетесь это тип IN OUT - то есть при объявлении это выглядит примерно вот так:

CREATE OR REPLACE PROCEDURE MYPROC(MYPARAM IN OUT NUMBER.......

Вот с этим параметром давайте разберемся подробнее. Давайте сформулируем правила, для такого тип параметров.

IN OUT - этот вид представляет собой комбинацию видов IN и OUT. Значение фактического параметра передается в процедуру при ее вызове. Внутри процедуры формальный параметр может быть считан и в него может быть записано значение. При завершении процедуры и возврате управления в вызывающую среду, содержимое формального параметра присваивается фактическому параметру.

Теперь давайте создадим следующую процедуру примерно вот такого вида:

CREATE OR REPLACE PROCEDURE TESTINOUT(NUM IN OUT NUMBER, DT OUT VARCHAR2)

IS

BEGIN

SELECT COMPANY INTO DT FROM customers

WHERE customers. CUST_NUM = NUM;

SELECT CUST_REP INTO NUM FROM customers

WHERE customers. CUST_NUM = NUM;

END TESTINOUT;

/

Не торопитесь ее компилировать, давайте порасcуждаем. Итак, теперь NUM параметр IN OUT - как видно второй SELECT принимает его как параметр и возвращает через него значение. То есть принимает условие и вернет результат. Удобно, не так ли? Компилируем:

SQL> CREATE OR REPLACE PROCEDURE TESTINOUT(NUM IN OUT NUMBER, DT OUT VARCHAR2)

2 IS

3

4 BEGIN

5

6 SELECT COMPANY INTO DT FROM customers

7 WHERE customers. CUST_NUM = NUM;

8

9 SELECT CUST_REP INTO NUM FROM customers

10 WHERE customers. CUST_NUM = NUM;

11

12 END TESTINOUT;

13 /

Процедура создана.

Вот теперь если сделать вот такой вызов:

SET SERVEROUTPUT ON

DECLARE

FRDT VARCHAR2(100);

FRNM NUMBER := 2103;

BEGIN

TESTINOUT(FRNM, FRDT);

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line('CUSTOMER '||FRDT||' CUST_REP '||TO_CHAR(FRNM));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 FRDT VARCHAR2(100);

4 FRNM NUMBER := 2103;

5

6 BEGIN

7

8 TESTINOUT(FRNM, FRDT);

9

10 DBMS_OUTPUT. enable;

11 DBMS_OUTPUT. put_line('CUSTOMER '||FRDT||' CUST_REP '||TO_CHAR(FRNM));

12

13 END;

14 /

CUSTOMER Крупное предприятие CUST_REP 105

Процедура PL/SQL успешно завершена.

Не трудно заметить, что первое значение фактического параметра FRNM равно 2103, а вот вернул он значение 105 - т. е. один параметр выполнил двойную работу. Вполне не плохо. К слову, если вы попытаетесь сделать что-то вроде:

SET SERVEROUTPUT ON

DECLARE

FRDT VARCHAR2(100);

BEGIN

TESTINOUT(2103, FRDT);

END;

/

То получите в ответ следующее:

DECLARE

FRDT VARCHAR2(100);

BEGIN

TESTINOUT(2103, FRDT);

END;

ORA-06550: Строка 7, столбец 12:

PLS-00363: выражение '2103' не м. б. использовано как адресат назначения

ORA-06550: Строка 7, столбец 2:

PL/SQL: Statement ignored

SQL>

В литерале 2103 нельзя сохранить возвращаемый результат, так как литерал не хранится в памяти после использования. Ну, что я думаю и так очевидно. Надеюсь, с данным типом параметра теперь вам все стало ясно! :)

Давайте теперь остановимся на понятии тела (body) процедуры. Тело процедуры содержит собственно исполняемый код и располагается между ключевыми словами BEGIN и EXCEPTION. Далее идет блок EXCEPTION и END, в котором располагается собственно обработчик исключительной ситуации. Раздел объявлений располагается между операторами CREATE и IS или AS (вот и снова язык Ada!) - а выглядит это все примерно вот так:

CREATE OR REPLACE PROCEDURE [имя процедуры] IS or AS

зона объявления переменных.

BEGIN

выполняемый раздел

EXCEPTION

раздел исключительных ситуаций

END [имя процедуры]

Такой скелет имеет процедура и все что к ней прилагается. Запомните это получше! :)

Шаг 91 - PL/SQL - Процедуры и параметры III

Думаю, что вам уже кажется, что с процедурами и их параметрами мы разобрались, а вот и нет! Есть еще кое-что. Думаю, кто-то из вас заметил, что при написании формального параметра процедуры, например, определяя ее как VARCHAR2 или NUMBER я никогда не делал вот так:

CREATE OR REPLACE PROCEDURE some_proc(NUM IN OUT NUMBER(3,2), DT OUT VARCHAR2(100))

И вот почему. Накладывать ограничения на формальные параметры функций в PL/SQL - ЗАПРЕЩЕНО! Например, вот такой пример, приведет к ошибке компиляции:

CREATE OR REPLACE PROCEDURE TESTINOUT(NUM IN OUT NUMBER(3,2), DT OUT VARCHAR2(100))

IS

BEGIN

SELECT COMPANY INTO DT FROM customers

WHERE customers. CUST_NUM = NUM;

SELECT CUST_REP INTO NUM FROM customers

WHERE customers. CUST_NUM = NUM;

END TESTINOUT;

/

В результате получите:

SQL> CREATE OR REPLACE PROCEDURE TESTINOUT(NUM IN OUT NUMBER(3,2), DT OUT VARCHAR2(100))

2 IS

3

4 BEGIN

5

6 SELECT COMPANY INTO DT FROM customers

7 WHERE customers. CUST_NUM = NUM;

8

9 SELECT CUST_REP INTO NUM FROM customers

10 WHERE customers. CUST_NUM = NUM;

11

12 END TESTINOUT;

13 /

Предупреждение: Процедура создана с ошибками компиляции.

Что и требовалось доказать. Можете убрать неверные объявления и еще раз перекомпилировать процедуру для того, чтобы она осталась исправной. А, вот вам еще один подводный камешек. Запишем вот такую процедуру:

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8