DB developers channel
803 subscribers
2 photos
46 files
102 links
💡 Канал для разработчиков баз данных: Oracle, PostgreSQL
📌 Интересные задачи, фрагменты кода, лучшие практики, архитектура, оптимизация
🔄 Присоединяйся к сообществу — развивайся вместе с нами!
#SQL #Oracle #PostgreSQL #PL/SQL #PL/pgSQL #DB
Download Telegram
DB developers channel
Задача от начальника разработки DB большого знатока Postgres - Ивана Петровича Могилы. "Она такая, из практики, поэтому не очень красивая. Я нашим бдшникам её давал. Но она очень завязана на особенности postgresql" Опишите логику, что делает эта функция CREATE…
Логика функции следующая:
1. Идем по записям определенного диапазона страниц таблицы (далее Х),
для этого нам нужен только ctid, он доступен всем кто имеет права на чтение таблицы
2. Для каждой записи делаем update, создается новая версия строки,
эта версия может быть как в том же диапазоне Х, так и выше или ниже
- Если новая версия строки оказалась в странице выше диапазона Х,
то выходим, поэтому диапазон лучше указывать из хвоста таблицы, чтобы такая ситуация была невозможна
- Если новая версия строки оказалась в том же диапазоне Х, то делаем update снова
- Если новая версия строки оказалась в странице ниже диапазона Х,
то идем дальше, старую версию потом удалит vacuum

Таким образом с помощью update мы пытаемся согнать все строки из указанного диапазона страниц в страницы ниже,
а этот диапазон освободить. Если он будет в хвосте таблицы, то vacuum сможет его освободить полностью.

У vacuum в postgres есть особенность, что он освобождает место занятое таблицей только с конца
т.е. полностью пустые странице в хвосте могут быть освобождены,
но пустые страницы в середине не могут, если за ними есть страницы с живыми строками.
Ну и ещё одна особенность.
UPDATE ONLY  t_table_ident SET
id = id
WHERE ctid = ANY($1)
RETURNING ctid;

Тут returning вернет ctid новой версии строки, так что значение будет отличаться от того, что передано в параметре.

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

💼 #RealInterviewTasks
👎1
Простая, но интересная задача на понимание.
(Мне задавали на собесе в 2022 году)

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

create table t1(a number, b number);

create table t2(a number, b number);

Пример данных:
T1:
a b
1 1
2 2
2 2
3 3
4 4
T2:
a b
1 1
2 2
3 3
3 3
4 4

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

💼 #RealInterviewTasks #SQL
2👎1
DB developers channel
Простая, но интересная задача на понимание. (Мне задавали на собесе в 2022 году) Необходимо написать запрос, который позволит понять, идентичны ли данные в двух таблицах. Порядок хранения данных в таблицах значения не имеет. create table t1(a number, b number);…
Решение задачи вариант 1:
На собесе я решил через FULL OUTER JOIN
На текущий момент добавил все красивости и мое решение выглядело бы так:
SELECT CASE
WHEN EXISTS
(SELECT NULL
FROM (SELECT STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t1
GROUP BY STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5')) t11
FULL OUTER JOIN
(SELECT STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t2
GROUP BY STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5')) t21
ON (t11.hash_row = t21.hash_row AND t11.row_amount = t21.row_amount)
WHERE t11.hash_row IS NULL OR t21.hash_row IS NULL) THEN
'DIFFERENT'
ELSE
'IDENTICAL'
END AS comparison_result
FROM DUAL;

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

💼 #RealInterviewTasks #SQL
1👎1
DB developers channel
Простая, но интересная задача на понимание. (Мне задавали на собесе в 2022 году) Необходимо написать запрос, который позволит понять, идентичны ли данные в двух таблицах. Порядок хранения данных в таблицах значения не имеет. create table t1(a number, b number);…
Кстати, чат GPT предложил решение через MINUS.
SELECT CASE
WHEN
(
SELECT COUNT(*) FROM (
SELECT a, b, COUNT(*) cnt FROM t1 GROUP BY a, b
MINUS
SELECT a, b, COUNT(*) cnt FROM t2 GROUP BY a, b
)
) = 0
AND
(
SELECT COUNT(*) FROM (
SELECT a, b, COUNT(*) cnt FROM t2 GROUP BY a, b
MINUS
SELECT a, b, COUNT(*) cnt FROM t1 GROUP BY a, b
)
) = 0
THEN 'IDENTICAL'
ELSE 'DIFFERENT'
END AS comparison_result
FROM dual;

Я слегка его переделал и
и это решение мне тоже нравится
Вариант 2
SELECT CASE
WHEN
EXISTS
(
SELECT STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t1
GROUP BY STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5')
MINUS
SELECT STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t2
GROUP BY STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5')
)
OR
EXISTS
(
SELECT STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t2
GROUP BY STANDARD_HASH (TO_CHAR (t2.a) || '/' || TO_CHAR (t2.b), 'MD5')
MINUS
SELECT STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5') AS hash_row, COUNT (*) AS row_amount
FROM t1
GROUP BY STANDARD_HASH (TO_CHAR (t1.a) || '/' || TO_CHAR (t1.b), 'MD5')
)
THEN 'DIFFERENT'
ELSE 'IDENTICAL'
END AS comparison_result
FROM dual;


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

💼 #RealInterviewTasks #SQL
👎1
Channel name was changed to «DB developers channel»
В книге Дж. Льюиса "Oracle. Основы стоимостной оптимизации" в Главе I на 7 странице на 20 строчке сказано "Приведи друга разработчика на канал и будет тебе удача на неделю. Приведи 3 друзей и будет тебе счастье на месяц". Мысль спорная. Как вы считаете?
Anonymous Poll
50%
Согласен
8%
Не согласен
42%
Не пудрите мне мозги!!! Дж. Льюис не тот автор, на которого стоит ориентироваться
👎1
🔎 Сложная задача с собеса в компанию UNLIMIT
(Я её не решил в моменте т.е. как не решил, я предложил вариант, но он ресурсный и потому неподходящий.)
Задача на уровень Senior, а может быть Expert.

💡 Условие:

У нас — высоконагруженная база ORACLE:
📈 до 1000 и выше транзакций в секунду.
Часть из них — commit, часть — rollback.

Нужно:
📆 Назначать каждой транзакции уникальный порядковый номер в пределах суток (часа, минуты)
При этом:

🔁 Номера должны идти без пропусков и дублей.

📌 Сохраняем их в таблице transactions.

Нельзя использовать блокировки, которые мешают другим транзакциям.

Назначение номера должно происходить быстро.

📊 Пример:

Дата Номер транзакции
01.01.2025 1
01.01.2025 2
... ...
01.01.2025 1000009
02.01.2025 1
02.01.2025 2
... ...

🤔 Как бы вы реализовали такой счётчик?
С условиями:

Без блокировок

Без пробелов

Быстро

И чтобы не сносило систему под нагрузкой

Пишите ваши идеи 👇

🔄 UPDATE 02.02.2025:

Спасибо, что с нами есть Иван Петрович.

📌 В PostgreSQL такое провернуть невозможно.
Дело в том, что PostgreSQL при попытке вставки уникального значения блокирует строку (если используется, например, SELECT ... FOR UPDATE, INSERT ... ON CONFLICT, уникальные индексы и т. д.).
Сессии, которые вставляют те же значения одновременно, вынуждены ждать — из-за row-level locks.

🔄 UPDATE 23.09.2025:

Спасибо, что с нами есть Евгений Артурович.

💡 В Oracle поведение аналогичное - при вставке двух новых значений в уникальный индекс ошибка проявляется в момент коммита. Поэтому для избежание конкуренции назначения номера должно быть в автономной транзакции.

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

#RealInterviewTasks #Oracle #PL/SQL
👎1
💡 Разбор «невозможной» задачи про сквозной счётчик-без-пробелов

🔑 Главные наблюдения
INSERT — самая быстрая DML-операция; читаем как можно меньше.

FAST FULL INDEX SCAN даёт O(1) чтение «хвоста» уникального индекса.

Сессии изолированы, но автономная транзакция и уникальный индекс гарантирует, что два одинаковых значения не вставятся одновременно.

🛠 Алгоритм
Шаг Действие Почему это безопасно
1 Читаем последний номер через SELECT … ORDER BY num DESC FETCH 1
(FAST FULL INDEX SCAN) Один блочный I/O, без блокировок
2 INSERT INTO period_tx_idx(period, num) VALUES(:p, :last_num) Дешевле, чем update
3 Если вставка успешна → номер наш Уникальный индекс не дал коллизии
4 Если ORA-00001 / unique constraint → кто-то уже взял этот num → num := num + 1 и GO TO 2 Перебираем до победы — обычно 1-2 попытки

🔸 На практике при 1 000 TPS конкурируют считанные сессии → конфликт мизерный.
🔸 «Дырки» возможны только при аварийном выключении питания в момент вставки, и то чисто теоретически.

❗️ Практический совет
Такой счетчик надо организовывать после всей логики и всех проверок, все констрейны на уровне таблицы тоже должны быть дополнительно проверены, чтобы избежать неожиданного EXCEPTION.

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

#RealInterviewTasks #Oracle #PL/SQL
2👎1
period_transaction_index.sql
2.8 KB
Скрипт для проверки. Можно запустить в разных сессиях и посмотреть.
UPDATE 23.09.2025 Указанный скрипт неточный.
Исправленный скрипт в комментариях.
👋 Друзья, хочу сделать контент полезнее для вас. Подскажите, что вам интереснее всего читать в канале? 🧠 Формат, о котором идёт речь — короткие задачки, фичи, кейсы из реальных проектов. Проголосуйте ниже 👇 📊 Что тебе интереснее всего?
Anonymous Poll
20%
Простые задачи с собесов (Junior–Middle)
53%
Сложные задачи с реальных интервью (Senior+)
27%
Сферические кони в вакууме надоели - давай приёмы, грабли и фичи из реальной практики (бой и прод)
👎1
🎵 "Вы хотите песен? Их есть у меня."
— С. Шнуров

Сегодня — не песня, а задачка на размышление (из собеса с одной иностранной компанией). На первый взгляд — идентичные конструкции, но за ними скрыта важная разница.

Сравните два варианта:
a)
SELECT *
FROM table1 t1
WHERE (SELECT t2.column2
FROM table2 t2
WHERE t2.id = t1.id) = t1.column1;

b)
CREATE OR REPLACE FUNCTION f1(id NUMBER) RETURN VARCHAR2 IS
x table2.column2%TYPE;
BEGIN
SELECT t.column2
INTO x
FROM table2 t
WHERE t.id = f1.id;

RETURN x;
END f1;
/

SELECT *
FROM table1 t1
WHERE f1(t1.id) = t1.column1;

📌 Вопрос:
В чём концептуальная разница между этими двумя подходами?
Ясно, что написано криво, но это специально.

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

Обсудим в комментариях 👇
(а позже добавлю разбор)
#RealInterviewTasks #sql #Oracle #PostgreSQL #PL/SQL #PL/pgSQL
2👎1🤔1
"Пусть я переору любого соловья..."
— Шнур


Недавний случай из практики.

Java-разработчики обращаются к БД, как умеют — через IN (...) :

<select id="select" resultType="Long">
SELECT order_id
FROM table_1
WHERE order_id IN
<foreach item="orderId" collection="orderIds" separator="," open="(" close=")">
#{orderId}
</foreach>
</select>

На выходе в логах базы — десятки разных SQL-запросов:

SELECT order_id FROM table_1 WHERE order_id IN (:1)
SELECT order_id FROM table_1 WHERE order_id IN (:1, :2, :3)
...
SELECT order_id FROM table_1 WHERE order_id IN (:1, ..., :999)

Вроде всё работает. Но вот вопрос:

Корректно ли так обращаться к базе?
Если нет — почему, и как бы вы это исправили?

💬 Делитесь опытом и решениями — интересно, кто как решает такие "мелочи", которые под нагрузкой превращаются в проблему.

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

#Cases #sql #Oracle #PostgreSQL #PL/SQL #PL/pgSQL
👎1😱1
DB developers channel
🎵 "Вы хотите песен? Их есть у меня." — С. Шнуров Сегодня — не песня, а задачка на размышление (из собеса с одной иностранной компанией). На первый взгляд — идентичные конструкции, но за ними скрыта важная разница. Сравните два варианта: a) SELECT * FROM…
Разбор задачи: В чём разница между SQL-запросом и вызовом PL/SQL-функции?
(К задаче из предыдущего поста)

💡 На первый взгляд оба варианта делают одно и то же — сравнивают значение из table1 с соответствующим значением из table2. Но давайте разберёмся, в чём концептуальная разница между двумя подходами.

📌 Вариант A — скалярный подзапрос
SELECT *
FROM table1 t1
WHERE (SELECT t2.column2
FROM table2 t2
WHERE t2.id = t1.id) = t1.column1;

Что происходит:
Это обычный SQL-запрос с коррелированным подзапросом.
Для каждой строки t1 выполняется подзапрос к table2.
Оптимизатор БД может применить merge join, hash join, nested loops или даже вынести подзапрос в джойн — всё зависит от статистики, индексов и плана выполнения.

Плюсы:
Оптимизируемо.
Может быть трансформировано оптимизатором.
Прозрачно для анализа выполнения.

📌 Вариант B — вызов пользовательской функции
CREATE OR REPLACE FUNCTION f1(id NUMBER) RETURN VARCHAR2 IS
x table2.column2%TYPE;
BEGIN
SELECT t.column2
INTO x
FROM table2 t
WHERE t.id = f1.id;

RETURN x;
END f1;
/
SELECT *
FROM table1 t1
WHERE f1(t1.id) = t1.column1;

Что происходит:

На каждую строку table1 вызывается функция f1.
Внутри функции выполняется SQL-запрос к table2.

Ключевое отличие:

🔐Оптимизатор не может "заглянуть" внутрь PL/SQL-функции.
Запрос к table2 не участвует в планировании — он "чёрный ящик".
Это приводит к контекстным переключениям (SQL ⇄ PL/SQL), что негативно влияет на производительность.
Невозможно применить стандартные оптимизации (например, замену на JOIN).

🔐 Ещё одно ключевое отличие — влияние уровня изоляции
На практике результат запроса A и запроса B может отличаться, даже если они запущены одновременно в разных сессиях.

Почему?

📌 По умолчанию в Oracle используется уровень изоляции READ COMMITTED.
Это означает, что:

В варианте A (чистый SQL) вся выборка выполняется как единое целое — данные читаются в рамках одного "снимка" данных на момент начала запроса.

А вот во втором варианте с функцией — каждое обращение к table2 происходит внутри отдельного запроса, в момент вызова функции.

👉 Итог:
Функция будет видеть уже изменённые данные, если они модифицированы между строками основного SQL.
Даже если изменения происходят прямо в момент выполнения запроса — это легально на READ COMMITTED.

🔄 Пример:
Вы запускаете SELECT ... WHERE f1(t1.id) = t1.column1.

В это время другая сессия меняет table2.

Результат работы f1(...) будет отличаться для разных строк, в зависимости от того, когда именно выполнялся каждый вызов функции.

🛡 Как избежать этого?
Чтобы зафиксировать момент чтения — можно использовать уровень изоляции SERIALIZABLE.

Однако:

Это не гарантирует успех — Oracle выдаст ошибку (ORA-08177: can't serialize access for this transaction), если во время выполнения будут обнаружены конфликтующие изменения.

Даже если изменён блок, в котором хранятся нужные строки (даже если сами строки не изменились), Oracle вернет ошибку.

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

#RealInterviewTasks #sql #Oracle #PostgreSQL #PL/SQL #PL/pgSQL
👎1🔥1
DB developers channel
"Пусть я переору любого соловья..." — Шнур Недавний случай из практики. Java-разработчики обращаются к БД, как умеют — через IN (...) : <select id="select" resultType="Long"> SELECT order_id FROM table_1 WHERE order_id IN <foreach item="orderId"…
🛠 Разбор кейса: IN (...), 999 параметров и производительность

Продолжение истории про Java-разработчиков и их любимый IN (...).

На первый взгляд — всё логично: список orderIds, XML-мэппер MyBatis, всё красиво раскладывается в IN (:1, ..., :N).
Но в реальности — десятки SQL-запросов с разным количеством параметров. И каждый — новый hard parse
(hard parse - это режим, когда оптимизатор определяет план запроса. soft parse, когда оптимизатор берет готовый план из Кэша).

📉 Что это означает:

Нет повторного использования плана выполнения (cursor sharing не спасает).
Под нагрузкой — рост CPU и latch contention.
Объём shared pool растёт, plan cache фрагментируется.

Почему это не ок:
Oracle не объединяет запросы с разным числом параметров.
При высоком QPS — постоянная генерация новых кусков кода (library cache misses).
Особенно тяжело в RAC — загружаются interconnect и global cache.

Что с этим делать?
Передавай список ID через TABLE(...) или временную таблицу (если элементов коллекций более 10000):

SELECT order_id
FROM table_1
WHERE order_id IN (SELECT column_value FROM TABLE(:order_id_array))


👨‍💻 Ну и это ещё не всё.
Такие решения, как выше, часто используются вынужденно — особенно у full-stack и прикладных разработчиков, где БД рассматривается как «глупое хранилище».

Но если хотите, чтобы проект не развалился под нагрузкой — не обращайтесь к БД напрямую через таблицы и вьюхи.
Даже самые простые INSERT, UPDATE, DELETE, SELECT стоит заворачивать в API на стороне БД — процедуры, функции, пакеты.

Не хотите переносить бизнес-логику в БД — не надо.
Но обращайтесь через API, а не напрямую.

📉 Пока строк в таблице — тысячи, «как-то работает».
📉 На миллионах — начинает тормозить.
🔥 А на сотнях миллионов — всё гарантированно подвиснет, и не спасут никакие индексы, если запросов с клиентской стороны будет хаос.

📦 Зачем нужен API к базе:
Код становится читаемым, стабильным и управляемым

Пакеты и процедуры компилируются заранее → экономия CPU

Внутри можно скрыть служебную механику: логирование, модификацию тех.полей, аудит, статистику

Можно свободно переносить таблицы между схемами — интерфейс не меняется

Упрощается миграция на новые модели хранения

Можно централизованно обрабатывать ошибки, транзакции, валидации

И ещё с десяток других плюсов

🧩 Итог:
Решения «в лоб» — работают, пока не стало больно.

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

#Cases
👎1
😌 Суббота, шабат, всё спокойно — разбираем лёгкую задачку.
Просто один странный запрос.

💡 Найдите, что не так с этим SQL-запросом

📦 У нас есть две таблицы:

CREATE TABLE table1 (id NUMBER NOT NULL, name VARCHAR2(100));
CREATE TABLE table2 (id NUMBER NOT NULL, address VARCHAR2(100));

🧩 И такой PL/SQL-блок:

DECLARE
a NUMBER;
b VARCHAR2(10);
BEGIN
SELECT id, address
INTO a, b
FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.id = t2.id
WHERE t2.address LIKE '%India%'
GROUP BY t1.name, t2.address, t1.id
HAVING MIN(t1.id) = MAX(t2.id);
END;

🔍 Задача:
В этом коде есть несколько ошибок и странных решений — как логических, так и синтаксических.

Я насчитал 6 неточностей и ошибок. Может быть есть больше?

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

Что здесь не так?
Напишите в комментариях, что бы вы исправили или переписали.

👇 Разбор выложу позже.
#RealInterviewTasks #sql #Oracle #PostgreSQL #PL/SQL #PL/pgSQL
👍2👎1
🤔 Как вы сравниваете два значения в Oracle, если оба могут быть NULL?

Ситуация простая:
col1 = col2

Но оба поля могут быть NULL, и тогда сравнение возвращает FALSE.

Да, можно:
NVL(col1, 0) = NVL(col2, 0)
COALESCE(col1, -1) = COALESCE(col2, -1)
DECODE(col1, col2, 1, 0) = 1
col1 = col2 OR (col1 IS NULL AND col2 IS NULL)

Но все эти методы требуют "заглушек" или слишком громоздки.

🔍 А что используете вы в таких случаях? Есть ли у вас удобная и универсальная конструкция для сравнения "NULL-aware"?

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

#RealInterviewTasks #sql #Oracle #PL/SQL
👎1
DB developers channel
🤔 Как вы сравниваете два значения в Oracle, если оба могут быть NULL? Ситуация простая: col1 = col2 Но оба поля могут быть NULL, и тогда сравнение возвращает FALSE. Да, можно: NVL(col1, 0) = NVL(col2, 0) COALESCE(col1, -1) = COALESCE(col2, -1) DECODE(col1…
Все варианты валидны.
⚠️ (В случае если вы уверены, что значения заглушек в таблице нет
и никогда не будет).
Но предлагаю рассмотреть ещё одну системную функцию,
которую Oracle использует сам внутри.

Она заменяет NULL на специальное внутреннее значение, чтобы можно было безопасно сравнивать:

SYS_OP_MAP_NONNULL(col1) = SYS_OP_MAP_NONNULL(col2)

Таким образом NULL = NULL будет возвращать TRUE, но без искажения логики (в отличие от NVL(col, 0)).

⚠️ Функция не документирована, но активно используется в системных операциях. Работает для разных типов и не требует подстановки "заглушек".

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

#RealInterviewTasks #sql #Oracle #PL/SQL
🤩2👎1
💡 Случай из практики.

Представим, что в проекте есть таблица table_1 с большим числом полей — 50, а то и 100.
Прикладные системы присылают данные в виде XML или JSON. На первом этапе мы их парсим, а затем вызываем метод, который должен обновить или вставить запись в таблицу.

Но есть нюанс:
🔹 один приклад может менять только 3–4 поля,
🔹 другой — 20–30,
🔹 третий вообще только одно.

Как быть?
Передавать 100 параметров в метод?
Писать 10 версий под каждый приклад?
Или, может, есть способ обойтись одним универсальным механизмом, который будет обновлять только то, что реально пришло?

🧩 Как бы вы это реализовали?

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

Пишите свои подходы — обсудим в комментариях или в следующем посте 😉
#CodeArchitecture
👎1
Универсальный метод обновления: магия значений-заглушек
Привет, друзья! 👋

В прошлом посте мы говорили о сложной задаче:
в таблице с 50–100 полями каждый вызов обновляет разное количество данных. Сегодня расскажу, как с этим можно справиться с помощью одного хитрого приёма — значений-заглушек (sentinel values).

Это — простой и рабочий способ, но есть и свои подводные камни. 🚧

🔍 Как это работает?
1️⃣ Для каждого типа данных выбираем уникальное «магическое» значение, которого точно не будет в реальных данных:

Числа — 2147483647 (максимум для 32-битного int)

Даты — 01.01.0101 (ну кто такое хранит?)

Строки — символ CHR(0) (невидимый и неиспользуемый)

2️⃣ В процедуре обновления ставим эти значения по умолчанию.

3️⃣ Когда приходит запрос, обновляем только те поля, где значение отлично от заглушки. Остальные — оставляем как есть.

⚖️ Плюсы и минусы
✔️ Гибко: обновляем ровно то, что нужно
✔️ Универсально: один метод на все случаи
✔️ Без дублирования кода

Длинная сигнатура: 50–100 параметров — тяжело читать и писать
Риск коллизий: кто-то вдруг захочет использовать заглушку в данных
Неочевидно: новичку сложно понять логику по умолчанию

🚀 Есть идеи получше?
Обо всём этом — в следующем посте! 😉

🧩 А как вы бы сделали?
Пишите свои мысли и опыт в комментариях!
Будем разбираться вместе 🔥
#CodeArchitecture
1👎1
table_update_method.sql
4.9 KB
Скрипт для проверки
👎1
💡 Простой вопрос из собесов по SQL и индексам
(про план запросов, но с подвохом)

У нас есть таблица:

CREATE TABLE employees (
fio VARCHAR2(50) NOT NULL,
department_id NUMBER NOT NULL,
start_date DATE NOT NULL
);

CREATE INDEX employees_i01 ON employees (fio, department_id);

И вот такой запрос:

SELECT fio
FROM employees
WHERE fio = :f AND department_id = :dep_id;

На него отлично работает индекс employees_i01, ведь все условия входят в ключ.

Теперь добавим новый фильтр:

SELECT fio
FROM employees
WHERE fio = :f AND department_id = :dep_id AND start_date >= :d;

Как изменится производительность запроса?
1️⃣ Станет быстрее
2️⃣ Станет медленнее
3️⃣ Ничего не изменится

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

🤔 А как думаете вы?
📥 Пишите свои варианты и размышления в комментарии — обсудим!
#RealInterviewTasks
👎1