- •Введение.
- •Соединение с бд 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.
- •Задача. Взятие последней записи о клиенте.
- •Задача. Отчет об изменениях зарплаты.
- •Задача. Пакет функций о вкладах.
- •Задача. Группировка лога выполнения процессов.
- •Задача. Вьюшка с аналитическими функциями по вкладам.
- •Задача. Календарь с аналитикой.
- •Задача. Поиск баланса счета на заданную дату.
- •Задача. Удаление исторических данных о рейтинге.
- •Функции, выдающие более одного значения.
- •Задача. Вызов многозначной функции.
- •"Расклейка" и "склейка" строк.
- •“Расклейка” одной строки.
- •“Расклейка” нескольких строк с группировкой.
- •“Склейка” в одну строку.
- •“Склейка” нескольких строк с группировкой.
- •Задача. Простая расклейка-склейка.
- •Задача. Скрипт создания индексов.
- •Задача. Скрипт создания таблиц.
- •Задача. Отчет о созданных объектах.
- •Задача. Отчет о числе строк в таблицах.
- •Задача. Расклейка списка хобби.
- •Задача. Склейка запроса о максимумах числовых полей.
- •Оптимизация запросов.
Автономные транзакции.
Создадим две таблицы:
create table kk_ordinal_table(id number);
create table kk_autonomous_commiting_table(id number);
С использованием директивы 'PRAGMA AUTONOMOUS_TRANSACTION' напишем процедуру kk_autonomous_insert, которая будет commit-ить вставку в таблицу kk_autonomous_commiting_table, но не будет при этом commit-ить вызвавшую kk_autonomous_insert внешнюю транзакцию:
create or replace procedure kk_autonomous_insert(p_id integer) as
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into kk_autonomous_commiting_table (id) values (p_id);
commit;
end kk_autonomous_insert;
В первой сессии выполняем сделующий блок. dbms_lock.sleep(10) - это 10 секунд безделия:
begin
dbms_lock.sleep(10);
insert into kk_ordinal_table (id) values (1);
kk_autonomous_insert(1);
dbms_lock.sleep(10);
insert into kk_ordinal_table (id) values (2);
kk_autonomous_insert(2);
dbms_lock.sleep(10);
insert into kk_ordinal_table (id) values (3);
kk_autonomous_insert(3);
commit;
end;
Во второй сессии во время выполнения вышеприведенного анонимного блока следует смотреть на то, как попадают данные в таблицы kk_ordinal_table и kk_autonomous_commiting_table. В kk_ordinal_table данные мы увидим только через 30 секунд (после commit в вызванном блоке), а в kk_autonomous_commiting_table будет появляться по одной строке каждые 10 секунд.
select * from kk_ordinal_table;
select * from kk_autonomous_commiting_table;
При желании можно сделать
truncate table kk_ordinal_table;
truncate table kk_autonomous_commiting_table;
и повторить эксперимент.
Задача. Автономное логирование этапов загрузки.
Дана таблица клиентов:
create table kk_clients_big_table(client_name varchar2(100), region_name varchar2(100), passport_ser_num varchar2(100));
Дана таблица логирования событий:
create table kk_events_log(event_date date, event_description varchar2(4000));
1) С использованием директивы 'PRAGMA AUTONOMOUS_TRANSACTION' создать процедуру kk_insert_kk_events_log(in_event_date in date default sysdate, in_event_description in varchar2) по вставке данных в kk_events_log.
2) Написать PL/SQL-блок, который заполняет данные о клиентах и логирует этапы загрузки:
2.1) Пишет в kk_events_log, что начата вставка данных об именах клиентов.
Вставляет в kk_clients_big_table 50000 случайно сгенерированных значений client_name. Поля region_name и passport_ser_num оставлять пустыми.
Пишет в kk_events_log, что завершена вставка данных об именах клиентов.
2.2) Пишет в kk_events_log, что начат update данных о регионах клиентов.
Делает update kk_clients_big_table.region_name случайными данными по всей таблице.
Пишет в kk_events_log, что завершен update данных о регионах клиентов.
2.3) Пишет в kk_events_log, что начат update данных о паспортах клиентов.
Делает update kk_clients_big_table.passport_ser_num случайными данными по всей таблице.
Пишет в kk_events_log, что завершен update данных о паспортах клиентов.
Случайные значения имен, регионов и паспортов клиентов можно брать с помощью конструкции translate(to_char(trunc(1000000 * dbms_random.value)), '1234567890', 'ABCDEFGHIJ').
3) Во время работы PL/SQL-блока в другой сессии регулярно смотреть, до какого этапа дошла загрузка, запросом из лога:
select * from kk_events_log order by event_date desc, event_description desc;
Создадим процедуру kk_insert_kk_events_log:
create or replace procedure kk_insert_kk_events_log(in_event_date in date default sysdate,
in_event_description in varchar2) as
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into kk_events_log
(event_date, event_description)
values
(in_event_date, in_event_description);
commit;
end kk_insert_kk_events_log;
Напишем требуемый PL/SQL-блок:
begin
-- 2.1
kk_insert_kk_events_log(in_event_description => 'Начата вставка данных об именах клиентов');
for i in 1 .. 50000 loop
insert into kk_clients_big_table
(client_name)
values
(translate(to_char(trunc(1000000 * dbms_random.value)),
'1234567890',
'ABCDEFGHIJ'));
end loop;
kk_insert_kk_events_log(in_event_description => 'Завершена вставка данных об именах клиентов');
-- 2.2
kk_insert_kk_events_log(in_event_description => 'Начат update данных о регионах клиентов');
for z in (select rowid rw from kk_clients_big_table) loop
update kk_clients_big_table
set region_name = translate(to_char(trunc(1000000 * dbms_random.value)),
'1234567890',
'ABCDEFGHIJ')
where rowid = z.rw;
end loop;
kk_insert_kk_events_log(in_event_description => 'Завершен update данных о регионах клиентов');
-- 2.3
kk_insert_kk_events_log(in_event_description => 'Начат update данных о паспортах клиентов');
for z in (select rowid rw from kk_clients_big_table) loop
update kk_clients_big_table
set passport_ser_num = translate(to_char(trunc(1000000 *
dbms_random.value)),
'1234567890',
'ABCDEFGHIJ')
where rowid = z.rw;
end loop;
kk_insert_kk_events_log(in_event_description => 'Завершен update данных о паспортах клиентов');
--
commit;
end;
Согласно требованию задачи во время работы этого PL/SQL-блока в другой сессии будем регулярно смотреть, до какого этапа дошла загрузка, запросом:
select * from kk_events_log order by event_date desc, event_description desc;
Только в конце PL/SQL-блока выполняется commit, потому что, если загрузка упадет на каком-то этапе, то недогруженные данные нам не нужны. А до какого этапа дошла загрузка, можно понять из лога.
По завершении PL/SQL-блока посмотрим на загрузившиеся данные:
select * from kk_clients_big_table;
Отметим, что update-ы выполнялись медленнее, чем insert-ы. Если бы это были update-ы не по rowid и не по проиндексированным полям, то было бы еще медленнее.
