SQL Academy: всё о реляционных БД и SQL
10.7K subscribers
154 photos
1 video
2 files
29 links
По всем вопросам и коммерческим предложениям писать @LadanovNick

Купить рекламу: https://telega.in/c/sqlacademyofficial

Чат студентов SQL Academy
https://t.me/sqlacademyorg
Download Telegram
ELT() и FIELD() — превращаем числовой код в текст без JOIN 🏷️

Зачем нужно
Частый кейс: в таблице хранится числовой статус (1 = “pending”, 2 = “done”, 3 = “failed”).
Обычно делают JOIN с маленьким справочником, но MySQL умеет отдать текст прямо в SELECT — скомпилируем «карманный словарь» функциями FIELD() + ELT().

1️⃣ FIELD(needle, list…) — возвращает позицию элемента

SELECT FIELD(3, 1,2,3,4);
-- Результат: 3
SELECT FIELD('b', 'a','b','c');
-- Результат: 2


2️⃣ ELT(index, list…) — берёт элемент по номеру

SELECT ELT(3, 'pending','done','failed','unknown');
-- Результат: 'failed'


💡 Объединяем: число → позиция → текст

SELECT
order_id,
status_code,
ELT(
FIELD(status_code, 1,2,3,4),
'pending','in_progress','done','failed'
) AS status_text
FROM orders;

🔹 FIELD находит позицию status_code в списке кодов,
🔹 ELT вытаскивает строку из второго списка той же длины.

3️⃣ Удобный вариант через CASE?
Да, но ELT/FIELD короче, особенно для 5-10 значений.

-- аналог на CASE (длиннее)
CASE status_code
WHEN 1 THEN 'pending'
WHEN 2 THEN 'in_progress'
WHEN 3 THEN 'done'
WHEN 4 THEN 'failed'
ELSE 'unknown'
END


4️⃣ Подводные камни ⚠️
🔹 Если FIELD вернёт 0 (код не найден) — ELT() даст NULL.
🔹Порядок важен: списки в FIELD и ELT должны совпадать по длине и позиции.

Итог
🔹FIELD() находит позицию кода, ELT() возвращает строку по этой позиции.
🔹Для 3-5 статусов — самый быстрый способ «раскрасить» отчёт без JOIN и CASE.
🔥228👍4🥰1🙏1
🎉 PostgreSQL теперь с нами! 🐘🎉

Мы расширили движок курса — добавили полную поддержку PostgreSQL.
Теперь все уроки, задачи и автотесты работают как на MySQL, так и на PostgreSQL. Выбирайте любимый диалект — знание SQL теперь прокачивается вдвойне! 🚀

Что нового:
1️⃣ Двойной режим — переключайтесь между MySQL PostgreSQL в один клик.
2️⃣ Все практические задачи проверяются в обоих СУБД, а значит больше гибкости и реальной пользы.
3️⃣ Обновлённые подсказки и примеры с учётом синтаксиса Postgres.

💡 Базовый контент и задания по-прежнему бесплатны.

Спасибо, что растёте вместе с SQL Academy. Теперь на MySQL и PostgreSQL! 💙
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥123👍3320
UUID() и UUID_SHORT() — генерируем уникальный ID без сервера приложений 🎲

Зачем знать
🔹Иногда нужно создать уникальный первичный ключ на стороне БД, а не приложения.

1️⃣ UUID() — стандартный 128-битный идентификатор

SELECT UUID();
-- '550e8400-e29b-41d4-a716-446655440000'

🔹36 символов (32 шестн. + 4 дефисa).
🔹Практически нулевая вероятность коллизии.
🔹Минусы: длинная строка → индекс ~4× крупнее, хуже кэшируется.

2️⃣ UUID_SHORT() — компактный 64-битный вариант

SELECT UUID_SHORT();
-- 281474976710661

🔹Возвращает BIGINT UNSIGNED (до 18 цифр).
🔹Формируется как: (server_id << 48) + (unix_ts << 24) + increment.
🔹Удобен для числовых PK 👉 индекс меньше, быстрее сортировка.
🔹Риск коллизии есть при одинаковом server_id (на реплике проверьте server_id!).

3️⃣ Практический пример: таблица заказов

CREATE TABLE orders (
id CHAR(36) DEFAULT (UUID()) PRIMARY KEY,
user_id INT,
total DECIMAL(10,2)
);


Итог
🔹UUID() — гарантированная уникальность, но тяжёлый индекс.
🔹UUID_SHORT() — компактный числовой ID, если контролируете server_id.
🔹Оба способа позволяют генерировать ключ прямо в MySQL без внешнего сервиса или кода приложения.
20👍5
Задача из собеседования (Cian, middle): считаем, сколько раз издавалось произведение 📚

Схема:
🔹Books(id, title) — произведение
🔹BookEditions(id, book_id, publish_year, pages) — издание произведения
🔹BookCopies(id, edition_id, inventory_num) — экземпляр издания

🎯 Формулировка
Найти произведения, которые издавались более 5 раз. Вывести только название произведения (title).

🧪 Сначала решите сами!
Откройте задачу и попробуйте написать запрос без подсказок:
👉 https://sql-academy.org/ru/trainer/tasks/125

Разбор ——
Как подойти шаг за шагом:
1️⃣ Что нужно посчитать?
Количество изданий на каждое произведение → считаем строки в BookEditions по book_id.

2️⃣ Где лежит название?
В Books. Значит, к агрегату нужно присоединить Books по Books.id = BookEditions.book_id.

3️⃣ По чему группировать?
По уникальному идентификатору книги (и для вывода — по названию): GROUP BY b.id, b.title.

4️⃣ Как отфильтровать только те, у кого >5 изданий?
Через HAVING, потому что фильтруем по агрегату (COUNT).

Правильный ответ

SELECT b.title
FROM BookEditions e
JOIN Books b ON b.id = e.book_id
GROUP BY b.id, b.title
HAVING COUNT(e.id) > 5;


На что обратить внимание ❗️
🔹Группируем по b.id, b.title, а не только по b.title: два разных произведения могут теоретически иметь одинаковое название; по id безопаснее.

А если в условии скрыт нюанс «издавалось в разные годы»?
Иногда собеседующий подразумевает уникальные годы издания. Тогда используйте COUNT(DISTINCT e.publish_year)

SELECT b.title
FROM BookEditions e
JOIN Books b ON b.id = e.book_id
GROUP BY b.id, b.title
HAVING COUNT(DISTINCT e.publish_year) > 5;
Please open Telegram to view this post
VIEW IN TELEGRAM
👍36🔥109👏2👌1
🌟 Считаем возраст человека правильно 🌟

Вы когда-нибудь задумывались, как правильно вычислить возраст человека в SQL? 🤔 Может показаться, что всё просто: возьмём текущий год, отнимем год рождения, и вуаля! Но ой, подстерегает соблазн ошибки! 😈

🚫 Неправильный подход:

SELECT YEAR(NOW()) - YEAR('2003-07-03 14:10:26');

Проблема такого подхода в том, что он не учитывает был ли день рождения у данного человека в этом году или ещё нет. То есть, если на момент запроса уже наступило 3-е июля (07-03), то человек отпраздновал свой день рождения и ему уже 21 лет, иначе ему по-прежнему 20 года. Разница функций YEAR тут будет бесполезна — в обоих случаях она даст 21 лет.

🤔 Что же делать? Мы могли бы пойти по пути вычисления разницы в днях и деления на 365:

SELECT FLOOR(DATEDIFF(NOW(), '2003-07-03 14:10:26') / 365);

Это лучше, но всё же не совсем точно из-за наличия високосных годов. 📆

Правильный подход с TIMESTAMPDIFF:

TIMESTAMPDIFF(YEAR, '2003-07-03 14:10:26', NOW());

Используя функцию TIMESTAMPDIFF, мы получаем точную разницу в годах между двумя датами, учитывая все нюансы календаря! 🎯

Так что, когда дело доходит до вычисления возраста, доверяйте TIMESTAMPDIFF — и ваши расчёты будут точны как никогда! 🚀💡
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥47👍179👏1
Деньги в MySQL: DECIMAL против FLOAT 💸

❗️Почему это важно
В финансах «копейка рубль бережёт»: ошибка 0.01 в одной транзакции, умноженная на тысячи строк, ломает отчёты и бухгалтерию.
Главный выбор — где хранить деньги: в DECIMAL или FLOAT?

1️⃣ Короткий ответ
🔹 Для сумм, цен, налогов — используйте DECIMAL(precision, scale).
🔹FLOAT/DOUBLE — приблизительные числа (двойичные), для денег не подходят.

2️⃣ Что такое DECIMAL и FLOAT?
🔹 DECIMAL(p, s) — точные десятичные числа.
Хранит каждую цифру (до 65 знаков, обычно s=2 или 4).
🔹 FLOAT/DOUBLE — числа с плавающей запятой в двоичной форме (IEEE 754).
Быстрые, но дают «хвосты» 0.1000000000001.

Пример проблемы с FLOAT:

CREATE TEMPORARY TABLE t_f (a FLOAT, b FLOAT);

INSERT INTO t_f VALUES (0.1, 0.2);
SELECT a + b AS sum_val FROM t_f;
-- sum_val может быть 0.3000000119...


Так же, но с DECIMAL:

CREATE TEMPORARY TABLE t_d (a DECIMAL(10,2), b DECIMAL(10,2));

INSERT INTO t_d VALUES (0.10, 0.20);
SELECT a + b AS sum_val FROM t_d;
-- sum_val = 0.30


3️⃣ Как выбрать размер DECIMAL
Типовой набор:
🔹DECIMAL(19,4) — для сумм и цен (4 знака после запятой хватает для НДС/комиссий).
🔹DECIMAL(10,2) — для розничных цен в «валютах с 2 знаками».

4️⃣ Альтернатива: хранить в «копейках»
Иногда суммы хранят как INT в минимальных единицах (центы/копейки).
Плюсы: быстрые индексы, чёткие сравнения.
Минусы: нужна дисциплина преобразований (делить/умножать на 100), разные валюты ≠ одинаковая точность.

5️⃣ Мини-резюме
🔹 Для денег — только DECIMAL (или INT в минимальных единицах).
🔹 Выберите подходящую точность (часто DECIMAL(19,4)).
🔹 Не складывайте «яблоки и апельсины»: валюты и точности должны быть явными.
1024👍10🔥6
Полезная шпаргалка по основам SQL 🧐
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6714🔥14
Бэкап vs снапшот vs реплика — простое объяснение

Зачем это знать?
В реальной работе регулярно случается одно из трёх: сервер падает, кто-то удаляет данные, выходит неудачное обновление.
Спасают три разных инструмента — бэкап, снапшот и реплика. Они дополняют, а не заменяют друг друга.

Три понятия «на пальцах»
💾 Бэкап (backup)
Это отдельная копия данных, из которой можно развернуть базу заново — даже на другом сервере, через день/неделю.

📸 Снапшот (snapshot)
Это «моментальный снимок» диска/тома в текущем состоянии (LVM/ZFS/EBS и т.п.).
🔹Создаётся быстро, удобно откатиться перед апдейтом.
🔹Хранится на том же хранилище → если диск/массив сломается, снимок пропадёт вместе с ним.

🪞 Реплика (replication)
Это вторая копия базы, которая почти в реальном времени «повторяет» изменения с основной.
🔹Нужна для отказоустойчивости и масштабирования чтения.
🔹Если на мастер попала ошибка/удаление, она уйдёт и на реплику.

Что решает каждый инструмент
Бэкап → «машина времени»
🔹Восстановить состояние за конкретный день/время.
🔹Долгое хранение (архив), юридические требования.

Снапшот → «быстрый откат»
🔹Перед деплоем/миграцией: если что-то пошло не так — откат за минуты.
🔹Клонирование окружения для тестов.

Реплика → «всегда доступно»
🔹Быстро переключиться при падении мастера (failover).
🔹Разгрузить чтение (направить часть трафика на реплику).

Риски и подводные камни ⚠️
Бэкап
🔹«Бэкап есть» не значит «восстановится» — обязательны регулярные тесты восстановления.
🔹Нельзя хранить единственную копию рядом с базой; нужна отдельная площадка и шифрование.

Снапшот
🔹Хранится на том же хранилище → общая точка отказа.

Реплика
🔹Может отставать (лаг) — отчёты «сейчас» иногда смотрят на прошлое.

Практические рекомендации
Минимум для проекта
1️⃣ Ежедневный бэкап (полный или инкрементальный) → хранить вне сервера + шифровать.
2️⃣ Раз в неделю — проверка восстановления на тестовом стенде (restore-drill).
3️⃣ Перед любым рискованным обновлением — снапшот тома.
👍237👌4👏2
Триггеры в MySQL 🚀

Триггеры в MySQL — это специальные процедуры, которые автоматически выполняются в ответ на определённые события внутри таблиц базы данных. Они срабатывают при выполнении операций вставки (INSERT), обновления (UPDATE) или удаления (DELETE) данных.

Для чего нужны триггеры 🔍
Триггеры используются для автоматизации выполнения задач в базе данных, что помогает обеспечить целостность данных. Например, они могут автоматически обновлять или проверять данные при изменении таблицы, запускать расчёты или создавать журнал изменений (логирование операций).

Создание триггера 🆕
Создать триггер можно с помощью команды CREATE TRIGGER. Например, триггер, который будет автоматически устанавливать текущую дату и время в поле last_updated при обновлении строки в таблице users:


CREATE TRIGGER before_user_update
BEFORE UPDATE ON users
FOR EACH ROW
SET NEW.last_updated = NOW();


Удаление триггера
Удалить триггер можно с помощью команды DROP TRIGGER. Например:

DROP TRIGGER before_user_update;

Полезный пример использования ℹ️
Предположим, в базе данных есть таблица orders с полями id, total и updated_at. Можно создать триггер, который будет обновлять updated_at каждый раз, когда меняется сумма заказа (total):


CREATE TRIGGER update_order_timestamp
BEFORE UPDATE ON orders
FOR EACH ROW
WHEN (OLD.total <> NEW.total)
BEGIN
SET NEW.updated_at = CURRENT_TIMESTAMP;
END;

Этот триггер помогает отслеживать момент последнего изменения суммы заказа, что может быть полезно для аудита изменений или для обновления связанных систем, например, систем бухгалтерского учета.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍258🔥8
Мини-квиз по дате и времени в MySQL

1️⃣ Вопрос 1: Что вернёт запрос?

SELECT DATE_FORMAT(
STR_TO_DATE('16-08-2024 21:15', '%d-%m-%Y %H:%i'),
'%Y/%m/%d %H:%i'
);


a) 2024/16/08 21:15
b) 16/08/2024 21:15
c) 2024/08/16 21:15
d) Ошибка парсинга

Правильный ответ: c) 2024/08/16 21:15

2️⃣ Вопрос 2: Какой результат вернёт функция LAST_DAY?

SELECT LAST_DAY('2024-02-10');


a) 2024-02-28
b) 2024-02-29
c) 2024-03-01
d) NULL

Правильный ответ: b) 2024-02-29

3️⃣ Вопрос 3: Чему равна разница в минутах?

SELECT TIMESTAMPDIFF(
MINUTE,
'2024-08-16 08:30:00',
'2024-08-16 10:05:00'
);


a) 90
b) 95
c) 120
d) 155

Правильный ответ: b) 95

4️⃣ Вопрос 4: Что произойдёт при добавлении интервала, если пересекается полночь?

SELECT TIMESTAMP('2024-08-16', '23:00:00') + INTERVAL 2 HOUR;


a) 2024-08-16 25:00:00
b) 2024-08-17 00:00:00
c) 2024-08-17 01:00:00
d) 2024-08-16 23:02:00

Правильный ответ: c) 2024-08-17 01:00:00
🔥3411👍11
Мини-квиз

1️⃣ Вопрос 1: Что гарантирует LEFT JOIN?

SELECT c.id, o.id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;


a) Вернутся только клиенты с заказами
b) Вернутся все заказы, даже без клиентов
c) Вернутся все клиенты, даже если у них нет заказов
d) Дубликаты строк будут удалены

Правильный ответ: c) Вернутся все клиенты, даже если у них нет заказов

2️⃣ Вопрос 2: Что фильтрует группы после агрегирования?

SELECT department, COUNT(*) AS cnt
FROM employees
GROUP BY department
-- ?


a) WHERE cnt > 5
b) HAVING cnt > 5
c) ORDER BY cnt > 5
d) WINDOW cnt > 5

Правильный ответ: b) HAVING cnt > 5

3️⃣ Вопрос 3: Какой запрос лучше всего использует составной индекс (department, salary)?
a) WHERE salary > 1000
b) WHERE department = 'IT' AND salary > 1000
c) WHERE department LIKE '%IT%'
d) ORDER BY salary

Правильный ответ: b) WHERE department = 'IT' AND salary > 1000
👍29🔥107👌3
Триггеры в PostgreSQL ⚡️

Зачем они нужны?
Триггеры помогают базе сама выполнять рутину: обновлять метки времени, писать журнал изменений, проверять данные. Это экономит код в приложении и снижает ошибки.

Что такое триггер
Триггер — это правило «когда случится X, сделай Y».
🔹 Время: BEFORE (до операции) или AFTER (после).
🔹Событие: INSERT / UPDATE / DELETE.
🔹Уровень:
— FOR EACH ROW — для каждой затронутой строки;
— FOR EACH STATEMENT — один раз на весь запрос.
Важно: в PostgreSQL триггер всегда вызывает функцию (обычно на PL/pgSQL).

Мини-пример: авто-обновление `updated_at` при любом UPDATE

-- 1) Добавим столбец с текущим временем по умолчанию
ALTER TABLE users
ADD COLUMN updated_at timestamptz NOT NULL DEFAULT now();

-- 2) Функция, которую будет вызывать триггер
CREATE OR REPLACE FUNCTION trg_set_updated_at() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
-- записываем текущее время
NEW.updated_at := now();
-- возвращаем изменённую строку
RETURN NEW;
END$$;

-- 3) Сам триггер: срабатывает перед UPDATE каждой строки
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION trg_set_updated_at();


Полезно знать 🧠
🔹Временно отключить/включить:
ALTER TABLE users DISABLE TRIGGER set_updated_at;
ALTER TABLE users ENABLE TRIGGER set_updated_at;
🔹Удалить триггер:
DROP TRIGGER set_updated_at ON users;
🔹Если несколько триггеров одного типа — они срабатывают по алфавиту имён.
Давайте им понятные префиксы (t10_…, t20_…).

Где новички чаще всего ошибаются ⚠️
1️⃣ «Скрытая магия»: непонятно, что меняет данные.
Решение — документируйте триггеры и давайте им говорящие имена.
2️⃣ Массовые операции: FOR EACH ROW на миллионах строк может замедлить UPDATE. Если возможно — переносите часть логики в периодические задачи или используйте FOR EACH STATEMENT.
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍5👌4🗿2👏1
мы постоянно улучшаем наш сервис и нам важно ваше мнение 🙌
заполните, пожалуйста, короткую форму — это займет пару минут:
https://docs.google.com/forms/d/e/1FAIpQLSd5kdm4NfgquCKWptO83R9qmyuIZAyk1fSzK4v3fiTIp7D84w/viewform

🎁 бонус: премиум на нашей платформе получат 2 автора самых интересных предложений.
📌 в поле «ваши контактные данные» укажите ваш @username в Telegram.
🗓 сбор обратной связи — до 27 числа.

спасибо! 💛
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥7👍1
Blob в mysql или ссылки на файлы — как выбрать? 🗂️
Задача: нужно хранить файлы (фото, pdf, видео). Где их держать: прямо в базе (BLOB) или во внешнем хранилище (например, S3) и в БД — только ссылку? Разберёмся коротко и понятно.

Что такое blob и «ссылки»
🔹 BLOB — двоичные данные прямо в таблице MySQL (поле BLOB/LONGBLOB).
🔹 Ссылка — файл лежит во внешнем хранилище, а в БД мы храним URL + метаданные (имя, размер, тип).

Когда хранить в базе (blob) 📦
Подходит, если:
🔹файлы небольшие (аватарки, превью, ≤ ~1 МБ);
🔹важна атомарность: данные и файл сохраняются/откатываются вместе;
🔹проект простой, без CDN и стриминга.

Плюсы: просто, транзакционно, один бэкап.
Минусы: база быстро растёт, бэкапы тяжелее, отдавать большие файлы медленно.

Мини-пример

CREATE TABLE file_blobs (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
mime VARCHAR(100),
size INT,
-- для дедупликации
sha256 BINARY(32),
-- сам файл
data LONGBLOB NOT NULL,
created_at TIMESTAMP,
UNIQUE KEY (sha256)
);


Когда хранить снаружи (ссылки) 🔗
Подходит, если:
🔹файлов много или они крупные (фото/видео/доки);
🔹нужна раздача через CDN (быстрая доставка);
🔹важны дешёвое хранилище и лёгкие бэкапы БД.

Плюсы: масштабируемо, дёшево, быстро отдаётся.
Минусы: две системы (БД + хранилище).

Мини-пример

CREATE TABLE files (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
mime VARCHAR(100),
size INT,
sha256 BINARY(32),
-- https://... или s3://...
storage_url VARCHAR(2048) NOT NULL,
created_at TIMESTAMP,
UNIQUE KEY (sha256)
);


Быстрый чек-лист выбора
🔹Размер: маленькие → BLOB; большие → ссылка.
🔹Транзакционность (вместе с бизнес-данными): нужна → BLOB.
🔹 Отдача файлов пользователям: нужен CDN → ссылка.
🔹Бэкапы и восстановление: хочется лёгких дампов → ссылка.
🔹Стоимость хранения: экономим → ссылка.

Вывод
🔹BLOB хорош для маленьких файлов и строгой консистентности.
🔹Ссылки — почти всегда лучший выбор для больших объёмов, скорости и экономии.
16👍6🔥4
SQL-Academy-Interview-Questions-ru.pdf
1.2 MB
Топ-вопросы с собеседований по SQL + ответы 📝
Мы собрали самые популярные вопросы и варианты ответов — читайте по ссылке:
https://sql-academy.org/ru/interview-questions

Чтобы было удобнее, подготовили офлайн-версию (PDF). Сохраните и используйте, чтобы быстро освежить знания перед важным собесом.
📥 офлайн-версия — в файле к этому посту

удачи на собеседованиях! 💪
🔥44👍157😎5🙏2😢1
Мини-квиз по дате и времени в PostgreSQL

1️⃣ Вопрос 1: Парсинг даты одной функцией

SELECT to_date('16-08-2024', 'DD-MM-YYYY');

a) 16/08/2024
b) 2024-16-08
c) 2024-08-16
d) Ошибка парсинга

Правильный ответ: c) 2024-08-16

2️⃣ Вопрос 2: Разница в днях

SELECT DATE '2024-03-15' - DATE '2024-03-01';

a) 13
b) 14
c) 15
d) 16

Правильный ответ: b) 14

3️⃣ Вопрос 3: Номер недели (ISO) для актуальной даты

SELECT EXTRACT(WEEK FROM DATE '2026-01-01');

a) 0
b) 1
c) 52
d) 53

Правильный ответ: b) 1

4️⃣ Вопрос 4: Переход через полночь

SELECT TIMESTAMP '2024-08-16 23:00:00' + INTERVAL '2 hours';

a) 2024-08-16 25:00:00
b) 2024-08-17 00:00:00
c) 2024-08-17 01:00:00
d) 2024-08-16 23:02:00

Правильный ответ: c) 2024-08-17 01:00:00
🔥3212👍9👨‍💻7
Всем привет! На канале Data analysis | Анализ данных | DA разбираются темы и вопросы, которые должен знать аналитик данных, имеющий опыт 3-6 лет. Все темы взяты из реальных вакансий, опубликованных на hh.ru.

Будет полезно, если вы являетесь аналитиком данных (начинающим или опытным) или работаете по смежной профессии, либо просто интересуетесь базами данных, Python, SQL, экономикой и финансами и всеми производными от этих тем.

Список разобранных вопросов:

🐍 Python:
Эмбеддинги предложений
Алгоритм кластеризации
Кластеризация текстовой информации
Визуализация: Matplotlib
Визуализация: Seaborn
Python в Tableau
Python + SQL: Cx_oracle
Большие данные в Python: Dask
Массовая загрузка файлов в БД
Продвинутая запись в Excel: XlsxWriter
Аномалии в данных
Аномалии в данных: применение скользящих средних
Автоматизация подбора чисел
Анализ динамики


📖 SQL:
PARTITION (оконные функции)
PARTITION (партиционирование)
Процедуры: разбор IN | OUT | IN OUT
Процедуры: объявления и исключения
PACKAGE (пакеты)
Циклы LOOP, WHILE, FOR
CURSOR
Индексы
Представления (Views)
Материализованные и нематериализованные views
Hints (хинты)
EXPLAIN PLAN
TRIGGER (триггеры)


📖 Базы данных:
Какие бывают базы данных
Виды БД наглядно
ACID и BASE
OLAP-кубы
Проектирование баз данных
Разница между БД и DWH
Витрины данных
ETL и ELT процессы
Звездочка, снежинка, Data Vault
Слои данных в DWH
Нормализация


⚙️ Инструменты:
Обзор Hadoop
Обзор Hive
Обзор Impala
Обзор Airflow
Обзор ClickHouse
Tableau
Arenadata Catalog
Qlik Sense
Informatica PowerCenter


🐞 А/Б тестирование:
Основы А/Б тестов
А/Б тесты на практике
Математические методы проверки результатов
Инструменты А/Б тестирования


📊 Работа с данными:
Парадокс Симпсона
Банковские клиенты
Клиентская информация в банковском DWH
Банковские продукты
Продуктовая информация в банковском DWH
Счета, баланс и фин рез в банковском DWH
Качество данных
Метаданные
Source-to-Target Mapping


В ближайшем будущем будем разбирать 👇
— Больше про SQL и базы данных: архитектуру и т.п.
— Больше питоновских библиотек и кейсов
— Про банковские данные
— Актуальные инструменты, в частности BI-инструменты и ETL-инструменты
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥85👍2
Soft Delete, Hard Delete или Архив? Как правильно удалять данные 🗑️

Задача: Пользователь нажал «Удалить аккаунт». Что делать базе? Стереть навсегда? Скрыть? Или перенести в чулан? Разбираем три стратегии.

1️⃣ Hard Delete (Физическое удаление) 🧨
Классический DELETE. Данные исчезают, место освобождается.

Плюсы:
🔹 Максимальная скорость работы базы (таблицы компактные).
🔹 Соблюдение GDPR (право на забвение).
🔹 Нет проблем с уникальностью (email можно использовать повторно сразу).

Минусы: Данные не восстановить без бэкапа. Опасность «битых ссылок», если забыли настроить каскадное удаление (Foreign Keys).

2️⃣ Soft Delete (Мягкое удаление) 👻
Мы не удаляем строку, а ставим метку deleted_at = NOW(). Данные лежат на месте, но приложение делает вид, что их нет.

Плюсы:
🔹 Легко восстановить («Ой, я случайно!»).
🔹 Сохраняется история и связи.

Минусы:
🔸 Раздувание таблицы: База хранит тонны «мертвых» данных, индексы тормозят.
🔸 Сложность запросов: Везде нужно писать WHERE deleted_at IS NULL.
🔸 Проблема уникальности: Если bob@site.com удален «мягко», создать нового Боба с тем же email не даст уникальный индекс (нужен частичный индекс).

3️⃣ Archiving (Архивирование / Cold Storage) 📦
Гибридный подход. Данные удаляются из основной («горячей») таблицы, но перед этим переносятся в отдельную таблицу-архив (users_archive).

Как это работает:
🔹Стартуем транзакцию.
🔹INSERT данные в таблицу архива.
🔹DELETE данные из основной таблицы.
🔹Коммит.

Плюсы:
Основная таблица летает (в ней только активные данные).
История сохранена (в архиве).
Нет проблем с уникальными индексами в основной таблице.

Элегантный перенос одной командой (PostgreSQL) :

WITH moved_rows AS (
DELETE FROM users
WHERE id = 101
RETURNING *
)
INSERT INTO users_archive
SELECT * FROM moved_rows;
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥28👍94👎1👌1🆒1
SQL & AI: Друзья или враги?
Еще пару лет назад мы обсуждали, заменит ли нейросеть разработчика. В 2026 году ответ стал очевиден: AI не заменил SQL-специалиста, но он радикально изменил правила игры.
Сегодня разбираемся, как превратить AI в мощного союзника и где расставлены ловушки, в которые попадают даже мидлы.

🤝 Почему AI - ваш лучший друг
🔹Прощай, шаблонный код
Написать 10 однотипных JOIN или сложную структуру CASE WHEN нейросеть может за секунды. Это экономит до 40% времени на рутине.

🔹Объяснение чужого кода
Получили в наследство legacy-запрос на 200 строк без единого комментария? AI отлично справляется с декомпозицией и объяснением логики «человеческим» языком.

🔹Генерация синтетических данных
Нужно быстро наполнить таблицу для тестов, соблюдая типы данных и связи? AI сделает это лучше любого скрипта-заполнителя.

⚠️ Почему AI - коварный враг
Главная проблема в том, что AI галлюцинирует уверенно.

🔹Каша из диалектов

Модель может предложить изящное решение на функциях PostgreSQL (например, DISTINCT ON), которые просто не существуют или работают иначе в вашей версии MySQL или ClickHouse.

🔹Производительность — не приоритет по умолчанию
Если не попросить специально оптимизировать запрос, AI выдаст код, который просто «работает». Он часто предлагает вложенные подзапросы там, где эффективнее CTE или оконные функции, и редко думает об использовании индексов.

🔹Отсутствие контекста БД
Нейросеть не знает объема ваших данных, наличия индексов и специфики «железа». Запрос, который AI посчитал идеальным, может «положить» ваш прод в пиковую нагрузку.

💡 Как выжить в эпоху AI-SQL?
Чтобы оставаться востребованным профи, фокус должен сместиться с «написания кода» на его аудит и архитектуру.

🔹Валидация — это закон
Никогда не копируйте код из чата в консоль без проверки EXPLAIN ANALYZE.

🔹AI как ревьюер
Попробуйте обратный подход — скормите нейросети свой рабочий запрос и спросите: «Как это оптимизировать?». Иногда она подсвечивает неочевидные узкие места.

🔹Изучайте теорию глубже
Чем лучше вы понимаете работу планировщика запросов и индексов, тем проще вам будет увидеть «галлюцинацию» в ответе нейросети.

AI - это не замена мозга, а мощный инструмент. Он делает вас быстрее, но очень важно валидировать самостоятельно любой ее ответ.
25👍23🔥8💯1
🚀 Вопросы с собеседования на позицию intern аналитика в Тинькофф: разбор SQL 🚀

Сегодня мы разберем некоторые интересные вопросы по SQL, которые могут встретиться на собеседовании в Тинькофф. 📊🔍

1️⃣ Может ли измениться результат запроса, если в LEFT JOIN поменять местами таблицы ?

Да, если поменять местами таблицы в LEFT JOIN, результат запроса кардинально изменится. Все потому, что LEFT JOIN берет все строки из "левой" таблицы, дополняя их данными из "правой". Смена местами меняет логику: теперь "правая" становится "левой" и наоборот. Это влияет на то, какие строки и как будут включены в результат. 🔄

2️⃣ 5 + NULL это сколько?

В SQL, когда вы выполняете арифметическую операцию с NULL, результатом всегда будет NULL. Это связано с тем, что NULL представляет собой неопределенное значение, и любая операция с неопределенным значением также является неопределенной. Таким образом, 5 + NULL будет равно NULL.

3️⃣ Какие функции умеют возвращать значения из предыдущих/последующих строк для заданной строки таблицы ?

В SQL, чтобы работать с данными из строк до и после текущей, используются оконные функции. Эти функции обеспечивают доступ к значениям предыдущих/последующих строк:

ℹ️LEAD(): Получает данные из строки после текущей, позволяя смотреть вперед на заданное количество строк.

ℹ️ LAG(): Доступ к данным из строки перед текущей, предоставляя возможность анализировать предыдущие значения.

ℹ️ FIRST_VALUE() и LAST_VALUE(): Возвращают первое и последнее значение в наборе строк соответственно, идеально для сравнения текущих значений с крайними в диапазоне.

ℹ️ NTH_VALUE(): Дает значение из конкретной позиции в окне, полезно для нахождения конкретных точек данных в последовательности.

Для тех, кто хочет углубиться в тему оконных функций:
https://sql-academy.org/ru/guide/windows-functions

#задание_из_собеседования #tinkoff #intern #analytic
Please open Telegram to view this post
VIEW IN TELEGRAM
49👍23🔥12
Views vs Materialized Views: в чем разница?
Когда вы только начинаете работать с SQL, вам быстро надоедает писать один и тот же запрос на 20 строк с кучей джоинов. Чтобы не копипастить код, его можно сохранить прямо в базе. Для этого есть два способа: обычные Views (вьюхи) и материализованные.

Что такое View?
Это просто запрос, которому дали имя. База не создает новую таблицу и не копирует данные. Она просто запоминает ваш SELECT.
Когда вы пишете SELECT * FROM my_view, база «под капотом» подставляет ваш исходный код и выполняет его заново.

Представьте, что вам постоянно нужно видеть комнаты вместе с именами владельцев. Чтобы не джойнить таблицы каждый раз руками, делаем так:
CREATE VIEW room_owners AS
SELECT r.id, r.home_type, u.name as owner_name
FROM Rooms r
JOIN Users u ON r.owner_id = u.id;

Теперь можно просто писать SELECT * FROM room_owners. База будет каждый раз пересчитывать джойн.
Плюс в том, что данные всегда актуальные.
Минус: если в таблицах миллионы строк, такая View начнет подтормаживать.

Что такое Materialized View
Здесь база выполняет запрос один раз и сохраняет результат в отдельную скрытую таблицу. Это спасение для тяжелых расчетов. Например, если мы хотим посчитать общую выручку по каждой комнате за всё время:
CREATE MATERIALIZED VIEW room_stats AS
SELECT room_id, SUM(total) as total_earned
FROM Reservations
GROUP BY room_id;

Результат читается мгновенно, потому что сумма уже посчитана и лежит на диске. Но есть нюанс: данные в ней «застывают». Если пришла новая бронь, сумма не изменится, пока вы не обновите View командой:
REFRESH MATERIALIZED VIEW room_stats;


Что выбрать?
Все зависит от того, что вам важнее: скорость или актуальность. Если данные нужны «прямо сейчас» — делайте обычную View. Если вы строите отчет за прошлый месяц, который не меняется каждую секунду — Materialized View сэкономит кучу ресурсов.
28👍17🔥4👎1