Oracle Developer👨🏻‍💻
3.22K subscribers
610 photos
68 videos
2 files
488 links
🔝 канал о разработке в СУБД Oracle:
SQL, PL/SQL, оптимизация, архитектура и многое другое...

Backend-pro.ru - обучение по различным программам, связанных с backend-разработкой для ФЛ и ЮЛ.

Отец-основатель: @denis_dbd Кивилёв Денис
Download Telegram
Задача: смотрите пост вторника.

Решение:

1. Добавим в запрос условие rownum <= p_count_rows.
Сократит итоговый набор строк получаемых запросом с ”всех что есть в таблице”, до "меньше либо равно p_count_rows". Этого вполне хватит, чтобы понять, есть ли в таблице требуемое количество или его нет.

2. Сократим “портянку” с if. Вернем сразу результат условия. Такие мелкие “хитрости” я буду показывать в своем курсе “Oracle PL/SQL.Основы”

В итоге получится:
create or replace function is_xxx_has(p_count_rows number) return boolean is
v_cnt number;
begin
select count(*) cnt into v_cnt
from xxx_tab t
where rownum <= p_count_rows;

return v_cnt = p_count_rows;
end;
/

Дополнительное условие:
Данная функция, при условии не частого изменения таблицы xxx_tab, отличный кандидат на кэширование результата (result_cache). О подобного рода функциях я уже делал видос.

Если задача понравилась - 👍

#решениезадачи #plsql #result_cache
1👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Задача:
Расскажите про код ниже, в том числе для чего он применяется, чего здесь не хватает, что бы вы изменили.

declare
v_date date;
v_query varchar2(1024);
begin
v_date := sysdate;

v_query := 'select *
from all_users
where created = ''' || v_date || '''';
end;

Любителям пожаловаться на “не точные/малоинформативные задания”,
Эта задача с одного из собеседований. Передаю в точности так же как она была задана мне когда-то 😉

Подробности, как всегда, в четверг 🎓

#задача
Друзья, всем привет!
Сегодня день знаний.
В некоторой степени, это тоже наш профессиональный праздник.

Работая в IT, нельзя в один прекрасный день сказать “всё, я теперь всё знаю. Больше не чему учиться”.
Для нас это постоянный процесс. Как только перестанешь учиться со временем знания “прокиснут”, станут не актуальными. Для профессионала это путь в никуда ☠️

Без преувеличения могу сказать, что после выпуска из университета не было периода, чтобы я чему-то не обучался. Я 16 лет работаю с Oracle и до сих пор есть моменты, которые для меня темный лес. А есть еще Java/Kotlin с кучей фреймворков и подходов. Не знать чего-то - это нормально. Не нормально, когда человек не развивается, застряв на своих предыдущих достижениях.

Конечно, в этом процессе важно качество обучающих материалов, подходы к самому обучению. Прогресс будет гораздо быстрее, если в процессе обучения вас будет сопровождать ментор - более опытный специалист. Спасибо, КЭП ) Но не все это понимают.

Всех с праздником! Не останавливайтесь 🎓
Задача: см пост вторника.

Решение:
Это больше задача “на поговорить”. Интервьювер хочет понять уровень ваших знаний в динамическом SQL.

Правило: если можно избежать использование динамического SQL, то лучше это сделать ☝🏻
В большинстве случаев, это реально.

Если же использовать динамический SQL все же приходится, то необходимо помнить про переменные подстановки (bind variables), задействовав эту возможность при написании кода.

Для данного примера:
1. Этот запрос легко выполнится без динамического SQL. Он тут не нужен.
2. Допустим, все же, применим динамику. Стоит изменить запрос - убрать конкатенацию, добавить в запрос переменную подстановки. Следующей строкой будет команда execute immediate в которой и надо будет передавать эту переменную. Результат выполнения нужно поместить в коллекцию.

Спасибо всем кто порассуждал под постом 😉

Как готовить динамический SQL, плюсы и минусы и т.п. я рассказываю на курсе “Oracle PL/SQL.Основы”. Если задачка вызвала вопросы, то самое время записаться на курс 🎓

#решениезадачи
1
Друзья, всем привет!

Информация для вновь прибывших в канал 😉

13 сентября начнется первый поток обучения на трехмесячном курсе “Oracle PL/SQL.Основы”.

Курс подойдет, если вы хотите начать читать чужие или создавать свои программы на PL/SQL.

Кратко о курсе
🔸 22 лекции с теорией около 10 минут;
🔸 20 видео с практикой около 5 минут;
🔸 практические задания, выполняя которые, вы к концу курса, получите один большой связный проект;
🔸 еженедельные встречи в Zoom;
🔸 закрытый Tg-канал с поддержкой и многое другое.

Вам понадобятся базовые знания SQL (select, DML) и хоть какая-то практика написания программ, пусть даже в университете на любом из языков.

Последний день, когда можно будет записаться - 10.09.

Не упустите свой шанс начать обучение в этом году.

Если есть сомнения? Пройдите первые три урока бесплатно и оцените качество курса.

Всем хорошей трудовой недели 👍

#обучение #plsql
Задача:
Опять вопрос на поговорить.
Расскажите про код ниже.

declare
...
begin
select count(id) into v_cnt
from my_data
where id_type = v_id_type;
exception
when no_data_found then
v_cnt := 0;
end;

Не удивляйтесь, это вопрос с реального собеседования.

#задача
Друзья, всем привет!

По идеи, сегодня я должен рассказать про решение задачки вторника.
Мне оcобо нечего добавить к тем комментариям, которые и так были под постом.

Самый очевидный вариант - это избыточность проверки на no_data_found.

Но мне понравились рассуждения и нестандартные подходы. Например, Alexei Onin.
Рекомендую заглянуть в обсуждение поста вторника.

В целом, меня радует тенденция, что в сообществе есть активные участники.
Для тех, кто боится высказывать своё мнение. Мы все учимся.
В нашей культуре совершение ошибок почему-то считается чем-то порочным и плохим. Ошибки - это нормально. Мы на них учимся.
Тем более, что все мы лажаем время от времени, вне зависимости от возраста или квалификации. Все мы люди.

Минутка философии. Сорян 😊

#решения
Друзья, всем привет!

На всякий случай, напоминаю, что сегодня в 23:00 исчезнет возможность попасть на первый поток курса “Oracle PL/SQL.Основы”.

Следующий запуск потока будет только в 2022. Зачем ждать 4е месяца, если можно начать менять свою жизнь уже сейчас? 😉
Не уверены? Еще есть время зарегистрироваться на обучающей платформе и посмотреть три первых урока - бесплатно.

Всем хороших выходных!

➡️Изучить PL/SQL в этом году ⬅️

#обучение #plsql
Задача
Всем привет! Задачка с собеса.
Нужно написать запрос, с использованием таблицы dual, который выведет календарь текущего месяца с первого по последнее число. Язык дней недели - украинский 😁

Пример вывода для текущей даты - 25.09 (две колонки):
01.09.2021  СЕРЕДА   
02.09.2021 ЧЕТВЕР
03.09.2021 П'ЯТНИЦЯ
04.09.2021 СУБОТА
05.09.2021 НЕДІЛЯ

30.09.2021 ЧЕТВЕР

Обсуждение под постом. Решение в четверг 🎓

#задача
Задача: вывести календарь за текущий месяц с использованием таблицы dual. Подробно см. постановку в посте.

Решение (например, такое):

select to_char(ddate, 'dd.mm.YYYY') dday
,to_char(ddate, 'DAY', 'nls_date_language = UKRAINIAN') day
from (select trunc(sysdate, 'mm') + level - 1 ddate
from dual
connect by level <= add_months(trunc(sysdate, 'mm'), 1) -
trunc(sysdate, 'mm')) x
order by x.ddate;

1️⃣ В таблице dual хранится только одна строка. Для того, чтобы вывести календарь нам нужно сгенерировать строки с использованием иерархического запроса - connect by level. Количество строк будет определяться как разница между первым днем текущего месяца и первым днем следующего.

2️⃣ trunc(sysdate, 'mm') - первый день текущего месяца.
add_months(trunc(sysdate, 'mm'), 1) - первый день следующего месяца.
select trunc(sysdate, 'mm') + level - 1 - каждый уровень иерархии даст день месяца.

3️⃣ Для вывода дат в определенном формате, используем функцию to_char с указанием формата. В случае, с выводом дня недели добавляем опцию украинского языка.

Задача не сильно сложная, но затрагивает разные моменты по написанию запросов. Всем отписавшимся под постом вторника - респект 🔥

Палец вверх, если понравилась задачка 👍

#решениезадачи #иерархическиезапросы #to_char
👍1
Задача на чтение планов запросов.
Для тех кто знает - элементарная.
Опять же, с реального собеседования.

Вопрос формулировался так: “расскажите как можно больше об этом плане”.

Комментарии приветствуются ⬇️😉
Разбор в четверг 🎓

План на скрине. Форматтер ТГ его просто размажет.

#задача
1
Всем привет!
Немного задержался с решением задачки. Постановку см. в посте 05.10.

Пройдемся по плану:
▫️ строка collection iterator говорит, о том что на шаге происходит работа с коллекцией.
▫️ pickler fetch - работа с “обработанной”/“форматированной”/”подготовленной” коллекцией, полученной из табличной функции.
▫️ num2tbl - табличная функция.
▫️ 8168 - предполагаемое количество элементов коллекции.

Код для воспроизведения:

create or replace type t_numbers is table of number(38);
/

create or replace function num2tbl return t_numbers
is
begin
return t_numbers(1, 2, 3, 4, 5);
end;
/

select * from table(num2tbl());

Если же в запросе не используется табличная функция, а выборка идет из коллекции, описание шага в плане будет:
collection iterator constructor fetch

Пример:
select * from t_numbers(1, 2, 3, 4, 5);

Насчет числа 8168
Это предполагаемое количество и оно, чаще всего, не совпадает с реальным значением. Ну и что с того? А то что, оптимизатор может построить неверный план. И вместо, скажем nested loops join, будет выбран hash join. Что приведет к деградации времени выполнения запроса.

Как с этим бороться?
Например, дать подсказку оптимизатору, хотя бы о порядке элементов коллекции.
Хинт cardinality может помочь. Например, так:

select /*+ cardinality(t 5) */ * from table(num2tbl()) t;

Более подробно об этом и других хинтах, я расскажу в своем курсе по оптимизации.
Он пока в разработке. Если интересно поучаствовать в пилотной группе - пишите в личку.

Хорошую статью закинул @alexeionin. Посмотрите на досуге.

Всем хорошей трудовой недели! 👍💻

#решениезадачи #cardinality #оптимизация
Задача
На этот раз вопрос не с собеседования, а из реальной практики. Если вы плотно работаете с СУБД Oracle вы обязательно столкнетесь с подобным.

Дан план. Выполняется некий select по таблице.
что можете сказать про этот план? Гуд? Можно лучше? Если можно, то как?

Задачка совмещает в себе знания по чтению планов и не простую тему с секционированием таблиц.

Детали решения в четверг 🎓

#задача #секционирование
Задача: смотрите постановку и план запроса в посте вторника.

Анализ:
Для начала пройдемся по плану.
🔸 SALE - источник данных - таблица.
🔸PARTITION RANGE - говорит о том, что таблица Range-секционированная (по диапазону).
🔸ALL - происходит просмотр всех секций.
🔸Pstart = 1 и Pstop = 1048575 - начинается сканирование с первой секции и доходит до самой последней. Максимум секций может быть 1М.
🔸С учетом того, что отображается Pstop = максимальному количеству секций, можно сделать вывод, о том что применена опция Range-секционирования - интервальное или автоматическое секционирование.
🔸звездочка на 2й позиции - означает, что есть какое-то дополнительное условие фильтрации.
🔸Доступ TABLE ACCESS FULL, говорит об отсутствии индекса или его бесполезности при фильтрации строк (звездочка) каждой секции.
🔸Финальная операция выполнения запроса - select.

Итого, мы имеем полное сканирование всех секций интервальной секционированной таблицы Sale.
Что должно вас насторожить? Слово “всех”.

Такое возможно, когда не задан ключ секционирования в условии where, т.е. не происходит отсечение секций. Очень распространенная ошибка среди "писателей" запросов.

Ключ секционирования - поле(я), по которому мы разбиваем таблицу на под-таблицы(секции). Наша задача - сканировать как можно меньше секций. В идеале - одну.

Для этого нужно:
🔸уметь правильно задавать секционирование таблицам;
🔸писать правильные запросы, отсекающие лишние секции.

TABLE ACCESS FULL - сам по себе ни хорош ни плох. Существует ряд ситуаций, когда он вполне себе допустим.

Летом я проводил 3х дневный интенсив на тему секционирования, на котором мы разбирали оба вопроса. По отзывам ребят, тема зашла и приносит пользу в повседневной работе. Как-нибудь опубликую отзывы.
Возможно, проведу обучение еще разок. Если что пишите.

Если задачка понравилась ставьте палец вверх 👍

#решениезадачи #секционирование
Всем привет!
Заметили, что постов не было? 😊
Подкосил меня один известный вирусок 🦠 Потихоньку восстанавливаюсь...

Что б сильно не скучали, расскажу про кейс одного из моих студентов. Упростил очень сильно для примера.
Дан PL/SQL-блок. Меняется таблица payment_detail. Она существует, в ней есть записи.

declare
v_payment_id payment.payment_id%type := 121;
v_field_id payment_detail.field_id%type := 2;
begin
update payment_detail
set field_value = 'xxxx'
where v_payment_id = v_payment_id
and field_id = v_field_id;
end;
/

Что можете сказать про этот код? Все ли с ним в порядке?

Определение таблицы можно посмотреть здесь.

#задача
Задача: постановку смотрите в посте вторника.

Решение:
В примере показана, довольно часто, встречающаяся ошибка у новичков.
Задумка автора: обновить значение в поле для клиента “121” с ID поля равным “2”.

По какой-то причине, автор указал “v_payment_id = v_payment_id” вместо “payment_id = v_payment_id”.

Если преобразовать исходный запрос получится:
  update payment_detail 
set field_value = 'xxxx'
where 121 = 121
and field_id = v_field_id;

Фактически первое условие можно отбросить, потому как оно всегда истинно. Таким образом, произойдет обновление всех строк в таблице payment_detail с field_id = “2”.
Неприятно 😕

Как бороться?
1️⃣ Внимательность при написании запросов.
2️⃣ Тестирование кода.
3️⃣ Code-review в команде.
4️⃣ Статические анализаторы кода. Например, SonarQube. Он, совершенно точно, умеет понимать такие ошибки.

Кстати, если интересно могу как-нибудь запилить видос с SonarQube 🎥

Всем хорошего дня!

#решениезадачи
Задача: дано три DML-триггера на некую таблицу some_tab.
Нужно чтобы при вставке в буфере вывода было: CBA

create table some_tab
(
some_col number(38) not null
);

create or replace trigger some_tab_trg_A
after insert
on some_tab
begin
dbms_output.put_line('A');
end;
/

create or replace trigger some_tab_trg_C
after insert
on some_tab
begin
dbms_output.put_line('C');
end;
/

create or replace trigger some_tab_trg_B
after insert
on some_tab
begin
dbms_output.put_line('B');
end;
/

insert into some_tab values(1);

Варианты:
A - никак не сделать, триггеры срабатывают в случайной последовательности.
B - триггеры нужно создать в той очередности, в которой нужно срабатывание.
C - есть опция Ordered в синтаксисе триггера, которая указывает очередность.
D - есть другая опция в синтаксисе триггера, которая указывает очередность.

Обсуждение задачи в четверг 🎓

#задача
Очередность срабатывания триггеров
Задача: см постановку в посте вторника.

Решение
В Oracle 11g, в синтаксисе создания триггера, появилась опция FOLLOWS.
Ей можно задать за каким триггером срабатывать текущему.

Итого:
create or replace trigger some_tab_trg_A
after insert
on some_tab
follows some_tab_trg_B
begin
dbms_output.put_line('A');
end;
/

create or replace trigger some_tab_trg_C
after insert
on some_tab
begin
dbms_output.put_line('C');
end;
/

create or replace trigger some_tab_trg_B
after insert
on some_tab
follows some_tab_trg_C
begin
dbms_output.put_line('B');
end;
/

Возможно, вам где-то это пригодится 😉
Ссылка на доку под постом ⬇️

#решениезадачи #trigger