
- •Лабораторная работа № 3
- •1. Проанализируйте блок кода и ответьте на вопросы:
- •4. В этом задании вы будете работать с переменными подстановки, запрашивая их
- •Лабораторная работа № 4
- •3. С помощью инструкции update измените значение location_id, для вновь
- •4. Откройте скрипт lab_03_05b.Sql.
- •Лабораторная работа № 5
- •Лабораторная работа № 6
- •1. Напишите скрипт для распечатки информации о выбранной стране:
- •2. Напишите блок кода для выборки имени u1076 департамента из специальной структуры
- •3. Измените скрипт из второго пункта, таким образом, чтобы в индексированной таблице хранились записи (record), содержащие всю информацию об отделах.
- •Лабораторная работа № 7.
- •Лабораторная работа № 8.
- •1. Основная задача этого упражнения – продемонстрировать использование
- •3. Загрузите скрипт lab_07_04_soln.Sql.
Лабораторная работа № 7.
1. Напишите PL\SQL блок для определения n самых высоких зарплат сотрудников.
a. Выполните скрипт lab_07_01.sql для создания новой таблицы top_salaries,
предназначенную для хранения зарплаты сотрудников.
b. Запросите у пользователя значение переменной n. Пользователи могут
захотеть увидеть зарплату 5, 10 и так далее сотрудников. С помощью
инструкции DEFINE заранее определите переменную p_num для хранения
значения n.
c. Декларируйте переменную num типа NUMBER для хранения значения
p_num, переменную sal типа employees.salary, курсор emp_cursor, который
выбирает зарплату сотрудников в порядке убывания. Помните, что
повторов значений быть не должно.
d. В исполняемой секции кода откройте цикл и выберите первые n записей из
курсора и добавьте их в таблицу top_salaries. Не забывайте про атрибуты
%ROWCOUNT и %FOUND.
e. После добавления значений в таблицу просмотрите их с помощью
инструкции SELECT. Пример результата:
SET SERVEROUTPUT ON; DEFINE p_num=&n DECLARE num NUMBER(3):=&p_num; sal employees.salary%type; CURSOR emp_cursor IS SELECT DISTINCT(salary) FROM employee_details ORDER BY salary DESC; BEGIN DELETE top_salaries; DBMS_OUTPUT.ENABLE(); OPEN emp_cursor; FOR i IN 1..num LOOP FETCH emp_cursor INTO sal; IF emp_cursor%found THEN INSERT INTO top_salaries (salary) VALUES (sal); ELSE DBMS_OUTPUT.PUT_LINE('Only ' || i || ' top salaries found'); num:=i; EXIT; END IF; END LOOP; DBMS_OUTPUT.PUT_LINE(num || ' rows inserted into top_salaries table'); END; / |
f. Протестируйте работу скрипта на различных значениях n: 0, 5, 10, 100,
1000. Не забывайте очищать таблицу top_salaries после каждого теста.
Пример работы кода при любом n>=59
anonymous block completed Only 59 top salaries found 59 rows inserted into top_salaries table |
2. Создайте PL\SQL блок, который делает следующее:
a. С помощью директивы DEFINE определите переменную p_deptno для
хранения department_id значения.
b. Декларируйте переменную deptno типа NUMBER и присвойте ей значение
p_deptno.
c. Декларируйте курсор emp_cursor для выборки last_name, salary и
manager_id сотрудников, работающих в отделе с указанным значением
deptno.
d. В исполняемой секции с помощью инструкции FOR и цикла пройдитесь по курсору и если salary меньше 5000 и manager_id 101 или 124 отобразите сообщение “<<last_name>> Due for a raise.” иначе покажите сообщение “<<last_name>> Not due for a raise.”.
SET SERVEROUTPUT ON; DEFINE p_deptno NUMBER DECLARE deptno NUMBER(3):=&p_deptno; CURSOR emp_cursor IS SELECT last_name, salary, manager_id FROM employee_details WHERE department_id = deptno; BEGIN DBMS_OUTPUT.ENABLE(); FOR cur IN emp_cursor LOOP IF cur.salary<5000 AND cur.manager_id IN (101,124) THEN DBMS_OUTPUT.PUT_LINE(cur.last_name || ' Due for a rase'); ELSE DBMS_OUTPUT.PUT_LINE(cur.last_name || ' Not due for a rase'); END IF; END LOOP; END; |
e. Примерный результат:
anonymous block completed Greenberg Not due for a rase Faviet Not due for a rase Chen Not due for a rase Sciarra Not due for a rase Urman Not due for a rase Popp Not due for a rase |
3. Напишите PL\SQL для работы с параметризованным курсором.
a. Декларируйте курсор dept_cursor для извлечения department_id, department_name для отделов с номером меньше 100. Отсортируйте выборку по возрастанию номеров отделов.
b. Декларируйте другой курсор emp_cursor, который принимает deptartment_id на вход в качестве параметра и извлекает last_name, job_id, hire_date и salary для тех сотрудников, у которых employee_id меньше 120 и работающих в соответствующем отделе.
c. Декларируйте переменные, для хранения значений, извлеченных из
каждого курсора. Воспользуйтесь директивой %TYPE.
d. Откройте dept_cursor и с помощью простого цикла и инструкции fetch
выберите значения в соответствующую переменную. Распечатайте имя и
номер отдела.
e. Для каждого отдела отройте emp_cursor. С помощью вложенного цикла
пробегитесь по нему, и извлеките значения в соответствующую
переменную и распечатайте их.
SET SERVEROUTPUT ON; DECLARE CURSOR dept_cursor IS SELECT department_id, department_name FROM departments WHERE department_id<100 ORDER BY department_id; CURSOR emp_cursor (p_dept_no departments.department_id%type) IS SELECT last_name, job_id, hire_date, salary FROM employee_details WHERE employee_id<120 AND department_id = p_dept_no; dept_no departments.department_id%type; dept_name departments.department_name%type; e_last_name employee_details.last_name%type; e_job_id employee_details.job_id%type; e_hire_date employee_details.hire_date%type; e_salary employee_details.salary%type; BEGIN DBMS_OUTPUT.ENABLE(); OPEN dept_cursor; LOOP FETCH dept_cursor INTO dept_no, dept_name; IF dept_cursor%found THEN DBMS_OUTPUT.PUT_LINE(dept_no||' '||dept_name); OPEN emp_cursor (dept_no); LOOP FETCH emp_cursor INTO e_last_name,e_job_id,e_hire_date,e_salary; IF emp_cursor%notfound THEN CLOSE emp_cursor; EXIT; ELSE DBMS_OUTPUT.PUT_LINE(e_last_name || ' ' || e_job_id || ' ' || e_hire_date || ' ' || e_salary); END IF; END LOOP; ELSE CLOSE dept_cursor EXIT; END IF;
END LOOP; END; |
f. Закрой все циклы и курсоры в правильной последовательности. Выполните
скрипт. Результат должен быть похож на рисунок:
anonymous block completed 10 Administration 20 Marketing 30 Purchasing Raphaely PU_MAN 07-DEC-02 11000 Khoo PU_CLERK 18-MAY-03 3100 Baida PU_CLERK 24-DEC-05 2900 Tobias PU_CLERK 24-JUL-05 2800 Himuro PU_CLERK 15-NOV-06 2600 Colmenares PU_CLERK 10-AUG-07 2500 40 Human Resources 50 Shipping 60 IT Hunold IT_PROG 03-JAN-06 9000 Ernst IT_PROG 21-MAY-07 6000 Austin IT_PROG 25-JUN-05 4800 Pataballa IT_PROG 05-FEB-06 4800 Lorentz IT_PROG 07-FEB-07 4200 70 Public Relations 80 Sales 90 Executive King AD_PRES 17-JUN-03 24000 Kochhar AD_VP 21-SEP-05 17000 De Haan AD_VP 13-JAN-01 17000 |
4. Загрузите скрипт lab_06_04_soln.sql.
a. Найдите инструкцию: “DECLARE A CURSOR CALLED emp_records TO
HOLD salary, first_name, and last_name of employees” и создайте декларацию
курсора emp_records с соответствующей структурой. Курсор FOR UPDATE
должен выбирать salary, first_name и last_name сотрудников определенного
отдела (WHERE department_id=emp_deptid).
b. Начните с помощью инструкции BEGIN исполняемую секцию в
соответствии с комментарием: “INCLUDE EXECUTABLE SECTION OF
INNER BLOCK HERE”.
c. Основной код во вложенном блоке должен выполняться только в том
случае, если emp_deptid содержит номера 20,60,80,100,110 отделов, иначе
сообщите о невозможности продолжения работы с помощью инструкции
DBMS_OUTPUT.PUT_LINE (пример фразы: 'SORRY, NO SALARY
REVISIONS FOR EMPLOYEES IN THIS DEPARTMENT'). Если номер
отдела все в порядке, то необходимо открыть emp_records курсор.
d. С помощью простого цикла и оператора fetch извлеките значения из
курсора в переменные emp_sal,emp_fname,emp_lname. Для завершения
работы цикла воспользуйтесь атрибутом %NOTFOUND.
e. В тело цикла включите инструкцию CASE для анализа значения
переменной emp_sal. Используйте для проверки константы range1, hike1 и
т.д., которые уже декларированы. Правила обработки приведены в таблице:
Пример кода для обработки одного из случаев:
WHEN emp_sal<c_range1 THEN
ename_table(i):=emp_fname||' '||emp_lname;
i:=i+1;
UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike1)
WHERE CURRENT OF emp_records;
f. Закройте цикл LOOP. С помощью атрибута %ROWCOUNT распечатайте
количество обновленных строк. Закройте курсор.
g. С помощью простого цикла LOOP распечатайте имена сотрудников, анализ
зарплаты которых был произведен. Список имен сохранен в INDEX BY
TABLE. Найдите комментарий: «CLOSE THE INNER BLOCK» и закройте оператор IF и вложенный блок.
SET SERVEROUTPUT ON SET VERIFY OFF ACCEPT emp_id PROMPT 'Please enter your employee number'; ACCEPT emp_dept PROMPT 'Please enter the department number for which salary revision is being done';
DECLARE emp_authorization NUMBER(5); emp_id NUMBER(5):=&emp_id; emp_deptid NUMBER(6):=&emp_dept; no_such_employee EXCEPTION; v_employee_id employee_details.employee_id%type;
-- INCLUDE EXECUTABLE SECTION OF OUTER BLOCK HERE BEGIN -- RAISE EXCEPTION HERE DBMS_OUTPUT.ENABLE(); -- INCLUDE SIMPLE IF STATEMENT HERE emp_authorization := emp_id; IF emp_authorization = emp_id THEN SELECT employee_id INTO v_employee_id FROM employee_details WHERE department_id IN (SELECT department_id FROM departments WHERE department_name = 'Human Resources'); DECLARE emp_sal employee_details.salary%TYPE; emp_fname employee_details.first_name%TYPE; emp_lname employee_details.last_name%TYPE; i NUMBER:=1;
-- DECLARE AN INDEX BY TABLE OF TYPE VARCHAR2(50). CALL -- IT ename_table_type TYPE ename_table_type IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER; ename_table ename_table_type; -- DECLARE A VARIABLE ename_table OF TYPE ename_table_type
c_hike1 constant real :=.20; c_hike2 constant real :=.15; c_hike3 constant real :=.08; c_hike4 constant real :=.03;
c_range1 constant number :=6500; c_range2 constant number :=9500; c_range3 constant number :=12000; -- DECLARE A CURSOR CALLED emp_records TO HOLD salary, -- first_name, and last_name of employees CURSOR emp_records (emp_deptid NUMBER) IS SELECT salary, first_name, last_name FROM employee_details WHERE department_id=emp_deptid FOR UPDATE; -- INCLUDE EXECUTABLE SECTION OF INNER BLOCK HERE BEGIN IF emp_deptid IN (20,60,80,100,110) THEN DBMS_OUTPUT.PUT_LINE('SORRY, NO SALARY REVISIONS FOR EMPLOYEES IN THIS DEPARTMENT'); ELSE OPEN emp_records (emp_deptid); LOOP FETCH emp_records INTO emp_sal, emp_fname, emp_lname; IF emp_records%notfound THEN EXIT; ELSE CASE WHEN emp_sal<c_range1 THEN ename_table(i):=emp_fname || ' ' || emp_lname; i:=i+1; UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike1) WHERE CURRENT OF emp_records; WHEN emp_sal<c_range2 THEN ename_table(i):=emp_fname || ' ' || emp_lname; i:=i+1; UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike2) WHERE CURRENT OF emp_records; WHEN emp_sal<c_range3 THEN ename_table(i):=emp_fname || ' ' || emp_lname; i:=i+1; UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike3) WHERE CURRENT OF emp_records; ELSE ename_table(i):=emp_fname || ' ' || emp_lname; i:=i+1; UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike4) WHERE CURRENT OF emp_records; END CASE; END IF; END LOOP; DBMS_OUTPUT.PUT_LINE('Number of records updated: '|| emp_records%rowcount); CLOSE emp_records; END IF; FOR k IN 1..i LOOP DBMS_OUTPUT.PUT_LINE(ename_table(k)); null; END LOOP; -- CLOSE THE INNER BLOCK END; ELSE DBMS_OUTPUT.PUT_LINE ('SORRY YOU ARE NOT AUTHORIZED TO USE THIS APPLICATION'); END IF;
-- INCLUDE EXCEPTION SECTION FOR OUTER BLOCK EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Exception occured'); -- CLOSE THE OUTER BLOCK END; / |
h. Сохраните скрипт под именем lab_04_07_soln.sql