Язык SQL — Извлечение данных из таблиц. Команда SELECT
1. Команда SELECT
1.1. Базовый синтаксис команды SELECT
Команда SELECT предназначена для извлечения информации из базы данных и позволяет делать выборку одной или нескольких строк или столбцов из одной или нескольких таблиц. При этом результатом выполнения всегда является таблица, и, даже если это только одно число, все равно оно рассматривается как таблица с одной строкой и одним столбцом.
Выполнение оператора SELECT не изменяет хранящихся в базе данных, однако в момент его выполнения запрашиваемые данные обычно блокируются от изменений.
С помощью команды SELECT можно найти и просмотреть данные, причем сделать это можно несколькими способами, и, будучи все правильными, они, тем не менее, могут существенно отличаться по времени исполнения, что особенно важно для больших баз данных. Поэтому писать запросы на языке SQL совсем не просто. Этому надо учиться, как учатся решать математические задачи или составлять алгоритмы решения задач на ЭВМ.
Базовый синтаксис команды SELECT:
SELECT [ALL | DISTINCT] < список выбираемых полей | *>
FROM [<Имя базы данных.>]<Имя таблицы> | <Имя представления>]
[WHERE < Условия выборки или соединения >]
[GROUP BY <Выражение>]
[HAVING <Выражение>]
[ORDER BY <Выражение>]
Для описания синтаксиса команд примем следующие обозначения:
[ ] – содержимое этих скобок является необязательным;
< > – содержимое этих скобок заменяется соответствующими ключевыми словами, литералами, идентификаторами или выражениями (в зависимости от контекста);
| – заменяет слово ИЛИ. Другими словами этот символ означает обязательный выбор из списка возможностей.
Хотя ключевые слова можно записывать в любом регистре, будем для выразительности записывать их прописными буквами.
В первом предложении команды SELECT определяются поля (столбцы), которые будут входить в результат выполнения запроса.
Опция ALL (это значение установлено по умолчанию) выводит все записи, попавшие в результат запроса. Значит, в результирующий набор могут попасть одинаковые строки. И это нарушение принципов теории отношений. Опция DISTINCT исключает из результата запроса повторяющиеся записи. DISTINCT опускает строки, где все выбранные поля идентичны, т.е. дубликаты строк результата не включаются в набор. Строки, в которых некоторые значения одинаковы, а некоторые различны – будут сохранены.
Аргумент <список выбираемых полей> содержит список полей, а также допустимых выражений, включаемых в результирующую таблицу. Элементы списка разделяются запятыми. Каждый элемент этого списка генерирует один столбец результатов запроса. В имя поля можно включать имя выбираемой таблицы или имя локального псевдонима таблица. Это бывает необходимо, если поля разных таблиц имеют одинаковые имена. Псевдоним и имя поля разделяются символом “.” (точка). Символ * (звездочка) означает, что в результирующий набор включаются все столбцы из исходных таблиц запроса.
Предложение FROM содержит список таблиц, из которых осуществляется выборка. Таблицы в этом списке разделяются запятой. Для каждой таблицы можно указать имя локального псевдонима, которое должно следовать сразу же за именем таблицы и отделяться от него одним или несколькими пробелами.
В предложении WHERE задаются условия отбора записей из исходных таблиц.
Предложение GROUP BY группирует строки в запросе на основании значения в одном или более полях результирующей таблицы.
Предложение HAVING задает условие фильтра, которому должны удовлетворять группы, чтобы быть включенными в результат запроса. Предложение HAVING следует использовать только вместе с GROUP BY.
Предложение ORDER BY сортирует результат запроса на основании одного или нескольких полей результирующей таблицы.
Обратите внимание, что каждое предложение в команде SELECT необходимо использовать, придерживаясь синтаксического порядка. Например, предложение GROUP BY должно идти до ORDER BY. Иначе вместо ожидаемого результата появится сообщение об ошибке.
Порядок выполнения команды SELECT:
- FROM – вначале определяются имена используемых таблиц;
- WHERE – из указанной таблицы выбираются записи, удовлетворяющие заданным условиям;
- GROUP BY – выполняется группировка полученных записей, т.е. образуются группы строк, имеющих одно и то же значение в указанном столбце;
- HAVING – выбор группы строк, удовлетворяющих указанным условиям;
- ORDER BY – выполняется сортировка записей в указанном порядке;
- SELECT – устанавливается, какие столбцы должны выводиться.
Гибкость и мощь языка SQL состоит в том, что он позволяет объединить все операции реляционной алгебры в одной команде, “вытаскивая” таким образом, любую требуемую информацию.
Костяк этой команды состоит из предложений SELECT, FROM, WHERE, условий поиска и выражений. Любой самый сложный запрос начинается с шаблона:
SELECT (выбрать) <Список полей>
FROM (из) <Список таблиц>
[WHERE (где) <Условия выборки или соединения >]
Для иллюстрации основных возможностей языка SQL мы будем использовать демонстрационную базу данных промышленного предприятия, которая отражает процесс поступления материалов и товаров на его склад. Демонстрационная база данных описана в приложении 3.
1.2. Список выбираемых столбцов
Первое предложение запроса, создаваемого с помощью команды SELECT, является обязательным. Оно включает в себя список выбираемых элементов, отделяемых друг от друга запятой. Элементами этого списка могут быть названия полей базы данных, вычисляемые поля, значения которых определяются с помощью соответствующих выражений, переменные, константы и функции.
В простейшем варианте команда SELECT, которая выбирает все поля и все записи из одной таблицы, например Склад, выглядит следующим образом:
SELECT * FROM Склад
Результат выполнения запроса приведен на рис. 1.
В этом случае поля будут выводиться на экран в том порядке, как они создавались.
Этот пример иллюстрирует выполнение операции выборки. Операция выборки позволяет получить все строки (записи) либо часть строк одной таблицы.
Рис. 1. Простейший вариант команды SELECT
Если нам не нужны все поля таблицы, необходимо требуемые поля перечислить в предложение SELECT, например:
SELECT Наименование, Количество, Цена FROM Склад Результат выполнения запроса приведен на рис. 2.
Рис. 2. Команда SELECT с требуемыми полями
Операция, которая позволяет выделить подмножество столбцов таблицы, называется операцией проекции.
Порядок, в котором поля выводятся в итоге, зависит только от того, в какой последовательности они перечислены в запросе. Если необходимо во второй колонке вывести цену, то следует изменить порядок указания полей в списке:
SELECT Наименование, Цена, Количество
FROM Склад
В запросах из нескольких таблиц можно использовать для столбцов одной таблицы звездочку, а для другой перечислить нужные поля. Например, для таблиц Документ и Приход можно написать запрос:
SELECT Документ.дата, Приход.*
FROM Документ, Приход
WHERE Документ.ном_док = Приход.ном_док
В этом случае результат запроса будет содержать поле дата таблицы Документ и все поля таблицы Приход (рисунок 3).
Рис. 3. Комбинированный способ задания списка выбираемых полей
Выражения и функции в выборках
Помимо полей таблиц, в список выводимых полей могут входить выражения и функции.
Все числовые поля могут входить в арифметические выражения. Правила вычисления их значений ни чем не отличаются от правил, известных по школьному курсу арифметики.
Например, из таблицы Склад выбрать наименование товара, цену с учетом НДС (20%) и сумму товара:
SELECT Наименование, [Цена с НДС] = Цена*1.2, [Сумма товара] = Количество*Цена*1.2
FROM Склад
Результат выполнения запроса приведен на рис. 4.
Рис. 4. Команда SELECT с вычисляемыми полями
В качестве элементов списка вывода можно использовать функции (приложение 2).
Очень часто в запросах требуется производить обобщенное групповое значение полей. Это делается с помощью агрегатых функций.
К агрегатным функциям относятся специальные функции, действующие “по вертикали“. Это функции вычисления суммы (SUM), максимального (MAX) и минимального (MIN) значений столбцов, арифметического среднего (AVG), а также количества строк, удовлетворяющих заданному условию (COUNT).
Агрегатные функции используются подобно именам полей в предложении SELECT запроса, но с одним исключением, они берут имя поля как аргумент. Только числовые поля могут использоваться с функциями SUM и AVG. С функции COUNT, MAX, и MIN могут использовать числовые, символьные поля, а также поля типа дата.
Пример: определить, сколько видов принтеров хранится на складе, их суммарную, минимальную, максимальную и среднюю цену
SELECT [Количество принтеров] = COUNT(*), [Сумма без НДС] = SUM(Цена), [Минимальная цена] = MIN(Цена), [Максимальная цена] = MAX(Цена), [Средняя цена] = AVG(Цена)
FROM Приход
WHERE Тип = 'Принтер'
Результат выполнения запроса приведен на рис. 5.
Рис. 5. Команда SELECT с агрегатными функциями
В качестве элементов списка вывода можно использовать различные функции, например, функции для работы с датами. Запрос
SELECT Ном_док, [Месяц] = Month(Дата)
FROM Документ
сформирует список номеров документов и номеров месяцев их оформления.
Результат выполнения запроса приведен на рис. 6.
Рис. 6. Команда SELECT с функцией для работы с датами
В запросах можно использовать строковые функции работы с данными. Например,
SELECT Ном_ном , [Наименование] = LEFT(Наименование,10)
FROM Склад
Из поля Наименование будут выделены первые 10 символов. Результат выполнения запроса приведен на рис. 7.
Рис. 7. Команда SELECT с функцией для работы со строками
В запросе можно использовать пользовательскую функцию.
Для придания большей наглядности получаемому результату можно использовать литералы. Литералы — это строковые константы, которые применяются наряду с наименованиями столбцов и, таким образом, выступают в роли “псевдостолбцов”. Строка символов, представляющая собой литерал, должна быть заключена в кавычки или апострофы. Например, получить список наименований товаров и их цену
SELECT Наименование, 'стоит', Цена, 'рублей'
FROM Склад
Результат выполнения запроса приведен на рис. 8.
Рис. 8. Использование литералов в списке выводимых полей
Определение заголовков столбцов
По умолчанию заголовками столбцов в итоговой выборке являются их имена, которые присвоены им при создании таблицы. Это часто бывает неудобно, особенно для вычисляемых полей. Так как имя заголовка такого столбца либо пусто, либо присваивается системой.
Если не устраивают имена столбцов, формируемые по умолчанию, то для придания наглядности получаемым результатам, программист может изменить их следующими способами:
SELECT <Заголовок столбца> = <Имя столбца>
или
SELECT <Имя столбца> AS <Заголовок столбца>
В приведенных ниже примерах продемонстрированы оба способа определения заголовков:
SELECT Наименование, [Сумма товара] = Cena*1.20*Kolvo FROM Склад
SELECT Наименование, (Kolvo*Cena*1.20) AS 'Сумма товара' FROM Склад
На рис. 9 приведен результат запросов.
Рис. 9. Определение заголовков столбцов
Определения заголовков присутствуют в запросах, приведенных на рис. 4 – 7.
1.3. Использование таблиц, входящих в базу данных
В обязательном предложении FROM перечисляются все объекты базы данных (один или несколько), из которых производится выборка данных. Каждая таблица или представление, которые упоминается в запросе, должны быть перечислены в предложении FROM.
При описании таблиц, входящих в базу данных, из которых производится выборка можно указывать полное имя таблицы:
FROM <Имя базы данных>.<Имя таблицы>
Это обязательно, если делается ссылка на таблицу не из текущей базы данных. Аналогично производится обращение к представлениям.
Установить текущую базу данных можно командой: USE <Имя базы данных>
В случаях, когда база данных не является текущей и в информационной системе установлено несколько серверов баз данных, при выборке имя столбца необходимо указывать полный адрес:
<Имя сервера>.<Имя базы данных>.<Владелец>.<Имя таблицы>.<Имя столбца>.
Упоминание нескольких таблиц в предложении FROM обеспечивает выполнение операции соединения. Операция соединения позволяет соединять строки из более чем одной таблицы (по некоторому условию) для образования новых строк данных.
1.4. Выборка строк
Таблицы имеют тенденцию становиться очень большими, поскольку с течением времени, все большее и большее количество строк в нее добавляется. Поскольку обычно из них только определенные строки интересуют пользователя в данное время, SQL дает возможность устанавливать критерии, чтобы определить какие строки будут выбраны для вывода. Для этого необходимо использовать предложения WHERE.
WHERE — предложение команды SELECT позволяющее устанавливать условие, которое может быть или верным или неверным для любой строки таблицы. Команда извлекает только те строки из таблицы, для которой такое условие верно.
Когда предложение WHERE присутствует, программа просматривает всю таблицу по одной строке и исследует каждую строку, чтобы определить, верно ли заданное условие.
Условия предложения WHERE могут включать в себя операторы сравнения (=, #, <, <=, >, >=), интервала (BETWEEN), вхождения в список (IN), соответствия шаблону LIKE, логические (AND, OR, NOT), сравнения с неопределенным значением (IS NULL).
Например, требуется вывести названия всех поставщиков из Владимирской области. Это можно сделать с помощью команды:
SELECT Название, Регион FROM Поставщик
WHERE Регион = 'Владимир.обл.'
Результат выполнения запроса приведен на рис. 10.
Рис. 10. Список поставщиков из Владимирской области
Оператор BETWEEN задает диапазон значений, для которого выражение принимает значение true. Формат этого оператора:
<выражение> BETWEEN <нижнее значение диапазона> AND <верхнее значение диапазона>
Например, вывести все записи таблицы Склад, у которых значение поля Ном_ном находится в диапазоне от 10020 до 10080
SELECT *
FROM Склад
WHERE Ном_ном BETWEEN 10020 AND 10080
Результат выполнения запроса приведен на рис. 11.
Рис. 11. Команда SELECT с оператором BETWEEN
Тот же результат вернет запрос с использованием операторов сравнения:
SELECT *
FROM Склад
WHERE (Ном_ном>=10020) AND (Ном_ном<=10080)
Значения, определяющие нижнюю и верхнюю границы диапазона, могут не являться реальными величинами из базы данных. И это очень удобно — ведь не всегда можно указать точные значения диапазонов. Например, получить список поставщиков, фамилии которых находятся между Вас и Ро
SELECT Код_постав, Название FROM Поставщик
WHERE Название BETWEEN 'Вас' AND 'Ро
В данном примере значений ‘Вас’ и ‘Ро’ в базе данных нет. Однако, все поставщики, входящие в диапазон, в нижней части которого начало название поставщика совпадает с ‘Вас’ (т.е. выполняется условие “больше или равно”), а в верхней части — не более ‘Ро’, попадут в выборку.
Результат выполнения запроса приведен на рис. 12.
Отметим, что при выборке с использованием оператора BETWEEN поле, на которое накладывается диапазон, считается упорядоченным по возрастанию.
Разрешено также использовать конструкцию NOT BETWEEN, что позволяет получить выборку записей, указанные поля которых имеют значения меньше нижней границы и больше верхней границы.
Рис. 12. Команда SELECT с оператором BETWEEN с не реальными значениями нижней и верхней границ диапазона
Оператор IN проверяет, входит ли заданное значение, предшествующее ключевому слову “IN” (например, значение столбца или функция от него) в указанный в скобках список. Если заданное проверяемое значение равно какому-либо элементу в списке, то оператор принимает значение true.
Например, вывести все записи таблицы Склад, у которых значение поля номенклатурный номер равно 10040, 10080, 10110:
SELECT *
FROM Склад
WHERE Ном_ном IN (10040, 10080, 10110)
Результат выполнения запроса приведен на рис. 13. Разрешено также использовать конструкцию NOT IN.
Рис. 13. Команда SELECT с оператором IN
Оператор соответствия шаблону LIKE используется только с символьными данными. Он определяет, совпадает ли проверяемая символьная строка с заданным шаблоном. Шаблон может включать все разрешенные символы (с учетом верхнего и нижнего регистров), а также специальные символы-шаблоны:
- % (символ процент) — замещает любое количество символов,
- _ (символ подчеркивание) — замещает только один символ.
Например, получить список поставщиков, названия которых начинаются с буквы ‘С’ и содержать любое количество символов:
SELECT Название FROM Поставщик
WHERE Название LIKE 'С%'
Результат выполнения запроса приведен на рис. 14.
Рис. 14. Команда SELECT выводящая список поставщиков, названия которых начинаются с буквы ‘С’
Команда
SELECT Название FROM Поставщик
WHERE Название LIKE '_етров'
выполняет поиск и выдает все имена, состоящие из шести букв и заканчивающиеся сочетанием «етров» (Петров, Ветров и т.п.).
Результат выполнения запроса приведен на рис. 15.
Рис. 15. Команда SELECT с оператором LIKE
В некоторых диалектах языка SQL, в том числе и Transact-SQL, поддерживаются еще два вида подстановки:
[] (квадратные скобки) — вместо символа строки будет подставлен один из возможных символов, указанный в диапазоне или наборе.
[^] — вместо соответствующего символа строки будут подставлены все символы, кроме указанных в диапазоне или наборе.
Рассмотрим примеры использования таких видов подстановки. Напишем запрос, с помощью которого выбираются названия регионов, начинающихся на любую букву в промежутке от В до К
SELECT Регион FROM Поставщик
WHERE Регион LIKE '[В-К]%'
Результат выполнения запроса приведен на рис. 16.
Рис. 16. Команда SELECT с оператором LIKE, использующий подстановку []
В следующем примере, команда
SELECT Регион
FROM Поставщик
WHERE Регион LIKE 'В[^л]%'
выполнит поиск и выдаст все названия поставщиков, начинающиеся на ‘В’, в которых вторая буква отличается от ‘л’.
Результат выполнения запроса приведен на рис. 17.
Рис. 17. Команда SELECT с оператором LIKE, использующий подстановку [^]
Разрешено также использовать конструкцию NOT LIKE. Допускается использование нескольких условий отбора, которые объединяются логическими операторами AND, OR, NOT.
Если на складе необходимо найти монитор 28 дюймов любой модели с ценой от 15000 до 17000 рублей, то запрос может выглядеть так:
SELECT *
FROM Склад
WHERE Наименование LIKE 'Монитор%28_' AND Cena BETWEEN 15000 AND 17000
Результат выполнения запроса приведен на рисунке 18.
Рис. 18. Команда SELECT с двумя условиями отбора строк
Для выявления равенства значения некоторого атрибута неопределенному значению применяется операторы IS NULL или IS NOT NULL. Их форматы следующие:
<имя атрибута (поля)> IS [NOT ]NULL .
Если в данной строке указанный атрибут имеет неопределенное значение, то оператор IS NULL возвращает значение true, а оператор IS NOT NULL – false, иначе оператор IS NULL принимает значение false, а оператор IS NOT NULL – true.
Неопределенное значение интерпретируется в реляционной модели как значение, неизвестное на данный момент времени. Это значение в любой момент времени может быть заменено на некоторое конкретное значение. При сравнении неопределенных значений не действуют стандартные правила сравнения: одно неопределенное значение никогда не считается равным другому неопределенному значению.
Введение неопределенных значений вызвало необходимость модификации двузначной логики и превращение ее в трехзначную.
Все логические операции, проводимые с неопределенными значениями, подчиняются этой логике в соответствии со следующей таблицей истинности (табл. 4).
Таблица 4. Таблица истинности
A | B | NotA | A And B | A Or B |
True | True | False | True | True |
True | False | False | False | True |
True | Null | False | Null | True |
False | True | True | False | True |
False | False | True | False | False |
False | Null | True | False | Null |
Null | True | Null | Null | True |
Null | False | Null | False | Null |
Null | Null | Null | Null | Null |
1.5. Группировка данных
При подготовке сложных выборок часто не обойтись без группировки данных. Группировка позволяет получить вычисляемую информацию о сводных характеристиках подгруппы таблицы. Например, сгруппировав данные в таблице Склад по полю Наименование, можно получить сведения о сумме товаров каждого наименования. Для того чтобы сгруппировать записи в запросе, используется предложение GROUP BY:
GROUP BY <Имя столбца (имя поля)>[,<Имя столбца (имя поля)>…]
С концептуальной точки зрения это предложение (группировать по) перекомпоновывает таблицу, представленную предложением FROM, в группы таким образом, чтобы в каждой группе все строки имели одно и то же значение поля, указанного в предложении GROUP BY. Это, конечно, не означает, что таблица физически перестраивается. Таким образом, в результате группировки все записи таблицы, для которых значения колонок совпадают, отображаются в выборке единственной строкой.
Если совместно с GROUP BY используется предложение WHERE, то оно обрабатывается первым, а группированию подвергаются только те строки, которые удовлетворяют условию поиска.
Кроме того, существуют ограничения на элементы списка возвращаемых столбцов. Все элементы этого списка должны иметь одно значение для каждой группы строк. Это означает, что возвращаемым столбцом может быть:
- константа;
- само поле, указанное в предложении GROUP BY;
- функция, которая подсчитывает какое-либо результирующее для данной группы значение. Поэтому в этом случае обычно используются функции AVG(), COUNT(), MAX(), MIN(), SUM().
- выражение, включающее в себя перечисленные выше элементы.
Например, определить из таблицы Приход общую сумму товара для каждого наименования
SELECT Ном_ном, SUM(Цена*Количество) AS 'Сумма товара'
FROM Приход
GROUP BY Ном_ном
Результат выполнения запроса приведен на рис. 19.
В результате выполнения предложения GROUP BY остаются только уникальные значения столбцов, по умолчанию отсортированные по возрастанию.
Рис. 19. Команда SELECT с предложением GROUP BY
На практике в список возвращаемых столбцов запроса с группировкой всегда входят столбец группировки и агрегатная функция. Если последняя не указана, значит, запрос можно более просто выразить с помощью предиката DISTINCT без использования предложения GROUP BY. И наоборот, если не включить в результаты запроса столбец группировки, вы не сможете определить, к какой группе относится каждая строка результатов.
Еще одно ограничение запросов с группировкой обусловлено тем, что в SQL игнорируется информация о первичных и внешних ключах при анализе правильности запроса с группировкой. Рассмотрим следующий запрос: подсчитать общее количество поставок для каждого поставщика.
SELECT Документ.Код_постав, Название, COUNT(Документ. Код_постав)
FROM Документ, Поставщик
WHERE Документ.Код_постав = Поставщик.Код_постав
GROUP BY Документ.Код_поставщика
Зная природу данных, можно сказать, что запрос правильный, поскольку группировка по коду поставщика — фактически то же самое, что и группировка по наименованию поставщика. Говоря более точно, столбец группировки Код_постав является первичным ключом таблицы Поставщик, поэтому столбец Название должен иметь одно значение для каждой группы. Тем не менее, выдается сообщение об ошибке, представленное на рис. 20.
Рис. 20. Сообщение об ошибке
Чтобы решить эту проблему, можно в данном примере просто включить этот столбец в предложение GROUP BY:
SELECT Документ.Код_постав, Название, [Количество поставок] = COUNT(Документ. Код_постав)
FROM Документ, Поставщик
WHERE Документ.Код_постав = Поставщик.Код_постав
GROUP BY Документ.Код_поставщика, Поставщик. Название
Результат выполнения запроса приведен на рис. 21.
Рис. 21. Команда SELECT с группировкой по двум полям
Конечно, если название поставщика в результатах запроса не требуется, можно вообще исключить его из списка возвращаемых столбцов:
SELECT Код_постав, [Количество поставок] = COUNT(*)
FROM Документ
GROUP BY Код_постав
Результат выполнения запроса приведен на рис. 22.
Часто бывает нужным вывести не все промежуточные итоги, а только какую-либо их часть. Для этого применяется предложение
HAVING <условие>,
где <условие> – это логическое выражение, составленное из агрегатных функций и/или столбцов группировки.
Рис. 22. Команда SELECT с группировкой
Есть существенное отличие между предложениями HAVING и WHERE. Агрегатные функции можно включать только в предложение HAVING. В этом случае агрегатная функция вычисляется для каждой группы.
Например, определить мониторы, поступившие на общую сумму более 50000 руб. При этом, полагая, что один и тот же товар мог поступать неоднократно.
SELECT Ном_ном AS 'Номенклатурный номер', SUM(Цена*Количество) AS 'Сумма'
FROM Приход
WHERE Тип = 'Монитор'
GROUP BY Ном_ном
HAVING SUM(Цена*Количество) > 50000
Результат выполнения запроса приведен на рис. 23.
Рис. 23. Команда SELECT с предложениями GROUP BY и HAVING
Имейте в виду, что критерии, устанавливаемые с помощью WHERE, делают выборки, проверяя запись за записью, а предложение HAVING отбирает группы.
Предложение HAVING не может использоваться отдельно от предложения GROUP BY.
1.6. Порядок вывода данных
Для вывода данных отсортированных по какому-либо столбцу, используется предложение ORDER BY. Это предложение имеет вид:
ORDER BY <Имя столбца | Номер столбца [ASC | ESC]>[,<Имя столбца | Номер столбца> [ASC | DESC]…]
Способ упорядочивания определяется дополнительными зарезервированными словами ASC и DESC. Способом по умолчанию — если ничего не указано — является упорядочивание “по возрастанию” (ASC). Если же указано слово DESC, то упорядочивание будет производиться “по убыванию”.
Подчеркнем еще раз, что предложение ORDER BY должно указываться в самом конце запроса.
Порядок строк может задаваться одним из двух способов:
- именами столбцов
- номерами столбцов.
Упорядочивание с использованием имен столбцов
Например, получить список поставщиков, упорядоченный по их названиям в алфавитном порядке
SELECT Название, Регион
FROM Поставщик
ORDER BY Название
Результат выполнения запроса приведен на рис. 24.
Рис. 24. Команда SELECT с сортировкой списка поставщиков
Упорядочивание с использованием номеров столбцов
Например, сделаем выборку наименований товаров на складе и сумм, упорядоченную по суммам.
SELECT Наименование, [Сумма] = SUM(Количество*Цена)
FROM Склад
GROUP BY Наименование
ORDER BY 2
Результат выполнения запроса приведен на рис. 25.
Рис. 25. Команда SELECT с сортировкой сумме
Допускается использование нескольких уровней вложенности при упорядочивании выводимой информации по столбцам. При этом разрешается смешивать оба способа задания порядка строк.
Вывести список товаров на складе, упорядоченный по убыванию их количества, а в пределах одинакового количества — по возрастанию цены:
SELECT Количество, Цена, Ном_ном
FROM Склад
ORDER BY Количество DESC, 2
Результат выполнения запроса приведен на рис. 26.
Столбец, определяющий порядок вывода строк, не обязательно должен присутствовать в списке выбираемых столбцов. Например, команда
SELECT Название
FROM Поставщик
ORDER BY Рейтинг
позволяет получить список поставщиков, отсортированный по их рейтингу.
Рис. 26. Команда SELECT с двух уровневой сортировкой
2. Выборка данных из нескольких таблиц
При обсуждении предыдущих примеров мы, как правило, использовали выборки из одной таблицы. На практике запросы к одной таблице составляют не более 10 % от общего количества запросов.
Для вывода связанной информации, хранящейся в нескольких таблицах, в языке SQL используется операция соединения. Операция соединения позволяет соединять по некоторому условию строки из более чем одной таблицы для образования новых строк данных.
Соединение выполняется путем подбора строк с одинаковыми значениями в общих для нескольких таблиц столбцах. Необходимо определить одну из таблиц так, чтобы один из столбцов первой таблицы дублировался во второй, тогда этот столбец будет общим для обеих таблиц (эти столбцы, как мы уже знаем, называются внешними ключами).
Можно объединять и отображать строки разных таблиц и манипулировать данными с помощью тех же команд, которые используются при работе с одной таблицей.
В этом проявляется одна из наиболее важных особенностей запросов SQL — способность определять связи между многочисленными таблицами и выводить информацию из них в рамках этих связей. Именно эта операция придает гибкость и легкость языку SQL.
Операции соединения подразделяются на два вида — внутренние и внешние. Внешние соединения поддерживаются стандартом SQL — 92 и содержат зарезервированное слово “JOIN”, в то время как внутренние соединения (или просто соединения) могут задаваться как без использования такого слова (в стандарте SQL-89), так и с использованием слова “JOIN” (в стандарте SQL -92).
2.1. Внутреннее соединение
Внутреннее соединение возвращает только те строки, для которых условие соединения принимает значение true.
Соединение с помощью предложения WHERE
Общий синтаксис соединения двух таблиц следующий:
SELECT <список столбцов>
FROM <Имя таблицы1>, <Имя таблицы2>
WHERE [<Имя таблицы1>.] <Имя столбца> <Оператор объединения> [<Имя таблицы2>.] <Имя столбца>
Предложение FROM должно включать две таблицы, а столбцы, указанные в предложении WHERE, должны быть совместимы. Если столбцы таблиц имеют одинаковые имена, то перед ними необходимо указать названия таблиц с точкой. Обычно при связывании двух и более таблиц используется оператор «=», но можно задействовать и другие операторы.
Рассмотрим пример выборки информации из нескольких таблиц. Пусть нам необходимо вывести наименование материалов и товаров вместе с датой их поступления на склад. Наименование товара хранится в таблице Склад, а дата поступления товара – в таблице Документ. Причем в этих таблицах нет одинаковых столбцов и, следовательно, соединить их напрямую нельзя. Однако таблицы Склад и Документ можно соединить, используя таблицу Приход:
SELECT Склад.Наименование, Документ. Дата
FROM Склад, Приход, Документ
WHERE Склад.Ном_ном = Приход.Ном_ном AND Приход.Ном_док = Документ. Ном_док
Результат выполнения запроса приведен на рис. 27.
Рис. 27. Внутреннее соединение
При написании запросов часто используют псевдонимы таблиц — временное имя таблицы.
Псевдонимы таблиц используются для сокращения SQL-кода, чтобы его было легче читать или когда вы выполняете самосоединение (т.е. перечисление одной и той же таблицы более одного раза в операторе FROM).
Синтаксис псевдонима таблицы в SQL:
Имя таблицы [AS] Псевдоним,
где Имя таблицы – оригинальное имя таблицы, которой вы хотите указать псевдоним;
Псевдоним – псевдоним для назначения.
Рассмотренный выше запрос, но с использованием псевдонимов таблиц выглядит следующим образом
SELECT s.Наименование, d.Дата
FROM Склад s, Приход p, Документ d
WHERE s.Ном_ном = p.Ном_ном AND p.Ном_док = d. Ном_Док
Результат выполнения запроса приведен на рис. 27. Псевдоним действителен только в рамках команды SQL.
Как видно из примера, для того чтобы связать две таблицы, мы использовали два столбца, по одному из каждой таблицы. Связующие столбцы имеют один и тот же тип данных. В рассмотренном примере совпадает все, вплоть до названия.
Соединение с использованием опции JOIN
В SQL-Server для соединения таблиц можно использовать предложение INNER JOIN. Стандарт соединения с использованием опции JOIN:
- в предложении FROM слева и справа от фразы INNER JOIN указываются соединяемые таблицы;
- условия соединения помещаются в предложение ON.
Для выше рассмотренного примера запрос с использованием фразы INNER JOIN выглядит следующим образом:
SELECT Наименование, Дата
FROM Склад s INNER JOIN Приход p
ON s.Ном_ном = p.Ном_ном
INNER JOIN Документ d
ON p.Ном_док = d.Ном_док
Результаты этого запроса представлены на рис. 27
Приведем пример выборки товаров, поступивших на склад в июле месяце от поставщика Веденеева Д.В.. Такой запрос имеет вид:
SELECT d. Ном_док, d.Дата, s.Наименование, p.Количество, p.Цена, pos. Название
FROM Документ d INNER JOIN Приход p
ON d. Ном_док = p. Ном_док
INNER JOIN Поставщик pos
ON d.Код_постав = pos.Код_постав
INNER JOIN Склад s
ON p. Ном_ном = s. Ном_ном
WHERE DatePart(Mm,Дата) = 7 AND pos. Название = ‘Веденеев Д.В.’
Результат выполнения запроса приведен на рис. 28.
Рис. 28. Запрос, использующий 4 таблицы базы данных
В данном примере создадим запрос об итоговом количестве и об итоговой сумме каждого поступившего на склад товара с 20 марта 2020 года по 24 апреля 2021 года:
SELECT p.Ном_ном, SUM(p.Количество) AS Количество, SUM(p.Количество * p.Цена) AS Сумма;
FROM Приход p INNER JOIN Документ d ON p. Ном_док = d. Ном_док
WHERE d.Дата BETWEEN ‘2021-03-20’ AND ‘2021-04-24’
GROUP BY p.Ном_ном
Результат выполнения запроса приведен на рис. 29.
Рис. 29. Запрос, использующий соединение таблиц и группировку
При создании условий соединения необходимо иметь ввиду следующее:
- Если в запрос включены две таблицы, а условия соединения не указаны, каждая запись из одной таблицы связывается с каждой записью из другой, и результат имеет число записей, равное произведению числа записей во всех таблицах, участвующих в запросе. Такой запрос может занять много времени.
- Нельзя связывать две таблицы по столбцам со значениями NULL, так как пустое поле одной таблицы соответствует пустому полю другой таблицы.
2.2. Внешнее соединение
Внешнее соединение возвращает все строки из одной таблицы и только те строки из другой таблицы, для которых условие соединения принимает значение true. Строки второй таблицы, не удовлетворяющие условию соединения (т.е. имеющие значение false), получают значение NULL в результирующем наборе.
Рассмотрим три вида внешнего соединения: LEFT JOIN, RIGHT JOIN и FULL JOIN.
В левом соединении (LEFT JOIN) запрос возвращает все строки из левой таблицы (т.е. таблицы, стоящей слева от зарезервированного словосочетания LEFT JOIN) и только те из правой таблицы, которые удовлетворяют условию соединения. Если же в правой таблице не найдется строк, удовлетворяющих заданному условию, то в результате они замещаются значениями NULL.
Например, даны две таблицы Tabl1 и Tabl2
Tabl1
X | Y |
0 | 5 |
1 | 6 |
3 | 10 |
Tabl2
X | Z |
0 | 3 |
1 | 4 |
2 | 5 |
В результате запроса
SELECT Y, Z FROM Tabl1 LEFT JOIN Tabl2 ON Tabl1.X = Tabl2.X
получим на экране следующую таблицу
Y | Z |
5 | 3 |
6 | 4 |
10 | NULL |
Правое соединение (RIGHT JOIN) создает соединение, в котором выбираются все записи из правой таблицы, а также записи из левой таблицы, значения поля связи которого совпадают со значениями поля связи правой таблицы. Если же в левой таблице не найдется строк, удовлетворяющих заданному условию, то в результате они замещаются значениями NULL.
Для таблиц Tabl1 и Tabl2 сделаем правое соединение
SELECT Y, Z FROM Tabl1 RIGHT JOIN Tabl2 ON Tabl1.X = Tabl2.X
В результате получим таблицу
Y | Z |
5 | 3 |
6 | 4 |
NULL | 5 |
Использование в запросе опции FULL JOIN создает соединение, в котором выбираются все записи из правой и левой таблицы. Например, полное объединение таблиц Tabl1 и Tabl2
SELECT Y, Z FROM Tabl1 FULL JOIN Tabl2 ON Tabl1.X = Tabl2.X
сформирует таблицу
Y | Z |
5 | 3 |
6 | 4 |
10 | NULL |
NULL | 5 |
2.3. Объединение выборок
Оператор UNION объединяет результаты выполнения одной команды SELECT с результатами другой команды. Он удобен, если требуется просмотреть аналогичные данные из разных таблиц. Его синтаксис:
Команда SELECT UNION [ALL]
Команда SELECT UNION [ALL]
. . . . . . . . . . . . . . . .
Команда SELECT
По умолчанию оператор UNION удаляет повторяющиеся записи. Предложение ALL запрещает удалять повторяющиеся записи из результата. Правила использования оператора UNION:
- Все команды SELECT должны возвращать одинаковое количество столбцов в результате выполнения запроса.
- Столбцы должны иметь одинаковые типы данных и размерность.
- Только последняя команда SELECT может иметь предложение ORDER BY.
Пример, получить данные о товарах в таблицах Приход и Склад
SELECT Ном_ном, Цена
FROM Приход
UNION ALL
SELECT Ном_ном, Цена
FROM Склад
Order BY 1
Результат выполнения запроса приведен на рис. 30
Рис. 30. Запрос с оператором UNION
В данном примере рассмотрим две таблицы:
АВТОР (Фамилия, Имя, Район);
СЛУЖАЩИЙ (Фамилия, Имя, Район, Должность).
В результате следующего запроса будут найдены все авторы и служащие, живущие в Октябрьском районе.
SELECT Имя, Фамилия, Район, ‘Автор’ FROM АВТОР
WHERE Район = ‘Октябрьский’
UNION
SELECT Имя, Фамилия, Район, Должность
FROM СЛУЖАЩИЙ
WHERE Район = ‘Октябрьский’ ORDER BY 1
Обратите внимание, что поскольку в примере указывается еще и должность сотрудников, в первый запрос пришлось включить еще один столбец, без которого было бы получено сообщение об ошибке.
Оператор UNION можно использовать в качестве оператора IF для отображения различных значений одного поля в зависимости от значений в других полях. Без оператора UNION для получения аналогичного результата потребовалось бы выполнение нескольких запросов.
Пусть требуется получить список товаров, указав для каждого из них процентное снижение цены и новую цену. При этом цена товаров до 5000 руб. снижается на 20%, цена товаров между 5000 руб. и 30000 руб. снижается на 10%, цена товаров больше 30000 руб. снижается на 30%.
SELECT ‘на 20%’, Наименование AS ‘Наименование’, Цена AS ‘Старая цена’, Цена * 8 AS ‘Новая цена’
FROM Склад WHERE Цена < 5000
UNION
SELECT ‘на 10%’, Наименование AS ‘Наименование’, Цена AS ‘Старая цена’, Цена * 9 AS ‘Новая цена’
FROM Склад
WHERE (Цена >=5000) AND (Цена <= 30000)
UNION
SELECT ‘на 30%’, Наименование AS ‘Наименование’, Цена AS ‘Старая цена’, Цена * 7 AS ‘Новая цена’
FROM Склад
WHERE Цена > 30000
Результат выполнения запроса приведен на рис. 31.
Далее:
Использование подзапросов в команде SELECT