Безопасность систем баз данных. Учебное пособие
.pdf
-> FROM gruppirovka
-> WHERE gruppirovka_name = "Potapovskaya"; mysql> SELECT gruppirovka_id id FROM gruppi-
rovka
-> WHERE gruppirovka_name = "Potapovskaya";
Рис. 7.4. Идентичные запросы
Рекомендуется применять ключевое словоAS, поскольку оно позволяет четко указать псевдоним столбца, особенно при выборе множества столбцов из списка, где они разделены запятыми.
Назовем еще несколько ограничений на использование псевдонимов. Они могут содержать любые символы, но их максимальная длина не должна превышать255 символов. Для псевдонимов использовать буквенно-цифровой набор символов в нижнем регистре и согласованном порядке — например, для разделения слов применяйте символы подчеркивания. Псевдонимы чувствительны к регистру на всех платформах.
Псевдонимы таблиц применяют по тем же причинам, что и псевдонимы столбцов, причем в некоторых случаях они представляют единственный способ выражения запроса. В этом разделе расскажем о принципах использования псевдонимов таблиц, а в разделе «Вложенные запросы» приведем примеры запросов, в которых псевдонимы таблиц играют весьма важную роль.
Представленный ниже базовый пример с псевдонимами таблиц наглядно демонстрирует, как можно экономить время на вводе данных (рис. 7.5):
mysql> SELECT gr.gruppirovka_id,
-> pr.prestupnik_name, gr.gruppirovka_name
-> FROM gruppirovka AS gr INNER JOIN prestup-
nik
81
-> AS pr USING (gruppirovka_id) -> WHERE pr.prestupnik_name = -> "Belov Aleksandr Petrovich";
Рис. 7.5. Псевдонимы таблиц
В этом примере для таблиц gruppirovka и prestupnik заданы соответственно псевдонимы gr и pr c использованием ключевого слова AS. Таким образом, выражаются имена столбцов в более компактном виде, например gr.gruppirovka_id. В данном случае название столбца начинается с названия таблицы и отделяется точкой. Обратите также внимание, что в отличие от псевдонимов столбцов можно применять псевдонимы таблиц в выражении WHERE. В отношении использования псевдонимов таблиц в запросах ограничений не существует. В данном примере ссылка на псевдонимы таблиц дается еще до их определения.
Как и в случае с псевдонимами столбцов, ключевое слово AS является опциональным. Инструкция:
gruppirovka AS gr INNER JOIN prestupnik AS pr
идентична инструкции:
gruppirovka gr INNER JOIN prestupnik pr
Тем не менее, мы предпочитаем использовать AS, поскольку так запрос будет легче понимать. Ограничения псевдонимов таблиц по длине такие же, как и для псевдонимов столбцов, и наши рекомендации по выбору псевдонимов остаются теми же.
Как ранее указывалось, псевдонимы таблиц позволяют писать запросы, которые в противном случае очень сложно выразить. Рассмотрим пример. Предположим, нужно узнать преступ-
ников, которые одновременно состоят в разных преступных группировках. Попробуем решить основную задачу, то есть определить, существуют ли преступники с одинаковыми фамилией,
82
именем и отчеством. Для этого можно ввести примерно следующее:
mysql> SELECT * FROM prestupnik WHERE -> prestupnik_name =
-> prestupnik_name;
Однако такой запрос не имеет смысла, поскольку в результатах будут представлены все преступники (рис. 7.6).
Рис. 7.6. Определение одинаковых фамилий
Как это сделать в одном запросе? Метод состоит в том, чтобы присвоить таблице два разных псевдонима, а затем сопоставить строки из таблиц, имеющих один и другой псевдоним: mysql> SELECT p1.prestupnik_name
-> FROM prestupnik AS p1, prestupnik AS p2
->WHERE p1.prestupnik_name=p2.prestupnik_name;(рис. 7.7)
83
Рис. 7.7. Сопоставление фамилий
В результате мы получили 17 преступников. Метод все еще не работает! Причина заключается в том, что преступник продолжает сопоставляться с самим собой, поскольку присутствует в обеих таблицах.
Запрос заработает правильно только в том случае, если преступник из таблицы с первым псевдонимом не будет сопоставляться с самим собой в таблице со вторым псевдонимом. Для этого следует указать, что преступники в каждой таблице не должны принадлежать одной преступной группировке:
mysql> SELECT p1.prestupnik_name
-> FROM prestupnik AS p1, prestupnik AS p2
-> WHERE p1.prestupnik_name=p2.prestupnik_name -> AND p1.gruppirovka_id <> p2.gruppirovka_id; Empty set (0.00 sec)
Теперь видно, что в базе данных нет преступников, входящих в разные преступные группировки.
7.2. Агрегирование данных
Агрегатные функции позволяют определять свойства для заданных групп строк. С их помощью, например, можно выяс-
84
нить, сколько всего строк присутствует в таблице или сколько строк в таблице имеют одно и то же свойство (скажем, одинаковое имя или дату рождения). Кроме того, агрегатные функции применяются для определения средних значений(к примеру, средней температуры в ноябре), а также для поиска максимального или минимального значения строк, соответствующих некоторому условию (допустим, определение самого холодного дня в августе).
Рассмотрим выражения GROUP BY и HAVING — команды SQL, чаще всего используемые для агрегации. Но вначале обсудим выражение DISTINCT, которое применяется для отчета об уникальных результатах для выходных данных запроса. Если в инструкции не указано ни выражениеDISTINCT, ни GROUP BY, то возвращаемые данные все еще могут быть обработаны с- по мощью агрегатных функций, описываемых в этом разделе.
Для начала обсудим выражениеDISTINCT. На самом деле это не агрегатная функция, а скорее фильтр последующей обработки, позволяющий удалять дубликаты. Рассматривается это выражение, так как отбирает, подобно агрегатным функциям, результаты из выходных данных, а не обрабатывает отдельные строки.
Рассмотрим следующий запрос (рис. 7.8):
mysql> SELECT DISTINCT gruppirovka_name FROM -> gruppirovka INNER JOIN prestupnik USING
(gruppirovka_id);
Рис. 7.8. Запрос путем объединения
85
Запрос выполняет поиск преступных группировок и входящих в них преступников путем объединения таблицgruppirovka и prestupnik посредством выражения INNER JOIN, после чего возвращает значение для каждой преступной группировки. Как показал запрос, в базе данных имеется семьпреступных
группировок |
с |
преступниками. Если |
удалить |
выражение |
DISTINCT, |
получим |
по одной строке для |
каждого преступника |
|
(рис. 7.9): |
|
|
|
|
mysql> SELECT gruppirovka_name FROM
-> gruppirovka INNER JOIN prestupnik USING
(gruppirovka_id);
Рис. 7.9. Краткая сводка
Таким образом, выражение DISTINCT позволяет получить краткую сводку.
Выражение DISTINCT применяется к выходным данным запроса и удаляет строки с идентичными значениями в столбцах, выбранных для выходных данных. Если переделать предыдущий пример так, чтобы получать оба значения: gruppirovka_name и prestupnik_пате (не изменяя выражение JOIN и все еще применяя DISTINCT), то в выходных данных получим 17всестрок
(рис.7.10):
mysql> SELECT DISTINCT gruppirovka_name, prestupnik_name
86
-> FROM gruppirovka INNER JOIN prestup-
nik
-> USING (gruppirovka_id);
Рис. 7.10. Выходные данные с DISTINCT
Поскольку ни одна из этих строк не является идентичной, дубликаты не будут удалены выражениемDISTINCT. Вы можете проверить это, пропустив в инструкции выражениеDISTINCT — получится тот же результат.
Для удаления дубликатов MySQL требуется отсортировать выходные данные. Если индексы выстраивают выходные данные в порядке, требуемом для сортировки, или же данные сами расположены в удобном порядке, то процесс будет лишь слегка за-
тормаживаться. Однако в больших таблицах без возможности получения доступа к данным в правильном порядке, сортировка может выполняться очень медленно.
Выражение GROUP BY сортирует данные в группы для агрегации. Оно подобно выражению ORDER BY, но выполняется гораздо раньше, до обработки запроса. Выражение GROUP BY используется для организации данных перед выполнением таких выражений, как WHERE, ORDER BY и других применяемых функций. В отличие от них выражениеORDER BY используется
87
последним после выполнения запроса для реорганизации выходных данных запроса.
Рассмотрим пример. Предположим, требуется выяснить, сколько преступников состоит в каждой преступной группировке. С помощью технологий, описанных выше, можно выполнить объединение INNER JOIN таблиц gruppirovka и prestupnik и ис-
пользовать выражение ORDER BY gruppirovka_пате для организации преступных группировок в порядке, удобном для подведения итогов. Стоит отметить, что при объединении таблиц, каждому преступнику ставится в соответствие преступная группировка, в которую он входит, что приводит к дублированию названий преступных группировок. Количество повторяющихся названий преступных группировок равно количеству преступников в них входящих (рис. 7.11). Применим такой запрос:
mysql> SELECT gruppirovka_name
-> FROM gruppirovka INNER JOIN prestupnik -> USING (gruppirovka_id)
-> ORDER BY gruppirovka_name;
Рис. 7.11. Подсчет количества преступников по группировкам
88
С помощью этого списка можно подсчитать, сколько преступников состоит в той или иной преступной группировке.
Выражение GROUP BY может автоматизировать этот процесс путем группирования преступников по группировкам. Затем применим функцию COUNT() для подсчета количества преступников в каждой группе (рис. 7.12):
mysql> SELECT gruppirovka_name, -> COUNT(gruppirovka_name) FROM
-> gruppirovka INNER JOIN prestupnik -> USING (gruppirovka_id)
-> GROUP BY gruppirovka_name;
Рис.7. 12. Сортировка количества преступников по группировкам
Выходные данные gruppirovka_name, COUNT (gruppirovka _пате) представляют именно то, что нужно. Обратите также внимание, что использовали GROUP BY gruppirovka_пате для предварительной сортировки перед агрегацией вместо выражения ORDER BY gruppirovka_пате для отображения.
Проанализируем этот запрос. Начнем с выражения GROUP BY. Оно указывает, каким образом объединять строки в группы. В данном примере MySQL было указано, что группировку строк следует выполнять по значениюgruppirovka_name. В результате
строки для преступной группировки с одним и тем же именем формируют кластер, то есть каждое уникальное имя становится группой. Сгруппированные строки интерпретируются в осталь-
89
ной части запроса как одна строка. Таким образом, если, к примеру, написать SELECT gruppirovka_name, то получим лишь по одной строке в каждой группе. То же самое делает выражение DISTINCT, которое выполняет группирование по имени столбца, а затем выбирает этот столбец для отображения. Функция COUNT() указывает свойства группы, точнее, она указывает количество строк, которые формируют каждую группу. Можно подсчитать все столбцы в группе и получите тот же самый ответ.
Таким образом, функции COUNT (gruppirovka_name), COUNT(*)
иCOUNT (gruppirovka_id) выдают идентичный результат. Для столбца COUNT() можно использовать псевдоним.
Рассмотрим еще один пример. Предположим, что необходимо выяснить, сколько преступлений совершил каждый преступник
ив какую преступную группировку он входит (рис. 7.13):
mysql> SELECT gruppirovka_name, -> prestupnik_name, COUNT(*) FROM
-> gruppirovka INNER JOIN prestupnik -> USING (gruppirovka_id)
-> INNER JOIN prestuplenie
-> USING (gruppirovka_id, prestupnik_id) -> GROUP BY gruppirovka.gruppirovka_id, -> prestupnik.prestupnik_id;
Рис. 7.13. Сортировка по каждому преступнику
90
