Shanraq.org Shanraq.org
Ключи и JOIN: связать операции со счетами и категориями
IT

Ключи и JOIN: связать операции со счетами и категориями

Нормализуем модель бюджета и соединяем таблицы по ключам. Учимся выбирать INNER и LEFT JOIN, замечать размножение строк и не связывать данные по похожему тексту.

Зачем это нужно

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

Образ. В операции лежит номер гардеробного жетона, а название категории — на самой вешалке. JOIN возвращает вещи по точному номеру, не по похожему цвету пальто.

Сразу целиком

SELECT t.happened_on, a.name AS account, c.name AS category,
       t.amount_tiyn / 100.0 AS amount_kzt
FROM transactions AS t
JOIN accounts AS a ON a.id = t.account_id
JOIN categories AS c ON c.id = t.category_id
ORDER BY t.happened_on, t.id;

Разбор

INNER JOIN оставляет только совпавшие строки. LEFT JOIN сохраняет каждую строку слева и подставляет NULL, когда пары справа нет. В нашей схеме обязательные внешние ключи гарантируют пару, но LEFT JOIN полезен, чтобы показать категории даже без расходов.

Связь «многие операции — одна категория» должна оставить число операций прежним. Если справа два одинаковых ключа, строки размножатся. Поэтому справочник защищён PRIMARY KEY/UNIQUE, а результат проверяется не только общей длиной: ищут отсутствующие пары и дубли ключей.

Фильтр правой таблицы после LEFT JOIN в WHERE может незаметно превратить его в INNER JOIN. Условие, которое относится к совпадению, часто должно стоять в ON.

Карта урока

JOIN соединяет строки по устойчивым ключам

Скажите своими словами

  1. Почему имя категории не служит внешним ключом?
  2. Когда нужен LEFT JOIN?
  3. Как связь многие-к-одному может размножить строки?

Задание

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

Куда это встанет в проекте

Отчёт связывает факты с понятными названиями, но хранит их без повторения текста.

Ответы

Показать ответы
SELECT c.name, COALESCE(SUM(t.amount_tiyn), 0) / 100.0 AS spent_kzt
FROM categories AS c
LEFT JOIN transactions AS t
  ON t.category_id = c.id
 AND t.happened_on >= '2026-09-01'
 AND t.happened_on <  '2026-10-01'
WHERE c.kind = 'expense'
GROUP BY c.id, c.name
ORDER BY c.name;

Источники

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Проверить задание

Сначала решите и запустите в VS Code — редактор покажет ошибку на месте. Готовое решение вставьте сюда. Проверяет модель: она укажет на ошибку, но не даст готовый ответ.

Чтобы проверить, нужно войти. Войти

Комментарии (0)

Пока нет комментариев. Будьте первым.