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

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

Отец-основатель: @denis_dbd Кивилёв Денис
Download Telegram
Всем хорошей пятницы и выходных 🎊

#юмор
Oracle Developer
👍12🔥6🎉3
Задача

Вам на ревью поступил следующий PL/SQL-код:

create or replace function get_text(p_id t1.id%type)
return varchar2
is
type my_type_cur is ref cursor;
v_curs my_type_cur;
v_text t1.text%type;
begin
open v_curs for
select text from t1 where id = p_id;

fetch v_curs into v_text;

close v_curs;

return v_text;
end;
/

Что делает данный код? Корректный ли он?
Как вы считаете, можно ли его переписать?
Действительно ли нужно использовать курсор?

Подобные вещи мы разбираем на 3х месячном курсе PL/SQL.Основы. Старт 9 сентября.

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

#задача
Oracle Developer
👍4
код к анализу ниже ⬇️
Ревью функции с курсором

Постановка: смотрите пост вторника.

Анализ
Кратко: я бы такой код не пропустил на ревью.
см код выше
1️⃣ Стр 2. Возвращается тип без привязки к колонки таблицы. Нет причин не использовать жесткую привязку к колонке text.
2️⃣ Стр 4. Избыточное объявление курсора. Можно использовать системный тип sys_refcursor.
3️⃣ Стр 13 и 16. Закрывать курсор надо 100%. В штатном режиме он закроется. А вот в случае возникновения исключения - нет закрытия. Ошибка неопытного курсоро-пользователя. Добавляется блок exception с проверкой на открытость курсора и его закрытием if v_curs%is_open then close v_curs; end if;
4️⃣ Но это частности. Основной вопрос к коду: зачем использовать явный курсор? Ответ: не имеет никакого смысла. Код можно переписать, например, так:

function get_text_new(p_id t1.id%type)
return t1.text%type
is
v_text t1.text%type;
begin
select max(t1.text)
into v_text
from t1 where t1.id = p_id;
return v_text;
end;
/

▫️В данном варианте, не важно id уникально или нет (как в первом так и во втором будет рендомно отдавать какую-то строку).
Есть ли значение по переданному id или нет. Поведение осталось прежним.

▫️Должна ли вызывающая среда знать, о том что строка не найдена? Не имея, каких-либо доп вводных ответить на этот вопрос сложно.

▫️Можно ли использовать result_cache? Определенно сказать сложно. Если таблица t1 постоянно меняется (это не справочник), то нет. Если меняется редко - можно попробовать. Опять же при условии, что тип колонки text проходит по ограничениям result cache.

▫️Если функция используется в SQL, то стоит подумать насчет pragma udf, deterministic (осторожно).

Мало чего ясно, но очень хочется понимать?
Есть возможность с 9-го сентября ворваться в магию PL/SQL 🎩
Напишите мне, если хотите забронировать место на новый поток. Оплатить можно непосредственно перед стартом.

Палец вверх, если задача понравилась. А еще можно перетереть в чатике.

#решениезадачи #cursor
@oracle_dbd
👍14
Всем хорошей пятницы и выходных 🎊

#юмор
Oracle Developer
👍13
Задача. Ревью анонимного PL/SQL-блока

И снова ревью кода.
Кстати, отличная практика проводить code review pull request’ов:
🔸 всякая дичь не попадает в prod;
🔸 команда шарит экспертизу и т.п.

Чем дальше от dev-стенда найдена ошибка, тем она дороже. Найти багу в prod совсем не то, что найти в test-окружении. Однако, это лирика, перейдем к нашему примеру.

declare
type name_salary_rt is record(
name varchar2(1000)
,salary number);

type name_salary_aat is table of name_salary_rt index by pls_integer;

l_employees name_salary_aat;
begin
execute immediate q'[select first_name || ' ' || last_name, salary
from employees
order by salary desc]' bulk collect
into l_employees;

for indx in 1 .. l_employees.count loop
dbms_output.put_line(l_employees(indx).name);
end loop;
end;
/

Что делает данный код? Корректный ли он? Как вы считаете, можно ли его переписать? Пропустили бы на code-review?

Подобные вещи мы разбираем на 3х месячном курсе PL/SQL.Основы. Старт 9 сентября.
Осталось 2️⃣ места 🔥

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

#задача
@oracle_dbd
👍5
Ревью функции с динамическим SQL. Решение

Постановка: смотрите пост вторника.

Анализ
Кратко: я бы такой код не пропустил на ревью.

Такое ощущение, что это писал человек, который вчера узнал про коллекции и динамический SQL и начал применять это везде.

Начнем с требуемого функционала: нужно вывести определенные поля из таблицы employees отсортированной по полю salary.

Весь код можно упростить до:
begin
for r in (select first_name || last_name name
from employees
order by salary desc) loop
dbms_output.put_line(r.name);
end loop;
end;
/

Определение локальных типов, коллекции, динамический SQL - все это не нужно и избыточно. Даже, не нужен столбец salary - он не выводится.
Вполне, подойдет проход в цикле по неявному курсору.

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

Хотите научиться писать PL/SQL-код, за который не будет стыдно?
Уже сегодня в 20:00 запускается очередной поток курса “Основы PL/SQL”. Не упустите свой шанс 😉

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

#решениезадачи #dynamicsql #cursor
@oracle_dbd
👍8
Коллеги, всем привет!

Не могу не поделиться ☺️
Вчера стартанул очередной поток курса "Основы Oracle PL/SQL". 10 человек отправились в трехмесячное увлекательное плаванье ⛵️

—-
Сегодня пятница и немного баянного юмора не помешает😉

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

#юмор
Oracle Developer
👍9🎉8🔥5🤯1
Вакансии в Дом.рф

Из рубрики "а вдруг!" 😄

Компания ДОМ.РФ в поисках Team Lead’a и разработчиков со знанием PL/SQL и Новой Афины

Предстоит:
• Проектирование и разработка бэк-офисной системы Банка (ИСУБД «Новая Афина»);
• Консультирование аналитиков и тестировщиков;
• Участие в выборе оптимальных решений, оценка работ;
• Участие в разборе инцидентов и исправление дефектов программного обеспечения;
• Подготовка релизов, сред тестирования функционала;
• Разработка автотестов;
• Ответственность за качество продукта.

Наши ожидания:
• Опыт работы в роли Разработчика на PL/SQL от 1.5-года;
• Знание архитектуры СУБД Oracle;
• Знание ИСУБД «Новая Афина».

Мы предлагаем:
• Офис в Москве или полная удаленка в пределах РФ;
• ЗП до 500 к gross;
• Расширенная программа ДМС, включая стоматологию;
• Компенсация абонемента в фитнес-клуб и обучения английскому языку (любые клубы и школы);
• Специальные условия по кредитам и ипотеке от Банка ДОМ.РФ для сотрудников.

Для связи: @technokotya @ValentinaKozyrevait

#вакансия #НоваяАфина
@oracle_dbd
🔥6
Всем привет!

Задача 2в1. Освежим немного знания по исключениям и транзакциям.

Дана таблица tab1.
create table tab1(
id number(38)
);
содержит одну строку, других сессий в БД нет.

Выполняется PL/SQL-блок:
declare
v_cnt number(30);
begin
insert into tab1 values (1);

v_cnt := 1/0;

dbms_output.put_line('1');

exception
when others then
select count(*) into v_cnt from tab1;
dbms_output.put_line(v_cnt);
end;
/


Какое число будет выведено в буфер вывода? Голосуем ⬇️
Рекомендую сначала ответить, затем уже запустить код в БД.

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

#задача
Oracle Developer
👍7
Задача 2в1 про исключения и транзакции

Сегодня маленько припозднился 😔

Постановка: смотрите пост вторника

Решение
1️⃣ В таблице tab1 на момент выполнения блока уже 1 строка. Вставка добавит еще одну строку.
2️⃣ Деление на ноль вызовет именованное системное исключение “деление на ноль” (ZERO_DIVIDE). Оно будет перехвачено в блоке обработки исключений - others.
3️⃣ Транзакция при этом не откатится.
Таким образом, select count(*) вернет “2”.

Правильный ответ: в буфере вывода будет - “2”

Интересно как распределились голоса 📊 Видимо, большинство уверено, что будет откат транзакции 😔

Если необходимо эмулировать откат, то надо было бы поставить savepoint перед вставкой и выполнить rollback на эту точку сохранения в секции обработки исключений.
declare

begin
savepoint sp1;
insert …

exception
when others then
rollback to sp1;
select count(*) …
end;
/

Забавно, что в PostgreSQL поведение отличается.
Поведение аналогично второму варианту - с откатом транзакции.
После begin ставится неявно точка сохранения и в случае ошибок происходит откат на эту точку. Этот код будет выводить “1”.

do $$
declare
v_cnt numeric(2);
begin
insert into tab1 values (1);
v_cnt := 1/0;
exception
when others then
select count(*) into v_cnt from tab1;
raise notice '%', v_cnt;
end
$$;

Смигрировали вы такие код с Oracle на PostgreSQL и … не заметили маааленькое различие в работе с транзакциями -> логика работы нарушилась 🤯

Если есть спецы в PG, напишите в комментариях, можно ли изменить это поведение какими-нибудь настройками?

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

#решениезадачи #транзакции #postgresql
👍22
Добрый день!
Сегодняшняя задача будет на тему проектирования.

Предположим, что нам необходимо хранить некую сущность с её свойствами. Пусть будет - Клиент.

Свойства двух типов:
🔸технические - id, активен/неактивен, некий текущий статус, дата создания, дата деактивации и т.п.
🔸чисто бизнесовые - ФИО, дата рождения, место жительства и т.д.

Требования:
1️⃣ поиск клиента по id;
2️⃣ поиск по комбинации бизнесовых свойств;
3️⃣ довольно часто добавляются новые свойства;
4️⃣ нагруженная система OLTP 24/7, остановки крайне нежелательны.

Как бы вы реализовали структуру(ы) хранения данных?

Обсудить можно в нашем чатике.

Разбор задачи, как всегда, в четверг 🎓

#задача
👍15
Задача о хранении объекта и его свойств

Постановка: см. пост вторника

Решение:
Для хранения технических полей используем основную таблицу сущности:
create table client(
client_id number(38) not null,
is_active number(1) not null,
status number(10) not null,
create_dtime date not null
);

Какие есть варианты хранение бизнесовых свойств объекта:
1️⃣ горизонтальное хранение;
2️⃣ вертикальное хранение (EAV);
3️⃣ другие более экзотические.

Постараюсь объяснить “на пальцах”. Допустим нам надо хранить всего 4е свойства: ФИО + ДР. Причем, отчество не обязательно.

1️⃣ Горизонтальное
Все свойства объекта располагаются в одной строке. Одно свойство = одному столбцу.

create table client_data_h(
client_id number(38) not null,
first_name varchar2(200 char) not null,
last_name varchar2(200 char) not null,
middle_name varchar2(200 char),
birth_day date not null
);

insert into client_data_h values(777, 'Иван', 'Иванов', null, date'1984-01-21');

Для поиска - индексируется поле(я).

Классика 😊
2️⃣ Вертикальное (EAV)
Каждое свойство - это одна строка. Строка содержит: ссылку на родительскую сущность, ссылку на бизнесовый тип поля и само значение.

— справочник типов бизнес-полей
create table client_data_field(
field_id number(10) not null,
field_name varchar2(100 char) not null
);

insert into client_data_field values(1, 'FIRST_NAME');
insert into client_data_field values(2, 'LAST_NAME');
insert into client_data_field values(3, 'MIDDLE_NAME');
insert into client_data_field values(4, 'BIRTH_DAY');

create table client_data_v(
client_id number(38) not null,
field_id number(10) not null,
field_value varchar2(1000 char) not null
);

insert into client_data_v values(777, 1, 'Иван');
insert into client_data_v values(777, 2, 'Иванов');
insert into client_data_v values(777, 4, to_char(date'1984-01-21','dd.mm.yyyy'));

Для поиска индексируются поля field_value, field_id.
Если нужен поиск по нескольким свойствам, придется писать join для каждого критерия.
Например поиск по last_name + др:
select ... 
from client_data bd
join client_data ln on ln.client_id = bd.client_id and ln.field_id = 1 and ln.field_value = ...
where bd.field_id = 4
and bd.field_value = ...;

При возрастании объема данных поиск может быть ооочень долгим.

Надеюсь, принцип понятен. Подробней в ссылке ниже.

3️⃣ Другие варианты
Я думаю, можно насобирать еще с десяток вариантов. Зависит от конкретных нужд системы.
Например, хранить часть свойств горизонтально, часть в json в одном поле. Как предложил Филип в этом видео.

⚠️ Каждый из вариантов имеет свои плюсы и минусы. Формат поста не позволяет рассмотреть их все.

——
Вернемся к задаче.
1️⃣ Требования: частое добавление новых свойств, нагруженная OLTP система.

🔸 Горизонтальное - нужно добавить новый столбец в таблицу client_data_h. Что выйдет? Скорее всего, ничего, т.к. система под нагрузкой - таблица заблокирована на изменение структуры.
🔸 Вертикальное - все сведется к вставке новой строки в client_data_field. После этого уже можно хранить свойство в client_data_v.

2️⃣ Требования: поиск по id клиента и бизнесовым свойствам.

С поиском по id клиента - проблем нет в любом варианте. По нему мы без проблем можем достать технические и бизнесовые свойства вне зависимости от объема данных.
🔸 Горизонтальное - PK по id клиента
🔸 Вертикальное - PK по комбинации id клиента + fld_id.

А вот с поиском клиентов по бизнесовым свойствам - проблема. Поиск в действительно большом объеме данных + по любому бизнес полю - это не задача OLTP.
Если оператору хочется производить поиск в данных, придется придумывать некие workaround-решения заточенные под поиск (это может быть, параллельно существующая структура для хранения бизнес полей; совсем другая БД и т.п.).

Если же данных не так что бы и много, то можем попробовать обойтись индексами:
🔸 Горизонтальное - нужно добавить новый индекс на новый столбец. С использованием опции online - это не большая проблема.
🔸 Вертикальное - у нас уже должен быть индекс на комбинацию полей (field_value, field_id). Ничего делать не нужно.

В любом случае, стоит дополнительно обговорить с бизнесом, точно ли им нужен поиск, по всем ли полям и т.п.

Выводы: для нашей задачи больше подходит вертикальное хранение свойств.

Понравилась задача? Палец вверх 👍
Тема холиварная - можно обсудить в нашем ламповом чатике 😉

P.S. В определениях таблиц опущены всевозможные ограничения, FK, PK и т.п.

#решениезадачи #проектирование
Oracle Developer
👍9
Oracle + Тинькофф. Введение

Друзья всем привет!

В начале этого года я уже публиковал историю моих собеседований в #яндекс. Очередь банка “Тинькофф” 💰

В ноябре на меня вышел HR с вакансией в процессинговый центр “Тинькофф”.
Вакансия: PL/SQL разработчик, готовый развиваться в сторону Java-стека.
Отличная возможность запилить контент в канал, подумал я, и согласился 🙃

Основные задачи:
1️⃣ Поддерживать текущее решение на Oracle 19;
2️⃣ Принимать участие в миграции этого хозяйства в Java-экосистему (Java11-17, PostgreSQL, NoSQL-решения и т.п.).

Перспективы: импортозамещение - тема крайне актуальна для российского рынка. Специалист, умеющий в Oracle + Java и участвовавший в проектах миграции (импортозамещении) в крупном ФинТех будет на вес золото в следующие 5-15 лет.

Я даже не упоминаю про плюшки самой компании + возможность работать удаленно как в РФ, так и в странах ближнего зарубежья.

Про з/п не пишу - тут многое зависит от вас.

продолжение ⬇️
👍24
Этапы собеседований

1️⃣ Предварительное общение с HR
Про опыт, про мотивацию и т.п. В том числе, было задано 8 контрольных технических экспресс-вопросов. Если кандидат плавает в них - есть ли смысл переходить к следующим стадиями… Считаю это отличной практикой - экономит время всем участникам процесса.
Время - 30 минут.

Опубликую вопросы - во вторник, ответы - в четверг.

2️⃣ Техническое интервью
Если ваше резюме и общение с HR всех удовлетворило, вы попадете на второй этап. В моем случае это был 1 человек - руководитель одного из направлений. Если в Яндекс упор был на практику (требовалось решить прям в онлайн несколько задач), то в Тинькофф - это теоретическое собеседование + написание запросов (до них дело не дошло). Спектр вопросов охватывал абсолютно разные области.
Время - 1-1.5 часа.

3️⃣ Общение с руководителями групп
Если не осрамились на тех собесе, то попадете на общение с другими руководителями групп. Это возможность задать вопросы, синхронизироваться по ожиданиям, показать ваши софт-скилы.
Не менее важный этап, чем тех собеседование. Вы присматриваетесь друг к другу.
Время - 1 час.

4️⃣ Оффер
Если все ок, то получаете заветный оффер.
Условия в оффере зависят от города/страны места работы.

Продолжение следует...

P.S. Уточню. Это серия постов не про то какой я супер пупер специалист, а про, то как устроены собеседования в одной из Топ-компаний РФ для Oracle-разработчиков. Что стоит ждать, какие вопросы задают и т.п. Возможно, кому-то будет интересно, кто-то взглянет под другим углом на свой процесс найма.

#тинькофф #собеседование
Oracle Developer
🔥41👍151
Тинькофф. Вопросы от HR

Экспресс-вопросы от HR

1️⃣ Есть две таблицы t1 и t2. В первой 10 строк, во второй 20.
Что вернет запрос?
select count(*) from t1,t2

2️⃣ Какие виды логического соединения таблиц вы знаете? Напр. inner join, какие еще?

3️⃣ Какие основные ТИПЫ индексов вы знаете?(или виды организации индексов)

4️⃣ Какие виды физического соединения таблиц в плане запроса вы встречали?

5️⃣ Для чего нужен оператор having?

6️⃣ Что такое автономная транзакция?

7️⃣ Какие DDL DML операции знаете?

8️⃣ С помощью каких операторов в запросе можно избавиться от дублирующих значений в поле?

Сказать, что это какой-то эксклюзив от Тинька и я что-то "спалил" нельзя. Обычно, задают примерно такие экспресс-вопросы 🤷‍♂️

Обсудить в чатике.
Разбор в четверг 🎓

#задача #тинькофф
Oracle Developer
👍18
Экспресс-вопросы от HR. Ответы

Список вопросов: см. в посте вторника.

Экспресс-вопросы задает HR, очень желательно давать ответы без “растекания мысли по древу”. У HR записаны четкие ответы, он сверяет их с тем, что вы говорите.
💡 Совет: говорите четко, быстро и по делу.

Ответы:
1️⃣ 200
обычное декартово произведение.

2️⃣ left/right/full outer join, inner join, cross join, natural join.

3️⃣ Уникальные/не уникальные, одностолбцовые/составные (более чем 1 столбец), функциональные (используют deterministic-функцию); реверсивные; с обратной сортировкой; локальные, глобальные;
B-tree индексы, bitmap-индексы; кластерные; прикладные индексы для узких задач.

100% попадете в список ответов у HR 😉

4️⃣ основные - nested loops, merge join, hash join

5️⃣ Having фильтрует получившиеся группы после group by

6️⃣ А.т. - отдельная транзакция порожденная из основной и не оказывающая влияние на основную транзакцию.

7️⃣ DDL - язык определения данных - create, drop, truncate, alter и т.д.
DML - язык манипуляции данными - delete, update, insert, select

8️⃣ distinct, group by, union (более 1 таблицы)

Вопросы довольно простые, уровня junior+-middle-.
Антиспам-вопросы 😊

На следующей неделе расскажу про техническое собеседование 😉

Перетереть в чатике.

#решениезадачи #тинькофф
Oracle Developer
👍39🔥43
Тинькоф. Техническое собеседование

Мне важно было пройти техническое собеседование блестяще.
Ведь читателям нужен happy end 😊 А я последний год больше занимаюсь Java-разработкой и кое-какие вещи стали забываться. Пришлось поднять свои же обучающие программы, которые я давал студентам и потратить полчасика на то, чтобы освежить некоторые моменты.

Каких-то конкретных задач с технического собеседования я вам дать не смогу. Ибо практики, лично у меня, не было, но у них есть задания с написанием запросов. Каких? Хз. Я бы погонял по аналитическим функциям 😁

Формат собеседования: созвон в Zoom, общение глаза в глаза 👀

Меня лично собеседовал 1 специалист. Грамотно и очень вежливо. Приятно пообщались 👍

Помню лет 7 назад общался со спецом в Краснодаре в филиале Спортмастера. Имя - Яков. Думаю, некоторые его узнают. Тогда осадок был тяжкий от собеседования. Было не приятно.

Завтра опубликую список тем, которые запомнились 😉

#тинькофф #собеседование
Oracle Developer
👍262