Министерство образования и науки Российской Федерации
Федеральное агентство по образованию
Санкт-Петербургский государственный университет
информационных технологий, механики и оптики
А.А. Бобцов, В.В. Шиегин
Банки и базы данных.
Основы работы с MS Access.
Часть 2 (для разработчиков)
Учебное пособие
Санкт-Петербург
2005
УДК 681.3 Бобцов А.А., Шиегин В.В. Банки и базы данных. Основы работы с MS Access.
Часть 2 (для разработчиков). Учебное пособие. – СПб., 2005. - 57 с.
Рецензенты: Л.С. Лисицына, к.т.н., доцент, зав. каф. КОТ СПбГУ ИТМО А.В. Лямин, к.т.н., доцент, директор ЦДО СПбГУ ИТМО Учебное пособие предназначено для дисциплины ОПД.Ф.14 “Банки и базы данных” для специальности 230202 – «Информационные технологии в образовании», а также для курсов повышения квалификации работников образования по программам соответствующего содержания.
Учебное пособие является продолжением Части 1 (для пользователей) и дает читателю знания, необходимые при проектировании и реализации баз данных на основе офисного пакета MS Access.
Методы проектирования и анализа моделей баз данных, рассмотренные в пособии, применимы в любой реляционной системе управления базами данных.
Печатается по решению УМС факультета ИТиП СПбГУ ИТМО © Санкт-Петербургский государственный университет информационных технологий механики и оптики, © Кафедра компьютерных образовательных технологий, © Бобцов А.А., Шиегин В.В., Содержание Введение
1. Язык SQL
1.1. SQL в простых запросах на извлечение данных
1.2. Подробнее о синтаксисе SQL
2. Основы проектирования баз данных
2.1. Модель «сущность-связь»
2.2. Реляционная модель данных
2.3. Нормализация
Приложение 1. Справочные сведения
Приложение 2. Практические задания
Задание 1. Создание запросов на языке SQL (часть 1, знакомство)
Задание 2. Создание запросов на языке SQL (часть 2, углубленное изучение)
Задание 3. Проектирование базы данных
Литература
Введение Данное учебное пособие знакомит с основами проектирования и реализации баз данных на основе офисного пакета MS Access. Пособие ориентировано на обучаемых, имеющих опыт программирования и может служить методической поддержкой практических занятий. За время обучения будут рассмотрены следующие темы:
• назначение и возможности языка структурированных запросов SQL;
• применение языка SQL при создании запросов и других объектов баз данных;
• синтаксис SQL-операторов в системе управления базами данных (СУБД) MS Access;
• типы данных, функции и операции, применяемые в MS Access;
• проектирование реляционных баз данных (построение модели, задача нормализации).
Данное пособие является продолжением пособия [1]. Предполагается, что читатель знаком с изложенным там материалом. Другие источники, перечисленные в списке литературы, также могут быть полезны для более подробного изучения вопросов проектирования и реализации баз данных.
Аббревиатура SQL означает Structured Query Language (структурированный язык запросов). Синтаксис SQL разрабатывался для удобства формирования запросов «близко к естественному английскому». Предполагалось, что его смогут использовать рядовые пользователи баз данных.
В настоящее время пользователи обычно общаются с БД через более удобный интерфейс клиентских приложений, но взаимодействие между приложением и СУБД часто происходит с использованием SQL. Составленный запрос на языке SQL передается клиентом серверу, на сервере производится его выполнение, после чего клиенту передается сформированный результирующий набор.
В системах «клиент-сервер» SQL чрезвычайно удобен, поскольку позволяет выполнить достаточно сложную обработку на сервере, без передачи промежуточных данных клиенту.
Существуют несколько стандартов языка [6] (различающихся временем их опубликования), но его реализация в различных СУБД может не полностью соответствовать этим стандартам.
В Access при обращении к БД также применяется язык SQL (Access изнутри организован по системе «клиент-сервер»). Любой запрос, построенный с помощью мастера или конструктора, имеет соответствующее представление на языке SQL. Конструктор – лишь визуальное средство для создания запросов. В Access имеется возможность редактировать запросы непосредственно в режиме SQL. Причем, не всякий составленный на SQL запрос, может быть отображен в режиме конструктора – SQL имеет более широкие возможности, чем визуальный конструктор.
Для переключения режимов отображения запросов используется кнопка «Вид» панели инструментов.
На рис. 1.1 показано, как выглядит один и тот же запрос в трех различных режимах – конструктора, таблицы и SQL. При освоении языка SQL бывает полезно составить запрос с помощью конструктора, а затем просмотреть или модифицировать его в режиме SQL.
Запрос на языке SQL может быть напрямую задан в свойствах «Источник записей» или «Источник строк» элементов форм и отчетов. Это позволяет обойтись без создания отдельного объекта «Запрос».
Кроме того, SQL используется при работе с внешними источниками данных (например, СУБД Oracle или Microsoft SQL Server). Однако, в этом случае используется уже синтаксис SQL этих СУБД, а не «внутренний» SQL.
1.1. SQL в простых запросах на извлечение данных Чаще всего возникает задача построения запросов на извлечение данных.
Для этих целей используется SQL-оператор SELECT. С него мы и начнем изучение языка SQL.
Простейшая форма оператора SELECT
SELECT
FROM ;Список полей – имена полей (столбцов), которые следует извлечь из источников (таблиц) и поместить в результирующий набор.
Пример 1.1.
SELECT Фамилия, Имя, Отчество FROM Клиент;
Результат работы этого запроса:
Смысл этого запроса таков: извлечь поля «Фамилия», «Имя», «Отчество» из таблицы «Клиент».
Пример 1.2.
SELECT * FROM Клиент;
Результат работы запроса:
Звездочка («*») означает «все поля» - если нужно извлечь не одно или несколько конкретных полей из таблицы, а все имеющиеся поля, не требуется перечислять их поименно.
Если говорить более точно, то простейшая форма оператора SELECT может не содержать даже предложения FROM.
Пример 1.3.
SELECT 123, “qwerty”, Date();
Результатом этого запроса будет строка, содержащая 3 столбца – число, текстовое значение и текущую дату (в предложении SELECT указываются не имена столбцов, а константы или выражения, возвращающие конкретные значения). Здесь нет предложения FROM, поскольку для получения данных не используются никакие источники (таблицы или запросы).
Использование нескольких источников (таблиц).
Пример 1.4. Есть две таблицы Построим запрос, выводящий фамилии клиентов и коды журналов.
SELECT Клиент.Фамилия, Подписка.КодЖурнала FROM Клиент, Подписка;
Результат представляет собой декартово произведение исходных таблиц.
Каждая запись таблицы «Клиент» объединяется с каждой записью таблицы «Подписка»
Следует ограничить результирующее множество комбинациями только тех записей этих двух таблиц, которые связаны между собой (содержат одинаковые значения в полях «КодКлиента»).
В предложении «FROM» вместо оператора объединения «,» (запятая) будем использовать оператор «INNER JOIN» - внутреннее объединение. Оператор «INNER JOIN» позволяет наложить ограничение на объединяемые записи.
Предложение ON определяет связь между полями объединяемых таблиц.
SELECT Клиент.Фамилия, Подписка.КодЖурнала FROM Клиент INNER JOIN Подписка ON Клиент.КодКлиента = Подписка.КодКлиента;
Результат содержит только комбинации записей, для которых выполняется заданное условие.
Рассмотрим подробнее разные виды объединения.
• INNER JOIN (внутреннее объединение). В результат включаются только те записи из обеих таблиц, которые связаны между собой.
• LEFT JOIN (левое внешнее объединение). В результат включаются все записи из первой таблицы. Если для них нет связанных записей во второй таблице, соответствующие поля результата будут пустыми.
• RIGHT JOIN (правое внешнее объединение). Операция, зеркально симметричная левому объединению. Включаются все записи из второй таблицы и связанные с ними записи из первой.
В режиме конструктора тип объединения можно изменить заданием свойств связи. Эта возможность была рассмотрена в [1], при описании работы с конструктором запросов. При создании запроса в режиме конструктора для таблиц, связи которых заданы в схеме данных, по умолчанию автоматически определяется операция «INNER JOIN».
Пример 1.5. Заменим в созданном запросе (пример 1.4) тип объединения на «LEFT JOIN».
SELECT Клиент.Фамилия, Подписка.КодЖурнала FROM Клиент LEFT JOIN Подписка ON Клиент.КодКлиента = Подписка.КодКлиента;
Результат работы измененного запроса:
Здесь присутствует фамилия «Федоров», для которой нет соответствий в таблице «Журнал». Вторая колонка этой строки содержит значение «Null»
(пусто).
Группировка, сортировка, имена столбцов. Продолжим доработку составленного запроса. Заметим, что фамилия «Иванов» в результатах запроса повторяется, поскольку для этого клиента оформлена подписка на два журнала.
Пример 1.6. Изменим запрос таким образом, чтобы фамилия каждого клиента выводилась только один раз, и для него отображалось общее количество выписанных журналов, а не коды каждого из журналов.
Зададим группировку записей по фамилии (фамилии не должны повторяться) и для групп определим групповую операцию «подсчет количества».
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала) FROM Клиент LEFT JOIN Подписка ON Клиент.КодКлиента = Подписка.КодКлиента GROUP BY Клиент.Фамилия;
Здесь подчеркнуты фрагменты, которые отличают этот запрос от предыдущего.
В предложении GROUP BY могут быть перечислены несколько полей через запятую. Если группировка производится по нескольким полям, объединяться в группу будут строки, для которых попарно равны значения всех группируемых полей. Для всех полей, перечисленных в предложении SELECT, но не вошедших в предложение GROUP BY, должны быть определены групповые операции.
Результат работы запроса:
Пример 1.7. Название второго столбца (в примере выше) сформировано автоматически. Надо задать осмысленное название. Кроме того, является лишь совпадением то, что фамилии расположены по алфавиту. Следует явно указать способ сортировки результирующего набора. Внесем соответствующие изменения в запрос.
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала) AS Количество FROM Клиент LEFT JOIN Подписка ON Клиент.КодКлиента = Подписка.КодКлиента GROUP BY Клиент.Фамилия ORDER BY Клиент.Фамилия ASC;
Результат работы запроса:
Ключевое слово AS указывает имя (псевдоним) для столбца. Если имя не задано явно, используется соответствующее ему имя поля исходной таблицы.
Если же столбец формируется с помощью некоторого выражения, Access присваивает ему имя самостоятельно (как было в предыдущем примере).
Псевдонимы можно задавать не только для столбцов, но и для источников данных (таблиц), указанных в предложении FROM. Тогда к ним можно обращаться внутри запроса по новому имени.
Параметры сортировки задаются в предложении ORDER BY. В предложении можно перечислять несколько полей через запятую. Сортировка будет выполняться сначала по первому полю, затем по второму (если совпадают значения первого поля) и т.п.
В предложении ORDER BY для каждого из столбцов может указываться одно из ключевых слов, задающих направление сортировки – ASC (по возрастанию) или DESC (по убыванию). Если направление не указано, подразумевается значение ASC.
Созданный запрос с точки зрения Access достаточно тривиален. Его можно просмотреть в режиме конструктора (как уже говорилось, все запросы, созданные в режиме конструктора могут быть представлены в режиме SQL, но не все, созданные в режиме SQL, могут быть представлены в режиме конструктора).
Линия связи, соединяющая таблицы, помечена стрелкой. Это указывает на то, что используется внешнее объединение, а не внутреннее.
Ограничение результирующих наборов. Оператор SELECT извлекает данные из одной или нескольких таблиц и из всех возможных комбинаций оставляет только те, которые соответствуют заданным критериям отбора.
Можно считать, что при этом последовательно выполняются две основные операции – умножение и сужение [5, 9 – 11, 13]. Умножение – построение всех возможных комбинаций записей (декартово произведение таблиц). Сужение (его также называют выборкой, ограничением или селекцией) – отсечение «лишних» комбинаций. Умножение выполняется в предложении FROM и там же с помощью слова ON может быть выполнено предварительное сужение (из всех комбинаций записей остаются только связанные между собой).
Для выполнения дальнейшего сужения в операторе SELECT могут присутствовать еще два вида предложений: WHERE и HAVING.
Предложение WHERE располагается после предложения FROM и позволяет наложить дополнительные ограничения на результат объединения. Ограничения, заданные словом ON иногда могут быть перенесены также в предложение WHERE.
Предложение HAVING может располагаться после предложения GROUP BY и применяться к данным каждой сформированной группы.
При использовании предложения HAVING без предложения GROUP BY, оно применяется ко всей результирующей таблице и действует аналогично предложению WHERE.
Пример 1.8. Дополним разработанный ранее запрос новыми ограничениями.
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала) AS Количество FROM Клиент LEFT JOIN Подписка ON Клиент.КодКлиента = Подписка.КодКлиента WHERE Left(Клиент.Фамилия,1) = "И" AND Подписка.КодЖурнала > GROUP BY Клиент.Фамилия HAVING Count(Подписка.КодЖурнала) > ORDER BY Клиент.Фамилия ASC;
В предварительный результат (после предложения WHERE) входят записи только для тех клиентов, фамилия которых начинается с «И» и при этом используются только журналы, коды которых больше «1». К сформированному набору применяется операция группировки. Уже после группировки исключаются те клиенты, у которых нет подписки (число выписанных журналов равно «0»), при подсчете количества не учитывается информация о подписке на журналы, исключенные ранее в предложении WHERE. То, что осталось, сортируется в алфавитном порядке.
Получившийся запрос не является оптимальным, он был составлен исключительно в демонстрационных целях. Например, способ объединения LEFT JOIN используется для включения фамилий клиентов, которые не имеют подписки. Поскольку такие клиенты все равно гарантированно не попадут в результирующий набор, вместо LEFT JOIN здесь вполне можно использовать INNER JOIN.
Общая форма оператора SELECT SELECT [DISTINCT] список_выражений|* [INTO новая_таблица] [FROM объединение_источников] [WHERE условие] [GROUP BY список_столбцов] [HAVING условие] [UNION [ALL] SELECT …] [ORDER BY список_столбцов] Некоторые входящие в состав оператора предложения были рассмотрены ранее на простых примерах. Ниже будут показаны более сложные конструкции.
Необязательное ключевое слово DISTINCT отвечает за то, чтобы в результирующем наборе не было полностью совпадающих строк (записей). Повторяющиеся строки будут исключены.
Вложенные запросы в предложении FROM. В операторе SELECT в предложении FROM перечисляются имена таблиц или запросов, которые являются источниками данных для этого запроса.
Пример 1.9.
SELECT Клиент.Фамилия, Подписка.Журнал FROM Клиент, Подписка Таблицы постоянно хранят данные, а запросы формируют временные результирующие наборы в форме таблиц в соответствии с определенными критериями отбора.
С точки зрения использования в качестве источников данных при составлении запроса, нет разницы между запросами и «постоянными» таблицами. В языке SQL есть возможность не только обращаться по имени к созданным ранее объектам – запросам, но и определять «вложенные» («подчиненные») запросы непосредственно внутри основного запроса.
Пример 1.10 (один из источников данных – вложенный запрос).
SELECT Клиент.Фамилия, Подписка2.Журнал FROM Клиент, (SELECT * FROM Подписка) AS Подписка Ключевое слово «AS» задает имя (псевдоним), по которому следует обращаться к полям временной таблицы, сформированной вложенным запросом, в пределах «главного» запроса.
Результаты работы запросов в первом и втором примерах идентичны. Вложенный запрос в данном случае не имеет практического смысла. Однако вложенные запросы могут иметь и более сложную структуру, и в некоторых ситуациях необходимы.
Вложенные запросы, в свою очередь, также могут содержать внутри себя вложенные запросы.
Пример 1.11 (трехуровневый запрос, действует аналогично двум предыдущим).
SELECT Клиент.Фамилия, Подписка2.Журнал FROM Клиент, (SELECT * FROM В операторе «SELECT», применяемом при создании вложенных запросов, могут быть использованы любые предложения, как и в операторах верхнего уровня («FROM», «WHERE», «GROUP BY», «ORDER BY» …).
Действующий пример с использованием вложенного запроса будет приведен ниже.
Вложенные запросы в предложении WHERE. Вложенные запросы могут быть использованы не только в качестве источников данных, но и в предложении WHERE, при определении ограничений результирующего набора.
Пример 1.12. Пусть существует таблица Зарплата(Номер, ФИО, Оклад) Запрос, выводящий ФИО и оклад работников, оклад которых выше среднего, может иметь следующий вид:
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад > (SELECT AVG(Оклад) FROM Зарплата) ORDER BY ФИО;
Для того чтобы выполнить проверку условия «выше среднего», требуется вычислить это самое среднее. Эту работу выполняет вложенный запрос, который обращается к той же самой таблице «Зарплата».
Вложенный запрос, для которого используются подобные операции сравнения, должен гарантированно выдавать только одну результирующую запись, состоящую только из одного столбца.
Пример 1.13. Запрос выводит список работников, получающих максимальный оклад:
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад = (SELECT MAX(Оклад) FROM Зарплата) ORDER BY ФИО;
Вместе с операциями сравнения могут быть использованы операторы ALL (все) и ANY (какой-нибудь). ALL требует, чтобы заданное условие выполнялось для всех записей из вложенного запроса, ANY - хотя бы для одной.
Пример 1.14. Запрос выполняет те же действия, что и предыдущий:
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад >= ALL (SELECT Оклад FROM Зарплата) ORDER BY ФИО;
При использовании операторов ALL и ANY, вложенный запрос может выдавать любое количество строк (записей), но в нем также должен быть только один столбец (запросы такого вида называют скалярными).
Пример 1.15. Вывести список работников, оклад которых НЕ САМЫЙ НИЗКИЙ (есть кто-то, кто получает еще меньше):
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад > ANY (SELECT Оклад FROM Зарплата) ORDER BY ФИО;
Пример 1.16. Эту же задачу можно решить иначе, без оператора ANY:
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад (SELECT MIN(Оклад) FROM Зарплата) ORDER BY ФИО;
Для работы с вложенными запросами также существуют операторы IN и NOT IN. Оператор IN требует, чтобы значение его левого аргумента содержалось в результирующем наборе правого аргумента (вложенного запроса). Оператор NOT IN имеет противоположное назначение.
Пример 1.17. Список работников с окладом выше среднего:
SELECT ФИО, Оклад FROM Зарплата WHERE Оклад NOT IN ( SELECT Оклад FROM Зарплата