Вот теперь, наконец, давайте рассмотрим такое понятие как функции 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! Я такое делал. Интересно, что у вас получится? Пробуйте!