SQL: Реляционные базы данных – Telegram
SQL: Реляционные базы данных
1.02K subscribers
85 photos
1 video
56 links
Канал айтишника о реляционных базах данных, SQL и модели данных. У нас тут много, очень много практических разборов))

Меня зовут Владимир Лунев (@lejnlune). Интересуюсь архитектурой систем и моделей данных.
Download Telegram
Forwarded from БАШНЯ
HARD SKILLS❗️

Продолжаем разбирать hard skills 🔥

Сегодня поговорим про SQL - что это такое и что спрашивают по нему на собеседованиях 👨‍💻

Делитесь этим постом с друзьями и пишите свои вопросы в комментарии ✍️

Автор поста:
Владимир Лунев, ментор в Башне

#hardskills
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👾6💯4
Сегодня столкнулся с гениальным описанием ошибки от СУБД.

Ок, понял 🗿
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣25🗿11🌚3
👩‍💻 Материализованные представления в SQL — погружаемся глубже в теорию

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

🧊 Что такое материализованное представление?
Материализованное представление (Materialized View) — это реальный объект базы данных, содержащий предрасчитанные данные.

В отличие от обычного VIEW, здесь:
Результат запроса сохраняется как отдельная таблица;
При чтении SELECT возвращает готовые, быстро читаемые данные;
Данные не обновляются автоматически (кроме некоторых случаев, например Oracle или с триггерами);
В основном требует явного ручного обновления — REFRESH.

🧊 Архитектурно материализованное представление — это:
Текст SQL-запроса,
Физическая таблица,
Метаданные для обновления

🧊 Ключевые особенности
Сохраняет данные — Да
Обновляется автоматически — Нет (нужно REFRESH), за исключением случаев, которые рассмотрим ниже.
Быстрое выполнение SELECT — Да
Требует места на диске — Да

🧊 Общий синтаксис для создания материализованного представления:
CREATE MATERIALIZED VIEW имя_представления AS
SELECT ...
FROM ...
[WHERE ...]
[GROUP BY ...]
[ORDER BY ...];

Дополнительно можно указать:
WITH NO DATA — представление создаётся, но не заполняется (нужно REFRESH).
WITH DATA (по умолчанию) — данные вычисляются сразу при создании.

🧊 Допустим, у нас есть таблица orders, в которой хранятся заказы клиентов. Она может содержать такие поля:
-----------------------------
id SERIAL
order_date TIMESTAMP
customer_id INT
amount NUMERIC

Таблица обновляется постоянно: пользователи делают заказы, и каждая строка — это один заказ.

Часто требуется строить отчёты:
Сколько заказов было каждый день
Какова средняя сумма заказа за день

Запрос к такой таблице может быть тяжёлым, особенно если в orders миллионы строк. Поэтому создаём материализованное представление — заранее рассчитанный агрегат, чтобы анализировать среднюю сумму заказов по дням:
CREATE MATERIALIZED VIEW daily_avg_orders AS
SELECT
order_date::date AS day,
COUNT(*) AS total_orders,
AVG(amount) AS avg_order_value
FROM orders
GROUP BY day
ORDER BY day;

Что делает это материализованное представление:
После выполнения CREATE MATERIALIZED VIEW — СУБД физически сохраняет результат запроса. Теперь мы можем быстро выполнять:
SELECT * FROM daily_avg_orders;

И получать результат без перерасчёта данных каждый раз.

🛠 Обновление (refresh)
Чтобы MView оставалось актуальным, его нужно обновлять вручную или автоматически.
При ручном обновлении, чтобы обновить данные в представлении после изменений в таблице orders, выполняем:
REFRESH MATERIALIZED VIEW daily_avg_orders;

Если при создании добавили WITH NO DATA — первый REFRESH обязателен.

Можно настроить автообновление через:
Планировщик задач (например, cron);
Расписание в СУБД (например, PostgreSQL pg_cron, Oracle DBMS_SCHEDULER);
Использование триггеров или CDC

⚙️ Индексы и уникальность
Во многих СУБД материализованные представления поддерживают индексы, особенно если нужно обеспечить уникальность:
CREATE UNIQUE INDEX ON имя_представления(ключ);

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

🖥 Поддержка материализованных представлений в разных СУБД:
PostgreSQL — Полноценная, ручное обновление
Oracle — Продвинутая (есть автообновление, query rewrite)
SQL Server — Аналог: Indexed Views
MySQL — поддержки нет
ClickHouse — Аналог через MATERIALIZED VIEW с INSERT
BigQuery — Поддержка с автообновлением

👾 Где это особенно нужно?
Сложные отчёты (много JOIN, WHERE, GROUP BY) — хранит результат и не пересчитывает каждый раз
BI и дашборды — быстрые ответы
Разгрузка сервера — меньше нагрузки на исходные таблицы
Разделение хранилищ — можно экспортировать MView в другие слои данных
Медленные источники данных — данные приходят редко, но запросы часты.

Так что, материализуемся 🥁

#Views #Materialized_views #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👾3💯22
Привет, нашел прикольную шпаргалку по основным джоинам от ByteByteGo.

Для инфо, JOIN в SQL — это операция, которая позволяет объединять данные из двух или более таблиц по связанному столбцу (обычно по ключу: первичному и внешнему).

Ранее писал посты про базовые джоины, однако, есть еще куча необычных join-операторов, конечно, в обиходе не все они используются часто, но кто знает, куда неофитов могут завести скитания по базе данных 😂

Скоро напишу пост про специфические джоины.
Лайк если надо 👩‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥28👾4😱2
👩‍💻 Специфические JOIN в SQL — тайные знания о соединениях

Итак, давайте разберем необычные виды join, про которые не так часто вспоминают, но они по своему прекрасны. Погнали.

💻 SELF JOIN — соединение таблицы с самой собой
SELF JOIN используется, когда нам нужно сравнить строки внутри одной и той же таблицы.
SELECT e1.name AS employee, e2.name AS manager
FROM employees e1
JOIN employees e2 ON e1.manager_id = e2.id;

Где полезен:
Связи типа «сотрудник – менеджер»
Поиск пар с определённым соотношением
Сравнение записей между собой (например, временных интервалов)

Обратить внимание:
Обязательно используйте алиасы (e1, e2) — иначе SQL не поймёт, откуда брать данные.
Производительность при больших таблицах может быть тяжёлой без индексов.

💻 CROSS JOIN — декартово произведение
Каждая строка из первой таблицы соединяется со всеми строками второй.
SELECT c.color, s.size
FROM colors c
CROSS JOIN sizes s;

Где полезен:
Генерация всех возможных комбинаций (цвет + размер, дата + товар и т.д.)
Математические переборы (в BI/аналитике)

Пример:
Таблица colors:
red
blue

Таблица sizes:
S
M
L

Результат:
color  size
red S
red M
red L
blue S
blue M
blue L

Обратить внимание:
Растёт в геометрической прогрессии — при 100 строках в каждой таблице будет 10 000 строк в результате (100×100 = 10 000 строк)!
Обычно требует явной фильтрации после соединения.

💻 NATURAL JOIN — соединение по совпадающим колонкам
Автоматически соединяет таблицы по колонкам с одинаковыми именами и типами.
SELECT *
FROM orders
NATURAL JOIN customers;

Где полезен:
Быстрые выборки, когда точно знаешь схему таблиц
Временные аналитические задачи или прототипирование

Обратить внимание:
SQL сам решает, по каким колонкам соединять! Если колонок с одинаковыми именами много, можно получить непредсказуемый результат.
Лучше не использовать в проде без явного указания колонок (ON), особенно если схему может кто-то изменить, потому что если структура изменится, все сломается.

💻 ANTI JOIN — найти то, чего нет
Ищем строки в первой таблице, у которых нет пары во второй.
На SQL делается через:
SELECT c.id
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE o.id IS NULL;

ИЛИ:
SELECT c.id
FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);


Где полезен:
Найти клиентов без заказов
Найти товары без продаж
Обнаружение "провалов" в связях

Обратить внимание:
Вариант с NOT EXISTS работает быстрее при наличии индекса
Убедитесь, что NULL действительно означает отсутствие связи, а не ошибку в данных

💻 SEMI JOIN — проверка на наличие
Найти строки из одной таблицы, у которых есть хотя бы одна пара в другой таблице, но не вытаскивать её. Забавно, но его синтаксис это JOIN без JOIN:
SELECT c.id
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);

В отличие от INNER JOIN, мы не получаем orders.* — только customers.

Где полезен:
Проверка: есть ли связи?
Ускорение выборок, когда нужны только факты "да/нет"

Обратить внимание:
Не получится использовать данные из второй таблицы (orders) в SELECT — она просто фильтрует
Неявный тип соединения, часто путают с INNER JOIN
Не вытаскивает данные из второй таблицы.

❗️ ANTI JOIN и SEMI JOIN — неофициальные типы (в ANSI SQL их нет), реализуются через LEFT JOIN + WHERE, EXISTS и т.п.

💻 Итого:
SELF — Сравнивает записи одной таблицы
CROSS — Сравнивает все на все, юзается для генерации комбинаций
NATURAL — Сравнивает по одинаковым колонкам, используем при уверенности неизменности структуры таблиц или с ON
ANTI — Выбирает всё, что не связано, используем для поиска отсутствий
SEMI — Выбирает всё, что связано, пишется без оператора JOIN

Поддержка:
SELF, CROSS, NATURAL — есть в большинстве СУБД (PostgreSQL, MySQL, Oracle, MS SQL)
SEMI JOIN, ANTI JOIN — не имеют отдельного синтаксиса, реализуются через EXISTS / NOT EXISTS / LEFT JOIN + IS NULL
В PostgreSQL и Oracle EXISTS работает особенно эффективно благодаря индексам.

#Join #SQL

📱 Подписаться на канал
📱Мы в VK
💻 Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥146💯4
Пишу пост про SQLi*, до конца недели опубликую. В июле, скорее всего буду много говорить о безопасности БД, методах их защиты, плюс затронем выдачу и управление правами пользователей в СУБД и бэкапы.

*⚠️SQL-инъекция (SQL injection)— это атака, при которой злоумышленник внедряет вредоносный SQL-код через поля ввода, например, на сайте (логин, пароль, поисковая строка), чтобы получить несанкционированный доступ к базе данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9🌚75
This media is not supported in your browser
VIEW IN TELEGRAM
Когда удалил не ту таблицу. Ну, главное, чтобы не на проде 😂
🤣16🔥5😱3🌚2
Привет, вписался в конкурс каналов с качественным авторским контентом. Потом будут голосования за лучшие посты по номинациям среди каналов и все такое — здесь @tg_contest_main. Так что, не удивляйтесь, иногда буду просить вас голосовать))

Ну а вобще, я считаю, круто, что мой канал начинает участвовать в таких штуках, для меня это своеобразный признак оценки моих стараний (как и ваши реакции) 😁
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15🌚3💯3
😵‍💫 Как посчитать дельту к предыдущему дню в SQL

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

SQL-инструмент для расчёта такой дельты — оконная функция LAG()

💻 Общий синтаксис:
LAG(столбец, смещение, значение_по_умолчанию) 
OVER (PARTITION BY ... ORDER BY ...)

LAG(column) возвращает значение из предыдущей строки.
PARTITION BY — разбивка по группам (например, по пользователям или магазинам).
ORDER BY — важный момент: он определяет, по какому порядку "сравнивать".

💻 Пример: считаем дельту выручки по дням.
Допустим, у нас есть таблица sales:
sale_date   amount
2024-06-01 1000
2024-06-02 1200
2024-06-03 800

Запрос:
select
sale_date,
amount,
amount - LAG(amount) OVER (ORDER BY sale_date) AS delta
FROM sales;

Результат:
sale_date   amount  delta
2024-06-01 1000 NULL
2024-06-02 1200 200
2024-06-03 800 -400

Что происходит в запросе?
LAG(amount) OVER (ORDER BY sale_date) берёт значение за предыдущий день.
amount - LAG(...) — рассчитывает дельту
В первый день delta = NULL, ибо в первом ряду нет предыдущего значения

💻 Пример с группировкой по магазину.
Если у нас несколько магазинов в таблице store_sales:
store_id  sale_date    amount
1 2024-06-01 1000
1 2024-06-02 1200
2 2024-06-01 700
2 2024-06-02 900

Запрос:
select
store_id,
sale_date,
amount,
amount - LAG(amount) OVER (PARTITION BY store_id ORDER BY sale_date) AS delta
FROM store_sales;

PARTITION BY store_id — Разбивает данные на группы по магазину. То есть, LAG() сравнивает значения только внутри одного store_id.
ORDER BY sale_date — Определяет порядок, в котором будет вычисляться «предыдущее значение» — по дате продаж.
LAG(amount) — Возвращает значение amount из предыдущей строки (внутри своей группы и в порядке дат).
amount - LAG(amount) — Вычисляет дельту: текущий объём продаж минус предыдущий.

Что получится в результате:
store_id  sale_date   amount  delta
1 2024-06-01 1000 NULL
1 2024-06-02 1200 200
2 2024-06-01 700 NULL
2 2024-06-02 900 200


Доп.ситуация:
Если значения amount могут быть NULL, то delta будет NULL даже при корректном LAG(). Можно использовать COALESCE():
amount - COALESCE(LAG(amount) OVER (...), 0) AS delta


❗️Частые ошибки:
Нет ORDER BY в OVER — дельта будет некорректной или всегда NULL
Если даты перепутаны или дубликаты — ORDER BY может вести себя нестабильно. Лучше явно указать второй ключ (при этом в больших таблицах обязательно, читай принудительно, надо прописывать сорировку по нескольким ключевым столбцам иначе отработка запроса может давать нестабильные результаты, у вас будут буквально разные цифры при каждом перезапуске)
Нет PARTITION BY, когда нужно сравнивать внутри группы, без оператора сравнение будет идти "вперемешку", не по логике.
Сравнение разных типов данных — приводит к ошибкам или некорректным значениям.
NULL-значения — дельта может стать NULL, если предыдущее значение отсутствует.

💻 Советы:
Если нет LAG() в вашей СУБД — можно сделать JOIN таблицы самой на себя, но это медленнее.
Дельту можно не только считать, но и фильтровать по ней (например: WHERE delta > 100).
Вместо LAG() можно использовать LEAD(), чтобы сравнить с будущим значением.

#LAG #SQL

📱 Подписаться на канал
📱Мы в VK
💻 Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥187👾5
Привет, немного порассуждал над собесами и подготовкой к ним, совместно с @bashnya_education
🔥7
Forwarded from БАШНЯ
РАЗБОР РУБРИКИ НОРМ ИЛИ СТРЕМ ❗️

Владимир Лунев - наш ментор подготовил разбор, где детально рассмотрел каждый наш вопрос 🔥

Не забывайте, что уже сейчас можно записаться на занятие с ментором через нашего менеджера - @bashnya_edu 🤯

Более подробно про менторство можно узнать в нашем миниаппе 💪

#mini_app
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17💯7👾5🤣1
🔓 SQL Injection: как одна кавычка может взломать базу данных

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

SQL-инъекция — это уязвимость, при которой злоумышленник может внедрить произвольный SQL-код в запрос и изменить его поведение. Обычно возникает, когда значения из внешнего ввода (пользователя) напрямую вставляются в SQL-запрос без очистки и параметризации.

❗️ Условный пример:
Представим, что на сайте есть форма входа, и backend формирует такой запрос на основе ввода пользователя:
SELECT * FROM users 
WHERE username = 'admin' AND password = '1234';

Но если пользователь введёт в поле password значение:
' OR '1'='1

Запрос превратится в нечто вроде:
SELECT * FROM users 
WHERE username = 'admin' AND password = '' OR '1'='1';

А это всегда истина. В итоге, пользователь войдёт без знания пароля.

⬇️ 💻 Вот несколько реальных случаев SQL-инъекций, которые нанесли урон крупным компаниям и организациям — как финансовый, так и репутационный:

❗️ 1. Heartland Payment Systems (2008)
Урон: более 130 миллионов украденных номеров кредитных карт.

Хакеры использовали SQL-инъекцию на публично доступном веб-сервере, чтобы получить доступ к внутренней сети компании. Далее они установили кейлоггер, чтобы собирать данные с систем обработки платежей.

Последствия:
Один из крупнейших в истории взломов по объёму похищенных карт.
Heartland потеряла сотни миллионов долларов на штрафах, судебных исках и модернизации безопасности.

❗️ 2. Sony Pictures (2011)
Урон: более 1 миллиона аккаунтов пользователей, включая пароли, e-mail и адреса.

Группа LulzSec заявила, что использовала простую SQL-инъекцию на одном из сайтов Sony, не требующую особых технических знаний. База данных была не зашифрована.

Последствия:
Массовый слив пользовательских данных.
Сильный удар по репутации компании, повторные взломы.
Общественная критика слабой кибербезопасности Sony.

❗️ 3. TalkTalk (2015)
Урон: утечка данных более 150 тыс. клиентов, включая банковские данные и номера карт.

Хакер использовал простейшую SQL-инъекцию в форме запроса на сайте, где не была проведена должная проверка входных данных.

Последствия:
Ущерб оценивался в более чем 77 миллионов фунтов.
Штраф в размере 400 000 фунтов от регулятора (ICO).
Генеральный директор публично признал: «атака была примитивной».

❗️ 4. U.S. Election Assistance Commission (2016)
Урон: утечка информации о безопасности выборов, продажа на чёрном рынке.

Что произошло:
SQL-инъекция позволила злоумышленникам получить доступ к серверу агентства. Они смогли создать привилегированную учётную запись администратора и продали доступ к базе данных на хакерских форумах.

Последствия:
Скандал на фоне выборов в США.
Подозрения в попытках повлиять на демократический процесс.
Усиление мер по кибербезопасности в госсекторе.

🔐 SQL-инъекция — это не баг кода, а баг архитектуры. Её можно полностью избежать, если изначально строить систему основанной на принципах безопасности данных.

Что объединяет все эти случаи?
Недостаточная защита ввода данных
Отсутствие параметризации запросов
Плохая архитектура безопасности
Данные хранились без шифрования

🔒Короткую методичку по защите от этого типа атак можно тезисно охарактеризовать так (подробно расписывать не буду, так как поста не хватит, если интересно почитать подробнее о способах защиты, пишите в коменты, сделаю отдельный пост):
Используйте подготовленные выражения (prepared statements)
Не собирайте SQL вручную через конкатенацию строк
Ограничьте права пользователям базы данных, контролируйте права ролей
Логируйте и анализируйте необычные запросы (Если в логах видите 1=1 или --, это может быть попыткой взлома)
Используйте ORM (SQLAlchemy, Django ORM, Hibernate)

#SQL_Injection #SQL

📱 Подписаться на канал
💻 Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👾6🤔3😱21