Mysql — Проектирование БД (Три нормальных формы)
Привет. Сегодня поговорим о проектировании бд. Без разницы какую вы используете БД, хоть access, все правила ровны для всех БД. А также настроим взаимосвязь между таблицами. И так существуют так называемые три нормальные формы, а может и больше, но я о них не знаю, если вы знаете, то обязательно пишите в комментариях. Будем использовать такую таблицу.
банк | валюта | значение |
Сбербанк | USD | 75 |
Сбербанк | EUR | 90 |
ВТБ | USD | 73 |
ВТБ | EUR | 88 |
Первая нормальная форма (1NF)
Основные критерии:
- Все строки должны быть различными.
- Все элементы внутри ячеек должны быть атомарными (не списками).
Другими словами, элемент является атомарным, если его нельзя разделить на части, которые могут использовать в таблице независимо друг от друга.
Методы приведения к 1NF:
- Устраните повторяющиеся группы в отдельных таблицах (одинаковые строки).
- Создайте отдельную таблицу для каждого набора связанных данных.
- Идентифицируйте каждый набор связанных данных с помощью первичного ключа (добавить уникальный id для каждой строки).
id | банк | валюта | значение |
1 | Сбербанк | USD | 75 |
2 | Сбербанк | EUR | 90 |
3 | ВТБ | USD | 73 |
4 | ВТБ | EUR | 88 |
Вторая нормальная форма (2NF)
Основные критерии:
- Таблица должна находиться в первой нормальной форме.
Любое её поле, не входящее в состав первичного ключа, функционально полно зависит от первичного ключа. Ваша таблица приведена к первой нормальной форме и у нее установлен уникальный id для каждой строки, то она находится и во второй нормальной форме.
Методы приведения к 2NF:
- Создайте отдельные таблицы для наборов значений, относящихся к нескольким записям.
- Свяжите эти таблицы с помощью внешнего ключа.
Name_banks
id | банк |
1 | Сбербанк |
2 | ВТБ |
Name_valute
id | валюта |
1 | EUR |
2 | USD |
Третья нормальная форма (3NF)
Основные критерии:
- Таблица находится во второй нормальной форме.
Любой её не ключевой атрибут функционально зависит только от первичного ключа. Проще говоря, второе правило требует выносить все не ключевые поля, содержимое которых может относиться к нескольким записям таблицы в отдельные таблицы.
Методы приведения к 3NF:
- Удаление полей не зависящих от ключа.
Valute
id | id банк | id валюта | значение |
1 | 1 | 1 | 75 |
2 | 1 | 2 | 90 |
3 | 2 | 1 | 73 |
4 | 2 | 2 | 88 |
Настройка связи между таблицам
Для этого нам понадобится foreign keys (внешний ключ). Можно настраивать мышкой через клиента управления бд, а можно с помощью запроса. Вначале разберем вариант добавления через интерфейс.
Вначале выбираем общею таблицу, в моем случае это «valute», затем переходим в настройки таблицы и ищем там вкладку Foreign keys, там настраиваем поля как у меня на скриншоте выше.
- Name — название правила.
- Fields — выбираем колонку, для которой создаем это правило.
- Referenced Schema — выбираем БД.
- Referenced Table — выбираем таблицу для которой настраиваем связь.
- Referenced Fields — выбираем колонку в этой таблицу.
- On Delete — если cascade, то при удалении строки из таблице valute, удалится строчка и из связующей таблицы.
- On Update — …
Все клиенты плюс-минус одинаковы, так что можете воспользоваться любым. Теперь давайте рассмотрим то же самое с помощью запроса.
ALTER TABLE `parser_valute`.`valute` ADD CONSTRAINT `fk_id_valute` FOREIGN KEY (`id_valute`) REFERENCES `parser_valute`.`name_valute` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
Теперь если выполнить обычный SELECT то получим таблицу следующего вида:
id | id банк | id валюта | значение |
1 | 1 | 1 | 75 |
2 | 1 | 2 | 90 |
3 | 2 | 1 | 73 |
4 | 2 | 2 | 88 |
Не совсем информативно. Хотелось бы видеть названия банка и название валюты. Для этого есть INNER JOIN. Выполним следующий запрос.
SELECT valute.id, name_bank, name_valute, rezult FROM valute INNER JOIN name_banks ON valute.id_banks = name_banks.id INNER JOIN name_valute ON valute.id_valute = name_valute.id
Получаем таблицу в читаемом виде.
id | name_bank | name_valute | rezult |
1 | Сбербанк | USD | 75,00 |
2 | ВТБ | USD | 73,00 |
3 | Сбербанк | EUR | 90,00 |
4 | ВТБ | EUR | 88,00 |
LEFT JOIN — Выводим все результаты которые есть.
Агрегирующие функции
SELECT * FROM valute; SELECT count(*) FROM valute; // количество строк SELECT sum(rezult), min(rezult), max(rezult) FROM valute; group by
Транзакции
Иногда требуется обязательно выполнить команду. Т.е. у вас есть два запроса, нужно чтобы оба запроса выполнились 100%. Списание и пополнение денег в личном кабинете пользователя. Для этого есть следующая команда:
START TRANSACTION; UPDATE ... UPDATE ... COMITСледующая