Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Lab_04_Oracle %28PL_SQL%29 / Додатково_Теорія_01_Блоки_керуючі_структури_ PL_SQL

.pdf
Скачиваний:
6
Добавлен:
11.02.2015
Размер:
518.25 Кб
Скачать

усередині блоку. При цьому будуть скасовані всі команди DML, виконані після завдання контрольної крапки:

SQL> SET SERVEROUTPUT ON SQL> DECLARE

2sal NUMBER;

3empno NUMBER(4) := 7788;

4BEGIN

5DBMS_OUTPUT.enable;

6SELECT оклад INTO sal FROM служ WHERE служ_номер = 7788;

7DBMS_OUTPUT.put_line('Оклад до відновлення: ' || sal);

8SAVEPOINT ok_back;

9UPDATE служ SET оклад = 9000

10WHERE служ_номер = empno;

11SELECT оклад INTO sal FROM служ WHERE служ_номер = 7788;

12DBMS_OUTPUT.put_line('Оклад після відновлення: ' || sal);

13END;

14/

Оклад до відновлення: 3000 Оклад після відновлення: 9000

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

SQL> ROLLBACK TO ok_back;

Відкіт завершений.

SQL> SELECT оклад FROM служ WHERE служ_номер = 7788;

ОКЛАД

------------------

3000

У наступному прикладі відкіт всієї транзакції – включаючи команди DML, виконані до входу в блок, – виробляється всередині блоку за умовою негативного результату виконання команди

Не забувайте, що SQL*Plus розглядає блок PL/SQL як одну команду. Якщо опція AUTOCOMMIT середовища SQL*Plus має значення ON, то

виконувані в блоці команди маніпулювання даними не закривають саму транзакцію до закінчення виконання блоку. Відповідно, якщо команда DML викликає неопрацьовану особливу ситуацію, то блок припиняє роботу з помилковим станом, і всі виконані в блоці команди DML відміняються.

4. Неявний курсор і його атрибути

При виконанні SQL-Команди резервується область пам'яті, в якій команда може бути оттрансльована й запущена на виконання. Ідентифікатор цієї області пам'яті називається курсором.

SQL-Команди, задані в тілі блоку, управляються «неявним курсором», що має ідентифікатор «SQL». Цей курсор управляється автома-тично оброблювачем PL/SQL (на відміну від явних курсорів, обумовле-них користувачем).

PL/SQL підтримує кілька атрибутів, які дозволяють аналізувати останні за часом дії неявного курсору. У число таких атрибутів входить:

SQL%ROWCOUNT – кількість рядків, оброблених SQL-Командою (цілочислове значення);

SQL%FOUND – логічне значення, рівне TRUE, якщо хоча б один рядок оброблений SQL-Командою, і FALSE у протилежному випадку;

SQL%NOTFOUND – логічне значення, яке дорівнює TRUE, якщо ж одного рядка SQL-Командою не оброблено, і FALSE у протилежному випадку.

Перераховані атрибути можуть використовуватися в PL/ SQLКомандах так само, як і стандартні функції, але тільки не в тексті самих SQL-Команд.

Ці атрибути зручно задавати в секції обробки особливих ситуацій для аналізу причин помилок у командах SELECT, які можуть вибрати один і тільки один рядок, і особливо корисно ставити після команд DML для визначення числа оброблених рядків, наприклад:

SQL> SET SERVEROUTPUT ON SQL> DECLARE

2row_del NUMBER;

3BEGIN

4DELETE FROM служ WHERE робота = 'МЕНЕДЖЕР';

5row_del := SQL%ROWCOUNT;

6ROLLBACK;

7DBMS_OUTPUT.enable;

8DBMS_OUTPUT.put_line('Вилучено й відновлено рядків: ' ||

row_del);

9END;

10/

Вилучено й відновлено рядків: 3

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

5. Використання команди SELECT в PL/SQL

Команди SELECT, задані в PL/SQL-Блоках, попадають по класифікації ANSI у число команд «убудованого SQL», для яких існує наступне правило:

запити повинні повертати один і тільки один рядок, інакше виникає помилка.

Таким чином, команди SELECT, за якими не знайдено жодного або знайдено більше одного рядка, викличуть відповідно наступні помилки:

ORA-01403: даних не знайдено

ORA-01422: точна вибірка повертає кількість рядків більше запитаного.

У випадку виникнення цих помилок PL/SQL активізує стандартні особливі ситуації, які можна обробити в секції EXCEPTION блоку. Як правило, команду SELECT варто задавати так, щоб вона свідомо знаходила тільки один рядок. В убудованій команді SELECT припустимі наступні пропозиції:

SELECT стовпець1, стовпець2, ...

INTO змінна1, змінна2, ...

FROM таблиця1, таблиця2, ...

WHERE умова

GROUP BY стовпець1, стовпець2, ...

HAVING (умова)

FOR UPDATE;

Службове слово INTO обов'язково ставиться між словами SELECT і FROM. Ця конструкція вживається для завдання імен змінних, котрим будуть привласнені знайдені командою SELECT значення із БД. Список стовпців повинен відповідати списку змінних у пропозиції INTO за кількістю, порядком завдання й типами даних.

У списку INTO можуть бути задані як локальні змінні PL/SQL, так і зовнішні змінні. В останньому випадку перед ім'ям змінної повинна стояти двокрапка, наприклад:

SQL> SET SERVEROUTPUT ON SQL> DECLARE

2v_job VARCHAR2(13);

3v_sal NUMBER(7,2);

4BEGIN

5SELECT робота, оклад

6INTO v_job, v_sal

7FROM служ

8WHERE служ_ім'я = 'ГОЛОВКО';

9DBMS_OUTPUT.enable;

10DBMS_OUTPUT.put_line('Співробітник: Головко');

11DBMS_OUTPUT.put_line('Спеціальність: ' || v_job);

12DBMS_OUTPUT.put_line('Оклад: ' || v_sal || ' гр.');

13END;

14/

Співробітник: Головко Спеціальність: МЕНЕДЖЕР Оклад: 2850 гр.

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

6. Сумісність типів і атрибут %TYPE

Повідомляючи змінні в PL/SQL-Блоці з метою наступного присвоєння їм значень зі стовпців бази даних, ви повинні бути впевнені, що вони сумісні за типом з тими стовпцями, під значення яких призна-чені. У випадку невідповідності типів даних у момент присвоєння може виникнути помилка.

Замість того, щоб у явному вигляді задавати тип і розмір змінної, ви можете оголосити її аналогічно типу стовпця таблиці БД, як цей стовпець описаний у словнику даних. Це робиться шляхом завдання атрибута %TYPE. При оголошенні змінної цей атрибут задається після ім'я таблиці й стовпця, тип якого повинен бути привласнений змінній, у такий спосіб:

<ідентифікатор>.<ім'я_таблиці>.<ім'я_стовпця>%TYPE;

Наприклад:

v_deptno отдел.відділ_номер%TYPE; v_loc отдел.розташований%TYPE;

За допомогою цього методу тип і розмір привласнюється змінній у момент компіляції блоку, і, таким чином, тип змінної буде відповідати типу стовпця таблиці, наприклад:

SQL> SET SERVEROUTPUT ON SQL> DECLARE

2v_deptno отдел.відділ_номер%TYPE;

3v_loc отдел.розташований%TYPE;

4BEGIN

5SELECT відділ_номер, розташований

6INTO v_deptno, v_loc

7FROM відділ

8WHERE відділ_ім'я = 'ДОСЛІДЖЕННЯ';

9DBMS_OUTPUT.enable;

10DBMS_OUTPUT.put_line('Відділ №' || v_deptno || ' - ДОСЛІДЖЕННЯ');

11DBMS_OUTPUT.put_line('Розташування: ' || v_loc);

12END;

13/

Відділ №20 - ДОСЛІДЖЕННЯ Розташування: МАКІЇВКА

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

Слід зазначити, що якщо із БД вибираються не самі значення, а функція від значення (наприклад, служ.оклад*12), то атрибут %TYPE не гарантує відповідності типів.

7. Мітки й видимість змінних

Мітки використовуються для ідентифікації вкладених циклів і блоків, визначаються вони в такий спосіб:

<<ім'я_мітки>>

Наприклад: blok1

loop2 <<ім'я_мітки>>

До імен міток пред'являються ті ж вимоги, що й до інших ідентифікаторів. Мітки ставляться перед командою або на тім же рядку, або на окремому рядку. Мітка може бути поміщена перед початком і після закінчення блоку й служити його ідентифікатором у структурі вкладених блоків. Уявимо собі наступну ситуацію:

SQL> SET SERVEROUTPUT ON SQL> DECLARE

2var1 NUMBER := -5;

3BEGIN

4DBMS_OUTPUT.enable;

5DECLARE

6var1 NUMBER := 400;

7BEGIN

8DBMS_OUTPUT.put_line('var1 = ' || var1);

9var1 := var1 + 5;

10DBMS_OUTPUT.put_line('Після математичних операцій:');

11DBMS_OUTPUT.put_line('var1 = ' || var1);

12END;

13END;

14/

var1 = 400

Після математичних операцій: var1 = 405

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

Змінна var1, оголошена в зовнішньому блоці, «невидима» під час виконання внутрішнього блоку, тому що в ньому оголошена змінна з таким же ім'ям. Таким чином, усі посилання на змінну var1 у внутрішньому блоці ставляться до локальної змінної цього блоку.

Однак, якщо блоки позначені мітками, тобто можливість указувати ідентифікатори змінних, ставлячи перед ними через крапку імена міток блоку як префікс. (Зауважимо, що зовнішній блок програми може бути й не позначений міткою). Приклад:

SQL> SET SERVEROUTPUT ON

SQL> BEGIN

2<<block1>>

3DECLARE

4var1 NUMBER := -5;

5BEGIN

6DBMS_OUTPUT.enable;

7<<block2>>

8DECLARE

9var1 NUMBER := 400; 10 BEGIN

11 DBMS_OUTPUT.put_line('var1 зовнішнього блоку = ' ||

block1.var1);

12DBMS_OUTPUT.put_line('var1 вкладеного блоку = ' || var1);

13var1 := var1 + block2.var1 + 33;

14block1.var1 := block1.var1 + 5;

15DBMS_OUTPUT.put_line('Після математичних операцій:');

16DBMS_OUTPUT.put_line('var1 зовнішнього блоку = ' ||

block1.var1);

17DBMS_OUTPUT.put_line('var1 вкладеного блоку = ' || var1);

18END block2;

19END block1;

20END;

21/

var1 зовнішнього блоку = -5 var1 вкладеного блоку = 400 Після математичних операцій: var1 зовнішнього блоку = 0 var1 вкладеного блоку = 833

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

Як видно з наведеного прикладу, оператор END закінчення позначеного блоку може також включати ім'я мітки блоку для прозорості коду.

8. Оператор безумовного переходу GOTO

Оператор GOTO здійснює безумовний перехід на мітку в програмі PL/SQL. Завдання подібних команд повинне бути зведене до мінімуму, тому що це веде до поганої структуризації програм.

Мітка є дійсною усередині блоку, у якому вона задана. Перехід на мітку командою GOTO може відповідно стояти в тілі блоку або у внутрішньому блоці (для переходу на мітку зовнішнього блоку). Загальний вид оператора GOTO наступний:

GOTO <<ім'я_мітки>>;

Наприклад:

GOTO blok1; GOTO loop2;

GOTO мітка;

Під «міткою» розуміється ім'я переходу, що стоїть в поточному або зовнішньому стосовно даного блоці. Команда GOTO не може передавати керування з зовнішнього блоку у внутрішній. Приклад використання оператора GOTO:

SQL> SET SERVEROUTPUT ON SQL> BEGIN

2DBMS_OUTPUT.enable;

3BEGIN

4DBMS_OUTPUT.put_line('Текст внутрішнього блоку до GOTO');

5GOTO label1;

6DBMS_OUTPUT.put_line('Текст внутрішнього блоку після

GOTO');

7END;

8DBMS_OUTPUT.put_line('Текст зовнішнього блоку до мітки');

9<<label1>>

10DBMS_OUTPUT.put_line('Текст зовнішнього блоку після мітки');

11END;

12/

Текст внутрішнього блоку до GOTO Текст зовнішнього блоку після мітки

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

9. Оператор умовного переходу IF

Команда IF має структуру, подібну до аналогічних команд в інших мовах програмування. Вона дозволяє здійснювати перехід на виконання тих або інших дій за умовою на основі дій логічного оператора. Загаль-ний вигляд команди наступний:

IF <умова> THEN <дії>

[ELSIF <умова> THEN <дії>] [ELSE <дії>]

END IF;

Під «діями» розуміється послідовність із однієї або більше PL/SQL чи SQL-Команд, кожна з яких закінчується символом крапка з комою (;). Ці «дії» можуть включати інші команди IF з тією же структурою, що дозволяє конструювати вкладені оператори IF, ELSE і ELSIF.

Почнемо з прикладу, що містить тільки одну умову без будь-яких додаткових пропозицій:

SQL> SET SERVEROUTPUT ON SQL> BEGIN

2DBMS_OUTPUT.enable;

3IF '&db_name' = 'NTBASE'

4THEN DBMS_OUTPUT.put_line('Ви правильно назвали ім'я БД.');

5END IF;

6DBMS_OUTPUT.put_line('Цей рядок друкується в кожному разі.');

7END;

8/

Уведіть значення для db_name: ppp

колишній 3: IF '&db_name' = 'NTBASE' новий 3: IF 'ppp' = 'NTBASE'

Цей рядок друкується в кожному разі.

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

SQL> /

Уведіть значення для db_name: NTBASE

колишній 3: IF '&db_name' = 'NTBASE' новий 3: IF 'NTBASE' = 'NTBASE'

Ви правильно назвали ім'я БД.

Цей рядок друкується в кожному разі.

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

Програма просить увести ім'я бази даних. Умовне вираження повертає результат TRUE, якщо воно збігається з ім'ям «NTBASE», виконується команда виводу на екран підтвердження «Ви правильно назвали ім'я БД». Якщо результатом умовного вираження буде FALSE або NULL, то ця команда не виконується. У кожному разі керування передається на команду, що випливає за оператором END IF.

Слід зазначити, що якщо конструкція END IF не стоїть наприкінці команди, то PL/SQL буде шукати її серед наступних команд аж до кінця процедурної частини блоку. Як і в інших процедурних мовах, це може призвести до видачі компілятором непередбаченої помилки.

У наступному прикладі додані альтернативні дії за допомогою завдання оператора ELSE. Команди, що стоять після ELSE, будуть виконуватися, якщо умова оператора IF повертає значення FALSE або NULL; після виконання заданої послідовності керування переходить до першої команди після END IF.

SQL> SET SERVEROUTPUT ON SQL> BEGIN

2DBMS_OUTPUT.enable;

3IF '&db_name' = 'NTBASE'

4THEN DBMS_OUTPUT.put_line('Ви правильно назвали ім'я БД.');

5ELSE DBMS_OUTPUT.put_line('Уведене ім'я БД невірно.');

6END IF;

7DBMS_OUTPUT.put_line('Цей рядок друкується в кожному разі.');

8END;

9/

Уведіть значення для db_name: ppp

колишній 3: IF '&db_name' = 'NTBASE' новий 3: IF 'ppp' = 'NTBASE'

Уведене ім'я БД невірно.

Цей рядок друкується в кожному разі.