DB developers channel
804 subscribers
2 photos
46 files
102 links
💡 Канал для разработчиков баз данных: Oracle, PostgreSQL
📌 Интересные задачи, фрагменты кода, лучшие практики, архитектура, оптимизация
🔄 Присоединяйся к сообществу — развивайся вместе с нами!
#SQL #Oracle #PostgreSQL #PL/SQL #PL/pgSQL #DB
Download Telegram
🎵«Если вы уже устали —
Сели-встали, сели-встали.
Не страшны вам Арктика с Антарктикой.» - В.С. Высоцкий

🚀 Простая задача с уникальными ключами и NULL 📝
Такая задача, вполне, может быть на собесе.
Спасибо подписчику Андрею. 😉

Условие:
Создаем таблицу с уникальным ограничением на два столбца и заполняем её NULL-значениями.
Нужно понять, как работает UNIQUE с NULL.

CREATE TABLE dropme_tt(
id INT,
a INT,
b INT,
CONSTRAINT tt_uk UNIQUE (a, b)
);

INSERT INTO dropme_tt (id, a, b)
SELECT level AS id, NULL AS a, NULL AS b
FROM dual
CONNECT BY level < 10;

SELECT * FROM dropme_tt;

Какой будет результат?

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

Ваши решения и сомнения туда👇
#sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👍1👎1
💬 Резюме: ИИ и будущее разработки

Вчера проходил собес (скорее, это была ознакомительная встреча) с CEO одной международной компании.
Мы также поговорили про влияние ИИ на разработку. Оказалось, что мой анализ ситуации полностью совпадает с его анализом и я решил свой анализ здесь озвучить.

🚀 Что умеет ИИ:
Решает SQL-задачи на уровне очень крепкого джуна / начинающего миддла.
Эффективен и быстрый в простых и стандартных задачах.
Инструмент для ускорения работы и тестирования.

⚠️ Ограничения:
В сложных решениях иногда ошибается.
Нужен синьор или эксперт для проверки и корректировки кода. (Пока нужен!!!)

💡 Влияние на рынок IT:
GPT, Gemini, Deepseek и другие меняют рынок:
Рутинная работа выполняется быстрее и качественнее, чем человеком.
В командах остаётся минимум людей (синьоров, экспертов).

💰 Карьерные выводы:
Зарплаты синьоров и экспертов будут расти 🚀.
Джуны будут работать за еду, в надежде когда-то стать синьорами.

Общий вывод:
Ребята! Пока эта канитель внедряется в международных компаниях, но на местах она придет чуть позже.
Пока есть время!
Учитесь, перенимайте чужой опыт, не бойтесь сложных задач.
Именно, решение сложных задач поднимает из рутины.

💎 Поддержка канала⁉️
👍2👎1
🚀 Разбор простой, но коварной задачи про UNIQUE и NULL
(идея от подписчика Андрея — спасибо! 😉)

Вопрос: что произойдет при таком коде?
CREATE TABLE dropme_tt(
id INT,
a INT,
b INT,
CONSTRAINT tt_uk UNIQUE (a, b)
);

INSERT INTO dropme_tt (id, a, b)
SELECT level, NULL, NULL
FROM dual
CONNECT BY level < 10;

🔎 Разбор:

В UNIQUE участвуют (a, b).
В SQL NULL — это «неизвестное значение».
Два NULL не равны друг другу.

👉 Значит, для UNIQUE это разные значения, и конфликтов нет.
Да и на все NULL значения индекс B-tree не строится.
Итог: все 9 строк спокойно вставятся. Ошибки не будет.

📌 Результат в Oracle и PostgreSQL одинаковый:
Таблица заполнится строками с id = 1..9, а (a, b) везде будут (NULL, NULL).

Важные замечания
Если бы на колонках стоял NOT NULL, фокус не прошёл бы.
👉 С этого и начинается консистентность данных — всегда анализируйте, может ли поле быть пустым.

На практике ограничения (CONSTRAINT ... UNIQUE) чаще создают отдельными командами:
CREATE TABLE dropme_tt
(
id INTEGER,
a INTEGER,
b INTEGER
);

CREATE UNIQUE INDEX dropme_tt_u01
ON dropme_tt (a, b);

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

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

#RealInterviewTasks #sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👍2👎1
🎵 «Я вытяну счастливую карту…» — Земфира

Сегодня суббота — отдыхаем от задач.
Запускаем рубрику «Полезные ресурсы» 🚀

🔗 Diffchecker (https://www.diffchecker.com/)
— простое и удобное web-средство для сравнения текста.

📌 Где может пригодиться:
быстро проверить изменения в SQL-скрипте или конфигурации;
сравнить два варианта кода;
увидеть, что именно поменялось в тексте документа.

Работает прямо в браузере, без установки.

💎 Поддержка канала⁉️

💡 Если у Вас есть свои полезные ссылки — не жадничайте, делитесь в комментах! 😉
#tools
👍3👎1
🎵 «На ель она взлетела,
А может, не взлетела,
А может быть, на пальму
Ворона взобралась» - Э. Успенский

Сегодня воскресенье, а значит — без задач

Сегодня про теоретические вопросы на собесах.
Честно говоря, я не считаю это валидным способом проверки разработчика.
(Может быть, потому что сам не смогу перечислить все формы нормализации данных — они мне интуитивно понятны, но выучить не получается 🤷‍♂️).

Тем не менее, когда я сам был интервьюером, не раз приходилось задавать классический вопрос:
👉 «Что такое ACID?»

📌 Обычно все знают расшифровку:

Atomicity (атомарность)
Consistency (консистентность)
Isolation (изоляция)
Durability (постоянство)

Но вот зачем эти критерии нужны и как именно понимать Consistency — отвечают далеко не все.

💡 В итоге у нас есть два вопроса для обсуждения:

Зачем вообще нужны критерии ACID?
Как именно вы понимаете Consistency (консистентность)?

💎 Поддержка канала⁉️

💬 Пишите в комментах, всё что в голову придет👇
#RealInterviewTasks #sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👎1
DB developers channel
🎵 «На ель она взлетела, А может, не взлетела, А может быть, на пальму Ворона взобралась» - Э. Успенский Сегодня воскресенье, а значит — без задач Сегодня про теоретические вопросы на собесах. Честно говоря, я не считаю это валидным способом проверки разработчика.…
Вчера в комментах произошёл очень показательный диалог.
Комменты получились интереснее поста.
Я уважаемому подписчику (DEN) весьма благодарен 🙏 (к сожалению, не знаю, как Вас зовут).
Примерно так или почти так и звучит ответ на простые и «ничего незначащие» вопросы на собеседованиях.

Вот разбор простыми словами.

Про Consistency в ACID:

👉 если две сессии одновременно запускают один и тот же запрос — они должны получить один и тот же результат.

Важно: это не про целостность данных в таблицах (FK, ограничения, каскады).
Это про то, что база показывает всем транзакциям одну и ту же «картину мира».

Зачем нужны критерии ACID?

Чтобы отличать настоящую DB от простого или сложного «файлового хранилища».
База гарантирует в многопользовательской среде корректную обработку и сохранение транзакций.

📌 Но есть системы, которые называются «базами данных», хотя полного ACID в них нет:

MongoDB (в ранних версиях классический ACID не обеспечивался по умолчанию).
Cassandra и другие NoSQL (делают ставку на масштабирование, жертвуя частью гарантий).
Redis (in-memory key-value store, без полноценного ACID).

💡 Плюсы таких решений: скорость и горизонтальное масштабирование.
Минус: «железобетонной гарантии» ACID нет, и это важно учитывать при проектировании.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

#RealInterviewTasks #sql #Oracle #PostgreSQL #PLSQL #PLpgSQL
👍4👎1🤔1
Допустим, Вы получили входящий параметр income_collection типа IS TABLE OF NUMBER. Вы знаете, что там могут быть дубли, которые нужно проигнорировать. Каким бы способом Вы бы это сделали?
Anonymous Poll
34%
Функция SET
55%
SELECT DISTINCT (с TABLE() оператором)
10%
Я знаю 3 вариант (Могу поделиться в комментах)
👎1
DB developers channel
Допустим, Вы получили входящий параметр income_collection типа IS TABLE OF NUMBER. Вы знаете, что там могут быть дубли, которые нужно проигнорировать. Каким бы способом Вы бы это сделали?
ORACLE_SET_TEST.sql
11.1 KB
🔥 Небольшой эксперимент с Oracle коллекциями

Я решил проверить, что реально происходит «под капотом», когда мы убираем дубликаты из коллекции TABLE OF NUMBER.
Сравнил два способа:

1️⃣ SET(collection)
2️⃣ SELECT DISTINCT FROM TABLE(collection)

Для чистоты — прогнал на миллионе элементов, собирал статистику из v$mystat (consistent gets, pga/uga, sorts, cpu и т.д.).

📊 Результаты
1️⃣ SET(collection)
time: +000000000 00:00:00.131000000
2️⃣ SELECT DISTINCT FROM TABLE(collection)
time: +000000000 00:00:00.125000000

💡Результат удивительный. Второй вариант быстрее, несмотря на смену контекста с PL/SQL на SQL, выгрузку BULK COLLECT.
У функции SET явно есть проблемы.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

#Cases
🔥7👍2👎1
🎵 «Ваше благородие, госпожа победа,
значит, моя песенка до конца не спета!
Перестаньте, черти,
клясться на крови...
Не везёт мне в смерти,
повезёт в любви.» — Булат Окуджава

Друзья, канал набрал 100 подписчиков меньше чем за месяц 🎉
Для меня это победа — он уже вышел далеко за рамки круга моих знакомых.

Изначально это задумывалось как публичная записная книжка, но постепенно канал стал чем-то большим — отдельным событием, живым и самостоятельным 🚀.

👋 Немного обо мне:
Меня зовут Поликарпов Кирилл Вадимович, я Senior DB Developer.
💾 Опыт — Oracle, PostgreSQL, MS SQL.
Но честно признаюсь — Oracle мне ближе всего ❤️.

🏦 СКБ-Банк — моя первая профессиональная работа как разработчика DB (2017 год).
Воспоминания тёплые: весёлое и живое время, отличная команда, дружеская атмосфера. Ребята, спасибо за старт! 🙌

💍 Кольцо Урала — для меня это особенное место. Для меня это лучшее место на земле. Я именно там состоялся как разработчик и понял что это моё.
Коллеги из Кольца я Вас не просто люблю - я Вас обожаю, преобожаю. Нигде и никогда мне не было так интересно, продуктивно и комфортно, как работать рядом с Вами.

🐹 Банк Хоум Кредит («Хомяк») — большой банк со своими плюсами и минусами. Здесь я встретил много хороших людей и настоящего друга — Ирека Вафина. Ирек, спасибо тебе, ты крутой человек и сильный разработчик 🤝.

🚕 Такси Максим — отличное место, если хочется много работать и при этом оставаться в позитивной атмосфере. Команда «Бобры» 🦫, которой я имел честь руководить, навсегда в моём сердце. И да, связь с аватаркой канала не случайна 😉.

🌍 Сейчас я работаю в международной процессинговой компании.
Здесь крутые ребята. Требования высокие, работать тяжело, но невероятно интересно. Спасибо и вам, коллеги 🙏.

Особое спасибо подписчикам, которых я не знаю лично. Рад видеть вас среди своих читателей 💫.

🎯 Цель: 1000 подписчиков до конца года.

⚙️ Как пишутся посты?
Я пишу «рыбу» ✍️, а затем прошу ИИ помочь с оформлением, эмодзи и упрощением сложных формулировок. Мы с ИИ — сильная команда 🤖.

Если хотите помочь каналу:
1️⃣ Главное — предлагайте задачи, темы и фичи. Моего материала хватит ещё на 3–4 месяца, а Ваши идеи сделают канал интереснее.
2️⃣ Если у вас есть знакомые, которым близка тема БД, — поделитесь с ними ссылкой.

Спасибо каждому из вас ❤️
👍9🔥5👏2👎1
DB developers channel
📌 Из предыдущего опроса стало ясно, что задачи на алгоритмы Вам интересны. Я прорешал около 💯 задач и понял, что почти все они делятся на 5 категорий:
👍5👎1
«Снежная королева:
— Кай, составь слово «Вечность» — и будешь свободен!
Кай:
— Сколько ни пробую, всё время выходит «ЖОПА»…
Снежная королева:
— Ну, в принципе, то же самое.» - детский анекдот.

🏛 Архитектура кода

Как и обещал подписчику Глебу Буланцеву: набрали 💯 — начинаю серию постов про архитектуру кода.

💡 Каждый разработчик уверен: его код пусть и не идеален, но всё же оптимален в данных обстоятельствах. И это абсолютно нормально — иначе можно утонуть в бесконечных сомнениях.

В этих постах я делюсь своими мыслями и опытом и, естественно, не претендую на вселенскую истину.

📌 Задача
Есть база данных (буду рассматривать Oracle, но подход универсален).
Есть несколько приложений, которые её используют.
Нужно смоделировать архитектуру кода так, чтобы он был:
безопасен
контролируем
гибок
удобен и понятен

Согласитесь, задачка непростая.

🧩 Модель архитектуры
Предлагаю делить код на 3 уровня:

1) 🔹 API-уровень
Это «витрина» для приложения.
Для каждого приложения создаём свой пакет с методами (например, APPLICATION_API или APPLICATION_SRV).

Здесь можно:
проверить входящие параметры,
отдавать курсоры наружу,
вызвать операцию из следующего уровня.

Здесь нельзя:
менять данные в таблицах,
хранить бизнес-логику,
выполнять валидации.

Главная цель: разграничение прав доступа и первичная проверка входа.

2) 🔹 OPER-уровень

Здесь живёт бизнес-логика.
Каждый внешний метод = отдельная операция.

Допустим вызов одной операции из другой, но запрещено обращаться к API-методам отсюда.
Иногда уровень делят ещё на подуровни (например LVL1 и LVL2), если нужно предварительно распарсить входящие JSON/XML.

3) 🔹 Табличный уровень

Самый простой, но ключевой.
Это точка работы с одной строкой таблицы:

вставка,
обновление,
удаление,
чтение,
блокировка.

Здесь же дублируется табличная валидация (те же ограничения, что и на уровне таблицы в БД)
Заполнение и или обновление технических полей.

🚫 Запрещено вызывать другие пакеты. Этот уровень должен быть полностью изолирован.

Чуть позже я опубликую упрошенный вариант кода. Где на примере, мы продолжим разговор уже в обратном направлении от таблиц до API уровня.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

💬 Если есть возражение, согласие или негодование — не сдерживайте себя👇
#CodeArchitecture
👍1👎1
"Там, где, сливаяся, шумят,
Обнявшись, будто две сестры,
Струи Арагвы и Куры" — М.Ю. Лермонтов 🌊💫

📌 Разбор задачи про объединение массивов 🛠️

Объединение массивов: Объедините два отсортированных массива в один отсортированный массив.

Даны два отсортированных массива с повторами:
set_1 = (1,2,2,5,7,9)
set_2 = (1,2,3,4,5,5,6,8)

Нужно получить массив: 1 2 3 4 5 6 7 8 9

🛠️ Алгоритм интуитивно понятен.
Идём по двум массивам одновременно,
в новый массив попадает только меньшее или равное значение.
Счетчики массивов либо по одному, либо по другому увеличиваются +1
sql
🔄
DECLARE
TYPE set_tab IS TABLE OF INTEGER;
set_1 set_tab := set_tab (1, 2, 2, 5, 7, 9);
set_2 set_tab := set_tab (1, 2, 3, 4, 5, 5, 6, 8);
index_1# INTEGER := 1;
index_2# INTEGER := 1;
newSet set_tab := set_tab ();
BEGIN
WHILE (index_1# <= set_1.COUNT OR index_2# <= set_2.COUNT) LOOP
IF index_1# > set_1.COUNT THEN
newSet.EXTEND;
newSet(newSet.COUNT) := set_2(index_2#);
index_2# := index_2# + 1;
CONTINUE;
END IF;
IF index_2# > set_2.COUNT THEN
newSet.EXTEND;
newSet(newSet.COUNT) := set_1(index_1#);
index_1# := index_1# + 1;
CONTINUE;
END IF;
IF set_1(index_1#) <= set_2(index_2#) THEN
IF newSet IS EMPTY OR newSet(newSet.COUNT) != set_1(index_1#) THEN
newSet.EXTEND;
newSet(newSet.COUNT) := set_1(index_1#);
END IF;

index_1# := index_1# + 1;
CONTINUE;
END IF;
IF set_1(index_1#) > set_2(index_2#) THEN
IF newSet IS EMPTY OR newSet(newSet.COUNT) != set_2(index_2#) THEN
newSet.EXTEND;
newSet(newSet.COUNT) := set_2(index_2#);
END IF;

index_2# := index_2# + 1;
CONTINUE;
END IF;
END LOOP;
DECLARE
str VARCHAR2(4000);
BEGIN
FOR i IN 1 .. newSet.COUNT LOOP
str := str ' ' TO_CHAR(newSet(i));
END LOOP;
DBMS_OUTPUT.put_line(str);
END;
END;
Сама по себе задача простая, но она перекликается с известным способом соединения таблиц MERGE 🔗

Merge Join работает именно по такому принципу: оба набора данных сначала сортируются, а потом сканируются «с двух концов» одновременно 🔄.
В чём отличие — он сравнивает не сами значения, а по условию равенства вычисляет хэш-функции (STANDARD_HASH('myValue', 'MD5')) 🧩.

Для новичков приведу пример:
SQL
CREATE TABLE table_1
(
id NUMBER
);
CREATE TABLE table_2
(
id NUMBER
);
INSERT INTO table_1 (id)
SELECT LEVEL AS id
FROM DUAL
CONNECT BY LEVEL < 10;
INSERT INTO table_2 (id)
SELECT LEVEL AS id
FROM DUAL
CONNECT BY LEVEL < 100;
SELECT /*+ LEADING (t1 t2) USE_MERGE(t2)*/
t1.id
FROM table_1 t1 INNER JOIN table_2 t2 ON (t1.id = t2.id);

Соединим таблицы и добавим хинт USE_MERGE, подсказывающий оптимизатору использовать MERGE JOIN:
SQL
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 54 | 8 | 00:00:01 |
| 1 | MERGE JOIN | | 9 | 54 | 8 | 00:00:01 |
| 2 | SORT JOIN | | 9 | 27 | 4 | 00:00:01 |
| 3 | TABLE ACCESS FULL | TABLE_1 | 9 | 27 | 3 | 00:00:01 |
| * 4 | SORT JOIN | | 99 | 297 | 4 | 00:00:01 |
| 5 | TABLE ACCESS FULL | TABLE_2 | 99 | 297 | 3 | 00:00:01 |
--------------------------------------------------------------------------

Видим, что Oracle отсортировал данные и применил алгоритм, похожий на наш первоначальный 👏

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

Пишите, если есть что писать. Ставьте эмодзи если вызывает эмоции👇
#sql #Oracle #PLSQL
👍8👎1🤓1
🎵 «Позабыты хлопоты
Остановлен бег
Вкалывают роботы
Счастлив человек!» — из к/ф "Приключения Электроника"

📌 Разбор задачи: Переворот строки

Сегодня у нас на разборе задача: 🔄 перевернуть слова в строке, сохраняя пробелы на своих местах.
⚙️ Важное ограничение: решение процедурными методами.

Исходная строка и нужный результат:

' 123 456 234 789 9 '
' 321 654 432 987 9 '

👉 Алгоритм:
Идём посимвольно по строке.
Если встречаем пробел — просто добавляем его в результат.
Если начинается слово — ищем его длину.
Переписываем слово в обратном порядке.
Двигаем указатель дальше.

📜 Решение на PL/SQL (первый вариант):
DECLARE
str VARCHAR2 (4000) := ' 123 456 234 789 9 ';
indexStart INTEGER;
newStr VARCHAR2 (4000);
index# INTEGER := 1;
BEGIN
WHILE index# < LENGTH (str) LOOP
IF SUBSTR (str, index#, 1) = ' ' THEN
newStr := newStr || ' ';
index# := index# + 1;
ELSE
indexStart := 0;

FOR j IN 1 .. LENGTH (str) LOOP
IF SUBSTR (str, index# + j - 1, 1) = ' ' THEN
EXIT;
ELSE
indexStart := indexStart + 1;
END IF;
END LOOP;

FOR q IN 1 .. indexStart LOOP
newStr := newStr || SUBSTR (str, index# + indexStart - q, 1);
END LOOP;

index# := index# + indexStart;
END IF;
END LOOP;

DBMS_OUTPUT.put_line (str);
DBMS_OUTPUT.put_line (newStr);
END;

🤖 Но машина оказалась умнее. ЧатGPT выдал решение оптимальнее.
Иногда так и хочется быть Джоном Коннором!
Сцену, когда Арни опускается в раскалённый металл, воспринимаю по-другому чем прежде.😉

📜 Оптимизированный вариант:
DECLARE
str VARCHAR2(4000) := ' 123 456 234 789 9 ';
word VARCHAR2(4000);
newStr VARCHAR2(4000) := '';
i PLS_INTEGER := 1;
ch CHAR(1);
BEGIN
WHILE i <= LENGTH(str) LOOP
ch := SUBSTR(str, i, 1);

IF ch = ' ' THEN
newStr := newStr || ch;
i := i + 1;
ELSE
word := '';
WHILE i <= LENGTH(str) AND SUBSTR(str, i, 1) <> ' ' LOOP
word := SUBSTR(str, i, 1) || word;
i := i + 1;
END LOOP;
newStr := newStr || word;
END IF;
END LOOP;

DBMS_OUTPUT.put_line(str);
DBMS_OUTPUT.put_line(newStr);
END;

Отличия от первого варианта:
🚫 Нет вложенного цикла для подсчёта длины слова.
🔄 Переворот делаем "на лету" при сборке.
📖 Код читается проще и выглядит короче.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

🤔 А какое чувство к машинам испытываете вы? Поделитесь в комментах 👇
#sql #Oracle #PLSQL
👍4🤓2👾2👎1
🎵 «Хочешь сладких апельсинов?
Хочешь вслух рассказов длинных?
Хочешь, я взорву все звёзды
Что мешают спать?» — Земфира

Сегодня суббота — отдыхаем от задач.
Рубрика «Полезные ресурсы»

Есть желание «вскрыть» содержимое wrapped-пакетов?
👉 https://www.codecrete.net/UnwrapIt/

Копируем и вставляем содержимое поля text.
⚠️В ресурс вставляем не сам запрос, а содержимое поля из выполненного в базе запроса:
SELECT  line, text
FROM ALL_SOURCE
WHERE owner = 'SYS'
AND name = 'DBMS_SCHEDULER'
AND type = 'PACKAGE BODY'
ORDER BY line;


И наслаждаемся «индусским» кодом 😎

Работает прямо в браузере, без установки.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

💡 Если у вас есть свои полезные ссылки — не жадничайте, делитесь в комментариях!
#tools #Oracle #PLSQL
🆒4👎1
🎵 «Труд мой
    любому
        труду
           родствен.
Взгляните —
      сколько я потерял,
какие
   издержки
        в моем производстве
и сколько тратится
         на материал.»
— В.В. Маяковский

📌 Разбор задачи: Максимальный квадрат (процедурными методами)

🧩 Условие:
Дана двоичная матрица (элементы 0 и 1).
Нужно найти самый большой квадрат, состоящий только из единиц.

🧩 Пример матрицы

0 1 1 0 1 0 1
1 1 1 1 1 0 0
0 1 1 1 1 1 0
0 1 1 1 1 1 0
0 0 1 1 1 0 0

🔵 В этой матрице максимальный квадрат состоит из 3x3 единиц (сверху слева от позиции (2,2)):

0 1 1 0 1 0 1
1 🔵 🔵 🔵 1 0 0
0 🔵 🔵 🔵 1 1 0
0 🔵 🔵 🔵 1 1 0
0 0 1 1 1 0 0

💻 Решение (PL/SQL):
SQL
DDECLARE
TYPE row_type IS TABLE OF NUMBER;

TYPE matrix_type IS TABLE OF row_type;

matrix matrix_type
:= matrix_type (row_type (0, 1, 1, 0, 1, 0, 1),
row_type (1, 1, 1, 1, 1, 0, 0),
row_type (0, 1, 1, 1, 1, 1, 0),
row_type (0, 1, 1, 1, 1, 1, 0),
row_type (0, 0, 1, 1, 1, 0, 0));

TYPE square IS RECORD
(
i INTEGER,
j INTEGER,
side_amount INTEGER
);

maxSquare square;
currentSquare square;
BEGIN
FOR i IN 1 .. matrix.COUNT LOOP
FOR j IN 1 .. matrix (i).COUNT LOOP
IF matrix (i) (j) = 1 THEN
currentSquare.i := i;
currentSquare.j := j;

--DBMS_OUTPUT.put_line ('--');
--DBMS_OUTPUT.put_line ('(' || TO_CHAR (i) || ', ' || TO_CHAR (j) || ')');

DECLARE
maxSide INTEGER := 1;
skip EXCEPTION;
BEGIN
WHILE maxSide <= LEAST (matrix.COUNT - i, matrix (i).COUNT - j) LOOP
/*
j
i 1 1 1 ..
1 1 0 ..
1 1 1 ..
. . . ..
*/
FOR q IN 0 .. maxSide LOOP
--DBMS_OUTPUT.put_line ('(' || TO_CHAR (i + maxSide) || ', ' || TO_CHAR (j + q) || ')');
--DBMS_OUTPUT.put_line ('(' || TO_CHAR (i + q) || ', ' || TO_CHAR (j + maxSide) || ')');

IF matrix (i + maxSide) (j + q) = 0 OR matrix (i + q) (j + maxSide) = 0 THEN
RAISE skip;
END IF;
END LOOP;

maxSide := maxSide + 1;
END LOOP;

currentSquare.side_amount := GREATEST (NVL (currentSquare.side_amount, 0), maxSide);
EXCEPTION
WHEN skip THEN
currentSquare.side_amount := GREATEST (NVL (currentSquare.side_amount, 0), maxSide);
END;

IF NVL (maxSquare.side_amount, 0) < currentSquare.side_amount THEN
maxSquare := currentSquare;
END IF;

currentSquare := NULL;
END IF;
END LOOP;
END LOOP;

DBMS_OUTPUT.put_line (
'side_amount = ' || TO_CHAR (maxSquare.side_amount) || ', i = ' || TO_CHAR (maxSquare.i) || ', j = ' || TO_CHAR (maxSquare.j));
END;

Итог: выводит координаты i, j и размер стороны найденного квадрата.

👍 Пальцы вверх — продолжаем разбирать задачи методами процедурного языка.
👎 Пальцы вниз — значит, тема надоела.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

#️⃣ #sql #Oracle #PLSQL
👍7🤔2👎1
🎵 «Во поле берёза стояла
Во поле кудрявая стояла
Люли-люли, стояла
Люли-люли, стояла» — народная 🌳

📌 Разбор задачи: Зеркальное отображение дерева

🧩 Условие:
Дана бинарная береза 🌲.
Преобразуйте бинарное дерево в его зеркальное отображение — то есть поменять местами все левые и правые поддеревья.

⚙️ Алгоритм (кратко):
Рекурсивно обходим дерево.

Для каждой вершины:
🔄 меняем местами левое и правое поддерево.

Возвращаем новую ссылку на корень.

💻 Решение (PL/SQL):
CREATE OR REPLACE TYPE node IS OBJECT (
value NUMBER,
left REF node,
right REF node
);
CREATE TABLE nodes OF node;

DECLARE
TYPE ref_tab IS TABLE OF REF node INDEX BY PLS_INTEGER;

refs ref_tab := ref_tab();
root REF node;
mirroredTreeRoot REF node;

PROCEDURE insert_node (root IN OUT REF node, new_value IN NUMBER) IS
current node;
BEGIN
IF root IS NULL THEN
INSERT INTO nodes n
VALUES (node(VALUE => insert_node.new_value, left => NULL, right => NULL))
RETURNING REF(n) INTO insert_node.root;
ELSE
SELECT DEREF(root) INTO current FROM DUAL;

IF new_value < current.VALUE THEN
insert_node(root => current.left, new_value => new_value);
UPDATE nodes n SET n.left = current.left WHERE REF(n) = insert_node.root;
ELSE
insert_node(root => current.right, new_value => new_value);
UPDATE nodes n SET n.right = current.right WHERE REF(n) = insert_node.root;
END IF;
END IF;
END insert_node;

PROCEDURE print_node (root IN OUT REF node) IS
current node;
skip EXCEPTION;
BEGIN
IF root IS NULL THEN RAISE skip; END IF;
SELECT DEREF(root) INTO current FROM DUAL;

DBMS_OUTPUT.put_line(
'node(' || TO_CHAR(current.VALUE)
|| ',' || CASE WHEN current.left IS NOT NULL THEN 'left=yes' ELSE 'left=no' END
|| ',' || CASE WHEN current.right IS NOT NULL THEN 'right=yes' ELSE 'right=no' END
|| ')'
);

IF current.left IS NOT NULL THEN print_node(root => current.left); END IF;
IF current.right IS NOT NULL THEN print_node(root => current.right); END IF;
EXCEPTION WHEN skip THEN NULL;
END print_node;

FUNCTION mirror_tree (root REF node) RETURN REF node IS
newNode REF node;
BEGIN
IF root IS NULL THEN RETURN NULL; END IF;

DECLARE
current node;
leftNext REF node;
rightNext REF node;
BEGIN
SELECT DEREF(root) INTO current FROM DUAL;
leftNext := mirror_tree(root => current.right);
rightNext := mirror_tree(root => current.left);

INSERT INTO nodes n
VALUES (node(VALUE => current.VALUE, left => leftNext, right => rightNext))
RETURNING REF(n) INTO newNode;

RETURN newNode;
END;
END mirror_tree;
BEGIN
FOR i IN 1..10 LOOP
DECLARE newValue NUMBER := TRUNC(DBMS_RANDOM.VALUE(1, 100));
BEGIN insert_node(root => root, new_value => newValue); END;
END LOOP;

DBMS_OUTPUT.put_line('root');
print_node(root => root);

mirroredTreeRoot := mirror_tree(root);
DBMS_OUTPUT.put_line('mirroredTreeRoot');
print_node(root => mirroredTreeRoot);
END;

👍 Пальцы вверх — продолжаем разбирать задачи методами процедурного языка.
👎 Пальцы вниз — значит, тема надоела.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

Вчера комменты были интереснее поста, надуюсь что "есть еще порох в пороховницах"👇
#️⃣ #SQL #Oracle #PLSQL
👍13👎4
🎵 «Киборг-убийца рвётся наружу,
Он не опасен, он безоружен.
Киборг-убийца на вечеринке,
Любит Анжелу, любит Маринку.
Киборг-убийца где-то внутри —
Может быть, я, может быть, ты…» — Ленинград 🤖🎤

📌 Разбор задачи: Путь робота в сетке

🧩 Условие:
Робот начинает движение в верхнем левом углу сетки m × n.
Он может двигаться только 👉 вправо или 👇 вниз.
Нужно найти количество уникальных путей до нижнего правого угла.

⚙️ Алгоритм (кратко):
1️⃣ Создаём матрицу n × m.
2️⃣ Заполняем первую строку и первый столбец единицами (робот может двигаться только по одной траектории).
3️⃣ Для каждой ячейки:
📐 matrix[i][j] = matrix[i-1][j] + matrix[i][j-1]
(сумма способов попасть сверху и слева).
4️⃣ В правом нижнем углу будет количество всех уникальных путей.

💻 Решение (PL/SQL):
DECLARE
TYPE row_tab IS TABLE OF NUMBER;
TYPE matrix_tab IS TABLE OF row_tab;

matrix matrix_tab := matrix_tab();
uniqueWayCount INTEGER;

PROCEDURE get_unique_way_count (
n IN INTEGER,
m IN INTEGER,
matrix IN OUT NOCOPY matrix_tab,
unique_way_count OUT INTEGER
) IS
PROCEDURE init_matrix (
n IN INTEGER,
m IN INTEGER,
matrix IN OUT NOCOPY matrix_tab
) IS
"row" row_tab := row_tab();
BEGIN
"row".extend(m);
matrix.extend(n);
FOR i IN 1..n LOOP
matrix(i) := "row";
END LOOP;
"row".delete;
END init_matrix;
BEGIN
init_matrix(n => n, m => m, matrix => matrix);

FOR i IN 1..n LOOP
FOR j IN 1..m LOOP
IF i = 1 OR j = 1 THEN
matrix(i)(j) := 1;
ELSE
matrix(i)(j) := matrix(i - 1)(j) + matrix(i)(j - 1);
END IF;
END LOOP;
END LOOP;

unique_way_count := matrix(n)(m);
END get_unique_way_count;

PROCEDURE print_matrix (matrix IN matrix_tab) IS
BEGIN
FOR i IN 1..matrix.COUNT LOOP
DECLARE
str VARCHAR2(200);
BEGIN
FOR j IN 1..matrix(i).COUNT LOOP
str := str || ' ' || TO_CHAR(matrix(i)(j));
END LOOP;
DBMS_OUTPUT.put_line(str);
END;
END LOOP;
END print_matrix;
BEGIN
get_unique_way_count(n => 10, m => 10, matrix => matrix, unique_way_count => uniqueWayCount);

print_matrix(matrix => matrix);

DBMS_OUTPUT.put_line('uniqueWayCount = ' || TO_CHAR(uniqueWayCount));
END;

📊 Для сетки 10 × 10 ответ будет: 48620 уникальных путей.

Можно усложнить задачу: сделать матрицу бинарной (1 и 0), и добавить условие, что робот может двигаться только по клеткам со значением 1.
💡 Желающие могут поэкспериментировать и поделиться своими решениями в комментах.

👍 Пальцы вверх — продолжаем разбирать задачи методами процедурного языка.
👎 Пальцы вниз — значит, тема надоела.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

💬 Каждый ваш коммент ценен, не сдерживайте себя — здесь цензуры нет 👇
#️⃣ #SQL #Oracle #PLSQL
👍6👎5
🚀 Хочется прокачать SQL, но под рукой нет базы данных?

Рекомендую дружественный ресурс от моего коллеги Славы Рожнева - автора курса SQL от Яндекс практикума.

У Славы Рожнева — есть два удобных инструмента:

🔹 sqltest.online — тренажёр с задачами и тестами для практики.
📢 Канал: t.me/sqltestonline

🔹 sqlize.online — онлайн-песочница для SQL-запросов прямо в браузере.
📢 Канал: t.me/sqlize

Отличный способ учиться и поддерживать навыки в любой момент и в любом месте.
👍11🤡3👎1🔥1
🎵 «Для меня деньги — бумага
Для тебя — свобода
На американскую мечту сегодня мода
К этой мечте стремишься ты
Работать роботом ради бумажной мечты» — Ленинград 🎸

📌 Задача из собеса в ЦБ (2020 год).
В самом первом посту канала (в прикреплённом файлике) — 3 задачи.
🔹 Первые две уже разобраны.
🔹 Вот третья:

🧩 Условие задачи:
Запрос формирует список действующих на sysdate ОКВЭД для всех организаций.

При выполнении возникает ошибка — нехватка табличного пространства TEMP.
Нужно оптимизировать запрос, чтобы он успешно выполнился.
SQL
select
t1.ogrn,
t2.ds,
t2.de,
o.kod,
o.name,
o.ver
from T2
join T1 on t1.id = t2.id
left join T_okved o on o.id = t2.okved_id
where sysdate between t1.ds and t1.de
and sysdate between t2.ds and t2.de;

💡 Примечание:
Структуру таблиц T1, T2, T_okved приводить не нужно — она условная, нужна только для понимания сути.

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

📝 В комментариях пишите свои мысли и варианты оптимизации
👇👇
#RealInterviewTasks #SQL #Oracle #PLSQL
👍5💩52👎1
DB developers channel
🎵 «Для меня деньги — бумага Для тебя — свобода На американскую мечту сегодня мода К этой мечте стремишься ты Работать роботом ради бумажной мечты» — Ленинград 🎸 📌 Задача из собеса в ЦБ (2020 год). В самом первом посту канала (в прикреплённом файлике) — 3…
📌 Разбор задачи из ЦБ (2020 год)
select 
t1.ogrn,
t2.ds,
t2.de,
o.kod,
o.name,
o.ver
from T2
join T1 on t1.id = t2.id
left join T_okved o on o.id = t2.okved_id
where sysdate between t1.ds and t1.de
and sysdate between t2.ds and t2.de;

Проблема: при выполнении возникает ошибка — нехватка табличного пространства TEMP.
Нужно оптимизировать запрос, чтобы он успешно выполнился.

💡 Решение
Основная причина переполнения TEMP — использование hash join, который строит большие промежуточные таблицы.
Чтобы этого избежать, можно подсказать оптимизатору использовать nested loop.

🔹 Оптимизированный запрос:
SELECT  --+ LEADING(T1 T2 o) USE_NL(T2 o)
t1.OGRN,
t2.DS,
t2.DE,
o.KOD,
o.NAME,
o.VER
FROM T1
JOIN T2 on (t1.id = t2.id)
left join T_okved o on o.id = t2.okved_id
WHERE sysdate between t1.ds and t1.de
and sysdate between t2.ds and t2.de;

Идея решения:

USE_NL → переключаем соединение на nested loop, чтобы уменьшить нагрузку на TEMP.
Таким образом, запрос выполнится без переполнения TEMP.

UPDATES: под справедливой критикой коллег, запрос и пост изменил

⚠️ Хотите проверить скрипты, но нет базы под рукой - онлайн-песочница
💎 Поддержка канала⁉️

📝 Как Вы бы решили?👇
#️⃣ #RealInterviewTasks #SQL #Oracle #PLSQL
🤡5👍3👎1