Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа 4.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
84.2 Кб
Скачать
  1. Выполните данное задание, при помощи агрегатных функций используя запрос:

SELECT employee.department_id, employee.last_name, employee.salary, sum(employee4.salary) cum_salary , round(100*employee.salary/employee2.salary_by_dept,1) AS pct_dept , round(100*employee.salary/employee3.salary_overall,1) AS pct_overall FROM employee , (SELECT department_id, sum(salary) AS salary_by_dept FROM employee GROUP BY department_id ) employee2 , (SELECT sum(salary) AS salary_overall FROM employee ) employee3 , employee employee4 WHERE employee.department_id = employee2.department_id AND employee.department_id = employee4.department_id AND (employee.salary > employee4.salary OR (employee.salary = employee4.salary AND employee.last_name >= employee4.last_name)) GROUP BY employee.department_id, employee.last_name, employee.salary , round(100*employee.salary/employee2.salary_by_dept,1) , round(100*employee.salary/employee3.salary_overall,1)

ORDER BY department_id, salary;

Агрегированные данные вычисляются при помощи подзапросов.

  1. Выполните запрос:

SELECT department_id, last_name, salary , SUM(salary) OVER (PARTITION BY department_id ORDER BY salary,last_name) AS cum_sal, ROUND(100*RATIO_TO_REPORT(salary) OVER (PARTITION BY department_id), 1 ) pct_dept, ROUND(100*RATIO_TO_REPORT(salary) OVER () , 1 ) AS pct_overall FROM employee ORDER BY department_id, salary;

Получаем такой же точно результат, какой был в предыдущем запросе, который выполнялся без аналитических функций. RATIO_TO_REPORT(salary) – краткая и удобная функция получения процентных долей как внутри отделов OVER (PARTITION BY department_id), так и по всей фирме OVER ().

Часть 2

Цель: научиться создавать объекты базы данных.

Задания:

  1. Создайте представление, для выборки данных из таблиц employee и department, в котором-бы выбирались сотрудники отдела продаж.

  2. Создайте представление с опцией READ ONLY.

  3. Удалите представление emp_dept.

  4. Создайте индекс для таблицы employee по полю last_name.

  5. Удалите индекс, созданный в прошлом задании.

  6. Создайте синоним job1 для таблицы job.

  7. Создайте функцию, которая бы возвращала имя и фамилию руководителя сотрудника.

  8. Создайте процедуру для внесения данных в таблицу employee.

  9. Создайте пакет, включив в него функцию и процедуру, которые создавались в предыдущих заданиях.

Технология работы:

  1. Создайте представление emp_dept, выполнив запрос:

CREATE OR REPLACE VIEW emp_dept AS

SELECT e.employee_id, e.last_name, department_id, d.name AS department

FROM employee e join department d USING (department_id) WHERE d.name='Отдел продаж';

Выберите данные из созданного представления:

select * from emp_dept;

Вставка значений в это представление не получится. Нельзя изменить более одной таблицы посредством связанного представления. Если мы попытаемся вставить только один столбец одной таблицы (employee_id), Oracle потребует вставки foreign key 68

(department_id) и т.д. для всех вариантов вставки столбцов. Изменение в одном варианте (UPDATE emp_dept SET employee_id WHERE employee_id…..) возможно, но только для строк служащего, у которого нет подчиненных.

  1. Создайте представления с опцией READ ONLY, запрещающей insert, update, delete с базовой таблицей, на основе которой создано представление, через это представление. Выполните запрос:

CREATE OR REPLACE VIEW emp_v1 AS SELECT employee_id,last_name, (salary+NVL(commission, 0)) AS "Зарплата_отдела", department_id FROM employee WITH READ ONLY;

Выберите данные из созданного представления:

select * from emp_v1;

  1. Для удаления представления, выполните запрос:

DROP VIEW emp_dept;

  1. При помощи команды create index создайте индекс для таблицы employee:

CREATE INDEX i_employee ON employee(last_name);

Выберите данные из таблицы для сотрудника с фамилией Мороз:

select * from employee where last_name='Мороз';

Посмотрите план этого запроса, перейдя на вкладке Explain:

  1. Удалите индекс при помощи команды drop:

DROP INDEX i_employee ;

Запросите данные из таблицы employee по сотруднику Мороз:

select * from employee where last_name='Мороз';

Посмотрите план этого запроса, перейдя на вкладке Explain:

Сравните план выполнения этого запроса и план, полученный в предыдущем задании, у какого плана меньшая стоимость?

  1. Создайте синоним при помощи запроса: CREATE SYNONYM job1 FOR job;

Запросите данные из таблицы employee, используя созданный синоним: select * from job1;

  1. Создайте функцию, которая находит по id сотрудника имя менеджера:

create or replace function manager_name(p_employee_id in number) return varchar2

as

cursor cur_manager is select e1.first_name||' '||e1.last_name name from employee e1, employee e2 where e1.employee_id=e2.manager_id and e2.employee_id=p_employee_id;

v_manager cur_manager%rowtype;

begin

v_manager.name:='Нет';

open cur_manager;

fetch cur_manager into v_manager;

close cur_manager;

return v_manager.name;

end;

Для нахождения имени менеджера в функции используется явный курсор - cursor cur_manager is далее идёт запрос данных. Открытие явного курсора выполняется командой open cur_manager. Заполняем переменную v_manager данными fetch cur_manager into v_manager. Далее закрываем курсор close cur_manager;

и возвращаем значение имени менеджера return v_manager.name. Если у сотрудника нет менеджера, то вернётся слово “Нет”.

Запросим данные из таблицы employee, и добавим поле с именем начальника каждого подчинённого при помощи обращения к созданной нами функции:

select manager_name(employee_id) "Начальник",employee.* from employee;

В запросе мы обращаемся к функции, и передаём ей в параметре ID сотрудника.

  1. Создадим процедуру new_employee для вставки данных в таблицу employee:

create or replace procedure new_employee(p_first_name varchar2,p_last_name varchar2,p_job varchar2,p_manager varchar2, p_hiredate date,p_salary number,p_department varchar2)

as

cursor cur_manager is select employee_id from employee where last_name||' '||first_name=p_manager;

v_manager number;

cursor cur_dept is select department_id from department where name=p_department;

v_dept number;

cursor cur_job is select job_id from job1 where job_name =p_job;

v_job_id number;

e_nodept EXCEPTION;

e_nomanager EXCEPTION;

e_nojob EXCEPTION;

begin

open cur_job;

fetch cur_job into v_job_id;

if cur_job%notfound then raise e_nojob;

end if;

v_dept:=0;

close cur_job;

open cur_dept;

fetch cur_dept into v_dept;

if cur_dept%notfound then raise e_nodept;

end if;

close cur_dept;

v_manager:=0;

open cur_manager;

fetch cur_manager into v_manager;

if cur_manager%notfound then raise e_nomanager ;

end if;

close cur_manager;

insert into employee(employee_id,first_name,last_name,job_id,manager_id ,

hire_date,salary,department_id) values(emplayeeseq.nextval,p_first_name,p_last_name ,v_job_id,

v_manager,sysdate, p_salary,v_dept);

commit;

exception

when e_nojob then

DBMS_OUTPUT.put_line('Нет такой специальности!');

when e_nomanager then

DBMS_OUTPUT.put_line('Нет такого начальника!');

when e_nodept then

DBMS_OUTPUT.put_line('Нет такого отдела!');

when others then

DBMS_OUTPUT.put_line('Сотрудник с таким именем уже существует!');

end;

В блоке Exception идёт обработка исключений, которые могут возникнуть при передачи в процедуру неверных данных:

when e_nojob then

DBMS_OUTPUT.put_line('Нет такой специальности!');

when e_nomanager then

DBMS_OUTPUT.put_line('Нет такого начальника!');

when e_nodept then

DBMS_OUTPUT.put_line('Нет такого отдела!');

when others then

DBMS_OUTPUT.put_line('Сотрудник с таким именем уже существует!');

Часть исключений пользовательские, e_nomanager EXCEPTION;

они вызываются при помощи команды raise e_nomanager . Выражение if cur_dept%notfound используя атрибут курсора notfound, проверяет, вернул ли курсор данные, и если нет, то вызывается исключение. В when others then

обрабатываются остальные стандартный оракловые ошибки.

Вставьте данные в таблицу employee при помощи созданной процедуры:

begin

new_employee('Кира','Ёлкина','Дизайнер','Конь Виктор',to_date('15.01.2014','dd.mm.yyyy'),35000,'Разработка ПО');

end;

Выведите вставленную запись:

select * from employee where last_name='Ёлкина'

Попробуйте вставить эту запись ещё раз:

begin

new_employee('Кира','Ёлкина','Дизайнер','Конь Виктор',to_date('15.01.2014','dd.mm.yyyy'),35000,'Разработка ПО');

end;

Попробуйте вставить запись с несуществующем в таблице department отделом:

begin

new_employee('Кира','Ёлкина','Дизайнер','Конь Виктор',to_date('15.01.2014','dd.mm.yyyy'),35000,'Разработка');

end;

Попробуйте вставить запись с несуществующей в таблице job должностью:

begin

new_employee('Кира','Ёлкина','Продавец','Конь Виктор',to_date('15.01.2014','dd.mm.yyyy'),35000,'Разработка ПО');

end;

Попробуйте вставить запись с несуществующей в таблице employee начальником:

begin

new_employee('Кира','Ёлкина','Дизайнер','Конь Анна',to_date('15.01.2014','dd.mm.yyyy'),35000,'Разработка ПО');

end;

  1. Для создания пакета, нужно сначала создаётся спецификация пакета, в которой могут описываться типы данных, курсоры, процедуры, функции и т.д. Создадим спецификацию пакета с описанием, созданных нами ранее, процедурой и функцией:

create or replace package manage_emloyee is

function manager_name(p_employee_id in number) return varchar2;

procedure new_employee(p_first_name varchar2,p_last_name varchar2,p_job varchar2,p_manager varchar2, p_hiredate date,p_salary number,p_department varchar2);

end;

Теперь создадим тело пакета:

create or replace package body manage_emloyee is

function manager_name(p_employee_id in number) return varchar2

as

cursor cur_manager is select e1.first_name||' '||e1.last_name name from employee e1, employee e2 where e1.employee_id=e2.manager_id and e2.employee_id=p_employee_id;

v_manager cur_manager%rowtype;

begin

v_manager.name:='Нет';

open cur_manager;

fetch cur_manager into v_manager;

close cur_manager;

return v_manager.name;

end;

procedure new_employee(p_first_name varchar2,p_last_name varchar2,p_job varchar2,p_manager varchar2, p_hiredate date,p_salary number,p_department varchar2)

as

cursor cur_manager is select employee_id from employee where last_name||' '||first_name=p_manager;

v_manager number;

cursor cur_dept is select department_id from department where name=p_department;

v_dept number;

cursor cur_job is select job_id from job1 where job_name =p_job;

v_job_id number;

e_nodept EXCEPTION;

e_nomanager EXCEPTION;

e_nojob EXCEPTION;

begin

open cur_job;

fetch cur_job into v_job_id;

if cur_job%notfound then raise e_nojob;

end if;

v_dept:=0;

close cur_job;

open cur_dept;

fetch cur_dept into v_dept;

if cur_dept%notfound then raise e_nodept;

end if;

close cur_dept;

v_manager:=0;

open cur_manager;

fetch cur_manager into v_manager;

if cur_manager%notfound then raise e_nomanager ;

end if;

close cur_manager;

insert into employee(employee_id,first_name,last_name,job_id,manager_id ,

hire_date,salary,department_id) values(emplayeeseq.nextval,p_first_name,p_last_name ,v_job_id,

v_manager,sysdate, p_salary,v_dept);

commit;

exception

when e_nojob then

DBMS_OUTPUT.put_line('Нет такой специальности!');

when e_nomanager then

DBMS_OUTPUT.put_line('Нет такого начальника!');

when e_nodept then

DBMS_OUTPUT.put_line('Нет такого отдела!');

when others then

DBMS_OUTPUT.put_line('Сотрудник с таким именем уже существует!');

end;

end manage_emloyee;

Чтобы использовать функцию и процедуру из нашего пакета, нужно перед именем функции и процедуры поставить название функции. Запросим данные о начальниках сотрудника при помощи функции пакета manage_employee:

select manage_emloyee.manager_name(employee_id) "Начальник",employee.* from employee;

Вставьте данные о новом сотруднике при помощи процедуры, созданного нами пакета:

begin

manage_emloyee.new_employee('Борис','Никулин','Программист','Конь Виктор',to_date('20.01.2014','dd.mm.yyyy'),35000,'Разработка ПО');

end;

Запросите данные об этом сотруднике:

select * from employee where last_name='Никулин'