
- •Введение.
- •Соединение с бд 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 перечень имен всех объектов текущей схемы (не только начинающихся с 'kk_'). С помощью конструкции sql%rowcount выдать в dbms_output количество вставившихся строк.
- •Задача. Удаление всех таблиц и вьюшек.
- •Часть 1. Написать pl/sql блок, который дропает все таблицы текущей схемы, начинающиеся на 'kk_'.
- •Часть 2. Написать pl/sql блок, который выдает в dbms_output скрипт удаления всех вьюшек текущей схемы, начинающихся с 'vw_kk%'.
- •Задача. Отчет о максимальных id.
- •Задача. Переименование столбцов.
- •Задача. Создание вьюшек.
- •Триггеры.
- •Задача. Автоинкрементное поле.
- •Задача. Триггер конвертации сумм в валюте.
- •Задача. Триггер логирования dml-операций.
- •Задача. Триггер зеркалирования.
- •Задача. Триггер по поиску в справочнике.
- •Задача. Триггер контроля.
- •Global temporary tables и переменные в заголовке пакета.
- •Переменные в заголовке пакета.
- •Регулярные выражения.
- •Задача. Правка некачественных данных регулярными выражениями.
- •Задача. Парсинг строк с помощью регулярных выражений.
- •Автономные транзакции.
- •Задача. Автономное логирование этапов загрузки.
- •Иерархические запросы.
- •Задача. Вывод иерархии с отступами.
- •Задача. Соединение иерархической таблицы с обычной.
- •Задача. Сумма зарплат подчиненных.
- •Задача. Простой календарь.
- •Задача. Детальный календарь.
- •Задача. Календарь с индикаторами выходных дней.
- •Аналитические функции.
- •Отступление о Rownum.
- •Негрупповые аналитические функции.
- •Групповая функция keep dense_rank.
- •Задача. Взятие последней записи о клиенте.
- •Задача. Отчет об изменениях зарплаты.
- •Задача. Пакет функций о вкладах.
- •Задача. Группировка лога выполнения процессов.
- •Задача. Вьюшка с аналитическими функциями по вкладам.
- •Задача. Календарь с аналитикой.
- •Задача. Поиск баланса счета на заданную дату.
- •Задача. Удаление исторических данных о рейтинге.
- •Типы данных clob и blob.
- •Функции, выдающие более одного значения.
- •Задача. Вызов многозначной функции.
- •Материализованные вьюшки
- •"Расклейка" и "склейка" строк.
- •“Расклейка” одной строки.
- •“Расклейка” нескольких строк с группировкой.
- •“Склейка” в одну строку.
- •“Склейка” нескольких строк с группировкой.
- •Задача. Простая расклейка-склейка.
- •Задача. Скрипт создания индексов.
- •Задача. Скрипт создания таблиц.
- •Задача. Отчет о созданных объектах.
- •Задача. Отчет о числе строк в таблицах.
- •Задача. Расклейка списка хобби.
- •Задача. Склейка запроса о максимумах числовых полей.
- •Ретроспективные запросы.
- •Оптимизация запросов.
Задача. Расклейка списка хобби.
Дан справочник хобби.
create table kk_hobby_list (hobby_id integer, hobby varchar2(100));
insert into kk_hobby_list (hobby_id, hobby) values (1, 'жить, как у Христа за пазухой');
insert into kk_hobby_list (hobby_id, hobby) values (2, 'колоть дрова');
insert into kk_hobby_list (hobby_id, hobby) values (3, 'сносить крышу');
insert into kk_hobby_list (hobby_id, hobby) values (4, 'удить рыбу');
insert into kk_hobby_list (hobby_id, hobby) values (5, 'пионервожатствовать');
Дана таблица прихожанок, с указанием по нескольку их хобби, разделенных символом ';' с возможными несколькими последующими пробелами. Не все их хобби есть в справочнике.
create table kk_hobby_uao (fio varchar2(30), hobby varchar2(100));
insert into kk_hobby_uao (fio, hobby) values ('Фёкла', 'пионервожатствовать; жить, как у Христа за пазухой');
insert into kk_hobby_uao (fio, hobby) values ('Февронья', 'удить рыбу; колоть дрова;убивать енотов; сносить крышу');
insert into kk_hobby_uao (fio, hobby) values ('Фотинья', 'бегать босиком; колоть дрова');
Составить отчет о том, у какой прихожанки какие имеются hobby_id из справочника kk_hobby_list.
Результатом итогового запроса должна получиться таблица:
FIO |
HOBBY_ID |
Фёкла |
5 |
Фёкла |
1 |
Февронья |
4 |
Февронья |
2 |
Февронья |
3 |
Фотинья |
2 |
В подзапросе q1 сделаем расклейку хобби, разделенный через ';'. Пробелы уберем с помощью trim(). Затем к q1 присоединим справочник хобби:
select q1.fio, l.hobby_id
from kk_hobby_list l
join (select fio,
trim(regexp_substr(hobby, '[^;]+', 1, column_value)) hobby
from kk_hobby_uao,
table(cast(multiset
(select level
from dual
connect by regexp_instr(hobby, '[^;]+', 1, level) > 0) as
sys.odcinumberlist))
order by fio, column_value) q1
on l.hobby = q1.hobby;
Задача. Склейка запроса о максимумах числовых полей.
По всем таблицам текущей схемы, где есть поля типа NUMBER составить отчет следующего вида:
TABLE_NAME |
COLUMNS_AND_MAXVALUES |
MAXVALUES_SEPARATED_BY_PLUSES |
SUM_MAXVALUES |
CLIENTS |
ID:3;REGION_ID:9 |
3+9 |
12 |
KK_RATE |
CURRENCY_CODE:840;RATE:32,91 |
840+32,91 |
872,91 |
KK_SALARY |
WAGE:100500 |
100500 |
100500 |
KK_TBL3 |
NAME:null |
0 |
0 |
Итак, нужно динамически склеить запрос следующего вида:
select 'KK_DEPOSIT' as TABLE_NAME,
'DEPOSIT_ID:' || nvl(to_char(max(DEPOSIT_ID)), 'null') || ';' ||
'AMOUNT:' || nvl(to_char(max(AMOUNT)), 'null') as COLUMNS_AND_MAXVALUES,
nvl(to_char(max(DEPOSIT_ID)), '0') || '+' ||
nvl(to_char(max(AMOUNT)), '0') as MAXVALUES_SEPARATED_BY_PLUSES,
nvl(max(DEPOSIT_ID), 0) + nvl(max(AMOUNT), 0) as SUM_MAXVALUES
from KK_DEPOSIT
union all
select 'KK_RATE' as TABLE_NAME,
'CURRENCY_CODE:' || nvl(to_char(max(CURRENCY_CODE)), 'null') || ';' ||
'RATE:' || nvl(to_char(max(RATE)), 'null') as COLUMNS_AND_MAXVALUES,
nvl(to_char(max(CURRENCY_CODE)), '0') || '+' ||
nvl(to_char(max(RATE)), '0') as MAXVALUES_SEPARATED_BY_PLUSES,
nvl(max(CURRENCY_CODE), 0) + nvl(max(RATE), 0) as SUM_MAXVALUES
from KK_RATE;
Опишем нижеприведенный запрос, решающий задачу.
В подзапросе q1 соберем информацию об имеющихся в текущей схеме полях типа NUMBER, а также конструкции по поиску максимальных значений, которые принимают эти поля.
Затем подставим q1 в запрос для склейки нескольких строк с группировкой. Будем создавать сразу три склеенных поля для каждой таблицы - column_and_max_col_value_list, to_char_max_col_value_0_list, max_col_value_0_list. Результат склейки назовем q2.
В итоговом запросе соберем select-ы по запросу требуемых значений из таблиц и соединим их конструкциями 'union all'.
Итоговый запрос выдает список select-ов, который можно скопировать, выполнить и получить результат.
Стандартный запрос по склейке имеет ограничение в 4000 символов на длину склееной строки, поэтому вполне вероятно, что получившиеся select-ы по суммарной длине превзойдут 4000 символов, поэтому подставлять итоговый запрос в стандартный запрос по склейке не будем.
select decode(rownum, 1, '', 'union all ') || 'select ''' || table_name ||
''' as TABLE_NAME, ' || column_and_max_col_value_list ||
' as COLUMNS_AND_MAXVALUES, ' || to_char_max_col_value_0_list ||
' as MAXVALUES_SEPARATED_BY_PLUSES, ' || max_col_value_0_list ||
' as SUM_MAXVALUES from ' || table_name as sql_statement
from (select table_name,
max(column_and_max_col_value_list) keep(dense_rank last order by lvl) as column_and_max_col_value_list,
max(to_char_max_col_value_0_list) keep(dense_rank last order by lvl) as to_char_max_col_value_0_list,
max(max_col_value_0_list) keep(dense_rank last order by lvl) as max_col_value_0_list
from (select table_name,
substr(sys_connect_by_path('''' || column_name ||
':''||' ||
max_col_value_null,
'||'';''||'),
8) as column_and_max_col_value_list,
substr(sys_connect_by_path(to_char_max_col_value_0,
'||''+''||'),
8) as to_char_max_col_value_0_list,
substr(sys_connect_by_path(max_col_value_0, '+'), 2) as max_col_value_0_list,
level lvl
from (select tc.table_name,
tc.column_id,
tc.column_name,
lag(tc.column_name) over(partition by tc.table_name order by tc.column_id) as prev_column_name,
'nvl(max(' || tc.column_name || '),0)' as max_col_value_0,
'nvl(to_char(max(' || tc.column_name ||
')),''0'')' as to_char_max_col_value_0,
'nvl(to_char(max(' || tc.column_name ||
')),''null'')' as max_col_value_null
from user_tab_columns tc, user_objects o
where tc.data_type = 'NUMBER'
and tc.table_name = o.object_name
and o.object_type = 'TABLE') q1
start with prev_column_name is null
connect by table_name = prior table_name
and prev_column_name = prior column_name)
group by table_name) q2;
Предлагается еще оин вариант решения – через WM_CONCAT (без сортировки по column_id):
select decode(rownum, 1, '', 'union all ') || str
from (select 'select ''' || tc.table_name || ''' as TABLE_NAME,' ||
replace(wm_concat('''' || tc.column_name ||
':''|| nvl(to_char(max(' || tc.column_name ||
')),''null'')') ||
' as COLUMNS_AND_MAXVALUES',
'''),',
''')||'';''||') || ',' ||
replace(wm_concat('nvl(to_char(max(' || tc.column_name ||
')),''0'')') ||
' as MAXVALUES_SEPARATED_BY_PLUSES',
'''),',
''')||''+''||') || ',' ||
substr(replace(wm_concat('+nvl(max(' || tc.column_name ||
'),0)') || ' as SUM_MAXVALUES ',
'0),',
'0)'),
2) || 'from ' || tc.table_name as str
from user_tab_columns tc
inner join user_tables t
on tc.table_name = t.table_name
where tc.data_type = 'NUMBER'
group by tc.table_name);