
- •Введение.
- •Соединение с бд 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.
- •Задача. Взятие последней записи о клиенте.
- •Задача. Отчет об изменениях зарплаты.
- •Задача. Пакет функций о вкладах.
- •Задача. Группировка лога выполнения процессов.
- •Задача. Вьюшка с аналитическими функциями по вкладам.
- •Задача. Календарь с аналитикой.
- •Задача. Поиск баланса счета на заданную дату.
- •Задача. Удаление исторических данных о рейтинге.
- •Функции, выдающие более одного значения.
- •Задача. Вызов многозначной функции.
- •"Расклейка" и "склейка" строк.
- •“Расклейка” одной строки.
- •“Расклейка” нескольких строк с группировкой.
- •“Склейка” в одну строку.
- •“Склейка” нескольких строк с группировкой.
- •Задача. Простая расклейка-склейка.
- •Задача. Скрипт создания индексов.
- •Задача. Скрипт создания таблиц.
- •Задача. Отчет о созданных объектах.
- •Задача. Отчет о числе строк в таблицах.
- •Задача. Расклейка списка хобби.
- •Задача. Склейка запроса о максимумах числовых полей.
- •Оптимизация запросов.
Задача. Триггер зеркалирования.
Создать таблицу KK_CLIENT(CLIENT_ID INTEGER, CLIENT_NAME VARCHAR2(40), AMOUNT NUMBER). У таблицы KK_CLIENT имеется первичный ключ CLIENT_ID.
Создать таблицу KK_CLIENT_MINUS - копию таблицы KK_CLIENT.
Написать триггер на KK_CLIENT, который в случае insert-ов, update-ов и delete-ов в KK_CLIENT зеркалирует изменения в таблицу KK_CLIENT_MINUS, т.е. всё время поддерживает, что в KK_CLIENT_MINUS всегда лежит копия KK_CLIENT, но только для отрицательных значений поля AMOUNT.
Создаем таблицы:
CREATE TABLE KK_CLIENT(CLIENT_ID INTEGER, CLIENT_NAME VARCHAR2(40), AMOUNT NUMBER);
CREATE TABLE KK_CLIENT_MINUS(CLIENT_ID INTEGER, CLIENT_NAME VARCHAR2(40), AMOUNT NUMBER);
Создаем триггер:
CREATE OR REPLACE TRIGGER KK_TRIG_AIUD_KK_CLIENT
AFTER INSERT OR UPDATE OR DELETE ON KK_CLIENT
FOR EACH ROW
BEGIN
IF (DELETING OR UPDATING) AND :OLD.AMOUNT < 0 THEN
DELETE FROM KK_CLIENT_MINUS WHERE CLIENT_ID = :OLD.CLIENT_ID;
END IF;
IF (INSERTING OR UPDATING) AND :NEW.AMOUNT < 0 THEN
INSERT INTO KK_CLIENT_MINUS
(CLIENT_ID, CLIENT_NAME, AMOUNT)
VALUES
(:NEW.CLIENT_ID, :NEW.CLIENT_NAME, :NEW.AMOUNT);
END IF;
END KK_TRIG_AIUD_KK_CLIENT;
Проверим:
insert into kk_client(client_id, client_name, amount) values (1, 'a', 10);
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
insert into kk_client(client_id, client_name, amount) values (2, 'b', -10);
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
update kk_client set amount = 20 where client_id = 1;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
update kk_client set amount = -20 where client_id = 2;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
update kk_client set amount = 20 where client_id = 2;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
update kk_client set amount = -30;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
update kk_client set amount = 20 where client_id = 2;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
delete from kk_client where client_id = 2;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
delete from kk_client where client_id = 1;
select client_id, client_name, amount from kk_client;
select client_id, client_name, amount from kk_client_minus;
Задача. Триггер по поиску в справочнике.
Дана таблица REGION(ID, NAME) с кодами и названиями регионов. Создать таблицу CLIENTS(ID, NAME, REGION_ID, REGION_NAME). Пользователь через форму ввода вставляет в таблицу CLIENTS имя клиента и строку с регионом. Требуется написать триггер на таблицу CLIENTS. Триггер автоматом вставляет ID (из сиквенса) и REGION_ID (из справочника REGION). Если записи нет в справочнике, то триггер вставляет запись в справочник.
Создадим таблицы и соответствующие им сиквенсы по генерации первичных ключей, заполним справочник данными:
CREATE TABLE REGION (ID INTEGER, NAME VARCHAR2(30));
CREATE TABLE CLIENTS (ID INTEGER, NAME VARCHAR2(30), REGION_ID INTEGER, REGION_NAME VARCHAR2(30));
CREATE SEQUENCE SQ_REGION;
CREATE SEQUENCE SQ_CLIENTS;
insert into region(id,name) values (sq_region.nextval,'Москва');
insert into region(id,name) values (sq_region.nextval,'Петербург');
create or replace trigger trig_biu_clients
before insert or update on clients
for each row
declare
v_region_id integer;
begin
/* сгенерируем новый clients.id */
if inserting then
select sq_clients.nextval into :new.id from dual;
end if;
/* найдем, есть ли в справочнике region запись с вставляемым названием региона. используем max(), чтобы избежать exception, если данные не найдены */
select max(region.id)
into v_region_id
from region
where region.name = :new.region_name;
/* если записи нет, то сгенерим новый первичный ключ для справочника region и вставим в справочник запись с этим ключом */
if v_region_id is null then
select sq_region.nextval into v_region_id from dual;
insert into region (id, name) values (v_region_id, :new.region_name);
end if;
/* в поле clients.region_id триггер записывает найденный или вновь сгенерированный v_region_id из справочника*/
:new.region_id := v_region_id;
end trig_biu_clients;
Проверяем, как работает триггер:
insert into clients (name, region_name) values ('Вася', 'Москва');
select * from clients;
insert into clients (name, region_name) values ('Петя', 'Рязань');
select * from clients;
select * from region;
update clients set region_name = 'Петербург' where name = 'Вася';
select * from clients;
update clients set region_name = 'Новгород' where name = 'Петя';
select * from clients;
select * from region;