plsql - RIP Tutorial · 2019-01-18 · PL / SQL доступен в Oracle Database (начиная...
Transcript of plsql - RIP Tutorial · 2019-01-18 · PL / SQL доступен в Oracle Database (начиная...
plsql
#plsql
1
1: PLSQL 2
2
Examples 2
PLSQL 2
, 3
PLSQL 4
% TYPE % ROWTYPE. 4
5
5
2: IF-THEN-ELSE 6
6
Examples 6
IF-THEN 6
IF-THEN-ELSE 6
IF-THEN-ELSE ELSIF- 7
3: 8
Examples 8
split 8
4: 9
9
9
Examples 9
«FOR loop» 9
«FOR loop» 9
SYS_REFCURSOR 10
, 10
: 10
11
5: 12
Examples 12
12
6: 13
Examples 13
PL / SQL 13
7: 15
15
Examples 15
15
15
16
17
18
, , 19
20
8: 22
22
Examples 22
22
, , 23
9: 25
25
Examples 27
27
27
28
. 28
10: 30
30
Examples 30
30
WHILE Loop 30
FOR Loop 31
11: PLSQL 33
33
Examples 33
33
, 33
/ 34
12: 35
35
Examples 35
BASE_TYPE 35
MID_TYPE 36
LEAF_TYPE 37
38
13: 40
40
40
Examples 40
INSERT UPDATE 40
14: 42
42
Examples 42
GUID 42
42
44
ОколоYou can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: plsql
It is an unofficial and free plsql ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official plsql.
The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ru/home 1
глава 1: Начало работы с PLSQL
замечания
В этом разделе представлен обзор того, что такое plsql, и почему разработчик может захотеть его использовать.
Следует также упомянуть о любых крупных предметах в рамках plsql и ссылаться на связанные темы. Поскольку Documentation for plsql является новым, вам может потребоваться создать начальные версии этих связанных тем.
Examples
Определение PLSQL
PL / SQL (язык процедур / язык структурированных запросов) является процедурным расширением Oracle Corporation для SQL и реляционной базы данных Oracle. PL / SQL
доступен в Oracle Database (начиная с версии 7), в базе данных TimesTen в памяти (начиная с версии 11.2.1) и IBM DB2 (начиная с версии 9.7).
Базовый блок в PL / SQL называется блоком, который состоит из трех частей: декларативной части, исполняемой части и части исключения.
DECLARE <declarations section> BEGIN <executable command(s)> EXCEPTION <exception handling> END;
Объявления. Этот раздел начинается с ключевого слова DECLARE. Это необязательный раздел и определяет все переменные, курсоры, подпрограммы и другие элементы, которые будут использоваться в программе.
Исполняемые команды - этот раздел заключен между ключевыми словами BEGIN и END,
и это обязательный раздел. Он состоит из исполняемых инструкций PL / SQL программы. Он должен иметь по крайней мере одну исполняемую строку кода, которая может быть просто командой NULL, чтобы указать, что ничего не должно выполняться.
Обработка исключений - этот раздел начинается с ключевого слова EXCEPTION. Этот раздел снова является необязательным и содержит исключения (исключения), которые обрабатывают ошибки в программе.
Каждый оператор PL / SQL заканчивается точкой с запятой (;). Блоки PL / SQL могут быть
https://riptutorial.com/ru/home 2
вложены в другие блоки PL / SQL с помощью BEGIN и END.
В анонимном блоке требуется только исполняемая часть блока, другие части не являются обязательными. Ниже приведен пример простого анонимного кода, который не делает ничего, кроме выполнения без сообщений об ошибках.
BEGIN NULL; END; /
Отсутствие команды excecutable приводит к ошибке, поскольку PL / SQL не поддерживает пустые блоки. Например, исключение кода ниже приводит к ошибке:
BEGIN END; /
Приложение вызовет ошибку:
END; * ERROR at line 2: ORA-06550: line 2, column 1: PLS-00103: Encountered the symbol "END" when expecting one of the following: ( begin case declare exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Символ «*» в строке ниже ключевого слова «END»; означает, что блок, который заканчивается этим блоком, пуст или плохо сконструирован. Каждый блок исполнения нуждается в инструкциях, даже если он ничего не делает, как в нашем примере.
Привет, мир
set serveroutput on DECLARE message constant varchar2(32767):= 'Hello, World!'; BEGIN dbms_output.put_line(message); END; /
set serveroutput on команд set serveroutput on SQL * Plus и SQL Developer необходим для включения вывода dbms_output . Без команды ничего не отображается.
end; строка сигнализирует о завершении анонимного блока PL / SQL. Чтобы запустить код из командной строки SQL, вам может потребоваться ввести / в начале первой пустой
https://riptutorial.com/ru/home 3
строки после последней строки кода. Когда вышеуказанный код выполняется в приглашении SQL, он производит следующий результат:
Hello, World! PL/SQL procedure successfully completed.
О PLSQL
PL / SQL означает расширение процедурных языков для SQL. PL / SQL доступен только как «технология разрешения» в других программных продуктах; он не существует как автономный язык. Вы можете использовать PL / SQL в реляционной базе данных Oracle, в Oracle Server и в средствах разработки приложений на стороне клиента, таких как Oracle
Forms. Вот некоторые из способов использования PL / SQL:
Чтобы создать хранимые процедуры. ,1. Чтобы создать триггеры базы данных.2. Для реализации клиентской логики в приложении Oracle Forms.3.
Чтобы связать домашнюю страницу World Wide Web с базой данных Oracle.4.
Разница между% TYPE и% ROWTYPE.
%TYPE : Используется для объявления поля с тем же типом, что и столбец указанной таблицы.
DECLARE vEmployeeName Employee.Name%TYPE; BEGIN SELECT Name INTO vEmployeeName FROM Employee WHERE RowNum = 1; DBMS_OUTPUT.PUT_LINE(vEmployeeName); END; /
% ROWTYPE: используется для объявления записи с теми же типами, что и в указанной таблице, представлении или курсоре (= несколько столбцов).
DECLARE rEmployee Employee%ROWTYPE; BEGIN rEmployee.Name := 'Matt'; rEmployee.Age := 31; DBMS_OUTPUT.PUT_LINE(rEmployee.Name); DBMS_OUTPUT.PUT_LINE(rEmployee.Age); END; /
https://riptutorial.com/ru/home 4
Создать или заменить вид
В этом примере мы создадим представление. Вид в основном используется как простой способ получения данных из нескольких таблиц.
Пример 1: Просмотр с выбором на один стол.
CREATE OR REPLACE VIEW LessonView AS SELECT L.* FROM Lesson L;
Пример 2: Просмотр с помощью выбора на нескольких таблицах.
CREATE OR REPLACE VIEW ClassRoomLessonView AS SELECT C.Id, C.Name, L.Subject, L.Teacher FROM ClassRoom C, Lesson L WHERE C.Id = L.ClassRoomId;
Чтобы вызвать эти представления в запросе, вы можете использовать оператор select.
SELECT * FROM LessonView; SELECT * FROM ClassRoomLessonView;
Создать таблицу
Ниже мы создадим таблицу с тремя столбцами. В столбце Id должен быть заполнен, так что мы определяем его NOT NULL . В столбце « Contract мы также добавляем чек, чтобы разрешалось только «Y» или «N».
Если вставленная вставка и этот столбец не указаны во время вставки, то по умолчанию вставлен «N».
CREATE TABLE Employee ( Id NUMBER NOT NULL, Name VARCHAR2(60), Contract CHAR DEFAULT 'N' NOT NULL, --- CONSTRAINT p_Id PRIMARY KEY(Id), CONSTRAINT c_Contract CHECK (Contract IN('Y','N')) );
Прочитайте Начало работы с PLSQL онлайн: https://riptutorial.com/ru/plsql/topic/1962/начало-работы-с-plsql
https://riptutorial.com/ru/home 5
глава 2: Заявление IF-THEN-ELSE
Синтаксис
IF [условие 1] THEN•
[инструкции для выполнения, когда условие 1 имеет значение ИСТИНА];•
ELSIF [условие 2] THEN•
[инструкции для выполнения, когда условие 2 имеет значение ИСТИНА];•
ELSE•
[инструкции для выполнения, когда оба условия 1 и условие 2 являются FALSE];•
END IF;•
Examples
IF-THEN
DECLARE v_num1 NUMBER(10); v_num2 NUMBER(10); BEGIN v_num1 := 2; v_num2 := 1; IF v_num1 > v_num2 THEN dbms_output.put_line('v_num1 is bigger than v_num2'); END IF; END;
IF-THEN-ELSE
DECLARE v_num1 NUMBER(10); v_num2 NUMBER(10); BEGIN v_num1 := 2; v_num2 := 10; IF v_num1 > v_num2 THEN dbms_output.put_line('v_num1 is bigger than v_num2'); ELSE dbms_output.put_line('v_num1 is NOT bigger than v_num2'); END IF;
https://riptutorial.com/ru/home 6
END;
IF-THEN-ELSE ELSIF-
DECLARE v_num1 NUMBER(10); v_num2 NUMBER(10); BEGIN v_num1 := 2; v_num2 := 2; IF v_num1 > v_num2 THEN dbms_output.put_line('v_num1 is bigger than v_num2'); ELSIF v_num1 < v_num2 THEN dbms_output.put_line('v_num1 is NOT bigger than v_num2'); ELSE dbms_output.put_line('v_num1 is EQUAL to v_num2'); END IF; END;
Прочитайте Заявление IF-THEN-ELSE онлайн: https://riptutorial.com/ru/plsql/topic/5871/
заявление-if-then-else
https://riptutorial.com/ru/home 7
глава 3: Коллекции и отчеты
Examples
Использовать коллекцию как возвращаемый тип для функции split
Необходимо указать тип; здесь t_my_list ; коллекция - TABLE OF something
CREATE OR REPLACE TYPE t_my_list AS TABLE OF VARCHAR2(100);
Вот функция. Обратите внимание: () используется как своего рода конструктор, а также ключевые слова COUNT и EXTEND которые помогают создавать и расширять вашу коллекцию;
CREATE OR REPLACE FUNCTION cto_table(p_sep in Varchar2, p_list IN VARCHAR2) RETURN t_my_list AS --- this function takes a string list, element being separated by p_sep -- as separator l_string VARCHAR2(4000) := p_list || p_sep; l_sep_index PLS_INTEGER; l_index PLS_INTEGER := 1; l_tab t_my_list := t_my_list(); BEGIN LOOP l_sep_index := INSTR(l_string, p_sep, l_index); EXIT WHEN l_sep_index = 0; l_tab.EXTEND; l_tab(l_tab.COUNT) := TRIM(SUBSTR(l_string,l_index,l_sep_index - l_index)); l_index := l_sep_index + 1; END LOOP; RETURN l_tab; END cto_table; /
Затем вы можете увидеть содержимое коллекции с помощью функции TABLE() из SQL; он может использоваться как список внутри инструкции SQL IN ( ..) :
select * from A_TABLE where A_COLUMN in ( TABLE(cto_table('|','a|b|c|d')) ) --- gives the records where A_COLUMN in ('a', 'b', 'c', 'd') --
Прочитайте Коллекции и отчеты онлайн: https://riptutorial.com/ru/plsql/topic/9779/коллекции-и-отчеты
https://riptutorial.com/ru/home 8
глава 4: курсоры
Синтаксис
Курсор cursor_name: your_select_statement•
Курсор cursor_name (param TYPE) Является вашим_select_statement_using_param•FOR x in ( your_select_statement ) LOOP ...•
замечания
Объявленные курсоры сложны в использовании, и в большинстве случаев вы должны предпочитать цикл FOR . Что очень интересно в курсорах по сравнению с простыми циклами FOR , так это то, что вы можете их параметризовать.
Лучше избегать выполнения циклов с PL / SQL и курсоров вместо использования Oracle
SQL в любом случае. Однако для людей, привыкших к процедурному языку, это может быть гораздо легче понять.
Если вы хотите проверить, существует ли запись, а затем делать разные вещи в зависимости от того, существует ли запись или нет, тогда имеет смысл использовать операторы MERGE в чистых запросах ORACLE SQL вместо использования курсоров. (Обратите внимание, что MERGE доступен только в версиях Oracle> = 9i).
Examples
Параметрированный курсор «FOR loop»
DECLARE CURSOR c_emp_to_be_raised(p_sal emp.sal%TYPE) IS SELECT * FROM emp WHERE sal < p_sal; BEGIN FOR cRowEmp IN c_emp_to_be_raised(1000) LOOP dbms_Output.Put_Line(cRowEmp .eName ||' ' ||cRowEmp.sal||'... should be raised ;)'); END LOOP; END; /
Неявный курсор «FOR loop»
BEGIN FOR x IN (SELECT * FROM emp WHERE sal < 100) LOOP dbms_Output.Put_Line(x.eName ||' '||x.sal||'... should REALLY be raised :D'); END LOOP; END; /
https://riptutorial.com/ru/home 9
Первое преимущество заключается в том, что нет утомительной декларации (подумайте об этом ужасном «КУРСОРЕ», которое у вас было в предыдущих версиях)
•
второе преимущество заключается в том, что вы сначала создаете свой запрос выбора, а затем, когда у вас есть то, что вы хотите, вы сразу можете получить доступ к полям вашего запроса ( x.<myfield> ) в вашем цикле PL / SQL
•
Цикл открывает курсор и выбирает по одной записи за каждый цикл. В конце цикла курсор закрывается.
•
Неявные курсоры быстрее, потому что работа интерпретатора возрастает по мере увеличения кода. Чем меньше кода, тем меньше работает интерпретатор.
•
Работа с SYS_REFCURSOR
SYS_REFCURSOR можно использовать как возвращаемый тип, когда вам нужно легко обрабатывать список, возвращенный не из таблицы, а, более конкретно, из функции:
функция, возвращающая курсорCREATE OR REPLACE FUNCTION list_of (required_type_in IN VARCHAR2) RETURN SYS_REFCURSOR IS v_ SYS_REFCURSOR; BEGIN CASE required_type_in WHEN 'CATS' THEN OPEN v_ FOR SELECT nickname FROM ( select 'minou' nickname from dual union all select 'minâ' from dual union all select 'minon' from dual ); WHEN 'DOGS' THEN OPEN v_ FOR SELECT dog_call FROM ( select 'bill' dog_call from dual union all select 'nestor' from dual union all select 'raoul' from dual ); END CASE; -- Whit this use, you must not close the cursor. RETURN v_; END list_of; /
и как его использовать:DECLARE v_names SYS_REFCURSOR;
https://riptutorial.com/ru/home 10
v_ VARCHAR2 (32767); BEGIN v_names := list_of('CATS'); LOOP FETCH v_names INTO v_; EXIT WHEN v_names%NOTFOUND; DBMS_OUTPUT.put_line(v_); END LOOP; -- here you close it CLOSE v_names; END; /
Обработка КУРСОРА
Объявить курсор для сканирования списка записей•Открой это•Получить текущую запись в переменные (это увеличивает положение)•Использовать %notfound для обнаружения конца списка•Не забудьте закрыть курсор, чтобы ограничить потребление ресурсов в текущем контексте
•
-
DECLARE CURSOR curCols IS -- select column name and type from a given table SELECT column_name, data_type FROM all_tab_columns where table_name='MY_TABLE'; v_tab_column all_tab_columns.column_name%TYPE; v_data_type all_tab_columns.data_type%TYPE; v_ INTEGER := 1; BEGIN OPEN curCols; LOOP FETCH curCols INTO v_tab_column, v_data_type; IF curCols%notfound OR v_ > 2000 THEN EXIT; END IF; dbms_output.put_line(v_||':Column '||v_tab_column||' is of '|| v_data_type||' Type.'); v_:= v_ + 1; END LOOP; -- Close in any case IF curCols%ISOPEN THEN CLOSE curCols; END IF; END; /
Прочитайте курсоры онлайн: https://riptutorial.com/ru/plsql/topic/5303/курсоры
https://riptutorial.com/ru/home 11
глава 5: Массовый сбор
Examples
Обработка объемных данных
локальные коллекции не допускаются в отдельных операторах. Следовательно, первым шагом является создание коллекции уровня схемы. Если коллекция не является уровнем схемы и используется в операторах SELECT, это приведет к появлению «PLS-00642:
локальные типы коллекций, недопустимые в операторах SQL»,
CREATE OR REPLACE TYPE table1_t IS OBJECT ( a_1 INTEGER, a_2 VARCHAR2(10) );
--Greg разрешения на сбор, чтобы он мог публично использоваться в базе данных
GRANT EXECUTE ON table1_t TO PUBLIC; CREATE OR REPLACE TYPE table1_tbl_typ IS TABLE OF table1_t; GRANT EXECUTE ON table1_tbl_typ TO PUBLIC;
- выбор данных из таблицы в коллекцию, а затем цикл по коллекции и печать данных.
DECLARE table1_tbl table1_tbl_typ; BEGIN table1_tbl := table1_tbl_typ(); SELECT table1_t(a_1,a_2) BULK COLLECT INTO table1_tbl FROM table1 WHERE ROWNUM<10; FOR rec IN (SELECT a_1 FROM TABLE(table1_tbl))--table(table1_tbl) won't give error) LOOP dbms_output.put_line('a_1'||rec.a_1); dbms_output.put_line('a_2'||rec.a_2); END LOOP; END; /
Прочитайте Массовый сбор онлайн: https://riptutorial.com/ru/plsql/topic/6855/массовый-сбор
https://riptutorial.com/ru/home 12
глава 6: Модель и язык заданий
Examples
Модель присвоений в PL / SQL
Все языки программирования позволяют присваивать значения переменным. Обычно значение присваивается переменной, стоящей с левой стороны. Прототип операций общего назначения в любом современном языке программирования выглядит следующим образом:
left_operand assignment_operand right_operand instructions_of_stop
Это назначит правый операнд левому операнду. В PL / SQL эта операция выглядит так:
left_operand := right_operand;
Левый операнд всегда должен быть переменной . Правильный операнд может быть значением, переменной или функцией:
set serveroutput on declare v_hello1 varchar2(32767); v_hello2 varchar2(32767); v_hello3 varchar2(32767); function hello return varchar2 is begin return 'Hello from a function!'; end; begin -- from a value (string literal) v_hello1 := 'Hello from a value!'; -- from variable v_hello2 := v_hello1; -- from function v_hello3 := hello; dbms_output.put_line(v_hello1); dbms_output.put_line(v_hello2); dbms_output.put_line(v_hello3); end; /
Когда блок кода выполняется в SQL * Plus, на консоли выводится следующий вывод:
Hello from a value! Hello from a value! Hello from a function!
В PL / SQL есть функция, которая позволяет нам назначать «справа налево». Это можно сделать в инструкции SELECT INTO. Прототип этого узла вы найдете ниже:
https://riptutorial.com/ru/home 13
SELECT [ literal | column_value ] INTO local_variable FROM [ table_name | aliastable_name ] WHERE comparison_instructions;
Этот код присваивает символьный литерал локальной переменной:
set serveroutput on declare v_hello varchar2(32767); begin select 'Hello world!' into v_hello from dual; dbms_output.put_line(v_hello); end; /
Когда блок кода выполняется в SQL * Plus, на консоли выводится следующий вывод:
Hello world!
Назначение «справа налево» не является стандартом , но это ценная функция для программистов и пользователей. Обычно он используется, когда программист использует курсоры в PL / SQL - этот метод используется, когда мы хотим вернуть одно скалярное значение или набор столбцов в одной строке курсора из курсора SQL.
Дальнейшее чтение:
Присвоение значений переменным•
Прочитайте Модель и язык заданий онлайн: https://riptutorial.com/ru/plsql/topic/6959/модель-и-язык-заданий
https://riptutorial.com/ru/home 14
глава 7: Обработка исключений
Вступление
Oracle производит множество исключений. Вы можете быть удивлены, насколько утомительным может быть ваш код с некоторым неясным сообщением. Чтобы улучшить способность кода PL / SQL легко фиксироваться, необходимо обрабатывать исключения на самом низком уровне. Никогда не скрывайте исключение «под ковром», если только вы здесь, чтобы сохранить свою часть кода только для вас и никому больше не поддерживать.
Предопределенные ошибки .
Examples
Обработка исключений
Что такое исключение?
Исключение в PL / SQL является ошибкой, созданной во время выполнения программы.
У нас есть три типа исключений:
Исключенные внутри страны исключения•Предопределенные исключения•Пользовательские исключения•
1.
Что такое обработка исключений?
Обработка исключений - это возможность поддерживать нашу программу даже при появлении ошибки времени выполнения, вызванной, например, ошибками кодирования, сбоями оборудования. Мы избегаем его внезапного выхода из строя.
2.
Синтаксис
Общий синтаксис для секции исключения:
declare declaration Section begin some statements exception when exception_one then
https://riptutorial.com/ru/home 15
do something when exception_two then do something when exception_three then do something when others then do something end;
Секция исключений должна быть в конце блока PL / SQL. PL / SQL дает нам возможность блокировать блоки, тогда каждый блок может иметь свой собственный раздел исключения, например:
create or replace procedure nested_blocks is begin some statements begin some statements exception when exception_one then do something end; exception when exception_two then do something end;
Если исключение будет поднято во вложенном блоке, оно должно быть обработано во внутреннем разделе исключения, но если внутренняя секция исключения не обрабатывает это исключение, то это исключение перейдет в секцию исключения внешнего блока.
Исключенные внутри страны исключения
Внутренне определенное исключение не имеет имени, но имеет свой собственный код.
Когда его использовать?
Если вы знаете, что в вашей операции с базой данных могут возникать определенные исключения, те, у которых нет имен, вы можете дать им имена, чтобы вы могли специально писать для них обработчики исключений. В противном случае вы можете использовать их только с others обработчиками исключений.
Синтаксис
declare my_name_exc exception; pragma exception_init(my_name_exc,-37); begin ... exception when my_name_exc then
https://riptutorial.com/ru/home 16
do something end;
my_name_exc exception; это объявление имени исключения.
pragma exception_init(my_name_exc,-37); присваивать имя коду ошибки внутреннего исключения.
пример
У нас есть emp_id, который является первичным ключом в таблице emp и внешним ключом в таблице dept. Если мы попытаемся удалить emp_id, когда у него есть дочерние записи, он будет исключен с кодом -2292.
create or replace procedure remove_employee is emp_exception exception; pragma exception_init(emp_exception,-2292); begin delete from emp where emp_id = 3; exception when emp_exception then dbms_output.put_line('You can not do that!'); end; /
Документация Oracle гласит: «Внутренне определенное исключение с объявленным пользователем именем по-прежнему является внутренне определенным исключением, а не определяемым пользователем исключением».
Предопределенные исключения
Предопределенные исключения являются внутренне определенными исключениями, но имеют имена. База данных Oracle автоматически генерирует этот тип исключений.
пример
create or replace procedure insert_emp is begin insert into emp (emp_id, ename) values ('1','Jon'); exception when dup_val_on_index then dbms_output.put_line('Duplicate value on index!'); end; /
Ниже приведены примеры исключений с их кодами:
https://riptutorial.com/ru/home 17
Имя исключения Код ошибки
ДАННЫЕ НЕ НАЙДЕНЫ -1403
ACCESS_INTO_NULL -6530
CASE_NOT_FOUND -6592
ROWTYPE_MISMATCH -6504
TOO_MANY_ROWS -1422
ZERO_DIVIDE -1476
Полный список имен исключений и их кодов на веб-сайте Oracle.
Пользовательские исключения
Как видно из названия, пользовательские исключения создаются пользователями. Если вы хотите создать свое собственное исключение, вы должны:
Объявить исключение1. Поднимите его из своей программы2. Создайте подходящий обработчик исключений, чтобы поймать его.3.
пример
Я хочу обновить все зарплаты рабочих. Но если нет рабочих, создайте исключение.
create or replace procedure update_salary is no_workers exception; v_counter number := 0; begin select count(*) into v_counter from emp; if v_counter = 0 then raise no_workers; else update emp set salary = 3000; end if; exception when no_workers then raise_application_error(-20991,'We don''t have workers!'); end; /
Что значит raise ?
Исключения создаются сервером базы данных автоматически, когда есть необходимость, но если вы хотите, вы можете явно выражать любое исключение, используя raise .
https://riptutorial.com/ru/home 18
Процедура raise_application_error(error_number,error_message);
error_number должен находиться между -20000 и -20999•
error_message для отображения при возникновении ошибки.•
Определите настраиваемое исключение, поднимите его и посмотрите, откуда он
Чтобы проиллюстрировать это, вот функция, которая имеет 3 разных «неправильных» поведения
параметр полностью тупой: мы используем пользовательское выражение•параметр имеет опечатку: мы используем стандартную ошибку Oracle NO_DATA_FOUND•
другой, но не обработанный случай•
Не стесняйтесь адаптировать его к своим стандартам:
DECLARE this_is_not_acceptable EXCEPTION; PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077); g_err varchar2 (200) := 'to-be-defined'; w_schema all_tables.OWNER%Type; PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2) Is w_err varchar2 (200) := 'to-be-defined'; BEGIN w_err := 'get_schema-step-1:'; If (p_table = 'Delivery-Manager-Is-Silly') Then raise this_is_not_acceptable; end if; w_err := 'get_schema-step-2:'; Select owner Into p_schema From all_tables where table_name like(p_table||'%'); EXCEPTION WHEN NO_DATA_FOUND THEN -- handle Oracle-defined exception dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.'); WHEN this_is_not_acceptable THEN -- handle your custom error dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.'); When others then dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm); raise; END Get_schema; BEGIN g_err := 'Global; first call:'; get_schema('Delivery-Manager-Is-Silly', w_schema); g_err := 'Global; second call:'; get_schema('AAA', w_schema); g_err := 'Global; third call:'; get_schema('', w_schema);
https://riptutorial.com/ru/home 19
g_err := 'Global; 4th call:'; get_schema('Can''t reach this point due to previous error.', w_schema); EXCEPTION When others then dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm); -- you may raise this again to the caller if error log isn't enough. -- raise; END; /
Предоставление регулярной базы данных:
[WARN]get_schema-step-1:Please don't make fun of the delivery manager. [WARN]get_schema-step-2:This can happen. Check the table name you entered. [ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows [ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
Помните, что исключение здесь для обработки редких случаев. Я видел приложения, которые создавали исключение при каждом доступе, просто чтобы запросить пароль пользователя, сказав «не подключен» ... столько отходов вычислений.
Исключение ошибок связи
Каждая стандартная ошибка Oracle связана с номером ошибки. Важно предугадать, что может пойти не так в коде. Здесь для подключения к другой базе данных это может быть:
-28000 заблокирован•-28001 пароль истек•-28002 льготный период•-1017 неправильный пользователь / пароль•
Вот способ проверить, что не так с пользователем, используемым ссылкой базы данных:
declare v_dummy number; begin -- testing db link execute immediate 'select COUNT(1) from [email protected]' into v_dummy ; -- if we get here, exception wasn't raised: display COUNT's result dbms_output.put_line(v_dummy||' users on PASS db'); EXCEPTION -- exception can be referred by their name in the predefined Oracle's list When LOGIN_DENIED then dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN'); When Others then -- or referred by their number: stored automatically in reserved variable SQLCODE If SQLCODE = '-2019'
https://riptutorial.com/ru/home 20
Then dbms_output.put_line('ORA-2019 / Invalid db_link name'); Elsif SQLCODE = '-1035' Then dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA'); Elsif SQLCODE = '-28000' Then dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA'); Elsif SQLCODE = '-28001' Then dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE'); Elsif SQLCODE = '-28002' Then dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT'); Else -- and if it's not one of the exception you expected dbms_output.put_line('Exception not specifically handled'); dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM); End if; END; /
Прочитайте Обработка исключений онлайн: https://riptutorial.com/ru/plsql/topic/6050/
обработка-исключений
https://riptutorial.com/ru/home 21
глава 8: Обработка исключений
Вступление
Oracle производит множество исключений. Вы можете быть удивлены, насколько утомительным может быть ваш код с некоторым неясным сообщением. Чтобы улучшить способность кода PL / SQL легко фиксироваться, необходимо обрабатывать исключения на самом низком уровне. Никогда не скрывайте исключение «под ковром», если только вы здесь, чтобы сохранить свою часть кода только для вас и никому больше не поддерживать.
Предопределенные ошибки .
Examples
Исключение ошибок связи
Каждая стандартная ошибка Oracle связана с номером ошибки. Его важно предвидеть, что может пойти не так в коде. Здесь для подключения к другой базе данных это может быть:
-28000 заблокирован•-28001 пароль истек•-28002 льготный период•-1017 неправильный пользователь / пароль•
Вот способ проверить, что не так с пользователем, используемым ссылкой базы данных:
declare v_dummy number; begin -- testing db link execute immediate 'select COUNT(1) from [email protected]' into v_dummy ; -- if we get here, exception wasn't raised: display COUNT's result dbms_output.put_line(v_dummy||' users on PASS db'); EXCEPTION -- exception can be referred by their name in the predefined Oracle's list When LOGIN_DENIED then dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN'); When Others then -- or referred by their number: stored automatically in reserved variable SQLCODE If SQLCODE = '-2019' Then dbms_output.put_line('ORA-2019 / Invalid db_link name'); Elsif SQLCODE = '-1035' Then
https://riptutorial.com/ru/home 22
dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA'); Elsif SQLCODE = '-28000' Then dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA'); Elsif SQLCODE = '-28001' Then dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE'); Elsif SQLCODE = '-28002' Then dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT'); Else -- and if it's not one of the exception you expected dbms_output.put_line('Exception not specifically handled'); dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM); End if; END; /
Определите настраиваемое исключение, поднимите его и посмотрите, откуда он
Чтобы проиллюстрировать это, вот функция, которая имеет 3 разных «неправильных» поведения
параметр полностью тупой: мы используем пользовательское выражение•параметр имеет опечатку: мы используем стандартную ошибку Oracle NO_DATA_FOUND•
другой, но не обработанный случай•
Не стесняйтесь адаптировать его к своим стандартам:
DECLARE this_is_not_acceptable EXCEPTION; PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077); g_err varchar2 (200) := 'to-be-defined'; w_schema all_tables.OWNER%Type; PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2) Is w_err varchar2 (200) := 'to-be-defined'; BEGIN w_err := 'get_schema-step-1:'; If (p_table = 'Delivery-Manager-Is-Silly') Then raise this_is_not_acceptable; end if; w_err := 'get_schema-step-2:'; Select owner Into p_schema From all_tables where table_name like(p_table||'%'); EXCEPTION WHEN NO_DATA_FOUND THEN -- handle Oracle-defined exception dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.'); WHEN this_is_not_acceptable THEN -- handle your custom error
https://riptutorial.com/ru/home 23
dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.'); When others then dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm); raise; END Get_schema; BEGIN g_err := 'Global; first call:'; get_schema('Delivery-Manager-Is-Silly', w_schema); g_err := 'Global; second call:'; get_schema('AAA', w_schema); g_err := 'Global; third call:'; get_schema('', w_schema); g_err := 'Global; 4th call:'; get_schema('Can''t reach this point due to previous error.', w_schema); EXCEPTION When others then dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm); -- you may raise this again to the caller if error log isn't enough. -- raise; END; /
Предоставление регулярной базы данных:
[WARN]get_schema-step-1:Please don't make fun of the delivery manager. [WARN]get_schema-step-2:This can happen. Check the table name you entered. [ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows [ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
Помните, что исключение здесь для обработки редких случаев. Я видел приложения, которые возбуждали исключение при каждом доступе, просто чтобы запросить пароль пользователя, говоря «не подключен» ... столько отходов вычислений.
Прочитайте Обработка исключений онлайн: https://riptutorial.com/ru/plsql/topic/9480/
обработка-исключений
https://riptutorial.com/ru/home 24
глава 9: пакеты
Синтаксис
CREATE [OR REPLACE] PACKAGE имя_пакета
[AUTHID {CURRENT_USER | DEFINER}]
{IS | КАК}
[PRAGMA SERIALLY_REUSABLE;]
[collection_type_definition ...]
[record_type_definition ...]
[subtype_definition ...]
[collection_declaration ...]
[constant_declaration ...]
[exception_declaration ...]
[object_declaration ...]
[record_declaration ...]
[variable_declaration ...]
[cursor_spec ...]
[function_spec ...]
[procedure_spec ...]
[call_spec ...]
[PRAGMA RESTRICT_REFERENCES (утверждения) ...]
END [имя_пакета];
•
СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ПАКЕТ PackageName IS
ФУНКЦИЯ FunctionName (параметр1 IN VARCHAR2, параметр2 IN NUMBER) RETURN VARCHAR2;
END PackageName;
•
https://riptutorial.com/ru/home 25
CREATE [OR REPLACE] PACKAGE BODY имя_пакета
{IS | КАК}
[PRAGMA SERIALLY_REUSABLE;]
[collection_type_definition ...]
[record_type_definition ...]
[subtype_definition ...]
[collection_declaration ...]
[constant_declaration ...]
[exception_declaration ...]
[object_declaration ...]
[record_declaration ...]
[variable_declaration ...]
[cursor_body ...]
[function_spec ...]
[procedure_spec ...]
[call_spec ...]
END [имя_пакета];
•
СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ПАКЕТНЫЙ ТЕЛО PackageName IS
ФУНКЦИЯ FunctionName (параметр1 IN VARCHAR2, paramter2 IN NUMBER) RETURN VARCHAR2 IS
декларации
НАЧАТЬ
операторы для выполнения
RETURN переменная varchar2
END FunctionName;
END PackageName;
•
https://riptutorial.com/ru/home 26
Examples
Использование пакета
Пакеты в PLSQL представляют собой набор процедур, функций, переменных, исключений, констант и структур данных. Как правило, ресурсы в пакете связаны друг с другом и выполняют аналогичные задачи.
Зачем использовать пакеты
модульность•Лучшая производительность / функциональность•
Части пакета
Спецификация - иногда называется заголовком пакета. Содержит объявления переменных и типов и подписи функций и процедур, которые находятся в пакете, которые публично вызывают извне пакета.
Body Package - содержит код и частные объявления.
Спецификация пакета должна быть скомпилирована перед телом пакета, иначе компиляция тела пакета сообщит об ошибке.
перегрузка
Функции и процедуры в пакетах могут быть перегружены. Следующий пакет TEST имеет две процедуры, называемые print_number , которые ведут себя по-разному в зависимости от параметров, с которыми они вызываются.
create or replace package TEST is procedure print_number(p_number in integer); procedure print_number(p_number in varchar2); end TEST; / create or replace package body TEST is procedure print_number(p_number in integer) is begin dbms_output.put_line('Digit: ' || p_number); end; procedure print_number(p_number in varchar2) is begin dbms_output.put_line('String: ' || p_number); end; end TEST; /
https://riptutorial.com/ru/home 27
Мы называем обе процедуры. Первый с целым параметром, второй с varchar2.
set serveroutput on; -- call the first procedure exec test.print_number(3); -- call the second procedure exec test.print_number('three');
Вывод приведенного выше сценария:
SQL> Digit: 3 PL/SQL procedure successfully completed String: three PL/SQL procedure successfully completed
Ограничения на перегрузку
Могут быть перегружены только локальные или упакованные подпрограммы или методы типа. Поэтому вы не можете перегружать автономные подпрограммы. Кроме того, вы не можете перегружать две подпрограммы, если их формальные параметры отличаются только именем или параметром
Определите заголовок и тело пакета с помощью функции.
В этом примере мы определяем заголовок пакета и тело пакета с функцией. После этого мы вызываем функцию из пакета, возвращающую возвращаемое значение.
Заголовок пакета :
CREATE OR REPLACE PACKAGE SkyPkg AS FUNCTION GetSkyColour(vPlanet IN VARCHAR2) RETURN VARCHAR2; END; /
Корпус упаковки :
CREATE OR REPLACE PACKAGE BODY SkyPkg AS FUNCTION GetSkyColour(vPlanet IN VARCHAR2) RETURN VARCHAR2 AS vColour VARCHAR2(100) := NULL; BEGIN IF vPlanet = 'Earth' THEN vColour := 'Blue'; ELSIF vPlanet = 'Mars' THEN vColour := 'Red';
https://riptutorial.com/ru/home 28
END IF; RETURN vColour; END; END; /
Вызов функции из корпуса пакета :
DECLARE vColour VARCHAR2(100); BEGIN vColour := SkyPkg.GetSkyColour(vPlanet => 'Earth'); DBMS_OUTPUT.PUT_LINE(vColour); END; /
Прочитайте пакеты онлайн: https://riptutorial.com/ru/plsql/topic/4764/пакеты
https://riptutorial.com/ru/home 29
глава 10: петля
Синтаксис
LOOP1. [заявления];2.
EXIT WHEN [условие для цикла выхода];3. END LOOP;4.
Examples
Простая петля
DECLARE v_counter NUMBER(2); BEGIN v_counter := 0; LOOP v_counter := v_counter + 1; dbms_output.put_line('Line number' || v_counter); EXIT WHEN v_counter = 10; END LOOP; END;
WHILE Loop
Цикл WHILE выполняется до тех пор, пока не будет выполнено условие конца. Простой пример:
DECLARE v_counter NUMBER(2); --declaration of counter variable BEGIN v_counter := 0; --point of start, first value of our iteration WHILE v_counter < 10 LOOP --exit condition dbms_output.put_line('Current iteration of loop is ' || v_counter); --show current iteration number in dbms script output v_counter := v_counter + 1; --incrementation of counter value, very important step END LOOP; --end of loop declaration END;
Этот цикл будет выполнен до тех пор, пока текущее значение переменной v_counter не будет меньше десяти.
https://riptutorial.com/ru/home 30
Результат:
Current iteration of loop is 0 Current iteration of loop is 1 Current iteration of loop is 2 Current iteration of loop is 3 Current iteration of loop is 4 Current iteration of loop is 5 Current iteration of loop is 6 Current iteration of loop is 7 Current iteration of loop is 8 Current iteration of loop is 9
Самое главное, что наш цикл начинается с значения «0», поэтому первая строка результатов «Текущая итерация цикла равна 0».
FOR Loop
Loop FOR работает по аналогичным правилам, как и другие циклы. FOR цикл выполняется точное число раз, и это число известно в начале - нижний и верхний пределы напрямую задаются в коде. На каждом шаге этого примера цикл увеличивается на 1.
Простой пример:
DECLARE v_counter NUMBER(2); --declaration of counter variable BEGIN v_counter := 0; --point of start, first value of our iteration, execute of variable FOR v_counter IN 1..10 LOOP --The point, where lower and upper point of loop statement is declared - in this example, loop will be executed 10 times, start with value of 1 dbms_output.put_line('Current iteration of loop is ' || v_counter); --show current iteration number in dbms script output END LOOP; --end of loop declaration END;
И результат:
Current iteration of loop is 1 Current iteration of loop is 2 Current iteration of loop is 3 Current iteration of loop is 4 Current iteration of loop is 5 Current iteration of loop is 6 Current iteration of loop is 7 Current iteration of loop is 8 Current iteration of loop is 9 Current iteration of loop is 10
Loop FOR имеет дополнительное свойство, которое работает в обратном порядке.
https://riptutorial.com/ru/home 31
Использование дополнительного слова «REVERSE» в объявлении нижнего и верхнего пределов цикла позволяет это сделать. Каждое выполнение значения декремента цикла v_counter на 1.
Пример:
DECLARE v_counter NUMBER(2); --declaration of counter variable BEGIN v_counter := 0; --point of start FOR v_counter IN REVERSE 1..10 LOOP dbms_output.put_line('Current iteration of loop is ' || v_counter); --show current iteration number in dbms script output END LOOP; --end of loop declaration END;
И результат:
Current iteration of loop is 10 Current iteration of loop is 9 Current iteration of loop is 8 Current iteration of loop is 7 Current iteration of loop is 6 Current iteration of loop is 5 Current iteration of loop is 4 Current iteration of loop is 3 Current iteration of loop is 2 Current iteration of loop is 1
Прочитайте петля онлайн: https://riptutorial.com/ru/plsql/topic/6157/петля
https://riptutorial.com/ru/home 32
глава 11: Процедура PLSQL
Вступление
Процедура PLSQL - это группа операторов SQL, хранящихся на сервере для повторного использования. Это увеличивает производительность, потому что SQL-запросы не нужно перекомпилировать каждый раз, когда они выполняются.
Хранимые процедуры полезны, когда один и тот же код требуется для нескольких приложений. Хранимые процедуры исключают избыточность и вводят простоту в код. Когда требуется передача данных между клиентом и сервером, процедуры могут снизить стоимость связи в определенных ситуациях.
Examples
Синтаксис
CREATE [OR REPLACE] PROCEDURE procedure_name [(parameter_name [IN | OUT | IN OUT] type [, ...])] {IS | AS} < declarations > BEGIN < procedure_body > EXCEPTION -- Exception-handling part begins <exception handling goes here > WHEN exception1 THEN exception1-handling-statements END procedure_name;
имя процедуры задает имя процедуры.•Опция [ИЛИ ЗАМЕНИТЬ] позволяет изменить существующую процедуру.•Дополнительный список параметров содержит имя, режим и типы параметров. IN
представляет, что значение будет передано извне, а OUT представляет, что этот параметр будет использоваться для возврата значения вне процедуры. Если режим не указан, предполагается, что параметр имеет режим IN.
•
В разделе декларации мы можем объявлять переменные, которые будут использоваться в части тела.
•
procedure-body содержит исполняемую часть.•
Ключевое слово AS используется вместо ключевого слова IS для создания автономной процедуры.
•
исключение будет обрабатывать исключения из процедуры. Этот раздел не является обязательным.
•
Привет, мир
https://riptutorial.com/ru/home 33
Следующая простая процедура отображает текст «Hello World» в клиенте, который поддерживает dbms_output .
CREATE OR REPLACE PROCEDURE helloworld AS BEGIN dbms_output.put_line('Hello World!'); END; /
Вам нужно выполнить это в приглашении SQL, чтобы создать процедуру в базе данных, или вы можете запустить запрос ниже, чтобы получить тот же результат:
SELECT 'Hello World!' from dual;
Параметры ввода / вывода
PL / SQL использует ключевые слова IN, OUT, IN OUT для определения того, что может случиться с переданным параметром.
IN указывает, что параметр только для чтения, и значение не может быть изменено процедурой.
OUT указывает, что параметр только для записи, и процедура может назначить ему значение, но не ссылаться на значение.
IN OUT указывает, что параметр доступен для справки и изменения.
PROCEDURE procedureName(x IN INT, strVar IN VARCHAR2, ans OUT VARCHAR2) ... ... END procedureName; procedureName(firstvar, secondvar, thirdvar);
Переменные, перечисленные в приведенном выше примере, должны быть напечатаны так, как они определены в разделе параметров процедуры.
Прочитайте Процедура PLSQL онлайн: https://riptutorial.com/ru/plsql/topic/2580/процедура-plsql
https://riptutorial.com/ru/home 34
глава 12: Типы объектов
замечания
Важно отметить, что тело объекта может не всегда быть необходимым. Если конструктор по умолчанию достаточен, и никакая другая функциональность не должна быть реализована, то его не следует создавать.
Конструктор по умолчанию представляет собой поставляемый Oracle конструктор, который состоит из всех атрибутов, перечисленных в порядке объявления. Например, экземпляр BASE_TYPE может быть сконструирован следующим вызовом, хотя мы явно не объявляем его.
l_obj := BASE_TYPE(1, 'Default', 1);
Examples
BASE_TYPE
Объявление типа:
CREATE OR REPLACE TYPE base_type AS OBJECT ( base_id INTEGER, base_attr VARCHAR2(400), null_attr INTEGER, -- Present only to demonstrate non-default constructors CONSTRUCTOR FUNCTION base_type ( i_base_id INTEGER, i_base_attr VARCHAR2 ) RETURN SELF AS RESULT, MEMBER FUNCTION get_base_id RETURN INTEGER, MEMBER FUNCTION get_base_attr RETURN VARCHAR2, MEMBER PROCEDURE set_base_id(i_base_id INTEGER), MEMBER PROCEDURE set_base_attr(i_base_attr VARCHAR2), MEMBER FUNCTION to_string RETURN VARCHAR2 ) INSTANTIABLE NOT FINAL
Тип кузова:
CREATE OR REPLACE TYPE BODY base_type AS CONSTRUCTOR FUNCTION base_type ( i_base_id INTEGER, i_base_attr VARCHAR2 ) RETURN SELF AS RESULT IS BEGIN self.base_id := i_base_id;
https://riptutorial.com/ru/home 35
self.base_attr := i_base_attr; RETURN; END base_type; MEMBER FUNCTION get_base_id RETURN INTEGER IS BEGIN RETURN self.base_id; END get_base_id; MEMBER FUNCTION get_base_attr RETURN VARCHAR2 IS BEGIN RETURN self.base_attr; END get_base_attr; MEMBER PROCEDURE set_base_id(i_base_id INTEGER) IS BEGIN self.base_id := i_base_id; END set_base_id; MEMBER PROCEDURE set_base_attr(i_base_attr VARCHAR2) IS BEGIN self.base_attr := i_base_attr; END set_base_attr; MEMBER FUNCTION to_string RETURN VARCHAR2 IS BEGIN RETURN 'BASE_ID ['||self.base_id||']; BASE_ATTR ['||self.base_attr||']'; END to_string; END;
MID_TYPE
Объявление типа:
CREATE OR REPLACE TYPE mid_type UNDER base_type ( mid_attr DATE, CONSTRUCTOR FUNCTION mid_type ( i_base_id INTEGER, i_base_attr VARCHAR2, i_mid_attr DATE ) RETURN SELF AS RESULT, MEMBER FUNCTION get_mid_attr RETURN DATE, MEMBER PROCEDURE set_mid_attr(i_mid_attr DATE), OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2 ) INSTANTIABLE NOT FINAL
Тип кузова:
CREATE OR REPLACE TYPE BODY mid_type AS CONSTRUCTOR FUNCTION mid_type ( i_base_id INTEGER, i_base_attr VARCHAR2, i_mid_attr DATE ) RETURN SELF AS RESULT IS
https://riptutorial.com/ru/home 36
BEGIN self.base_id := i_base_id; self.base_attr := i_base_attr; self.mid_attr := i_mid_attr; RETURN; END mid_type; MEMBER FUNCTION get_mid_attr RETURN DATE IS BEGIN RETURN self.mid_attr; END get_mid_attr; MEMBER PROCEDURE set_mid_attr(i_mid_attr DATE) IS BEGIN self.mid_attr := i_mid_attr; END set_mid_attr; OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2 IS BEGIN RETURN (SELF AS base_type).to_string || '; MID_ATTR [' || self.mid_attr || ']'; END to_string; END;
LEAF_TYPE
Объявление типа:
CREATE OR REPLACE TYPE leaf_type UNDER mid_type ( leaf_attr VARCHAR2(1000), CONSTRUCTOR FUNCTION leaf_type ( i_base_id INTEGER, i_base_attr VARCHAR2, i_mid_attr DATE, i_leaf_attr VARCHAR2 ) RETURN SELF AS RESULT, MEMBER FUNCTION get_leaf_attr RETURN VARCHAR2, MEMBER PROCEDURE set_leaf_attr(i_leaf_attr VARCHAR2), OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2 ) INSTANTIABLE FINAL
Тип кузова:
CREATE OR REPLACE TYPE BODY leaf_type AS CONSTRUCTOR FUNCTION leaf_type ( i_base_id INTEGER, i_base_attr VARCHAR2, i_mid_attr DATE, i_leaf_attr VARCHAR2 ) RETURN SELF AS RESULT IS BEGIN self.base_id := i_base_id; self.base_attr := i_base_attr; self.mid_attr := i_mid_attr;
https://riptutorial.com/ru/home 37
self.leaf_attr := i_leaf_attr; RETURN; END leaf_type; MEMBER FUNCTION get_leaf_attr RETURN VARCHAR2 IS BEGIN RETURN self.leaf_attr; END get_leaf_attr; MEMBER PROCEDURE set_leaf_attr(i_leaf_attr VARCHAR2) IS BEGIN self.leaf_attr := i_leaf_attr; END set_leaf_attr; OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2 IS BEGIN RETURN (SELF AS mid_type).to_string || '; LEAF_ATTR [' || self.leaf_attr || ']'; END to_string; END;
Доступ к хранимым объектам
CREATE SEQUENCE test_seq START WITH 1001; CREATE TABLE test_tab ( test_id INTEGER, test_obj base_type, PRIMARY KEY (test_id) ); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, base_type(1,'BASE_TYPE')); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, base_type(2,'BASE_TYPE')); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, mid_type(3, 'MID_TYPE',SYSDATE - 1)); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, mid_type(4, 'MID_TYPE',SYSDATE + 1)); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, leaf_type(5, 'LEAF_TYPE',SYSDATE - 20,'Maple')); INSERT INTO test_tab (test_id, test_obj) VALUES (test_seq.nextval, leaf_type(6, 'LEAF_TYPE',SYSDATE + 20,'Oak'));
Возвращает ссылку на объект:
SELECT test_id ,test_obj FROM test_tab;
Возвращает ссылку на объект, нажав все на подтип
SELECT test_id ,TREAT(test_obj AS mid_type) AS obj FROM test_tab;
https://riptutorial.com/ru/home 38
Возвращает дескриптор строки каждого объекта по типу
SELECT test_id ,TREAT(test_obj AS base_type).to_string() AS to_string -- Parenthesis are needed after the function name, or Oracle will look for an attribute of this name. FROM test_tab;
Прочитайте Типы объектов онлайн: https://riptutorial.com/ru/plsql/topic/7699/типы-объектов
https://riptutorial.com/ru/home 39
глава 13: Триггеры
Вступление
Вступление:
Триггеры - полезная концепция в PL / SQL. Триггер - это особый тип хранимой процедуры, который не требует явного вызова пользователем. Это группа инструкций, которая автоматически запускается в ответ на конкретное действие модификации данных в конкретной таблице или отношении или при выполнении определенных условий. Триггеры помогают поддерживать целостность и безопасность данных. Они делают работу удобной, автоматически выполняя требуемые действия.
Синтаксис
СОЗДАТЬ [ИЛИ ЗАМЕНИТЬ] TRIGGER trigger_name•
ПЕРЕД ОБНОВЛЕНИЕМ [или ВСТАВИТЬ] [или УДАЛИТЬ]•ON table_name•[ДЛЯ КАЖДОГО РУКА]•DECLARE•- объявления переменных•
НАЧАТЬ•- код запуска•
ИСКЛЮЧЕНИЕ•КОГДА ...•-- Обработка исключений•
КОНЕЦ;•
Examples
Перед вызовом INSERT или UPDATE
CREATE OR REPLACE TRIGGER CORE_MANUAL_BIUR BEFORE INSERT OR UPDATE ON CORE_MANUAL FOR EACH ROW BEGIN if inserting then -- only set the current date if it is not specified if :new.created is null then :new.created := sysdate; end if; end if; -- always set the modified date to now if inserting or updating then
https://riptutorial.com/ru/home 40
:new.modified := sysdate; end if; end; /
Прочитайте Триггеры онлайн: https://riptutorial.com/ru/plsql/topic/7674/триггеры
https://riptutorial.com/ru/home 41
глава 14: функции
Синтаксис
CREATE [OR REPLACE] FUNCTION имя_функции [(параметр [, параметр])]
RETURN return_datatype
IS | КАК
[Declaration_section]
BEGIN исполняемый_секретарь
[EXCEPTION exception_section]
END [имя_функции];
•
Examples
Создать GUID
Create Or Replace Function Generateguid Return Char Is V_Guid Char(40); Begin Select Substr(Sys_Guid(),1,8)||'-'||Substr(Sys_Guid(),9,4)||'-' ||Substr(Sys_Guid(),13,4)||'-'||Substr(Sys_Guid(),17,4)||'-' ||Substr(Sys_Guid(),21) Into V_Guid From Dual; Return V_Guid; Exception When Others Then dbms_output.put_line('Error '|| SQLERRM); End Generateguid;
Функции вызова
Существует несколько способов использования функций.
Вызов функции с оператором присваивания
DECLARE x NUMBER := functionName(); --functions can be called in declaration section BEGIN x := functionName(); END;
https://riptutorial.com/ru/home 42
Вызов функции в выражении IF
IF functionName() = 100 THEN Null; END IF;
Вызов функции в выражении SELECT
SELECT functionName() FROM DUAL;
Прочитайте функции онлайн: https://riptutorial.com/ru/plsql/topic/4005/функции
https://riptutorial.com/ru/home 43
кредиты
S. No
Главы Contributors
1Начало работы с PLSQL
Community, Dinidu, JDro04, m.misiorny, Prashant Mishra, Tenzin, user272735
2Заявление IF-THEN-ELSE
massko
3Коллекции и отчеты
J. Chomel
4 курсоры dipdapdop, J. Chomel, Jucan
5 Массовый сбор Prashant Mishra
6Модель и язык заданий
m.misiorny, user272735
7Обработка исключений
Ice, J. Chomel, jiri.hofman, Tony Andrews, Zug Zwang
8 пакеты JDro04, jiri.hofman, StewS2, Tenzin
9 петля m.misiorny, massko
10 Процедура PLSQL Dinidu, Doruk, Harjot, JDro04, Kekar, William Robertson
11 Типы объектов HepC
12 Триггеры Harjot, jiri.hofman
13 функции JDro04, Jon Clements, user3216906
https://riptutorial.com/ru/home 44