Вы находитесь на странице: 1из 10

1

Лабораторная работа №20


Запросы

Тема: Запросы
Цель: Изучение свойств и работу компонента TADOQuery, разработка
приложения SQL-монитор с применением операторов SQL.
Оборудование: IBM – совместимые компьютеры.
Место проведения: Компьютерный класс.
Техника безопасности: См. инструкцию.

Теоретическая часть
Язык запросов SQL.
SQL (Structured Query Language) – Это Язык Структурированных Запросов.
Он не такой богатый, как языки программирования высокого уровня. Тем не
менее, это язык, без владения которым программисту, работающему с базами
данных, не обойтись. Запросы, написанные на SQL, часто называют скриптами.
Эти скрипты можно непосредственно вводить в свойство SQL компонента-
запроса в момент проектирования приложения, а можно значение этого свойства
менять и в процессе прогона программы. Однако нередко используют и третий
способ: программист создает набор скриптовых файлов, в процессе работы
программа считывает из них SQL-инструкции в компоненты запросов и
выполняет их. Это простые текстовые файлы, созданные в любом редакторе
текстов, например, стандартном Блокноте Windows. Расширение может быть
любым, но традиционно используется *.sql.
Все это позволяет создавать гибкие программы. Если организации,
использующей ваше приложение, в дальнейшем потребуются какие-то новые
возможности, например, им нужно дополнительно создать еще один отчет, то
применение скриптовых файлов избавит вас от необходимости переделывать
программу, для этого достаточно будет написать скрипт.
В этой работе разберем работу основных операторов SQL, после чего вы
сможете создавать простые и сложные запросы и получать необходимые наборы
данных. Тем, кто пожелает расширить свои познания SQL, рекомендую пройти
соответствующий курс, посвященный этому языку, или прочитать книгу М.
Грубера «Понимание SQL». Книга описывает стандартный синтаксис языка SQL
и затрагивает все его возможности.
2

Команда SELECT
Команда SELECT является основой запроса. Большинство SQL-запросов
начинаются с нее.
Множество других команд вкладываются в блок SELECT. Полный
синтаксис этой команды таков:

SELECT * | { [ DISTINCT | ALL] <value expression>.,..} FROM { <table


name> [ <alias> ] }.,..
[ WHERE <predicate>]
[ GROUP BY { <column name> | <integer> }.,..] [ HAVING <predicate>]
[ ORDER BY { <column name> | <integer> }.,..];

Здесь используются следующие элементы:

Таблица 20.1. Элементы команды SELECT


Элемент Описание
<value Выражение, которое производит значение. Оно может
expression> включать имена столбцов.
<table name> Имя или синоним таблицы или представления
<alias> Временный синоним для <table name>, определенный в
этой таблице и используемый только в этой команде.
<predicate> Условие, которое может быть верным или неверным для
каждой строки или комбинации строк таблицы в
предложении FROM.
<column name> Имя столбца в таблице.
Число с десятичной точкой. В этом случае, оно показывает
<integer> <value expression> в предложении SELECT с помощью
идентификации его местоположения в этом предложении.

В простейшем случае применение команды SELECT выглядит так:

SELECT *
FROM Table_Name;

Звездочка указывает, что нужно показать все поля. Вместо звездочки можно
указать конкретное поле или поля, разделяя их запятыми. Иногда бывает, что
требуются данные из разных таблиц, которые имеют поля с одинаковым именем.
В этом случае, перед именем полей указывают имя таблицы, или ее псевдоним,
разделяя имена таблицы и поля точкой:

SELECT Field1, Table1.Field2, Table2.Field2…


FROM Table1, Table2;

Команда FROM определяет имена таблиц, из которых осуществляется


выборка данных. Если таблиц несколько, их имена разделяются запятыми. Иногда
3

таблицы имеют длинные имена. В этом случае бывает выгодно использовать


псевдонимы (alias) имен таблиц, указывая их через пробел после имени таблицы:

SELECT Field1, f.Field2, s.Field2


FROM Table1 f, Table2 s;

Команда WHERE
Команда WHERE позволяет использовать условие, которые может быть
верным или нет для каждой записи НД. Если условие верное, то запись
добавляется в набор данных, иначе отвергается. Давайте рассмотрим пример.
Загрузите SQL-монитор из прошлой лекции. Предположим, нам нужно получить
следующие данные на каждого сотрудника: Фамилия, Имя, Отдел, Должность.
Пишем соответственный SQL-запрос:

SELECT Фамилия, Имя, Отдел, Должность


FROM LichData, Doljnost;

Выполнив этот запрос, вы получите нечто непонятное. В полученном


наборе данных всем сотрудникам подряд присваивается вначале первая
должность, затем вторая, и так до конца. Другими словами, если у вас 10
сотрудников и 10 должностей, то вместо ожидаемых десяти записей вы получите
10 * 10 = 100 записей! Полученные данные называют недостоверными.
Чтобы избежать этого, существует команда WHERE, которая позволяет задать
условие выборки данных:

SELECT Фамилия, Имя, Отдел, Должность


FROM LichData, Doljnost
WHERE Ключ = Сотрудник;

Теперь все в порядке, отдел и должность соответствуют каждому


сотруднику. Мы указали, что нам нужны лишь те записи, значения которых в
поле «Ключ» одной таблицы соответствуют значениям в поле «Сотрудник»
другой таблицы. Полный синтаксис требует указания таблицы вместе с полем:

WHERE LichData.Ключ = Doljnost.Сотрудник;

Однако поскольку у нас в этих таблицах нет полей с похожими именами,


мы можем воспользоваться упрощенным вариантом. И в том, и в другом случае
мы получим одинаковый набор данных.
Как и в любом условии, здесь можно применять различные операторы
сравнения:
4

Таблица 20.2. Операторы сравнения


Оператор Описание
= Равно
> Больше
< Меньше
>= Больше или равно
<= Меньше или равно
<> Не равно

Кроме того, мы можем использовать логические операторы AND, OR и


NOT, формируя более сложные запросы:

SELECT Фамилия, Имя, Отдел, Должность


FROM LichData, Doljnost
WHERE (LichData.Ключ = Doljnost.Сотрудник) AND (Должность =
"Бухгалтер");

Логические операторы имеют более высокий приоритет, поэтому в


приведенном примере можно обойтись и без скобок. Данный запрос выдаст нам
данные только на бухгалтеров. Как вы могли заметить, в отличие от Delphi,
строка в SQL заключается не в одинарные, а в двойные кавычки! Однако SQL
более демократичен, одинарные кавычки тоже принимаются. Обычно их
используют, если внутри строки требуется указать кавычки, например, ‘Строка “в
кавычках” будет отображена’.
Еще следует заметить, что подобное связывание таблиц не требует наличия
индексных полей. Но если такие поля есть, механизм доступа к данным будет их
использовать для более эффективной выборки данных.

Команда ORDER BY
Команда ORDER BY позволяет сортировать записи по определенному
полю как в возрастающем, так и в убывающем порядке. Воспользуемся
предыдущим примером, и отсортируем записи по полю «Фамилия»:

SELECT Фамилия, Имя, Отдел, Должность


FROM LichData, Doljnost
WHERE Ключ = Сотрудник
ORDER BY Фамилия;

Как уже говорилось, мы можем сортировать данные как по возрастанию


(ASC), так и по убыванию (DESC) значений. Сортировка по возрастанию
установлена «по умолчанию», а вот чтобы сортировать записи по убыванию,
после имени поля следует поставить служебное слово DESC:

ORDER BY Фамилия DESC;


Опять заметим, что для сортировки записей наличие индексных полей
5

необязательно. Часто бывает, что нужно вывести данные из двух таблиц,


имеющих связь один-ко-многим. При этом нужно сортировать данные не по
одному, а по двум полям:

SELECT Фамилия, Имя, Телефон, Примечание


FROM LichData, Telephones
WHERE Ключ = Сотрудник
ORDER BY Фамилия, Телефон;

В этом случае мы получим набор данных, в котором записи отсортированы


вначале по фамилии сотрудника, затем по его номеру телефона:

Рис. 20.1. Двойная сортировка данных

Оператор IN
Оператор IN позволяет определить набор значений. Предположим, нам
нужны сотрудники, проживающие в городах Москва и Санкт-Петербург. Мы
можем сформировать сложный запрос:

SELECT Фамилия, Имя, Город


FROM LichData, Adres
WHERE Ключ = Сотрудник AND (Город = "Москва" OR Город = "Санкт-
Петербург");

Последнюю строку запроса можно упростить, если использовать оператор


IN:
WHERE Ключ = Сотрудник AND Город IN ("Москва", "Санкт-Петербург");

Если бы запрос был организован по десятку городов, то запрос был бы со


сложным условием, если не использовать IN! При перечислении строк можно
использовать как двойные, так и одинарные кавычки, при перечислении числовых
значений кавычки не нужны. Все значения разделяются запятой.

Оператор BEETWEEN
Оператор BEETWEEN работает примерно так же, как IN, но задает не
список, а диапазон значений. Предположим, нам нужно выявить сотрудников,
которые имеют стаж работы от 4 до 10 лет включительно. Подобный запрос
выглядит так:

SELECT Фамилия, Имя, Стаж


FROM LichData
6

WHERE Стаж BETWEEN 4 AND 10;

Оператор LIKE
Оператор LIKE работает только с символьными и строковыми полями.
Этот оператор позволяет находить записи, имеющие заданную подстроку.
Предположим, нам требуется вывести всех сотрудников, чья фамилия начинается
на букву «Л». Запрос будет таким:

SELECT Фамилия, Имя, Отчество


FROM LichData
WHERE Фамилия LIKE 'Л%';

Следует учитывать, что оператор LIKE чувствителен к регистру букв. Если


вы будете производить поиск записи в программе при помощи SQL-запроса,
позаботьтесь заранее привести буквы к нужному регистру.
Оператор LIKE использует маску символов, что позволяет задавать
довольно сложные условия.
Маска может иметь два специальных символа:
▪ «_» - Символ подчеркивания обозначает, что в этом месте должен
быть любой символ. Например, «м_р» может выводить такие слова, как «мир»,
«мор» или «мур», но не сможет вывести слово «мера».
▪ «%» - Символ процента обозначает, что в этом месте может быть
любое количество любых символов. Например, маска '_и_и%' выведет такие
фамилии, как Лисичкин, Синичкин, Милиев.

Агрегатные функции
Агрегатные функции используются в запросах SQL, чтобы из группы
записей сформировать одиночное значение одного поля. Имеются следующие
агрегатные функции:
AVG – Функция возвращает среднее арифметическое значение из всех
значений данного поля. Предположим, нам требуется выяснить средний стаж всех
сотрудников предприятия. Такие данные могут быть сформированы следующим
запросом:

SELECT AVG (Стаж)


FROM LichData;

MAX – Функция возвращает максимальное значение указанного поля.


Синтаксис аналогичен функции AVG.
MIN – Функция возвращает минимальное значение указанного поля.
Синтаксис аналогичен функции AVG.
SUM – Функция возвращает максимальное значение указанного поля.
Синтаксис аналогичен функции AVG.
COUNT – Функция возвращает общее количество строк, сформированных
запросом. В нашем случае это количество будет равно количеству сотрудников.
7

Однако так называемые NULL-строки, то есть строки без значения, функция не


учитывает. Если у какого-то сотрудника нет указания стажа его работы, то
COUNT вернет меньшее количество, чем имеется сотрудников на предприятии.
Синтаксис аналогичен функции AVG.

При выполнении запросов с применением функций MAX, MIN, SUM,


COUNT, AVG, полям в которых отображаются данные, не задаются имена, чтобы
исправить эту ситуацию при выполнении выше перечисленных функций добавить
в запрос следующие данные (Среднее, Максимальное, Минимальное и т.д) в
соответствием с выбранной функции.

SELECT AVG (Стаж) AS Среднее


FROM LichData;

С помощью агрегатных функций можно формировать более сложные


значения. Предположим, у нас есть таблица покупателей. В ней указан
покупатель, код приобретенного товара, его стоимость и количество. Если
требуется, например, вычислить общую сумму проданного товара, то можно
выполнить запрос:

SELECT SUM (Стоимость * Количество)


FROM Pokupateli;

В скобках функции указаны нужные параметры. Вначале для каждой записи


вычисляется значение, в нашем случае, значение поля «Стоимость» умножается
на значение поля «Количество». Таким образом, мы находим общую сумму,
которую заплатил данный покупатель. Обойдя все поля таблицы, получим все
суммы всех покупателей, после чего функция SUM вернет нам общую сумму,
полученную от всех покупателей.
В выражении агрегатных функций может участвовать любое количество
полей таблицы, а само выражение может быть сколь угодно сложным, содержать
различные арифметические операции, иметь вложенные скобки и т.д.

Команда GROUP BY
Команда GROUP BY позволяет группировать записи по какому-то
определенному значению, и применяется совместно с агрегатными функциями.
Предположим, нам требуется не просто получить средний стаж всех сотрудников,
а еще и разбить эти данные по отделам. Вдруг директору захочется узнать, в
каком отделе у него работает больше всего молодых или старых специалистов! В
нашу задачу входит выявить средний стаж сотрудников для каждого имеющегося
отдела. Это мы можем выявить таким запросом:

SELECT AVG(Стаж), Отдел


8

FROM LichData, Doljnost


WHERE Ключ = Сотрудник
GROUP BY Отдел;

Как видите, команда GROUP BY используется после команды WHERE и


группирует записи по значению поля «Отдел». В результате получим таблицу из
двух полей. Первое поле будет сформировано агрегатной функцией, второе поле
«Отдел» из таблицы Doljnost. Для каждого отдела будет рассчитано среднее
значение поля «Стаж».
Команда GROUP BY позволяет группировать записи не только по одному,
но и по множеству полей. Предположим, одну и ту же должность могут иметь
несколько человек (например, пять бухгалтеров в бухгалтерии). Нам требуется
найти самого старого сотрудника не только по отделу, но и по занимаемой
должности. Нас выручит следующий запрос:

SELECT Отдел, Должность, MAX(Стаж)


FROM LichData, Doljnost
WHERE Ключ = Сотрудник
GROUP BY Отдел, Должность;

В результате мы получим набор данных, сгруппированный не только по


отделам, но и по должностям. Если должность занимает только один человек, то
мы получим его стаж. Если несколько – то наибольший из них.

Команда DISTINCT | ALL


Команда DISTINCT (Отличие) предназначена для удаления избыточных
(дублирующих) данных. Предположим, нам нужно получить список отделов на
предприятии. Мы можем воспользоваться запросом:

SELECT Отдел
FROM Doljnost;

Однако поле «Отдел» не является уникальным в этой таблице, то есть, если


в отделе работает десяток специалистов с разными должностями, то мы получим
десяток повторяющихся записей. Команда DISTINCT позволяет убрать такие
избыточные данные:

SELECT DISTINCT Отдел


FROM Doljnost;

В результате мы получим все названия имеющихся отделов, но эти названия


не будут повторяться.
Обратной командой является ALL, принятая по умолчанию. Если вы не
используете DISTINCT, то автоматически используется ALL (то есть,
9

показываются все записи).

Команда HAVING
Команда HAVING позволяет определить условия, чтобы удалить
определенные группы из полученного набора данных, точно так же, как команда
WHERE делает это для отдельных записей. Предположим, нам нужно получить
максимальный стаж работы по каждой должности, как это мы делали выше, но
при этом указать, что этот максимальный стаж должен быть более 7 лет.
Следовательно, если на какой-то должности работают молодые сотрудники,
имеющие меньший стаж работы, эта должность не будет приниматься. Для
задания условия мы обычно используем команду WHERE, но в этой команде
нельзя использовать агрегатные функции, формирующие значение из группы
записей. Другими словами, запрос, подобный этому:

SELECT Отдел, Должность, MAX(Стаж)


FROM LichData, Doljnost
WHERE Ключ = Сотрудник AND (MAX(Стаж) > 7)
GROUP BY Отдел, Должность;

вызовет ошибку. Использование в запросе команды HAVING решает эту


проблему:

SELECT Отдел, Должность, MAX(Стаж)


FROM LichData, Doljnost
WHERE Ключ = Сотрудник
GROUP BY Отдел, Должность HAVING MAX(Стаж) > 7;

Мы изучили все основные команды SQL-запросов. На основе этих команд


можно создавать запросы любой сложности. Однако еще раз заметим, что
хорошие знания языка SQL позволят вам создавать более гибкие и мощные
приложения, так что не ленитесь, изучайте SQL. Ведь вам наверняка придется
создавать клиент-серверные базы данных, а в этой архитектуре вся работа с
данными осуществляется только посредством SQL.
10

Задание
Добавить в приложение, разработанное в Лабораторной работе №20,
контекстное меню (или другой компонент), выполняющее перечисленные
запросы.

Студент должен знать: Основные положения теории баз данных, хранилищ


данных, баз знаний, создание базы данных, операторы языка SQL
Студент должен уметь: Создавать объекты баз данных в современных
системах управления базами данных, разработать проект с выполнением запросов
с помощью операторов языка SQL.