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

Меня зовут Владимир Лунев (@lejnlune). Интересуюсь архитектурой систем и моделей данных.
Download Telegram
🏷 Псевдонимы в SQL: зачем нужны AS и как правильно их использовать?

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

🔧 Синтаксис:
SELECT выражение AS псевдоним
FROM таблица AS псевдоним;

Слово AS можно опустить — но явное лучше неявного.

Пример 1: псевдоним для столбца
SELECT name, salary * 1.15 AS adjusted_salary
FROM employees;

adjusted_salary — это новое имя для результата выражения salary * 1.15.

Пример 2: псевдонимы в соединениях таблиц
SELECT e.name, d.name AS department
FROM employees AS e
JOIN departments AS d ON e.dept_id = d.id;

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

Что происходит в этом запросе?
1. employees AS e — Мы даём псевдоним e таблице employees. Теперь к её столбцам можно обращаться коротко: e. name, e. dept_id.
2. departments AS d — Аналогично, таблице departments присваиваем алиас d.
3. e. name и d. name — Здесь мы явно указываем, откуда брать каждый name, чтобы избежать путаницы.
4. d. name AS department — Мы даём столбцу более говорящий псевдоним, в результате запроса он будет отображаться как department, а не просто name.

Зачем нужны псевдонимы?
✔️ Читабельность: особенно полезно в сложных выражениях и подзапросах.
✔️ Разрешение конфликтов: если в нескольких таблицах одинаковые названия столбцов.
✔️ Переименование данных в отчётах: чтобы результат выглядел понятнее пользователю.

⚠️ Важно помнить:
Псевдонимы столбцов нельзя использовать в WHERE, потому что WHERE выполняется до SELECT.
Зато можно использовать в ORDER BY и HAVING. Пост про очередность выполнения тут

Пример из практики: расчёт налога и итоговой зарплаты
Задача: рассчитать 13% налог с зарплаты и итоговую сумму к выплате, вывести имя сотрудника, оклад, налог и сумму "на руки".
SELECT 
name AS employee_name,
salary AS base_salary,
salary * 0.13 AS tax_amount,
salary * 0.87 AS net_salary
FROM employees;


📎 Что происходит:
employee_name — читаемое имя вместо name
base_salary — для акцента на том, что это до вычета
tax_amount — отдельный расчёт налога
net_salary — итоговая сумма после удержания налога

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

📘 Заключение:
Псевдонимы — это не просто «красивости», а важный инструмент в арсенале каждого, кто работает с SQL. Они делают код читаемым, поддерживаемым и профессиональным.

#Операторы_и_работа_с_данными #Alias #Оптимизация_SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
👾9🔥4💯2
🔁 Что такое транзакция?

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

Если посмотреть с точки зрения машинной философии механизм транзакции можно выразить принципом «всё или ничего»

Ключевые команды:
1. BEGIN / START TRANSACTION – начало транзакции
2. COMMIT – подтверждение изменений
3. ROLLBACK – откат всех изменений с начала транзакции

💡 Почему это важно?
Представь, что ты переводишь деньги между счетами:
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

Если после первого запроса произойдёт сбой, то деньги «пропадут».

А если всё это завернуть в транзакцию — либо оба запроса сработают, либо ни один:
START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;

Если что-то пойдёт не так, можно сделать откат:
ROLLBACK;


Полезно знать:
Транзакции подчиняются принципам ACID:
1. Atomicity — атомарность
2. Consistency — согласованность
3. Isolation — изолированность
4. Durability — надёжность

Заключение
Транзакции — это не просто дополнительная опция. Это механизм, который:
1. Защищает данные от потерь и ошибок;
2. Позволяет писать надёжные и предсказуемые бизнес-логики;
3. Обеспечивает правильность даже в условиях высокой нагрузки.

Делись с командой — это основа безопасной работы с данными.

#Операторы_и_работа_с_данными #Транзакция #Оптимизация_SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👾5
🔔 Триггеры в SQL: автоматические действия в базе данных

Что такое триггер?
Триггер (trigger) — это специальная программа внутри СУБД, которая автоматически выполняет определённый SQL-код при наступлении события в таблице. Иными словами, триггер — это реакция базы данных на изменение данных.

Какие события могут активировать триггер?
Триггеры можно настроить на 3 типа событий:
1. INSERT — Добавление новой строки
2. UPDATE — Изменение существующей строки
3. DELETE — Удаление строки

Когда срабатывает триггер?
Есть два режима срабатывания:
1. BEFORE — До того, как операция будет завершена
2. AFTER — После выполнения операции

Это позволяет:
С BEFORE — предотвратить нежелательные действия (например, отклонить запись с ошибкой).
С AFTER — реагировать на уже выполненные изменения (например, логировать, уведомлять, синхронизировать).

Зачем нужны триггеры?
Примеры использования:
1. Автоматический лог изменений: записывать, кто и когда внёс изменения.
2. Синхронизация таблиц: при удалении строки из одной таблицы, удалить её из другой.
3. Уведомления: запускать действия при изменении статуса заказа.
4. Бизнес-правила: блокировать операции, нарушающие правила компании.

🛠 Синтаксис (на примере MySQL):
CREATE TRIGGER имя_триггера
[BEFORE | AFTER] [INSERT | UPDATE | DELETE]
ON имя_таблицы
FOR EACH ROW
BEGIN
-- SQL-действия*
END;
FOR EACH ROW означает, что триггер сработает для каждой строки, к которой применимо событие.

* - Внутри BEGIN ... END пишем обычный SQL-код.

Пример 1: логируем добавление сотрудника
Допустим, у нас есть таблица employees и таблица logs для записей о событиях.
CREATE TRIGGER log_employee_insert
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
INSERT INTO logs(message)
VALUES (CONCAT('Добавлен сотрудник: ', NEW.name));
END;

🔍 Объяснение:
AFTER INSERT — триггер сработает после добавления нового сотрудника.
NEW. name — обращение к значению поля name в новой строке (та, что только что вставлена).
Вставляется строка в таблицу logs.

Пример 2: предотвратить удаление важной записи
CREATE TRIGGER protect_admin_delete
BEFORE DELETE ON users
FOR EACH ROW
BEGIN
IF OLD.role = 'admin' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Нельзя удалить администратора!';
END IF;
END;

🔍 Объяснение:
BEFORE DELETE — триггер срабатывает до удаления.
OLD. role — значение удаляемой строки.
Если роль admin, выбрасывается ошибка, и удаление не происходит.

Разница между NEW и OLD
В INSERT только NEW — новая строка
В DELETE только OLD — удаляемая строка
В UPDATE оба: OLD — старая, NEW — новая

⚠️ Важные замечания
1. Один триггер = одно событие + одно время (BEFORE/AFTER).
2. Если нужно реагировать на разные события, создавайте несколько триггеров.
3. Не стоит делать сложную логику внутри триггера — это замедлит работу.
4. Циклические триггеры (когда один вызывает другой) могут привести к ошибкам или зависанию — избегайте этого.

📚 Резюме
CREATE TRIGGER — создание триггера
BEFORE / AFTER — время срабатывания
INSERT, UPDATE, DELETE — тип события
NEW, OLD — доступ к значениям до/после
FOR EACH ROW — выполняется для каждой строки

📌 Сохрани этот пост как шпаргалку!
🔁 Делись с коллегами — триггеры полезны, но ими часто пренебрегают.

#Операторы_и_работа_с_данными #Trigger

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👾6💯3
🧬 INSERT через SELECT: массовый перенос данных

INSERT INTO ... SELECT — это оператор массовой вставки. Вместо ручного ввода значений через VALUES, мы берем данные из существующей таблицы (или нескольких) и вставляем их в другую таблицу.

Это — основа для:
1. Копирования данных между таблицами
2. Архивирования записей
3. Миграции и трансформации данных
5. Наполнения витрин и отчётов
6. Подготовки временных таблиц в ETL-процессах

Синтаксис:
INSERT INTO target_table (col1, col2)
SELECT col_a, col_b
FROM source_table
WHERE condition;

Это не просто копирование — можно фильтровать, преобразовывать и агрегировать данные прямо на лету.

⚙️ Как работает?
1. Сначала выполняется SELECT — он формирует временный набор данных.
2. Затем INSERT INTO вставляет эти данные в указанную таблицу.
3. Всё это работает как единая транзакция.

Важно: порядок и типы колонок должны совпадать или быть совместимыми.

🔒 Строгие правила:
1. Количество колонок в INSERT INTO и SELECT должно совпадать.
2. Типы данных должны быть совместимыми: нельзя вставить TEXT в INT.
3. Если в целевой таблице есть NOT NULL, UNIQUE, FOREIGN KEY или DEFAULT, они тоже применяются.
4. Если есть автоинкремент (AUTO_INCREMENT), значение можно не указывать, оно подставится само.

⚠️ Частые ошибки:
1. Забыли WHERE — и вставили весь набор, включая ненужное.
2. Не проверили SELECT — и получили не те данные.
3. Не учли дубликаты — и получили ошибки или лишние строки.
4. Совпали ID-шники — и нарушили целостность данных.

🧠 SQL-инсайты:
1. Можно использовать JOIN в SELECT — перенос с объединением.
2. Можно использовать CASE, чтобы пересчитывать данные на лету.
3. LIMIT полезен при вставке порциями.
4.Поддерживается во всех основных СУБД (MySQL, PostgreSQL, SQL Server, Oracle).

ПРИМЕР 1: копирование всех данных
INSERT INTO employees_backup
SELECT * FROM employees;

Что здесь происходит:
1. SELECT * FROM employees — выбираются все строки и все столбцы из таблицы employees.
2. INSERT INTO employees_backup — полученные строки вставляются в таблицу employees_backup.

❗️ Таблицы employees и employees_backup должны иметь одинаковую структуру — одинаковые столбцы в том же порядке и с совместимыми типами данных.

ПРИМЕР 2: выборочная вставка (фильтрация)
INSERT INTO orders_archive
SELECT * FROM orders
WHERE order_date < CURDATE() - INTERVAL 1 YEAR;

Что происходит:
1. SELECT * FROM orders — берутся все заказы.
2. WHERE order_date < CURDATE() - INTERVAL 1 YEAR — фильтрация: только те заказы, которым больше года.
3. Результат вставляется в orders_archive.

Это пример архивации старых данных — очень частая задача в реальной работе с базами.

ПРИМЕР 3: агрегация и вставка
INSERT INTO sales_summary (category, total_sales)
SELECT category, SUM(amount)
FROM sales
GROUP BY category;

Что делает запрос:
1. SELECT category, SUM(amount) — для каждой категории считается общая сумма продаж.
2. GROUP BY category — группирует строки по категориям.
3. INSERT INTO sales_summary (...) — вставляет результат в таблицу итогов.

В INSERT INTO перечислены имена столбцов, куда вставляются значения. Это повышает читаемость и защищает от ошибок при изменении структуры таблиц.

ПРИМЕР 4: выборка с JOIN
INSERT INTO newsletter_subscribers (user_id, user_name)
SELECT u.id, u.name
FROM users AS u
JOIN subnoscriptions AS s ON u.id = s.user_id
WHERE s.active = 1;

Что происходит по шагам:
JOIN объединяет таблицы users и subnoscriptions по user_id.
WHERE s.active = 1 — выбирает только активных подписчиков.
SELECT u. id, u. name — выбираем только нужные поля.
INSERT INTO newsletter_subscribers (...) — вставляем их в целевую таблицу.

Это пример массового импорта данных в отдельный список.

💡Вывод
INSERT INTO ... SELECT — это не просто способ скопировать данные, а инструмент для построения гибких потоков данных между таблицами. Это основа работы с отчетами, витринами, архивами и резервным копированием.

🔁 Делись с коллегами — особенно с теми, кто до сих пор вставляет данные вручную через VALUES

#Операторы_и_работа_с_данными

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👾6
🔗 INNER JOIN в SQL — объединяем таблицы

В реальных базах данных информация часто хранится в нескольких связанных таблицах. Чтобы собрать все нужные данные в один результат — используют соединения (JOIN). Самый базовый и часто используемый тип соединения — INNER JOIN.

Что такое INNER JOIN?
INNER JOIN возвращает только те строки, где есть совпадения в обеих таблицах по заданному условию (обычно по ключам).

То есть: если связь не найдена — строка не попадёт в результат.

Синтаксис:
SELECT t1.column, t2.column
FROM table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.foreign_id;


ПРИМЕР:
Структура и данные исходных таблиц:
Таблица employees:
id   name     dept_id
1 Alice 10
2 Bob 20
3 Charlie NULL
4 Diana 30

Таблица departments:
id    name
10 HR
20 Engineering
30 Marketing
40 Sales

Пример запроса:
SELECT e.name, d.name AS department
FROM employees AS e
INNER JOIN departments AS d
ON e.dept_id = d.id;

Что делает запрос:
1. Обходит сотрудников (employees)
2. Находит отделы (departments) по полю dept_id
3. Возвращает только те строки, где dept_id найден в departments. id

Результат:
name   department
Alice HR
Bob Engineering
Diana Marketing

Charlie не попал в результат, потому что у него dept_id = NULL, а значит нет совпадения с таблицей departments.

🧠 Когда использовать INNER JOIN?
1. Когда нужно объединить связанные таблицы: сотрудники → отделы, заказы → клиенты, товары → категории и т.д.
2. Когда важны только те данные, у которых есть соответствие в обеих таблицах.
3. В отчетах, аналитике и выборках на основе бизнес-связей.

Вывод:
INNER JOIN — это основной способ объединить данные из разных таблиц, сохраняя логическую связь между ними. Если нет совпадения — строки просто игнорируются. Небольшой обзор на все виды Join тут

#Операторы_и_работа_с_данными #INNER_LOIN

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
💯7👾6🔥4
Удаление данных в РБД SQL: общая заметка про DML и DLL

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

Уровень DML - можно удалить данные очень безопасно. DML-команды изменяют именно данные, но не трогают структуру таблиц:
DELETE FROM таблица1
WHERE признак = 'значение';

Особенности:
1. Можно удалить часть данных с фильтрацией (WHERE).
2. Структура таблицы остаётся без изменений.
3. Можно откатить операцию с помощью транзакции (ROLLBACK). Пост про транзакции и откат изменений тут
4. Может быть медленным на больших объёмах (поскольку строки удаляются одна за одной с фиксацией).

🛠 Уровень DDL
DDL-команды влияют на структуру и метаданные базы данных. Даже если кажется, что они просто удаляют строки они могут серьезно повлиять на целостность данных, поэтому применять их нужно только будучи абсолютно уверенным в своих действиях (и желательно с бэкапом БД в кармане)

TRUNCATE таблица1;

1. Очищает таблицу полностью: удаляются все строки без условия, сбрасываются счётчики (AUTO_INCREMENT), освобождаются ресурсы.
2. Быстрее, чем DELETE, так как нет построчной обработки.
3. В большинстве СУБД невозможно откатить TRUNCATE через ROLLBACK.
4. В лог транзакций (transaction log) записывается не каждая удалённая строка, а сам факт очистки.

DROP таблица1;

1. Полностью удаляет таблицу из базы, вместе со всеми данными и схемой столбцов.
2. Требует осторожности: восстановление возможно только из бэкапа.

Кратко:
DELETE — DML, удаляет строки, фильтрация доступна, построчная обработка
TRUNCATE — DDL, очищает всю таблицу, нет фильтрации, откат изменений обычно недоступен
DROP — DDL, удаляет таблицу полностью, восстановление таблицы возможно только при наличии бэкапа

На что обратить внимание:
1. Если нужно удалить часть данных — выбирай DELETE.
2. Если нужно быстро очистить всю таблицу перед новой загрузкой данных TRUNCATE.
3. Если таблица должна быть предана полному забвению — юзай DROP.

#Операторы_и_работа_с_данными #DELETE #TRUNCATE #DROP

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👾5🌚3
🧩 Что такое ER-диаграммы и зачем они нужны?

В этом посте немного поработаем, с любимой темой автора — архитектурой. Когда вы проектируете базу данных, важно понять не только, какие таблицы будут, но и что они означают и как связаны. Для этого используют ER-модель (Entity-Relationship Model) — инструмент, созданный Питером Ченом в 1976 году.

Теоретическая база
ER-модель — это абстракция предметной области, которая позволяет выразить:
2. Сущности (Entity) — уникальные объекты (например, Пользователь, Товар, Заказ)
3. Атрибуты (Attributes) — свойства этих объектов (например, имя, цена, дата)
4. Связи (Relationships) — логические ассоциации между сущностями (например, "Пользователь оформляет Заказ")
Пост про реляционную модель

ER-модель помогает перевести бизнес-требования в техническую структуру, которую можно реализовать в СУБД.

Основные понятия подробно:
1. Сущность (Entity). Это классы объектов реального мира, которые мы хотим сохранить в базе. Например, Student, Course, Invoice.
2. Слабая сущность. Не имеет собственного первичного ключа. Например, Payment может зависеть от Invoice.
3. Атрибут (Attribute). Конкретная характеристика сущности. Могут быть: Простыми (name, price), составными (full_name → first_name + last_name), многозначными (телефоны), производными (возраст можно вычислить по дате рождения)
4.Первичный ключ (Primary Key). Уникальный идентификатор сущности — обязателен. Посты про первичный и внешний ключи
5.Связь (Relationship) определяет, как сущности взаимодействуют. Может быть:
— бинарной (между двумя сущностями)
— тернарной (между тремя)
— рекурсивной (сущность связана сама с собой, например, Employee → Manager)
6, Кардинальность. Указывает, сколько экземпляров одной сущности может быть связано с другой. Форматы: 1:1, 1:N, M:N.
7, Обязательность (Optionality). Определяет, обязательно ли участие в связи. Например, заказ может иметь доставку, а может не иметь.

🔗 Типы связей в деталях
1, Один к одному (1:1) — Реализуется через внешний ключ с ограничением уникальности.
Пример: каждый человек имеет один паспорт.
2, Один ко многим (1:N) — Внешний ключ указывается на стороне "многих".
Пример: один клиент может сделать несколько заказов.
3, Многие ко многим (M:N) — Требует связующей таблицы.
Пример: студент может записаться на много курсов, курс — иметь много студентов.

Пример: интернет-магазин:
Фрагмент ER-диаграммы (в текстовом виде):
Customer ─< Order >─ Product
| | |
id order_id id
name order_date name
email total price

Сущности:
Customer (атрибуты customer_id, name, email)
Order (атрибуты order_id, order_date, total)
Product (атрибуты product_id, name, price)

Связи:
Customer ─────< Order

1. Это связь "один ко многим" (1:N).
2. Один покупатель (Customer) может сделать много заказов, но каждый заказ принадлежит только одному покупателю.
3. На практике в таблице Order будет внешний ключ customer_id. Чтобы реализовать такую связь в базе данных, в таблице заказов (Order) нужно указать, кто из клиентов сделал заказ.
Order >───── Product

1. Это связь "многие ко многим" (M:N).
2. Один заказ может включать много товаров, и один товар может быть в многих заказах.
3. Для реализации такой связи создаётся промежуточная таблица (не показана здесь, но подразумевается) — например, OrderItem:
OrderItem (
order_id INT, -- внешний ключ к Order
product_id INT, -- внешний ключ к Product
quantity INT -- количество единиц товара
)

Эта таблица реализует связь и дополнительные данные (например, количество).

Советы:
1. Используйте ER-диаграмму до нормализации — это первый логический шаг. Пост про нормализацию данных
2. Хорошие инструменты: dbdiagram.io, draw.io, Lucidchart
3. Храните диаграмму рядом с документацией — она пригодится через год, когда все забудут, зачем нужно некое поле.

ER-модель — это язык проектировщика баз данных.
Научитесь его читать и писать — и ваши БД будут чёткими, масштабируемыми и поддерживаемыми.

#Реляционные_базы_данных #Архитектура_РБД

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👾8🤔4
Ежемесячный дайджест — апрель 2025

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

🔁 Написание и исполнение SQL-запросов

ORDER BY — как управлять порядком строк в результатах запроса?
Объяснение сортировки данных по столбцам и выражениям: по возрастанию, убыванию и с учётом NULL.

Псевдонимы в SQL: зачем нужны AS и как правильно их использовать?
Упрощай чтение запросов и избегай конфликтов с помощью AS для столбцов и таблиц.

INSERT через SELECT: массовый перенос данных
Приёмы копирования данных между таблицами — быстро, надёжно, масштабируемо.

INNER JOIN в SQL — объединяем таблицы
Как связать таблицы по ключам и извлечь данные из нескольких источников сразу.

Удаление данных в РБД SQL: общая заметка про DML и DLL
Чем отличается DELETE, TRUNCATE и DROP? Разбираем на практике и по теории.

⚙️ Механизмы обработки и автоматизации

Что такое транзакция?
Твёрдая основа надёжных операций: свойства ACID и как СУБД следит за целостностью данных.

Триггеры в SQL: автоматические действия в базе данных
Как запускать автоматические действия при вставке, обновлении или удалении данных.

Порядок выполнения SQL-запроса: не такой, как кажется на первый взгляд!
SQL читается не сверху вниз: узнай, с чего действительно начинается выполнение запроса.

🛠 Проектирование баз данных

Что такое ER-диаграммы и зачем они нужны?
Основы моделирования: сущности, связи и атрибуты в текстовом формате и с пояснениями.


🏆 Популярное за месяц

Самый обсуждаемый пост:
Удаление данных в РБД SQL: общая заметка про DML и DLL

Самый просматриваемый пост:
Порядок выполнения SQL-запроса: не такой, как кажется на первый взгляд!

👾В мае вас ждёт:
— Бесплатный мини-курс по нормализации данных в РБД от автора канала на Stepik
— Разбор реального кейса моделирования БД
— Ещё больше практики и SQL-хаков
— Еще в последних постах я стал делать мемы, так что мемы тоже будут))

Напиши, какой пост был для тебя самым полезным — или чего не хватает в канале?
Спасибо, что читаешь!

#Дайджест

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👾6💯5
🪟 Представления (Views) в SQL — базовая теория

Представление — это виртуальная таблица, которая формируется на основе результата SQL-запроса. Представления не содержат собственных данных, а при обращении к ним СУБД повторно исполняет сохранённый запрос, чтобы сгенерировать актуальные результаты.

Теория: как это работает?
1. Представление определяется через конструкцию CREATE VIEW, внутри которой задаётся любой корректный SELECT-запрос.
2. При использовании представления в других запросах оно обрабатывается СУБД как подзапрос, «разворачиваясь» в изначальный SQL.
3. Представления — это не таблицы, они не хранят данные, а только логику запроса (за исключением материализованных представлений, которые имеют такую возможность)
4. Представления можно использовать в SELECT, JOIN, WHERE, ORDER BY и других операторах как обычную таблицу.
5. Если данные в исходных таблицах меняются — результаты представления тоже изменятся.
6. Некоторые представления нельзя обновлять напрямую, особенно если они содержат JOIN, GROUP BY, DISTINCT, подзапросы и агрегаты.

Пример 1: Обычные (логические) представления
CREATE VIEW active_customers AS
SELECT id, name, email
FROM customers
WHERE status = 'active';

Что происходит:
1. CREATE VIEW active_customers AS — создаёт представление с именем active_customers.
2. Внутри — обычный SELECT-запрос: выбираем id, name, email из таблицы customers, но только те строки, где status = 'active'. Представление не копирует данные из customers, а сохраняет структуру запроса. Когда вы запрашиваете SELECT * FROM active_customers, СУБД как бы вставляет туда оригинальный SELECT.

Использование представления
SELECT * FROM active_customers WHERE email LIKE '%@gmail. com';

Что происходит:
1. Вы запрашиваете все поля из представления active_customers, но фильтруете их по email.
2. На самом деле СУБД превращает этот запрос во что-то вроде:
SELECT id, name, email
FROM customers
WHERE status = 'active' AND email LIKE '%@gmail.com';

Представления можно перезаписывать.
Обновление представления — означает изменение данных, которые оно отображает.
CREATE OR REPLACE VIEW active_customers AS
SELECT id, name, email, created_at
FROM customers
WHERE status = 'active';

Что происходит:
1. Ключевая фраза CREATE OR REPLACE означает: если представление уже существует — оно будет перезаписано новым определением.
2. К предыдущему представлению добавляется колонка created_at.

Пример 2: с объединением таблиц (JOIN)
CREATE VIEW employee_departments AS
SELECT e.id, e.name, d.name AS department
FROM employees AS e
JOIN departments AS d ON e.dept_id = d.id;

Что происходит:
1.Создаётся представление employee_departments, в котором:
e — псевдоним для таблицы employees
d — псевдоним для таблицы departments
2. Мы соединяем сотрудников с отделами по dept_id.
3. Выводим:
e. id, e. name — данные сотрудника
d. name AS department — название отдела (переименовываем колонку name из таблицы departments в department, чтобы не было конфликта имён)

Пример использования:
SELECT * FROM employee_departments WHERE department = 'IT';

Получим выгрузку из объединенных таблиц.

Материализованные представления (команда создания CREATE MATERIALIZED VIEW)
Материализованные представления (materialized views) поддерживаются основными СУБД. Они отличаются от обычных тем, что хранят результат запроса физически, а не вычисляют его каждый раз при обращении.

Подходящие случаи для использования представлений:
1. Создание стандартных витрин для аналитики (упрощение запросов)
2. Подготовка отчётности с агрегацией (Повторное использование логики)
3. Маскирование конфиденциальных столбцов (например, зарплаты)
4. Предоставление пользователю ограниченного доступа к БД
5, Снижение дублирования,
представления позволяют вынести повторяющиеся фрагменты запросов в отдельную конструкцию, улучшая читаемость и поддержку кода.

Вывод:
Представления в SQL — это способ упростить работу с базой данных, сделать запросы чище, безопаснее и переиспользуемыми. Особенно актуальны в больших проектах с командной разработкой и аналитикой.

#Views

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👾4🌚2
🪟Оконные функции в SQL — как они работают и где применяются?

Когда обычный GROUP BY не даёт нужной гибкости, на помощь приходят оконные функции.

Оконные функции (Window Functions) — это инструмент SQL, который позволяет выполнять операции, не изменяя структуру набора данных, а сохраняя доступ ко всем строкам в результирующем наборе. Они часто используются для выполнения аналитических задач, таких как ранжирование, вычисление агрегатов по окну или анализ данных с учётом контекста и позволяют выполнять вычисления по частям набора без потери информации о отдельных строках.

Оконная функция выполняет операцию на наборе строк, называемом "окном" — это подмножество данных, которое определяется с помощью ключевых слов OVER(), оно производит вычисления над набором строк, связанных с текущей записью, без группировки. Можно представить окно, как рамку, которая двигается вдоль данных, вычисляя значения для каждой позиции.

Образец общего синтаксиса:
SELECT 
column1,
column2,
ОКОННАЯ_ФУНКЦИЯ() OVER (
[PARTITION BY partition_expression, ...]
[ORDER BY sort_expression [ASC | DESC], ...]
[ROWS | RANGE frame_specification]
) AS result_column
FROM
table_name;

Типы оконных функций:
ROW_NUMBER() — присваивает уникальный номер каждой строке в окне.
RANK() — ранжирует строки с учётом возможных одинаковых значений.
DENSE_RANK() — похож на RANK(), но без пропусков в номерах рангов.
NTILE(n) — делит данные на n равных частей.
SUM(), AVG(), MIN(), MAX() — агрегатные функции, применяемые к окну.

Пример 1: AVG()
Посчитать зарплату каждого сотрудника и среднюю зарплату по его отделу, не теряя строк.
SELECT
name,
department,
salary,
AVG(salary) OVER (PARTITION BY department) AS avg_dept_salary
FROM employees;

Что происходит:
1. PARTITION BY department делит строки на группы (по отделам),
2. AVG(salary) считает среднюю по каждой такой группе.

Пример 2: NTILE(n)
NTILE(n) делит данные на n равных частей и присваивает каждому элементу номер его "порции".
Это полезно, например, для разбивки данных на квартили или группы.
SELECT
employee_id,
salary,
NTILE(4) OVER (ORDER BY salary DESC) AS quartile
FROM employees;

Здесь сотрудники будут разделены на 4 группы по зарплатам.

Еще пример: ROW_NUMBER()
Функция присваивает уникальный номер каждой строке в окне. Строки нумеруются по порядку, начиная с 1, на основе сортировки в ORDER BY. Это полезно, например, для генерации уникальных идентификаторов в рамках группы.
SELECT
employee_id,
salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;

В этом примере всем сотрудникам будет присвоен уникальный номер, начиная с самого высокооплачиваемого.

Важно!
1. Оконные функции не сворачивают строки (в отличие от GROUP BY).
2. Работают после WHERE и GROUP BY, но до ORDER BY в основном запросе.
3. Поддерживаются в PostgreSQL, MySQL 8+, SQL Server, Oracle.

Преимущества оконных функций:
1. Гибкость — оконные функции позволяют решать сложные аналитические задачи, не меняя структуру данных.
2. Скорость — они могут быть быстрее, чем использование подзапросов или объединений, поскольку не нужно выполнять дополнительные агрегации.
3. Удобство — оконные функции позволяют работать с большими объёмами данных и производить расчёты, сохраняя доступ к каждой строке.

#Оконные_функции #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥11👾7🌚3
🧊 Материализованные представления — базовая теория

Когда вы создаёте обычное представление (разобрал ранее в посте) в SQL, вы, по сути, сохраняете тело запроса, но не его результат. Каждый раз при обращении к такому представлению СУБД выполняет запрос заново, извлекая данные из указанных таблиц. Это гарантирует актуальность, но процесс может быть медленным, особенно если запрос тяжёлый и работает с большим количеством данных.

Чтобы ускорить работу, особенно для выполнения аналитики и подготовки отчётности, придумали материализованные представления.

🔍 Что такое материализованное представление?
Это объект базы данных, который сохраняет результат выполнения SQL-запроса — то есть не только структуру, но и сами данные. Он существует как полноценная таблица с данными, которые можно быстро читать без перерасчёта.

Разумеется, это порождает главный компромисс: такие представления не обновляются автоматически. Если в исходных таблицах изменились данные, то материализованное представление останется устаревшим, пока вы его не обновите вручную или по расписанию.

🧠 Теория: зачем нужны материализованные представления?
Материализованные представления применяются, когда:
1. Данные редко меняются, но часто читаются.
2. Запросы сложные и требуют много ресурсов.
3. Нужно сократить время ответа в BI-системах, аналитике, отчётах.
4. Вы строите ETL/ELT пайплайн и хотите сохранить промежуточные агрегаты.
5. Нужен кэш сложного запроса, особенно с объединениями и агрегациями.

Их можно рассматривать как оптимизированные, частично "ручные" кеши внутри базы данных.

Пример: агрегаты по продажам
Исходная таблица:
CREATE TABLE sales (
id SERIAL PRIMARY KEY,
product_id INT,
quantity INT,
total NUMERIC,
sale_date DATE
);

Создаём материализованное представление (CREATE MATERIALIZED VIEW имя_представления), в котором храним сумму продаж и количество товаров по каждому продукту и месяцу:
CREATE MATERIALIZED VIEW sales_summary AS
SELECT
product_id,
DATE_TRUNC('month', sale_date) AS month,
SUM(quantity) AS total_quantity,
SUM(total) AS total_revenue
FROM sales
GROUP BY product_id, DATE_TRUNC('month', sale_date);

Теперь можно обращаться к sales_summary, как к обычной таблице — всё уже посчитано и лежит в готовом виде.

🔄 Обновление данных
Так как данные в материализованном представлении со временем устаревают, их нужно обновлять вручную:
REFRESH MATERIALIZED VIEW sales_summary;

Если вы не хотите блокировать чтение из представления во время обновления (например, в боевой системе), используйте:
REFRESH MATERIALIZED VIEW CONCURRENTLY sales_summary;

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

⚙️ Технические особенности
1. Нельзя использовать функции, которые дают разные результаты при каждом вызове: NOW(), RANDOM(), CURRENT_USER и пр.
2. В представление нельзя передавать параметры (например, даты).
3. Представление ведёт себя как таблица: в нём есть строки и столбцы, и оно занимает место на диске.
4. Можно создавать индексы на материализованном представлении, как на обычной таблице — это даёт дополнительный прирост производительности.
5. Обновление может быть затратным по времени — особенно если исходные таблицы большие и часто меняются.

🔧 Поддержка в разных СУБД
1. В PostgreSQL материализованные представления поддерживаются нативно. Можно использовать REFRESH и CONCURRENTLY.
2. В Oracle поддержка есть с 8 версии, и она даже продвинутая — позволяет настраивать автоматическое обновление по расписанию.
3. В SQL Server их нет как отдельного объекта, но похожее поведение обеспечивают Indexed Views.
4. В MySQL и SQLite — отсутствуют, но можно эмулировать, создавая таблицу + триггеры или процедуры обновления.

#Views #Materialized_views #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
👾9🔥5💯4
🔧 Партиционирование таблиц в SQL

Когда таблица становится слишком большой, работа с ней замедляется. Представь таблицу с миллионами заказов за несколько лет — каждый SELECT, UPDATE или DELETE начинает тормозить.

Решение — партиционирование (partitioning).
Партиционирование — это способ разделить одну физическую таблицу на несколько более мелких частей, называемых секциями (partitions). Каждая секция обрабатывает данные в диапазоне или по определённому условию.

Партиционирование создаётся на уровне DDL — команд, которые описывают структуру таблиц в базе данных. Партиционирование задаётся при создании таблицы, потому что большинство СУБД (включая PostgreSQL, MySQL и др.) не позволяют ретроспективно изменить обычную таблицу на партиционированную. В случае наличия огромной таблицы без партиций, этот процесс можно выполнить путем создания ее аналога с партициями и осуществления миграции данных.

Зачем использовать партиционирование?
1. Повышение производительности — запросы работают только с нужной секцией, а не со всей таблицей.
2. Упрощение администрирования — старые секции можно удалять или архивировать.
3. Чёткая логическая организация данных — например, по годам или регионам.

Основные типы партиционирования:
1. Диапазонное (RANGE) — делит таблицу по значениям в диапазоне. Например: заказы по годам.
2. Списковое (LIST) — делит по значениям из списка. Например: по странам или типу продукта.
3. Хэш-партиционирование (HASH) — делит данные равномерно по хешу поля. Используется, когда нет логического критерия разделения.

Существует два основных варианта партиционирования в SQL — горизонтальное и вертикальное:
1. Горизонтальное — разделение таблицы на партиции, основанное на строках. Каждая партиция содержит определённое количество строк.
2. Вертикальное — разделение таблицы на партиции, основанное на столбцах. Каждая партиция содержит определённый набор столбцов.

Пример (PostgreSQL, RANGE партиционирование)
ТЗ: Создать таблицу orders горизонтально разбитую на секции по годам, чтобы упростить работу с большим объёмом данных в будущем — ускорить запросы, сделать более быстрым архивирование, повысить производительность.

Создаем таблицу orders:
CREATE TABLE orders (
id SERIAL,
order_date DATE NOT NULL,
customer_id INT,
amount NUMERIC
) PARTITION BY RANGE (order_date);

Что делаем:
1. PARTITION BY RANGE (order_date) означает, что данные будут автоматически распределяться по секциям в зависимости от значения order_date.
2. Сама таблица orders теперь — логическая оболочка, а данные будут физически храниться в её партициях (субтаблицах).

Создаём секции:
CREATE TABLE orders_2023 PARTITION OF orders
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');

CREATE TABLE orders_2024 PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

1. Теперь все заказы автоматически попадут в нужную секцию в зависимости от order_date.
2. orders_2023 хранит все строки, где order_date от 2023-01-01 до 2023-12-31.
3. orders_2024 — за 2024 год.
4. Диапазоны не пересекаются и не перекрываются, иначе возникнет ошибка при вставке.

🛠 Что происходит при обращении к партиционированным таблицам?
Когда пользователь выполняет запрос:
SELECT * FROM orders WHERE order_date >= '2024-01-01';

PostgreSQL понимает, что нужны только данные из orders_2024, и вообще не трогает остальные таблицы. Это называется pruning — отсечение ненужных секций.

Что нужно помнить
1. Партиционирование — даёт прирост при правильных запросах, особенно с фильтрацией по колонке партиционирования.
2. Партиции ведут себя как обычные таблицы — можно создавать на них отдельные индексы, статистику, правила.
3. Логика запросов остаётся на уровне родительской таблицы — СУБД сама направляет данные в нужную субтаблицу.
3. Хорошее партиционирование требует продуманной модели данных и нагрузки.

#Partition #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
👾13🔥5💯5
🔍 BETWEEN в SQL: удобный инструмент фильтрации, но есть нюансы

В SQL оператор BETWEEN используется для фильтрации значений в заданном диапазоне, включая границы этого диапазона. Синтаксис прост, но за ним скрываются важные детали, особенно при работе с датами и временем.

Общий синтаксис:
SELECT ...
FROM ...
WHERE столбец BETWEEN значение_1 AND значение_2;

Это полностью эквивалентно:
WHERE столбец >= значение_1 AND столбец <= значение_2

Границы включаются! Это главный момент, который необходимо помнить.

Пример с числами:
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;

Этот запрос вернёт все товары, цена которых от 100 до 500 включительно.
То же самое, что:
WHERE price >= 100 AND price <= 500

Обратите внимание: порядок имеет значение!
Если перепутать границы — результат будет пустым:
WHERE price BETWEEN 500 AND 100  
-- Вернёт 0 строк


Пример с датами:
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';

На первый взгляд запрос безопасен, но всё зависит от типа данных order_date
— Если это DATE, то всё хорошо: вернутся все заказы от 1 января до 31 декабря 2024 года включительно.
— Если это DATETIME или TIMESTAMP, то 31 декабря попадут только записи с временем 00:00:00. То есть, большая часть заказов за 31 декабря может быть пропущена!

Как правильно писать условия для DATETIME.
Используйте открытый верхний предел:
WHERE order_date >= '2024-01-01'
AND order_date < '2025-01-01'

Такой стиль абсолютно безопасен и широко применяется в профессиональной практике, особенно в BI и аналитике.

Что ещё важно?
1. Типы данных должны быть совместимы
WHERE product_id BETWEEN 'a' AND 'z'  -- OK для строк

BETWEEN работает и с текстами (сравнение лексикографическое), и с датами, и с числами.

2. NOT BETWEEN тоже существует!
WHERE age NOT BETWEEN 18 AND 60;

Возвращает все строки, где значение меньше 18 или больше 60.

BETWEEN и NULL:
Если значение в проверяемом столбце — NULL, то условие BETWEEN вернёт не TRUE, а UNKNOWN, что эквивалентно тому, что строка не попадёт в результат.
SELECT * FROM employees
WHERE commission_pct BETWEEN 0.1 AND 0.3; -- NULL значения исключаются

Чтобы явно включить такие строки, добавьте отдельное условие:
WHERE (commission_pct BETWEEN 0.1 AND 0.3 OR commission_pct IS NULL)


Итого:
1. BETWEEN включает границы, то есть условие BETWEEN 10 AND 20 вернёт и 10, и 20.
2. При работе с типами DATETIME следует быть особенно осторожным: BETWEEN '2024-01-01' AND '2024-12-31' не захватит все записи за 31 декабря, если в них указано время.
3. BETWEEN чувствителен к порядку значений: если нижняя граница больше верхней — результат будет пустой.
4. Не забывайте про NULL: записи с NULL в проверяемом столбце не попадут в выборку.
5. Альтернативный и более безопасный способ — использовать условия вида >= ... AND < ..., особенно при работе с временными диапазонами.

В целом, BETWEEN — удобный инструмент, если применять его правильно с учётом особенностей данных, с которыми вы работаете.

#BETWEEN #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👾4🤯2💯1
🔗 Типы связей в реляционных БД: что, зачем и как?

Связи между таблицами — основа реляционных баз данных. Именно они позволяют создавать сложные модели данных. В теории баз данных тип связи (relationship type) — это формализованное описание ассоциации между двумя или более сущностями, указывающее, сколько экземпляров одной сущности может быть связано с экземплярами другой.

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

1. Один к одному (1:1)
Каждая запись в таблице A соответствует ровно одной записи в таблице B и наоборот.

Пример:
Таблица users — содержит пользователей
Таблица passports — содержит паспортные данные
Каждому пользователю соответствует один паспорт, и каждый паспорт — одному пользователю.

Как реализуется:
Вторичная таблица (passports) содержит внешний ключ на users. id
Иногда связи 1:1 выделяются в отдельную таблицу для повышения безопасности или для разделения редко используемых данных
users            passports
+---------+ +------------+
| id (PK) <--- |user_id (PK,FK)
| name |passport_number
+---------+ +------------+

Связь: users. id (PK) — 1:1 — passports.user_id (PK, FK)

2. Один ко многим (1:N)
Каждая запись в таблице A может соответствовать нескольким записям в таблице B, но каждая запись в таблице B соответствует только одной записи в A.

Пример:
Таблица departments — отделы
Таблица employees — сотрудники
Один отдел включает многих сотрудников, но каждый сотрудник относится к одному отделу.

Как реализуется:
Во второй таблице (employees) создаётся внешний ключ department_id, указывающий на departments. id первой таблицы. Это — самый распространённый тип связи.
departments         employees
+----------+ +-----------------+
| id (PK) <----- | id (PK)
| name | name
+----------+ | department_id(FK)
+-----------------+

Связь: departments. id (PK) — 1:N — employees.department_id (FK)

3. Многие ко многим (N:M)
Каждая запись в таблице A может соответствовать нескольким записям в таблице B, и наоборот.

Пример:
Таблица students — студенты
Таблица courses — курсы
Один студент записан на много курсов, и каждый курс включает много студентов.

Как реализуется:
1. Создаётся связующая таблица (например, student_course)
2. Она содержит два внешних ключа: student_id и course_id
3. Иногда добавляют дополнительные атрибуты
students      student_courses     
+---------+ +--------------+
| id (PK) | student_id(FK)
| name | course_id(FK)
+---------+ +--------------+

courses
+----------+
| id (PK)
| noscript
+----------+

Связи:
1. students. id — 1:N — student_courses.student_id
2. courses. id — 1:N — student_courses.course_id

Коротко о реализации типов связей:
1. Один к одному — внешний ключ + уникальность
2. Один ко многим — внешний ключ в "многой" таблице
3. Многие ко многим — связующая таблица с 2 FK

Почему это важно?
Правильное определение и реализация связей:
1. Обеспечивает целостность данных
2. Обязательно для нормализации данных и устранения дублирования
4. Необходимо для поддержки бизнес-логики и целевого использования данных БД
5. Улучшает производительность (меньше дублирования, легче кэшировать);
6. Делает базу пригодной к росту (easy to scale).

Таким образом, связи в реляционной БД — это основа структурированной, надёжной и масштабируемой системы хранения данных.

#Ключи_и_связи_между_таблицами #SQL

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
👾9🔥5🌚1
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👾5🤯1
📀Заметка о том, как создать собственную одомашненную БД

Рассказываю, как создать локальную тестовую БД для практики буквально за пару минут.
Для начала качаем DBeaver, это бесплатное программное обеспечение с открытым исходным кодом, распространяемое по лицензии Apache, по сути клиент для SQL и инструмент для администрирования баз данных.

После установки запускаем приложение и в меню кликаем: Справка → Создать тестовую базу данных (всё показал на скринах последовательно). В результате получаем полноценную базу данных на SQLite.

💽 Из плюсов то, что в отличие от других систем баз данных (MySQL, Postgres и прочих) для SQLite не требует отдельного сервера. Это встраиваемый движок, который работает напрямую с файлом базы данных на диске. То есть ничего дополнительно устанавливать или конфигурировать не нужно — всё уже готово.

Но есть нюанс, у SQLite несколько ограниченный функционал по сравнению с обычными СУБД (например, нет поддержи RIGHT JOIN, FULL OUTER JOIN), однако, для практики, я думаю, это не помеха.

🖥Поэтому юзайте способ, чтобы получить представление об SQL и о том как происходит работа с БД.

P.S. на последнем скрине для проверки создал в новой БД таблицу, все ок

📱 Подписаться на канал | Курс автора по SQL DDL
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👾5💯2
Подготовили пост про хард скиллс в SQL совместно с @bashnya_education 👾
🔥4👾1
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