Шаг 93 - PL/SQL - Функции

Вот теперь, наконец, давайте рассмотрим такое понятие как функции PL/SQL. Раньше в шагах мы с вами рассмотрели так называемые встроенные функции PL/SQL. А сейчас мы попробуем сами научится писать то, что называется функциями. По своей сути функция это то же, что и процедура, она может принимать параметры по всем тем же правилам, что и процедуры, и кроме всего она может возвращать значения! Но не применением OUT типа передаваемого параметра, а сама по себе. То есть функция, принимает параметры и возвращает одно(!), значение! В принципе в функции можно применять параметры с типом OUT - но это очень плохая идея! Такой метод я использовать не рекомендую! Определение функции таково:

-------------- CREATE [OR REPLACE] FUNCTION - имя_функции -------------------------------------
-------------- (аргумент [IN] [OUT] [IN OUT] тип, ..... ) AS [IS] -----------------------------
-------------- тело процедуры -----------------------------------------------------------------
-------------- RETURN (возвращаемое_значение) -------------------------------------------------

Кое-что вам уже знакомо, за исключением того, что присутствует оператор RETURN. Посредством этого оператора функция возвращает значение. Функция, как правило, вызывается внутри какого-либо определения, т.к. вызывать функцию как оператор нет смысла. Но как вы дальше убедитесь, с помощью функция можно делать очень полезные вещи. Итак, давайте напишем функцию преобразования BOOLEAN типа в тип VARCHAR2 - это самая простая задачка во всех учебниках. Итак:

CREATE OR REPLACE FUNCTION BOOL_TO_CHAR(INBL IN BOOLEAN) RETURN VARCHAR2
IS

OUT_ST VARCHAR2(5);

BEGIN

	IF (INBL) THEN
	OUT_ST := 'TRUE';
	ELSIF (NOT INBL) THEN
	OUT_ST := 'FALSE';
	ELSE 
	OUT_ST := 'NULL';
	END IF;

	RETURN(OUT_ST);

END BOOL_TO_CHAR;
/

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

SQL> CREATE OR REPLACE FUNCTION BOOL_TO_CHAR(INBL IN BOOLEAN) RETURN VARCHAR2
  2  IS
  3  
  4  OUT_ST VARCHAR2(5);
  5  
  6  BEGIN
  7  
  8   IF (INBL) THEN
  9   OUT_ST := 'TRUE';
 10   ELSIF (NOT INBL) THEN
 11   OUT_ST := 'FALSE';
 12   ELSE 
 13   OUT_ST := 'NULL';
 14   END IF;
 15  
 16   RETURN(OUT_ST);
 17  
 18  END BOOL_TO_CHAR;
 19  /

Функция создана.

Теперь попробуем применить ее на практике. Запишем такой анонимный блок:

SET SERVEROUTPUT ON

DECLARE

BEGIN

	DBMS_OUTPUT.enable;
    DBMS_OUTPUT.put_line(BOOL_TO_CHAR(TRUE));
    DBMS_OUTPUT.put_line(BOOL_TO_CHAR(FALSE));
    DBMS_OUTPUT.put_line(BOOL_TO_CHAR(NULL));
    
END;
/

Получаем:

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2  
  3  BEGIN
  4  
  5   DBMS_OUTPUT.enable;
  6      DBMS_OUTPUT.put_line(BOOL_TO_CHAR(TRUE));
  7      DBMS_OUTPUT.put_line(BOOL_TO_CHAR(FALSE));
  8      DBMS_OUTPUT.put_line(BOOL_TO_CHAR(NULL));
  9      
 10  END;
 11  /
TRUE
FALSE
NULL

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

Как видите, наша функция BOOL_TO_CHAR вызвана внутри определения DBMS_OUTPUT.put_line(..), так обычно и происходит. Хорошо видно, что мы получили строки, передав булевы значения.

Теперь давайте поговорим об операторе RETURN. Этот оператор возвращает значение функции, приводя его к типу возвращаемого функцией.

------------ RETURN (значение) ------------------------------

Где значение - это то что и возвращает функция. Здесь скобки "()" - это только стиль при написании функций, для того чтобы было немного понятнее. Операторов RETURN в функции может быть несколько, при этом первый из них, завершит ее работу и вернет управление в вызывающую процедуру! Давайте напишем еще одну функцию преобразования BOOLEAN в VARCHAR2, но при этом используем немного другую логику:

CREATE OR REPLACE FUNCTION BOOL_TO_CHARTWO(INBL IN BOOLEAN) RETURN VARCHAR2
IS

BEGIN

	IF (INBL) THEN
	RETURN('TRUE');
	ELSIF (NOT INBL) THEN
	RETURN('FALSE');
	ELSE 
	RETURN('NULL');
	END IF;

END BOOL_TO_CHARTWO;
/

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

SQL> CREATE OR REPLACE FUNCTION BOOL_TO_CHARTWO(INBL IN BOOLEAN) RETURN VARCHAR2
  2  IS
  3  
  4  BEGIN
  5  
  6   IF (INBL) THEN
  7   RETURN('TRUE');
  8   ELSIF (NOT INBL) THEN
  9   RETURN('FALSE');
 10   ELSE 
 11   RETURN('NULL');
 12   END IF;
 13  
 14  END BOOL_TO_CHARTWO;
 15  /

Функция создана.

Хорошо видно, что мы заменили промежуточную переменную и применили три оператора RETURN. В данном случае это будет то же, что и первая функция хоть и немного в другом контексте. Запишем вот такой анонимный блок:

SET SERVEROUTPUT ON

DECLARE

BEGIN

	DBMS_OUTPUT.enable;
    DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(TRUE));
    DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(FALSE));
    DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(NULL));
    
END;
/

Получаем:

SQL> SET SERVEROUTPUT ON
SQL> 
SQL> DECLARE
  2  
  3  BEGIN
  4  
  5   DBMS_OUTPUT.enable;
  6      DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(TRUE));
  7      DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(FALSE));
  8      DBMS_OUTPUT.put_line(BOOL_TO_CHARTWO(NULL));
  9      
 10  END;
 11  /
TRUE
FALSE
NULL

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

Что и требовалось доказать! Так же смею заметить, что в PL/SQL с успехом можно применять рекурсию. Рекурсивные вызовы иногда делают код меньше, но запутаннее! Приведу один пример расчета факториала числа, это я подглядел у Билла Гейтса в его MSDN и переложил на PL/SQL, не все же ему таскать у других! :) Итак:

CREATE OR REPLACE FUNCTION FACTORIAL(NUM IN NUMBER) RETURN NUMBER
IS

BEGIN

IF (NUM <=1) THEN
 RETURN (NUM);
ELSE
 RETURN (NUM * FACTORIAL(NUM-1));

END IF;

END FACTORIAL;
/

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

SQL> CREATE OR REPLACE FUNCTION FACTORIAL(NUM IN NUMBER) RETURN NUMBER
  2  IS
  3  
  4  BEGIN
  5  
  6  IF (NUM <=1) THEN
  7   RETURN (NUM);
  8  ELSE
  9   RETURN (NUM * FACTORIAL(NUM-1));
 10  
 11  END IF;
 12  
 13  END FACTORIAL;
 14  /

Функция создана.

Запишем анонимный блок для трех значений - вот такой:

SET SERVEROUTPUT ON

DECLARE

BEGIN

	DBMS_OUTPUT.enable;
    DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(5)));
    DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(7)));
    DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(12)));
    
END;
/

Получаем:

SQL> SET SERVEROUTPUT ON
SQL> 
SQL> DECLARE
  2  
  3  BEGIN
  4  
  5   DBMS_OUTPUT.enable;
  6      DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(5)));
  7      DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(7)));
  8      DBMS_OUTPUT.put_line(TO_CHAR(FACTORIAL(12)));
  9      
 10  END;
 11  /
120
5040
479001600

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

Ух, ты! Работает! Привет Биллу! Получили три значения факториала чисел 5, 7, 12. Проверьте правильно или нет?

Вот собственно так пишутся функции. Хотите задание? А вот - в PL/SQL нет функции сложения и вычитания одного времени суток и другого! Напишите функции, которые, например, складывают и вычитают, скажем, 10:34 и 5:08! Я такое делал. Интересно, что у вас получится? Пробуйте!


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Летучий Сергей - 05.02.2004