
- •Разработка баз данных средствами MySql
- •Содержание
- •Введение
- •1. Основы работы в субд MySql
- •Системы управления базами данных
- •Основные характеристики MySql
- •Команда create database
- •Работа с таблицами
- •Синтаксис команды create table
- •Удаление таблиц
- •Синтаксис команды drop table
- •Типы данных
- •Числовые данные
- •Строковые данные
- •Календарные данные
- •Тип данных null
- •Выбор типа данных
- •1 Вариант.
- •2 Вариант.
- •3 Вариант.
- •2. Работа с таблицами. Ввод, извлечение, поиск и удаление данных Запись данных в таблицы
- •Заполните таблицу employee_data 5-10 записями. Запрос данных из таблицы MySql
- •Выборка данных с помощью условий
- •Операторы больше и меньше
- •Поиск текстовых данных по шаблону
- •Предложение group by и having
- •Удаление записей из таблицы
- •Задание 1
- •Задание 2
- •Задание 3
- •3. Логические операции в MySql
- •Операторы in и between
- •Упорядочивание данных
- •Ограничение количества извлекаемых данных
- •Извлечение подмножеств
- •Ключевое слово distinct
- •Изменение записей
- •Задание 1
- •Задание 2
- •Задание 3
- •Вычисление среднего значения
- •Именование столбцов
- •Подсчет числа записей
- •Группировка данных
- •5. Математические функции в MySql. Строковые функции. Работа с датой Математические функции MySql
- •Строковые функции
- •Ascii(строка)
- •Concat(строка1, строка2, ...)
- •Особенности типа данных Date
- •Операции с датами
- •Определение диапазонов
- •Использование Date для сортировки данных
- •Выбор данных с помощью Date
- •Текущие даты
- •Тип столбца Null
- •Задание 1
- •Задание 2
- •Задание 3
- •6. Переменные и временные таблицы. Многотабличные запросы
- •7. Вложенные запросы в MySql
- •8. Хранимые процедуры и функции
- •9. Курсоры в MySql. Представления. Конструкции управления потоком данных
- •10. Анализ и моделирование предметной области
- •1. Выбор и текстовое описание предметной области
- •2. Разработка концептуальной er-модели предметной области
- •3. Определение функциональных требований
- •11. Проектирование базы данных
- •1. Создание логической реляционной модели базы данных
- •2. Нормализация логической реляционной модели базы данных
- •1Нф (Первая Нормальная Форма)
- •2Нф (Вторая Нормальная Форма)
- •3Нф (Третья Нормальная Форма)
- •12. Проектирование физической модели бд и ее реализация
- •1. Создание физической модели базы данных
- •2. Реализация физической модели базы данных в коде
- •13. Наполнение и тестирование бд
- •1. Наполнение базы данных
- •2. Тестирование базы данных
- •14. Создание приложения к бд в среде delphi 7, с использованием AnyDac framework 1.7.0
- •1. Начало работы
- •2. Связь с таблицами
- •3. Отображение таблицы на форме
- •4. Компонент adQuery
- •5. Экспорт данных в Excel
- •6. Работа с внешними ключами
- •Рекомендуемая литература
- •Разработка баз данных средствами MySql
- •460844, Г. Оренбург, ул. Советская, 19
Задание 2
Вывести идентификаторы, даты рождения и адреса e-mail сотрудников, родившихся в апреле.
Вывести идентификаторы, даты рождения и имена супругов сотрудников, родившихся в 1968 г., и отсортируйте записи на основе имен их супругов.
Выведите идентификаторы сотрудников, родившихся в текущем месяце.
Сколько в базе данных имеется уникальных годов рождения?
Вывести список уникальных годов рождения и число сотрудников, родившихся в каждом таком году.
Сколько сотрудников родились в каждом месяце? Выдача должна содержать названия месяцев (не номера), и записи должны быть упорядочены по убыванию по месяцам, начиная от наибольшего номера.
Задание 3
Найти и вывести идентификаторы и имена супругов всех сотрудников, которые состоят в браке.
Изменить предыдущее задание так, чтобы вывод был отсортирован по именам супругов.
Сколько имеется сотрудников каждого пола (мужчин и женщин)?
Сколько сотрудников состоят в браке, и сколько холостых?
Найдите общее число детей.
Сделайте уникальные группы по количеству детей и определите число детей каждой группы. Отсортируйте вывод групп по убыванию по количеству детей.
6. Переменные и временные таблицы. Многотабличные запросы
Часто результаты запроса необходимо использовать в последующих запросах. Для этого полученные данные необходимо сохранить во временных структурах. Эту задачу решают переменные SQL и временные таблицы.
Переменные SQL
СУБД MySQL предоставляет возможность сохранения результатов текущего запроса для использования в следующих запросах в переменных SQL. Объявление переменных начинается с символа @, за которым следует имя переменной. Значения переменным присваиваются посредством оператора SELECT с использованием символа присваивания «:=».
Рассмотрим учебную базу данных, созданную для компьютерного магазина, торгующего комплектующими (скрипт test.sql).
База данных состоит из четырех таблиц:
Catalogs – список торговых групп; Products – товарные позиции; Users – список зарегистрированных пользователей; Orders – список осуществленных сделок.
Таблица сatalogs предназначена для хранения торговых групп, таких как «Материнские платы», «Процессоры», «Видеокарты» и т.п. Таблица состоит из двух полей:
id_catalog – уникальный номер;
name – имя раздела.
Таблица products содержит конкретные товарные позиции, такие как «Celeron 2.0GHz», «Intel Pentium 4 3.0GHz» и т.п. Таблица состоит из семи полей:
id_product – уникальный номер товарной позиции;
name – название товарной позиции;
price – цена;
count – количество товарных позиций на складе;
mark – относительная оценка товара;
description – описание;
id_catalog – номер торговой группы из таблицы catalogs, которой принадлежит товарная позиция.
Замечание: Обратите внимание, что в таблице products содержится поле id_catalogs, которое поддерживает связь с таблицей catalogs. Такие поля в теории баз данных называются внешними ключами.
Таблица users содержит записи с информацией о зарегестрирвоанных покупателях и состоит из восьми полей:
id_user – уникальный номер покупателя;
surname – фамилия покупателя;
patronymic – отчество покупателя;
name – имя покупателя;
phone – телефон покупателя (если имеется);
email – e-mail покупателя (если имеется);
url – домашняя страница покупателя (если имеется);
status – статус покупателя, поле типа ENUM, которое может принимать одно из четырех значений: авторизованный покупатель (active), неавторизованный покупатель (passive), заблокированный покупатель (lock) и активный покупатель (gold).
Таблица orders содержит информацию о покупках, совершенных в магазине, и включает пять полей:
id_order – уникальный номер сделки;
id_user – номер пользователя из таблицы users;
ordertime – время совершения сделки;
number – число приобретенных товаров;
id_product – номер товарной позиции из таблицы products.
Замечание: Обратите внимание, что все таблицы содержат уникальный идентификатор, который является первичным ключом таблицы.
Задание. Запустите скрипт на выполнение, рассмотрите структуру и ознакомьтесь с содержимым учебной базы. Вывите связи между таблицами, добавьте внешние ключи, постройте диаграмму и сохраните ее.
Пример. Объявление и использование переменных SQL
SELECT @total := COUNT(*) FROM `products`
@total := COUNT(*) |
30 |
SELECT @total
@total |
30 |
В примере объявляется переменная @total, которой присваивается число записей в таблице products учебной базы test. Затем в рамках текущего сеанса в последующих запросах появляется возможность использования этой переменной.
Замечание: Переменная действует только в рамках одного сеанса соединения с сервером MySQL и прекращает свое существование после разрыва соединения.
Переменные также могут объявляться при помощи оператора SET, например:
SET @last = CURDATE() - INTERVAL 7 DAY;
Просмотр SELECT CURDATE(), @last;
CURDATE() |
@last |
15.03.2007 |
2007-03-08 |
Удобство использования оператора SET заключаетмся в том, что он, в отличие от оператора SELECT, не возвращает результирующую таблицу.
Временные таблицы
Переменная SQL позволяет сохранить одно промежуточное знаечние. Когда необходимо сохранить результирующую таблицу, прибегают к временным таблицам.
Создание временных таблиц осуществляется при помощи оператора CREATE TEMPORARY TABLE, синтаксис которого ничем не отличается от синтаксиса оператора CREATE TABLE.
Временная таблица автоматически удаляется по завершении соединения с сервером, а ее имя действительно только в течение данного соединения. Это означает, что два разных клиента могут использовать временные таблицы с одинаковыми именами без конфликта друг с другом или с существующей таблицей с тем же именем (существующая таблица остается скрытой, пока не будет удалена временная таблица).
Содание временной таблицы temp:
CREATE TEMPORARY TABLE temp (id_catalog INT, name VARCHAR(50));
Просмотр структуры таблицы:
DESCRIBE temp;
Если возникает необходимость удалить таблицу до момента завершения соединения с сервером, можно воспользоваться оператором DROP TABLE.
Временные таблицы можно заполнять обычным способом, но наиболее удобно производить заполнение таких таблиц при помощи вложенных запросов, когда результат запроса SELECT непосредственно помещается во временную таблицу.
Содание временной таблицы temp при помощи вложенного запроса:
CREATE TEMPORARY TABLE temp
SELECT id_catalog, COUNT(id_catalog) AS total
FROM products GROUP BY id_catalog;
Просмотр результата SELECT * FROM temp.
id_catalog |
total |
1 |
9 |
2 |
6 |
3 |
4 |
4 |
5 |
5 |
6 |
Следует обратить внимание на тот факт, что при таком способе создания таблицы не требуется определять структуру таблицы temp – она автоматически принимает структуру результирующей таблицы оператора SELECT.
Временная таблица temp может выступать в качестве предмета запроса. Например, подсчитаем сумму значений столбца total.
SELECT SUM(total) FROM temp
SUM(total) |
30 |
Замечание: В MySQL 5.0.1 появилась серьезная альтернатива временным таблицам в виде представлений (Views). На самом деле представления часто также являются временными таблицами, только об их создании и уничтожении заботится СУБД MySQL.
Перекрестное соединение таблиц
Рассмотренные ранее SQL-запросы обращались к одной таблице. Но в реальных приложениях часто требуется использовать сразу несколько таблиц базы данных. Запросы, которые обращаются одновременно к нескольким таблицам, называются многотабличными запросами. Именно в таких запросах проявляется одно из преимуществ реляционных баз данных – связь таблиц друг с другом.
Рассмотрим несколько сложных запросов на примере учебной базы данных test.
Пусть, например, требуется вывести названия и цены всех жёстких дисков, имеющихся в магазине. Данную задачу можно решить, используя следующий запрос:
SELECT `products`.`name` , `products`.`price`
FROM `products`, `catalogs`
WHERE `products`.`id_catalog`=`catalogs`.`id_catalog` AND
`catalogs`.`name` = 'Жёсткие диски';
name |
price |
Maxtor 6Y120P0 |
2 456 |
Maxtor 6B200P0 |
3 589 |
Samsung SP0812C |
2 093 |
Seagate Barracuda ST3160023A |
3 139 |
Seagate ST3120026A |
2 468 |
Пусть требуется решить задачу подсчета товарных позиций, а также общего числа товаров на складе для каждого из каталогов:
SELECT `catalogs`.`name`, count(id_product), sum(count)
FROM `products`, `catalogs`
WHERE `products`.`id_catalog`=`catalogs`.`id_catalog`
group by `products`.`id_catalog`
name |
count(id_product) |
sum(count) |
Процессоры |
9 |
47 |
Материнские платы |
6 |
27 |
Видеоадаптеры |
4 |
17 |
Жёсткие диски |
5 |
26 |
Оперативная память |
6 |
85 |
Обратите внимание, что обязательным условием в данных запросах является равенство полей id_catalogs таблиц products и catalogs (`products`.`id_catalog`=`catalogs`.`id_catalog`). Именно при помощи данного условия осуществляется связь этих двух таблиц.
Среди таблиц учебной базы данных test примечательной является таблица orders, которая содержит внешний ключ id_product для связи с таблицей products и внешний ключ id_user для связи с таблицей users. Поэтому, чтобы результирующая таблица содержала данные заказа, фамилию покупателя и название товара, требуется осуществить трехтабличный запрос.
SELECT `orders`.`id_order`, `users`.`surname`, `orders`.`ordertime`, `products`.`name`
FROM `products`, `users`, `orders`
WHERE `products`.`id_product` = `orders`.`id_product` AND
`users`.`id_user` = `orders`.`id_user`
id_order |
surname |
ordertime |
name |
1 |
Симдянов |
04.01.2005 10:39 |
Intel Pentium 4 3.0GHz |
2 |
Корнеев |
10.02.2005 9:40 |
Gigabyte GA-8I848P-RS |
3 |
Иванов |
18.02.2005 13:41 |
Maxtor 6Y120P0 |
4 |
Симдянов |
10.03.2005 18:20 |
Maxtor 6Y120P0 |
5 |
Симдянов |
17.03.2005 19:15 |
Maxtor 6Y120P0 |
Если, кроме представленной информации, в результирующую таблицу необходимо поместить столбец с названием каталога, к которому относится выбранный товар, потребуется осуществить четырехтабличный запрос:
SELECT `orders`.`id_order`, `users`.`surname`, `orders`.`ordertime`, `products`.`name`, `catalogs`.`name`
FROM `products`, `users`, `orders`, `catalogs`
WHERE `products`.`id_product` = `orders`.`id_product` AND
`users`.`id_user` = `orders`.`id_user` AND
`catalogs`.`id_catalog` = `products`.`id_catalog`
id_order |
surname |
ordertime |
name |
name_1 |
1 |
Симдянов |
04.01.2005 10:39 |
Intel Pentium 4 3.0GHz |
Процессоры |
2 |
Корнеев |
10.02.2005 9:40 |
Gigabyte GA-8I848P-RS |
Материнские платы |
3 |
Иванов |
18.02.2005 13:41 |
Maxtor 6Y120P0 |
Жёсткие диски |
4 |
Симдянов |
10.03.2005 18:20 |
Maxtor 6Y120P0 |
Жёсткие диски |
5 |
Симдянов |
17.03.2005 19:15 |
Maxtor 6Y120P0 |
Жёсткие диски |
С увеличением количества таблиц в запросе резко возрастает объем работы, необходимой для выполнения запроса, поэтому по возможности в запросе не следует использовать больше трех-четырех таблиц.
Объединение таблиц при помощи JOIN
Оператор JOIN позволяет объединять таблицы и имеет многочисленные варианты использования, которые будут рассмотрены далее. В SQL-запросе данный оператор располагается между именами соединяемых таблиц после ключевого слова FROM. Без дополнительных ключевых слов соединение при помощи ключевого слова JOIN аналогично перекрестному соединению таблиц.
Например,
SELECT *
FROM `products`, `catalogs`
WHERE `products`.`id_catalog` = `catalogs`.`id_catalog`
SELECT *
FROM `products` JOIN `catalogs`
WHERE `products`.`id_catalog` = `catalogs`.`id_catalog`
Эти два запроса полностью идентичны. Для формирвоания условия а запросах, использующих объединение JOIN, вместо ключевого слова WHERE предпочтительно использовать ключевое слово ON, как это продемонстрирвоано ниже:
SELECT *
FROM `products` JOIN `catalogs`
ON `products`.`id_catalog` = `catalogs`.`id_catalog`
Замечание: Ключевое слово JOIN имеет два синонима: CROSS JOIN и INNER JOIN.
Помимо перекрестного соединения таблиц, предусмотрено левое и правое соединение таблиц, которое осуществляется при помощи конструкций LEFT JOIN и RIGHT JOIN соответственно.
При левом соединении результирующая таблица содержит комбинации строк обеих таблиц, удовлетворящих условию соединения и позволяет включить строки «левой» таблицы, которым не нашлось соответствия в «правой» таблице. При правом соединении возвращаются строки, удовлетворяющие условию соединения, и строки «правой» таблицы, которым не нашлось соединения в «левой» таблице.
Ключевое слово USING()
Другим способом установки связи между таблицами при правом и левом соединениях является использование ключевого слова USING(). В круглых скобках перечисляются имена столбцов, которые должны присутствовать в обеих таблицах и для которых необходимо соблюдение равенства. Данный оператор предназначен для создания более компактных SQL-запросов.
Например, при помощи JOIN … USING() извлечем число товарных позиций в каталоге.
SELECT `catalogs`.`name`, COUNT(id_product)
FROM `catalogs` JOIN `products` USING(id_catalog)
GROUP by `products`.`id_catalog`;
name |
count(id_product) |
Процессоры |
9 |
Материнские платы |
6 |
Видеоадаптеры |
4 |
Жёсткие диски |
5 |
Оперативная память |
6 |
Предположим, что происходит расширение ассортимента товарных позиций и в списке каталогов появляется новый каталог ‘Периферия’. SQL-запрос, добавляющий этот каталог:
INSERT INTO catalogs VALUES (null, 'Периферия');
Однако предыдущий запрос не отразит наличие нового каталога в электронном магазине, т.к. таблица products еще не содержит ни одной записи, относящейся к новому каталогу. Для того, чтобы название каталога ‘Периферия’ появилось в результирующей таблице, необходимо провести левое соединение таблиц catalogs и products, причем таблица catalogs должна выступать в качестве «левой» таблицы.
SELECT `catalogs`.`name`, COUNT(id_product)
FROM `catalogs` LEFT JOIN `products` USING(id_catalog)
GROUP by `products`.`id_catalog`;
name |
count(id_product) |
Периферия |
0 |
Процессоры |
9 |
Материнские платы |
6 |
Видеоадаптеры |
4 |
Жёсткие диски |
5 |
Оперативная память |
6 |
Пусть требуется вывести список покупателей и число осуществленных ими покупок, причем покупателей необходимо отсортировать в порядке убывания числа оплаченных ими заказов.
SELECT `users`.`surname`, `users`.`name`, `users`.`patronymic`, COUNT(`orders`.`id_order`) AS total
FROM `users` JOIN `orders` USING(id_user)
GROUP BY users.`id_user`
ORDER BY total DESC
surname |
name |
patronymic |
total |
Симдянов |
Игорь |
Вячеславович |
3 |
Иванов |
Александр |
Валерьевич |
1 |
Корнеев |
Александр |
Александрович |
1 |
Можно заметить, что в списке присутствуют только те покупатели, которые оплатили хотя бы одну покупку, покупатели, на счету у которых нет ни одной покупки, в список не входят. Для того, чтобы вывести полный список покупателей, необходимо вместо перескрестного соединения таблиц users и orders воспользоваться левым соединением, где в качестве «левой» таблицы выступит таблица users:
SELECT `users`.`surname`, `users`.`name`, `users`.`patronymic`, COUNT(`orders`.`id_order`) AS total
FROM `users` LEFT JOIN `orders` USING(id_user)
GROUP BY users.`id_user`
ORDER BY total DESC
surname |
name |
patronymic |
total |
Симдянов |
Игорь |
Вячеславович |
3 |
Иванов |
Александр |
Валерьевич |
1 |
Корнеев |
Александр |
Александрович |
1 |
Лосев |
Сергей |
Иванович |
0 |
Кузнецов |
Максим |
Валерьевич |
0 |
Нехорошев |
Анатолий |
Юрьевич |
0 |
Ключевое слово WHERE
Помимо условия USING, в запросах на соединение могут использоваться традиционные конструкции условия.
Например, составим запрос, который извлекает список покупателей и число их покупок при условии, что покупателя зовут «Александр».
SELECT `users`.`surname`, `users`.`name`, `users`.`patronymic`, COUNT(`orders`.`id_order`) AS total
FROM `users` LEFT JOIN `orders` USING(id_user)
WHERE name = 'Александр'
GROUP BY users.`id_user`
ORDER BY total DESC
surname |
name |
patronymic |
total |
Иванов |
Александр |
Валерьевич |
1 |
Корнеев |
Александр |
Александрович |
1 |
Для этого используется условие WHERE name = 'Александр'. Однако использовать столбец total в условии WHERE уже не получится, т.к. групповой столбец, сформированный агрегатной функцией COUNT() и конструкцией GROUP BY.
Для формирования условия с его участием необходимо использовать условие HAVING.
Пусть требуется извлечь всех покупателей магазина, число покупок (total) у которых меньше трёх:
SELECT `users`.`surname`, `users`.`name`, `users`.`patronymic`, COUNT(`orders`.`id_order`) AS total
FROM `users` LEFT JOIN `orders` USING(id_user)
GROUP BY users.`id_user`
HAVING total < 3
ORDER BY total DESC
surname |
name |
patronymic |
total |
Иванов |
Александр |
Валерьевич |
1 |
Корнеев |
Александр |
Александрович |
1 |
Лосев |
Сергей |
Иванович |
0 |
Кузнецов |
Максим |
Валерьевич |
0 |
Нехорошев |
Анатолий |
Юрьевич |
0 |
Задания
Замечание: При создании таблиц необходимо выбрать тип таблицы – InnoDB, так как это единственный тип который поддерживает внешние ключи и каскадное удаление.
Вариант 1
Создать БД, состоящую из таблиц АВТОР (Фамилия, имя, отчество, пол, дата рождения, телефон) и КНИГА (Название, цена, тематика, издательство, тираж). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы в предположении, что у книги может быть только один автор. Построить диаграмму и сохранить ее.
Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Вывести список авторов, работающих в издательстве «Мир».
Предположим, что не все зарегестрированные в БД авторы имеют изданные книги. Вывести список всех авторов с указанием тематики изданных книг.
Найти авторов, работающих как с издательством «Мир», так и с издательством «АСТ».
Рассчитать общую стоимость тиража и 5% налог с продаж для книг каждого автора.
На какую сумму были проданы книги каждого автора?
Определить число различных наименований проданных в издательстве «АСТ» книг, количество книг каждого наименования и вырученную сумму.
Вариант 2
Создать БД, состоящую из таблиц РЕЙС (№ рейса, конечный пункт, дата вылета, продолжительность маршрута) и БИЛЕТ (Номер места, дата продажи, фамилия пассажира). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы. Построить диаграмму и сохранить ее.
Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Вывести номера мест и дату продажи билетов на рейсы до Москвы.
Вывести список рейсов, на которые не были проданы билеты.
Составить список пассажиров, которые летают и в Москву, и в Киев.
Рассчитать общую стоимость билетов для каждого рейса, 5% налог с продаж и общий доход рейса.
Определить количество проданных на каждый рейс билетов.
На какую сумму были проданы билеты в день вылета?
Вариант 3
Создать БД, состоящую из таблиц БЛЮДО (Название, время приготовления, повар, стоимость_блюда) и КОМПОНЕНТ (Название, калорийность, вес, стоимость 100 гр). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы в предположении, что один определенный компонент принимает участие только в одном блюде. Построить диаграмму и сохранить ее.
Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Вывести список компонент, которые использует повар Иванов для приготовления своих блюд.
Вывести список поваров, использующих для приготовления блюд и масло и молоко.
Сформировать список поваров, которые используют масло, но обходятся без молока.
Рассчитать общую стоимость блюда по компонентам и его калорийность.
Для каждого повара определить количество используемых компонентов.
Для каждого повара определить колчество десертов и количество компонентов в каждом из них.