
- •Разработка баз данных средствами 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
7. Вложенные запросы в MySql
Вложенный запрос позволяет использовать результат, возвращаемый одним запросом, в другом запросе. Возможность применения одного запроса внутри другого и была причиной появления слова «структурированный» в названии «структурированный язык запросов» (SQL). Так как результат возвращает только оператор SELECT, то в качестве «вложенного» запроса всегда выступает SELECT-запрос. В качестве внешнего запроса может выступать запрос с участием любого SQL-оператора: SELECT, INSERT, UPDATE, DELETE и др.
Замечание: Термин «вложенный запрос» имеет различные варианты в русскоязычной литературе, такого рода запросы часто называют подчиненными запросами и подзапросами.
Замечание: Вложенные запросы появились в СУБД MySQL, начиная с версии 4.1
Рассмотрим учебную базу данных, которая является базой компьютерного магазина, торгующего комплектующими (скрипт test.sql).
Пусть требуется вывести название товарных позиций из таблицы products для раздела «Процессоры» таблицы catalogs. Решить эту задачу можно, например, при помощи двух SQL-запросов.
Первый запрос извлекает первичный ключ (id_catalogs) записи из таблицы catalogs, соответствующей каталогу «Процессоры».
SELECT @id:=id_catalog FROM `catalogs` WHERE name='Процессоры'
Второй запрос выводит названия товарных позиций и их цены для данного каталога.
SELECT name, price FROM `products`
WHERE id_catalog = @id
ORDER BY price
name |
price |
Celeron 1.8 |
1 595 |
Celeron D 315 2.26GHz |
1 880 |
Celeron D 320 2.4GHz |
1 962 |
Celeron 2.0GHz |
1 969 |
Celeron 2.4GHz |
2 109 |
Celeron D 325 2.53GHz |
2 747 |
Intel Pentium 4 3.0GHz |
5 673 |
Intel Pentium 4 3.0GHz |
6 147 |
Intel Pentium 4 3.2GHz |
7 259 |
Как видно из примера, промежуточное значение помещается в переменную @id. Вложенные запросы позволяют осуществить подобную выборку в одном запросе.
SELECT name, price FROM `products`
WHERE id_catalog = (SELECT @id:=id_catalog FROM `catalogs` WHERE name='Процессоры')
ORDER BY price;
Таким образом, результат вложенного запроса (id_catalog), минуя промежуточные переменные в MySQL или внешней программы, применяется в качестве элемента внешнего запроса. Вложенный запрос всегда помещается в круглые скобки.
Получить аналогичный результат можно при помощи многотабличного запроса:
SELECT `products`.name, `products`.price FROM `products`, `catalogs`
WHERE `catalogs`.id_catalog = `products`.`id_catalog` AND
`catalogs`.name='Процессоры'
ORDER BY price
В отличие от вложенного запроса, многотабличный запрос менее нагляден, хотя в ряде случаев выполняется быстрее, так как оптимизация многотабличных запросов происходит быстрее вложенных. В большинстве случаев запросы можно представить как при помощи одного из соединений (перекрестного, левого, правого), так и при помощи вложенных запросов, но все же имеется ряд задач, которые решаются только при помощи вложенных запросов.
Вложенный запрос может применяться не только с условием WHERE, но также в конструкциях DISTINCT, GROUP BY, ORDER BY, LIMIT, JOIN, UNION и др.
Вложенный запрос как скалярный операнд
В данном виде запроса вложенный запрос возвращает одно-единственное значение, которое используется во внешнем запросе. Такой вложенный запрос можно использовать в любом месте, где допустимо использование скалярного значения или литерала.
Пусть требуется определить название каталога, в котором присутствует самая дорогая товарная позиция
SELECT name FROM `catalogs`
WHERE id_catalog = (SELECT id_catalog FROM `products`
WHERE price = (SELECT MAX(price)
FROM `products`))
name |
Процессоры |
Как видно из примера, степень вложенности запросов не ограничивается вторым уровнем, могут использоваться трёхуровневые и многоуровневые вложенные запросы. Первый внутренний запрос определяет максимальную цену в таблице products:
SELECT MAX(price) FROM `products`
Внешний по отношению к нему запрос определяет значение первичного ключа (id_catalog) для товарной позиции с максимальным значением цены (7259.00):
SELECT id_catalog FROM `products` WHERE price = 7259.00
Полученное значение поля id_catalog (равное 1) подставляется во внешний запрос:
SELECT name FROM `catalogs` WHERE id_catalog = 1
Замечание: На практике редко прибегают к вложенным запросам со степенью вложенности больше трёх, так как большая степень вложенности быстро приводит к увеличению времени выполнения запроса.
Вложенные запросы, возвращающие несколько строк
Если вложенный запрос возвращает несколько строк, СУБД MySQL возвращает ошибку №1242 – вложенный запрос возвращает более чем одну строку.
Для того чтобы, например, выбрать строки из таблицы catalogs, у которых первичный ключ id_catalog совпадает с одним из значений, возвращаемых вложенным запросом, следут воспользоваться коснструкцией IN:
SELECT name FROM `catalogs`
WHERE id_catalog IN (SELECT id_catalog FROM `products`
GROUP BY id_catalog)
name |
Процессоры |
Материнские платы |
Видеоадаптеры |
Жёсткие диски |
Оперативная память |
Для того, чтобы возвратить строки, которые отстутствуют в результирующей таблице, возвращиемой вложенным запросом, следует воспользоваться оператором NOT IN.
Конструкция IN позволяет осуществить поиск величины в списке и выражает логику операции отношения «=». Однако на месте этой операции может стоять другой операция отношения. Для этого используется ключевое слово ANY
Например,
SELECT name FROM `catalogs`
WHERE id_catalog > ANY (SELECT id_catalog FROM `products`
GROUP BY id_catalog)
name |
Материнские платы |
Видеоадаптеры |
Жёсткие диски |
Оперативная память |
Вместо ключевого слова ANY может быть использовано ключевое слово ALL, которое точно так же используется совместно с одним из шести операций отношения («=», «<>», «<», «<=», «>», «>=»).
Например,
SELECT name, price FROM `products`
WHERE price > ALL (SELECT AVG(price) FROM `products`
GROUP BY id_catalog);
name |
price |
Intel Pentium 4 3.2GHz |
7 259 |
Intel Pentium 4 3.0GHz |
6 147 |
Intel Pentium 4 3.0GHz |
5 673 |
Asustek P4C800-E Delux |
5 395 |
ASUSTEK A9600XT/TD |
5 156 |
GIGABYTE AGP GV-N59X128D |
5 886 |
Для того чтобы понять логику запроса полезно выполнить вложенный запрос отдельно:
SELECT AVG(price) FROM `products` GROUP BY id_catalog
AVG(price) |
3482.333333 |
2801.166667 |
3843.500000 |
2749.000000 |
1417.000000 |
Условие ALL в примере эквивалентно требованию вывести все товарные позиции, цена которых больше каждого из значений результирующей таблицы запроса.
Проверка на существование
Результирующая таблица, которая возвращается вложенным запросом, может быть пустой, т.е. не содержать ни одной строки. Для проверки данного факта используются ключевые слова EXISTS и NOT EXISTS. Данные ключевые слова не требуют левого операнда, они просто сообщают, имеются ли в результирующей таблице строки или нет. Если вложенный запрос возвращает более одной строки, EXISTS возвращает 1 (истина), в противном случае ключевое слово возвращает 0 (ложь). Ключевое слово NOT EXISTS действует противоположным образом.
Замечание: Проверка на существование допустима только во вложенных запросах.
Например, пусть требуется вывести названия товарных позиций из таблицы products, которые были выбраны покупателями, т.е. для которых имеется отметка о покупке в таблице orders.
SELECT id_product, name, price FROM `products`
WHERE EXISTS (SELECT * FROM `orders`
WHERE `orders`.`id_product`=`products`.`id_product`)
id_product |
name |
price |
8 |
Intel Pentium 4 3.0GHz |
6 147 |
10 |
Gigabyte GA-8I848P-RS |
1 896 |
20 |
Maxtor 6Y120P0 |
2 456 |
Внешний запрос последовательно перебирает все строки таблицы products и для каждой товарной позиции выполняет вложенный запрос, который проверяет, имеется ли в таблице orders текущая товарная позиция. Число записей, которые возвращает вложенный запрос, может быть более одной.
Подзапросы в конструкции FROM
Так как вложенные запросы возвращают результирующую таблицу, которая становится предметом дальнейших запросов, стандарт SQL разрешает использование вложенных запросов везде, где допускаются ссылки на таблицы. В частности, вложенный запрос может указываться вместо имени таблицы в предложении FROM. В примере представлен запрос, в котором в качестве одной из таблиц используется результирующая таблица вложенного запроса.
SELECT usr.surname, usr.name, orders.`ordertime`
FROM `orders`,
(SELECT * FROM `users`) AS usr
WHERE `orders`.`id_user`=usr.id_user;
surname |
name |
ordertime |
Симдянов |
Игорь |
04.01.2005 10:39 |
Корнеев |
Александр |
10.02.2005 9:40 |
Иванов |
Александр |
18.02.2005 13:41 |
Симдянов |
Игорь |
10.03.2005 18:20 |
Симдянов |
Игорь |
17.03.2005 19:15 |
Ключевое слово AS, назначающее псевдоним результирующей таблице, является обязательным, т.к. каждая таблица в конструкции FROM должна иметь имя.
Задания
Вариант 1
Создать БД, состоящую из таблиц АВТОР (Фамилия, имя, отчество, пол, дата рождения, телефон) и КНИГА (Название, цена, тематика, издательство, тираж). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы.
Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Определить автора самой дорогой книги.
Определить авторов, не печатающих свои книги в издательстве «АСТ».
Определить авторов, написавших наибольшее количество книг.
Удалить информацию об авторах, не имееющих телефона.
Увеличить на 50% цену книг, вышедших в издательстве «АСТ».
Удалить сведения об авторах, чьи произведения не издаются.
Вариант 2
Создать БД, состоящую из таблиц РЕЙС (№ рейса, конечный пункт, дата вылета, продолжительность маршрута) и БИЛЕТ (Номер места, дата продажи, фамилия пассажира). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы. Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Определить список пассажиров, покупающих билеты на самые дальние рейсы.
Вывести список пассажиров, не летающих в Самару.
Определить, кто из пассажиров потратил наибольшую сумму на покупку авиабилетов.
Удалить данные о билетах, проданных за прошлый месяц.
Увеличить на 10% стоимость билетов на рейсы 23-45 и 56-78.
Удалить информацию о билетах, ошибочно проданных после вылета самолета.
Вариант 3
Создать БД, состоящую из таблиц БЛЮДО (Название, время приготовления, повар, стоимость_блюда) и КОМПОНЕНТ (Название, калорийность, вес, стоимость 100 гр). Дополнить первичными и внешними ключами, уточнить структуру и связать таблицы в предположении, что один определенный компонент принимает участие только в одном блюде.
Заполнить таблицы данными – 5-6 записей.
Реализовать следующие запросы:
Определить блюдо, которое можно приготовить быстрее всех остальных блюд.
Определить, кто из поваров не готовит десерт.
Определить самое калорийное блюдо.
Удалить сведения о блюдах, для которых не указаны имя повара или время приготовления.
Установить калорийность 100 ккал, для компонентов, у которых она не указана.
Удалить сведения о блюдах, стоимость которых меньше средней стоимости их компонентов.