- •Лекция №1 Введение. Основные понятия.
- •Субд ms Access
- •Лекция 2. Системы управления бд
- •1. Файловые системы.
- •2. История развития.
- •3. Функции субд
- •4. Типовая организация современной субд
- •5. Архитектура многопользовательских субд.
- •Лекция №3 Процесс разработки бд.
- •Логическая структура бд преобразуется в физическую с учетом аспектов производительности. Элементы модели "сущность-связь"
- •Основные понятия er-диаграмм
- •Пример разработки простой er-модели
- •Концептуальные и физические er-модели
- •Лекция №4 Реляционная модель данных
- •Аномалии отношений
- •Лекция №5 Нормализация отношений
- •4Нф (Четвертая Нормальная Форма)
- •Лекция №6 Реляционная алгебра.
- •Типы данных.
- •Создание таблиц.
- •Команды модификации.
- •Встроенные функции
- •Группировка и агрегаты.
- •Связи между таблицами.
- •Операторы работы с множествами
- •Подзапросы.
- •Условная логика
- •Представления и хранимые процедуры и триггеры.
- •Конструкция while
- •Транзакции и типы хранилищ бд.
- •Тестирование производительность InnoDb и MyIasm
- •Применение
- •Индексы.
- •1. Чтение данных с диска
- •2. Поиск данных в MySql
- •3. Сортировка данных
- •4. Выбор индексов в MySql
- •Уникальные индексы
- •5. Составные индексы
- •Устройство составного индекса
- •Поиск по диапазону
- •Сортировка
- •6. Использование explain для анализа индексов
- •Когда создавать индексы?
- •Администрирование сервера.
- •Разделение прав пользователей;
Связи между таблицами.
До сих пор мы работали с одной таблицей. Теперь посмотрим, как получать данные из нескольких таблиц. Большинство запросов все же обращены к двум, трем или даже более таблицам.
Чтобы получить информацию из нескольких таблиц их необходимо соединить. Соединений бывает несколько:
Внутреннее соединение
Внешнее соединение
Левое соединение
Правое соединение
Кросс-соединение
Для иллюстрации этих соединений рассмотрим две таблицы:
СОТРУДНИКИ |
||
ID |
ФИО |
ID_Отдел |
1 |
Иванов |
1 |
2 |
Петров |
2 |
3 |
Сидоров |
1 |
4 |
Лосев |
2 |
5 |
Чуркин |
3 |
6 |
Лисин |
5 |
7 |
Конев |
2 |
8 |
Попов |
2 |
9 |
Иваненко |
3 |
10 |
Туманов |
1 |
Отделы |
|
ID |
Наименование |
1 |
Бухгалтерия |
2 |
Снабжение |
3 |
Продажи |
4 |
Маркетинг |
Обратите внимание, что есть отдел маркетинга, в таблице Отделы, в этом отделе никто не работает и есть некто Лисин, который работает в отделе, который не существует.
Внутреннее соединение получит у нас данные из таблиц, но только те, для которых есть связные данные в каждой таблице. Запрос будет выглядеть следующим образом:
SELECT *
FROM сотрудники INNER JOIN отделы
ON Сотрудники.ID_Отдел = Отделы.ID;
Левое соединение. Левой таблицей считается таблица, которая в запросе встречается первая, вторая таблица будет правой. При левом соединении мы получим все записи из левой таблицы, независимо от того есть ли соответствующая запись в правой таблице. Если соответствующей записи не будет, мы получим в результате NULL значение. Запрос будет выглядеть следующим образом:
SELECT *
FROM сотрудники LEFT JOIN отделы
ON Сотрудники.ID_Отдел = Отделы.ID;
Правое соединение аналогично левому, только будут выведены все записи из правой таблицы.
Запрос будет выглядеть следующим образом:
SELECT *
FROM сотрудники RIGHT JOIN отделы
ON Сотрудники.ID_Отдел = Отделы.ID;
Внешнее соединение. Получим все записи из всех таблиц, и по возможности соответствующие записи из связных таблиц. Запрос будет выглядеть следующим образом:
SELECT *
FROM сотрудники FULL OUTER JOIN отделы
ON Сотрудники.ID_Отдел = Отделы.ID;
Кросс объединение. Соответствует операции произведения в реляционной алгебре. Условие связи отсутствует и мы получим всевозможные соответствия между двумя таблицами.
SELECT *
FROM сотрудники CROSS JOIN отделы ;
Рассмотрим пример.
Схема будет следующая:
Запрос для схемы:
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- Schema Lessons
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema Lessons
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `Lessons` DEFAULT CHARACTER SET utf8 ;
USE `Lessons` ;
-- -----------------------------------------------------
-- Table `Lessons`.`teachers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Lessons`.`teachers` (
`idteacher` INT NOT NULL,
`FIO` VARCHAR(100) NULL,
`DATA` DATE NULL,
PRIMARY KEY (`idteacher`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `Lessons`.`courses`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Lessons`.`courses` (
`idcourses` INT NOT NULL,
`title` VARCHAR(100) NULL,
`hour_count` INT NULL,
PRIMARY KEY (`idcourses`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `Lessons`.`lesson`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Lessons`.`lesson` (
`idlesson` INT NOT NULL,
`data` DATE NULL,
`class` CHAR(3) NULL,
`teachers_idteacher` INT NOT NULL,
`courses_idcourses` INT NOT NULL,
PRIMARY KEY (`idlesson`),
INDEX `fk_lesson_teachers_idx` (`teachers_idteacher` ASC),
INDEX `fk_lesson_courses1_idx` (`courses_idcourses` ASC),
CONSTRAINT `fk_lesson_teachers`
FOREIGN KEY (`teachers_idteacher`)
REFERENCES `Lessons`.`teachers` (`idteacher`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_lesson_courses1`
FOREIGN KEY (`courses_idcourses`)
REFERENCES `Lessons`.`courses` (`idcourses`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Заполним таблицу данными. Запрос на внесение данных:
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('1', 'WEB-мастеринг. Основы серверного программирования.', '100');
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('2', 'Web-маркетинг', '106');
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('3', 'Разработка WEB-приложений ASR.net', '134');
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('4', 'Базы данных', '146');
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('5', 'Основы С++', '96');
INSERT INTO `lessons`.`courses` (`idcourses`, `title`, `hour_count`) VALUES ('6', 'Современные языки программирования', '86');
INSERT INTO `lessons`.`teachers` (`idteacher`, `FIO`, `DATA`) VALUES ('1', 'Иванов Иван Иванович', '1982-10-12');
INSERT INTO `lessons`.`teachers` (`idteacher`, `FIO`, `DATA`) VALUES ('2', 'Петров Петр Петрович', '1970-12-12');
INSERT INTO `lessons`.`teachers` (`idteacher`, `FIO`, `DATA`) VALUES ('3', 'Лосев Игорь Викторович', '1975-08-08');
INSERT INTO `lessons`.`teachers` (`idteacher`, `FIO`, `DATA`) VALUES ('4', 'Чуркин Петр Иванович', '1991-01-13');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('1', '2016-11-07', '301', '1', '1');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('2', '2016-11-07', '302', '2', '1');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('3', '2016-11-07', '303', '3', '2');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('4', '2016-11-08', '301', '1', '2');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('5', '2016-11-08', '302', '2', '1');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('6', '2016-11-08', '303', '3', '4');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('7', '2016-11-09', '301', '1', '1');
INSERT INTO `lessons`.`lesson` (`idlesson`, `data`, `class`, `teachers_idteacher`, `courses_idcourses`) VALUES ('8', '2016-11-09', '302', '2', '5');
Требуется получить:
Кто из преподавателей читал курс 30 сентября
SELECT teachers.FIO FROM teachers
INNER JOIN lesson ON teachers.idteacher = lesson.teachers_idteacher
WHERE lesson.data = '2016-11-07';
Кто из преподавателей читает курсы WEB
SELECT distinct teachers.FIO, courses.title FROM teachers
INNER JOIN lesson ON teachers.idteacher = lesson.teachers_idteacher
INNER JOIN courses ON courses.idcourses = lesson. courses_idcourses
WHERE courses.title LIKE '%web%';
Какие курсы читает преподаватель Иванов
SELECT distinct courses.title FROM courses
INNER JOIN lesson ON courses.idcourses = lesson. courses_idcourses
INNER JOIN teachers ON teachers.idteacher = lesson.teachers_idteacher
WHERE teachers.FIO = 'Иванов Иван Иванович';
Когда последний раз преподаватели вели занятия
SELECT teachers.FIO, max(lesson.Data) FROM teachers
INNER JOIN lesson ON teachers.idteacher = lesson.teachers_idteacher
GROUP BY teachers.FIO;
Если есть преподаватели, которые курсы еще не читали, то записи о них отсутствуют в таблице уроков. Но что делать, если нам они тоже нужны в результате? Тогда соединение в запросе будет не внутренним, а левым:
SELECT teachers.FIO, max(lesson.Data) FROM teachers
LEFT JOIN lesson ON teachers.idteacher = lesson.teachers_idteacher
GROUP BY teachers.FIO;
