- •Введение.
- •Соединение с бд Oracle.
- •Типы данных Oracle, создание и модификация таблиц и вьюшек.
- •Задача. Удаление дубликатов.
- •Задача. Удаление по условию not in.
- •Функции по работе со строками.
- •Функции по работе с числами.
- •Задача. Факториал.
- •Задача. Подсчет числа вхождений символа в строку.
- •Троичная логика, конструкция with, функции nvl, coalesce, case, decode.
- •Основы pl/sql.
- •Задача. Подсчет числа вхождений подстроки в строку.
- •Задача. Копирование таблицы фиксированной структуры.
- •Задача. Простановка count в цикле.
- •Задача. Распределение данных по условию.
- •Задача. Использование сиквенсов и dbms_random.
- •Задача. Процедура с out параметрами. Нотации.
- •Задача. Простой пакет.
- •Задача. Разные виды Count.
- •Задача. Получение скрипта заполнения таблицы имеющимися данными.
- •Раздача прав (grants).
- •Операции над множествами, joins.
- •Задача. Сравнение множеств.
- •Задача. Загрузка данных с помощью full join.
- •Задача. Проставление роста животных.
- •Оператор merge.
- •Задача. Merge данных о студентах.
- •Задача. Merge данных о клиентах.
- •Функции по работе с датами.
- •Словарь данных.
- •Задача. Last_ddl_time.
- •Задача. Отчет об объектах текущей схемы.
- •Задача. Dbms_output из явного курсора по словарю данных.
- •Задача. Компиляция схемы.
- •Задача. Поиск текста во вьюшках.
- •Динамический sql.
- •Задача. Удаление конкретной таблицы, если она существует.
- •Задача. Удаление любой таблицы с проверкой на существование.
- •Задача. Конструкция '%rowcount'.
- •1) С помощью динамического вызова команды truncate очистить таблицу kk_objects_list от данных.
- •3) Вставить в таблицу kk_objects_list перечень имен всех объектов текущей схемы. С помощью конструкции sql%rowcount выдать в dbms_output количество вставившихся строк.
- •Задача. Удаление всех таблиц и вьюшек.
- •Часть 1. Написать pl/sql блок, который дропает все таблицы текущей схемы, начинающиеся на 'kk_'.
- •Часть 2. Написать pl/sql блок, который выдает в dbms_output скрипт удаления всех вьюшек текущей схемы, начинающихся с 'vw_kk%'.
- •Задача. Отчет о максимальных id.
- •Задача. Переименование столбцов.
- •Задача. Создание вьюшек.
- •Триггеры.
- •Задача. Автоинкрементное поле.
- •Задача. Триггер конвертации сумм в валюте.
- •Задача. Триггер логирования dml-операций.
- •Задача. Триггер зеркалирования.
- •Задача. Триггер по поиску в справочнике.
- •Задача. Триггер контроля.
- •Global temporary tables и переменные в заголовке пакета.
- •Переменные в заголовке пакета.
- •Регулярные выражения.
- •Задача. Правка некачественных данных регулярными выражениями.
- •Задача. Парсинг строк с помощью регулярных выражений.
- •Автономные транзакции.
- •Задача. Автономное логирование этапов загрузки.
- •Иерархические запросы.
- •Задача. Вывод иерархии с отступами.
- •Задача. Соединение иерархической таблицы с обычной.
- •Задача. Сумма зарплат подчиненных.
- •Задача. Простой календарь.
- •Задача. Детальный календарь.
- •Задача. Календарь с индикаторами выходных дней.
- •Аналитические функции.
- •Отступление о Rownum.
- •Негрупповые аналитические функции.
- •Групповая функция keep dense_rank.
- •Задача. Взятие последней записи о клиенте.
- •Задача. Отчет об изменениях зарплаты.
- •Задача. Пакет функций о вкладах.
- •Задача. Группировка лога выполнения процессов.
- •Задача. Вьюшка с аналитическими функциями по вкладам.
- •Задача. Календарь с аналитикой.
- •Задача. Поиск баланса счета на заданную дату.
- •Задача. Удаление исторических данных о рейтинге.
- •Функции, выдающие более одного значения.
- •Задача. Вызов многозначной функции.
- •"Расклейка" и "склейка" строк.
- •“Расклейка” одной строки.
- •“Расклейка” нескольких строк с группировкой.
- •“Склейка” в одну строку.
- •“Склейка” нескольких строк с группировкой.
- •Задача. Простая расклейка-склейка.
- •Задача. Скрипт создания индексов.
- •Задача. Скрипт создания таблиц.
- •Задача. Отчет о созданных объектах.
- •Задача. Отчет о числе строк в таблицах.
- •Задача. Расклейка списка хобби.
- •Задача. Склейка запроса о максимумах числовых полей.
- •Оптимизация запросов.
Иерархические запросы.
С помощью директивы connect by таблица соединяется сама с собой несколько раз по заданному условию, пока это возможно.
Подробности мы разберем в задачах ниже.
Задача. Вывод иерархии с отступами.
Создать таблицу иерархии сотрудников KK_MKB(ID - код сотрудника, NAME - ФИО сотрудника, BOSS_ID - код непосредственного начальника).
Написать запрос, выдающий список сотрудников как оглавление книги (босс, а под ним его сотрудники).
Перед сотрудником следует поставить столько пробелов, сколько уровней ему осталось до вершины иерархии. Например,
Президент
Премьер-министр
Вице-премьер деловой
Министр сельского хозяйства
Министр финансов
Министр экономического развития
Вице-премьер силовой
Министр внутренних дел
Министр обороны
Генерал
Капитан
Спикер
Вице-спикер1
Вице-спикер2
Создадим таблицу и заполним ее данными:
CREATE TABLE KK_MKB(ID INTEGER, NAME VARCHAR2(50), BOSS_ID INTEGER);
insert into KK_MKB(ID, NAME, BOSS_ID) values (1,'Президент',null);
insert into KK_MKB(ID, NAME, BOSS_ID) values (2,'Премьер-министр',1);
insert into KK_MKB(ID, NAME, BOSS_ID) values (3,'Спикер',1);
insert into KK_MKB(ID, NAME, BOSS_ID) values (4,'Вице-премьер деловой',2);
insert into KK_MKB(ID, NAME, BOSS_ID) values (5,'Вице-премьер силовой',2);
insert into KK_MKB(ID, NAME, BOSS_ID) values (6,'Вице-спикер1',3);
insert into KK_MKB(ID, NAME, BOSS_ID) values (7,'Вице-спикер2',3);
insert into KK_MKB(ID, NAME, BOSS_ID) values (8,'Министр сельского хозяйства',4);
insert into KK_MKB(ID, NAME, BOSS_ID) values (9,'Министр финансов',4);
insert into KK_MKB(ID, NAME, BOSS_ID) values (10,'Министр экономического развития',4);
insert into KK_MKB(ID, NAME, BOSS_ID) values (11,'Министр внутренних дел',5);
insert into KK_MKB(ID, NAME, BOSS_ID) values (12,'Министр обороны',5);
insert into KK_MKB(ID, NAME, BOSS_ID) values (13,'Генерал',12);
insert into KK_MKB(ID, NAME, BOSS_ID) values (14,'Капитан',13);
Напишем иерархический запрос, решающий задачу:
select id, name, boss_id, level, substr(lpad(' ', level) || name, 2)
from KK_MKB
connect by prior id = boss_id
start with boss_id is null;
Внесем зацикливание в данные, нарушив структуру дерева. Подчиним Премьер-министра еще и капитану:
insert into KK_MKB(ID, NAME, BOSS_ID) values (2,'Премьер-министр',14);
Теперь для "раскручивания дерева" добавим опцию nocycle, иначе запрос выругается:
select id, name, boss_id, level, substr(lpad(' ', level) || name, 2)
from KK_MKB
connect by nocycle prior id = boss_id
start with boss_id is null;
Видим, что Oracle "починил" дерево с помощью своего алгоритма. Это дает шанс взглянуть на данные и убрать зацикливание, чтобы обойтись уже без nocycle.
Задача. Соединение иерархической таблицы с обычной.
Создать иерархическую таблицу сотрудников, а также таблицу с хобби этих сотрудников. Создать отчет об иерархии сотрудников с отступами с указанием хобби.
Создадим и заполним данными таблицы:
create table kk_employee (id integer, fio varchar2(50), boss_id integer, wage integer);
insert into kk_employee (id, fio, boss_id, wage) values (1, 'Антон Юрьевич', null, 300);
insert into kk_employee (id, fio, boss_id, wage) values (2, 'Дмитрий Анатольевич', 1, 200);
insert into kk_employee (id, fio, boss_id, wage) values (3, 'Михаил Иванович', 1, 190);
insert into kk_employee (id, fio, boss_id, wage) values (4, 'Андрей Иванович', 2, 100);
insert into kk_employee (id, fio, boss_id, wage) values (5, 'Борис Кимович', 2, 60);
insert into kk_employee (id, fio, boss_id, wage) values (6, 'Мария Владимировна', 3, 125);
insert into kk_employee (id, fio, boss_id, wage) values (7, 'Антон Алексеевич', 3, 80);
insert into kk_employee (id, fio, boss_id, wage) values (8, 'Михаил Юрьевич', 3, 140);
insert into kk_employee (id, fio, boss_id, wage) values (9, 'Рашитзай Марданович', 3, 105);
insert into kk_employee (id, fio, boss_id, wage) values (10, 'кошка Мэгги', 5, 20);
insert into kk_employee (id, fio, boss_id, wage) values (11, 'черепашка Ниндзя', 4, 15);
insert into kk_employee (id, fio, boss_id, wage) values (12, 'кот Мурзик', 7, 10);
insert into kk_employee (id, fio, boss_id, wage) values (13, 'мышь Пухлик', 12, 3);
create table kk_hobby (id integer, hobby varchar2(50));
insert into kk_hobby (id, hobby) values (1, 'клеить самолетики');
insert into kk_hobby (id, hobby) values (2, 'лепить из пластилина');
insert into kk_hobby (id, hobby) values (3, 'рисовать карикатуры');
insert into kk_hobby (id, hobby) values (4, 'собирать марки');
insert into kk_hobby (id, hobby) values (5, 'выращивать орхидеи');
insert into kk_hobby (id, hobby) values (6, 'разводить щенков');
insert into kk_hobby (id, hobby) values (7, 'писать мемуары');
insert into kk_hobby (id, hobby) values (8, null);
insert into kk_hobby (id, hobby) values (9, null);
Можно написать итоговый запрос, выделив раскручивание иерархии в отдельный подзапрос:
with a as
(select id, lpad(chr(9), level - 1, chr(9)) || fio as name
from kk_employee
connect by prior id = boss_id
start with boss_id is null)
select a.name, h.hobby from a left join kk_hobby h on a.id = h.id;
А можно и соединить таблицы, раскручивая иерархию после соединения:
select lpad(chr(9), level - 1, chr(9)) || u.fio as name, h.hobby
from kk_employee u
left join kk_hobby h
on u.id = h.id
connect by prior u.id = u.boss_id
start with u.boss_id is null;
