Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Основы языка SQL

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

При написании статьи использовалась следующая литература:
1. Шумаков П.В. - Delphi3 и создание приложений для баз данных;
2. Oracle University - Oracle 8i SQL Fundamentals, Student Guide;
3. Oracle University - PL/SQL Fundamentals, Student Guide;
4. Oracle Press, Christopher Allen - 101: Oracle PL/SQL.

Примечание: Если что то будет непонятно, или вы встретите по началу какие-либо трудности в усвоении данного материала, то не отчаивайтесь. Дальше будет очень подробно и детально рассмотрены все места, которые могут вызвать у вас на первых порах затруднения.

P.S. Ради справедливости, должен заметить, что очень многое, в данной статье взято из книги Шумакова В.П. - Delphi3 и создание приложений для баз данных. Как я уже говорил рашьше, это пожалуй самая лучшая книга по програмированию приложений для баз данных в среде Delphi. Доходчивей и понятливей, объяснить данную тематику, чем написано в этой книги, я думаю очень трудно.


ОСНОВЫ ЯЗЫКА SQL

История развития SQL

Небольшой экскурс в историю позволит получить лучшее представление об изучаемом предмете. История SQL развивалась параллельно с историей развития реляционных баз данных. В 1969 г. д-р Эдгар Ф. Кодд опубликовал в серии исследовательских отчетов IBM сообщение под названием Derivability, Redundancy, and Consistency of Relation Stored in Large Data Banks. Там описывался подход к структурированию баз данных, основанный на использовании связных таблиц, который значительно отличался от принятого в то время подхода с плоскими файлами. Это сообщение имело пометку «для ограниченного распространения» и поэтому не получило широкой известности. Кодд переработал свои концепции и в 1970 г. Опубликовал их в статье под названием A Relational Model of Data for Large Shared Data Banks в журнале ACM (Association of Computer Machinery). Реляционная модель, описанная Коддом. В 1974 г. Была использована в прототипе реляционной системы управления базами данных (РСУБД), названной System R. Описывая системный язык запросов в ноябрьском номере IBM Journal of R&D за 1976 г., корпорация IBM использовала для него название Structured English QUEry Language (SEQUEL, язык структурированных английских запросов). В ходе эволюции языка название изменилось на Structured Query Language (SQL, язык структурированных запросов, произноситься как сиквел (sequel) или “S-Q-L”). Первая коммерческая версия SQL была выпущена в 1979 г. Корпорацией Oracle (в то время называвшейся Relational Software Inc.).
В 1986г. К работе подключился Американский национальный институт стандартов (ANSI), опубликовавший официальный стандарт SQL с кодовым названием ANSI X3.135-1986. В следующем году этот стандарт был опубликован Международной организацией по стандартизации (ISO) как ISO 9075-1987. Спецификация SQL дважды расширялась – в 1992 и 1999 г. Текущая спецификация состоит из пяти частей, имеющих название ANSI/ISO/IEC9051-1-1999-9051-5-1999.
SQL фактически стал стандартным языком для выполнения запросов к базам данных. Каждый производитель систем управления базами данных слегка модифицирует его, чтобы приспособить к своим потребностям, но ядро SQL по существу остается неизменным. От этого выигрывают пользователи и разработчики баз данных, поскольку усилия, потраченные на изучение SQL, будут приносить свои плоды в течении долгих лет, при смене версий программы и даже при переходе на другие продукты. Иначе говоря, SQL – это универсальный инструмент, необходимый каждому кто регулярно работает с базами данных.


Общие сведения о SQL

Команды SQL делятся на функциональные группы, что облегчает из запоминание. Вот эти группы:
• Определение данных (Data Definition)
• Манипулирование данными (Data Manipulation)
• Управление данными (Data Control)
• Выборка данных (Data Retrieval)
• Управление транзакциями (Transaction Control)

Теперь разберем более подробно эти группы:

Определение данных
Все основные СУБД, являются так называемыми платформами баз данных. Это означает, что они предоставляют среду, очень хорошо поддерживающие работу с таблицами, но не содержит никаких заранее созданных таблиц. Вы должны сами определять состав и конфигурацию хранимых данных (т.е. их тип и т.д.). Для этого в SQL существует ряд специальных команд: CREATE, ALTER, DROP, RENAME и TRUNCATE.
Эти команды входят в группу, называемых языком определения данных (DDL, Data Definition Language).

Манипулирование данными
Допустим, вы научились создавать таблицы. Что же дальше? Разумеется поместить в них данные. В SQL есть команда INSERT, позволяющая добавлять данные в таблицы. После того как данные вставлены, их можно изменять, используя команду UPDATE, или удалять, используя команду DELETE.
Эта категория команд называется языком манипулирования данными (DML, Data Manipulation Language).

Управление данными
Возможность предоставлять некоторым пользователям доступ к определенным таблицам, в то время, как другим это запрещено, обеспечивается за счет присваивания пользователям привилегий на таблицы или действия. Существуют два вида привилегий:
• объектная
• системная
Объектная привилегия разрешает пользователю выполнять определенные действия над таблицей (или другими объектами баз данных)
Системная привилегия, напротив, разрешает пользователю выполнять действия определенного типа во всей базе данных.
Привилегии базы данных присваиваются и удаляются с помощью SQL-команд GRANT и REVOKE, соответственно. Эти команды относятся к категории, называемой языком управления данными (DCL, Data Control Language).

Выборка данных
Смысл помещения информации в базу данных состоит в том, чтобы получить ее обратно контролируемым образом. В этой категории всего одна команда – SELECT, но она имеет широкий набор параметров, обеспечивающих огромную гибкость. Вероятно, именно эту команду вы будете использовать чаще всего, особенно если планируете обращаться к SQL из другого языка программирования, такого, как Java, C++ или Pascal.

Управление транзакциями
SQL позволяет отменять любые из последних команд языка манипулирования данными (DML) до того, как они будут применены к базе данных. После выполнения одной, или нескольких команд DML вы можете ввести либо команду COMMIT для сохранения изменений в базе данных, либо команду ROLLBACK для их отмены («отката»).
Отмена возможна на разных уровнях: вы можете отменить самую последнюю транзакцию DML, несколько последних транзакций или выполнить отмену на любую нужную глубину. Однако для того, чтобы выполнять многоуровневый повтор, требуется несколько больше предварительных действий, чем в вашем любимом текстовом процессоре. Если вы хотите иметь возможность отката к промежуточным точкам, они должны быть предварительно отмечены с помощью команды SAVEPOINT.


Структура базы данных

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

Мы будем работать с четырьмя таблицами:

Товаров (Tovar)
1) ID;
2) NameTovar – наименование товара;
3) Unit – единица измерения;
4) Price – цена за одну единицу измерения;

ID
NameTovar
Unit
Price
1
Носки
шт.
10
2
Рубашка
шт.
50
3
Сахар
кг.
5
4
Колбаса
кг.
7
5
Мука
кг.
3
6
Пиво
бут.
6
7
Сигареты
пач.
9


Клиентов (Clients)
1) ID;
2) NameClients – наименование клиента;
3) Adres – адрес;

ID
NameClients
Adres
1
ООО Евразия
ул. Ольшанского, 19
2
ООО Пертовка
ул. Петровка, 38
3
АО Центрснаб
ул. Заболотная, 8
4
ЗАО Геркулес
ул. Якиманка, 45
5
АО Центр
м-н Молодежный, 20


Накладных (Waybill)
1) ID;
2) Num_waybill – номер накладной;
3) Clients_ID – ID клиента;

ID
Num_waybill
Client_ID
1
1
1
2
2
2
3
3
3
4
4
4
5
5
5
6
6
1
7
7
2
8
8
3
9
9
4
10
10
5
11
11
1
12
12
2


Отпуска товаров (Sale)
1) ID;
2) Tovar_ID – ID товара;
3) Waybill_ID – ID накладной;
4) Number_sale – количество отпущенных единиц
5) Date_sale – дата продажи;
6) Sum_sale – сумма продажи;

ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
1
2
15
12.01.2003
750
2
2
20
12.01.2003
1000
3
2
40
12.01.2003
2000
4
2
25
12.01.2003
1250
5
5
500
12.01.2003
1500
6
5
100
13.01.2003
300
7
5
5500
13.01.2003
16500
8
5
1000
13.01.2003
3000
9
5
250
13.01.2003
750
10
1
400
13.01.2003
4000
11
1
300
13.01.2003
3000
12
2
30
14.01.2003
1500
13
2
75
14.01.2003
3750
14
4
800
14.01.2003
5600
15
4
600
14.01.2003
4200
16
4
155
14.01.2003
1085
17
5
95
14.01.2003
285


Схема взаимосвязи таблиц:
user posted image

По началу мы будем рассматривать примеры только лишь на одной таблице - Tovar, но по ходу изучения, усложняя материал, мы будем строить примеры, используя все четыре таблицы.


Написание команд SQL

Вот простые правила, которые позволяют создавать команды, удобные для чтения и редактирования:
• Команды SQL не различают регистры символов, если не указано иного.
• Команды SQL могут занимать одну или несколько строк;
• Ключевые слова нельзя сокращать и переносить с одной строки на другую.
• Для упрощения чтения и редактирования предложения обычно пишуться на отдельных строках.
• Для упрощения чтения команды можно использовать табуляцию и отступы.
• Ключевые слова обычно вводятся заглавными буквами, а все остальные (например, имена таблиц и столбцов) – строчными.

Примечание: В данной статье используются термины ключевое слово, предложение, команда.
Ключевое слово (keyword) - это отдельный элемент SQL (например, SELECT и FROM)
Предложение (clause) - это часть комманды SQL (например, SELECT ID, NameTovar, ...)
Команда (statement), оператор (operator) - это комбинация из двух и более предложений (например, SELECT * FROM Tovar).

Оператор SELECT
(Выборка данных /Data Retrieval)

Оператор SELECT – одни из наиболее важных, и самый используемый оператор SQL. Он позволяет производить выборки данных из таблиц базы данных и преобразовывать их нужному виду получаемые результаты. Это очень мощный и гибкий оператор. При его помощи можно реализовывать весьма сложные и громоздкие условия выборки данных из различных таблиц.
Оператор SELECT – средство, полностью абстрагировано от вопросов представления данных; все внимание при его применении сконцентрировано на проблемах доступа к данным.

Оператор SELECT имеет следующий формат:

SELECT [DISTINCT | ALL] {* | <значение1> [, <значение2> …]}
FROM <таблица1> [, <таблица2> …]
[WHERE <условия поиска>]
[GROUP BY столбец [COLLATE collation] [, столбец1 [COLLATE collation]…]]
[HAVING <условие_поиска>]
[UNION <оператор_select>]
[PLAN <план_выполнения_зпроса>]
[ORDER BY <список_столбцов> [ASC|DESC]]


Этот формат с первого взгяда достаточно громоздок и кажется поэтому сложным. Такое впечатление при дальнейшем изучении оператора SELECT наверняка покажется вам неверным.

Как уже говорилось ранее, команда SELECT осуществляет выборку информации из базы данных. С помощью этой команды можно делать следующее:
Выбор (selection): SQL позволяет осуществлять выборочный вывод строк таблицы (записей). Для этого можно задать различные критерии выборки.
Проекция (projection): SQL позволяет задать столбцы (поля) таблицы, возвращаемые запросом. Количество выходных столбцов может быть любым.
Соединение (join): SQL позволяет объединить данные из разных таблиц на базе соединения между ними.

Поэтапно рассмотрим возможности, которые предоставляет оператор SELECT.


Простейший вид оператора SELECT (SELECT..FROM)

В простейшем виде, оператор SELECT имеет вид:

SELECT {* | <значение1> [, <значение2> …]}
FROM <таблица1> [, <таблица2> …]


После ключевого слова FROM приводиться список таблиц, из которых будет происходить выборка данных.
После ключевого слова SELECT приводиться список значений. Каждое из них определяет столбец результирующего набора данных, возвращаемого оператором SELECT. В большинстве случаев это имена столбцов таблиц, перечисленных после слова FROM. Звездочка (*) указывает, что в результат выполнения запроса нужно включить все столбцы той или иной таблицы.

Пример: Выдать набор данных, состоящий из всех столбцов и всех записей из таблицы товаров (Tovar)

SQL
SELECT *
FROM Tovar


что идентично

SQL
SELECT ID, NameTovar, Unit, Price
FROM Tovar


Результат запроса:
ID
NameTovar
Unit
Price
1
Носки
шт.
10
2
Рубашка
шт.
50
3
Сахар
кг.
5
4
Колбаса
кг.
7
5
Мука
кг.
3
6
Пиво
бут.
6
7
Сигареты
пач.
9



ИСПОЛЬЗОВАНИЕ ПРЕДЛОЖЕНИЯ WHERE

С использованием приложения WHERE оператор SELECT имеет следующий формат:

SELECT [DISTINCT | ALL] {* | <значение1> [, <значение2> …]}
FROM <таблица1> [, <таблица2> …]
WHERE <условия поиска>]


В набор данных, который возвращается, как результат выполнения оператора SELECT, будут включаться только те записи, которые удовлетворяют условию поиска. Ниже, будут рассмотрены варианты формирования разнообразных условий поиска - их для оператора SELECT в SQL имеется достаточное количество, и все вместе они делают оператор исключительно мощным средством для построения запросов к БД.
Пока же рассмотрим два простейших условий поиска.

Сравнение значения столбца с константой
При сравнении значения столбца с константой условие поиска имеет вид:
<имя столбца> <оператор> константа

где в качестве оператора могут выступать операции отношения
= равно
> меньше
< больше
<= меньше или равно
>= больше или равно
!< не меньше (т.е. больше или равно)
!> не больше (т.е. меньше или равно)
<> не равно
!= не равно

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

Пример: Выдать из таблицы товаров (Tovar) все товары, цена (Price) которых, больше или равна 10.

SQL
SELECT *
FROM Tovar WHERE Price > = 10

Результат запроса:
ID
NameTovar
Unit
Price
1
Носки
шт.
10
2
Рубашка
шт.
50


Пример: Выдать из таблицы товаров (Tovar) все записи, единица измерения (Unit) для которых является киллограм «кг.».

SQL
SELECT *
FROM Tovar WHERE Unit = ‘кг.’

Результат запроса:
ID
NameTovar
Unit
Price
3
Сахар
кг.
5
4
Колбаса
кг.
7
5
Мука
кг.
3


Пример: Выдать из таблицы продаж (Sale) все продажи, которые были осуществлены до 13.01.2003 г.
SQL
SELECT *
FROM Sale WHERE Date_Sale < ’13.01.2003’

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
1
2
15
12.01.2003
750
2
2
20
12.01.2003
1000
3
2
40
12.01.2003
2000
4
2
25
12.01.2003
1250
5
5
500
12.01.2003
1500


Примечание: В некоторых базах данных строковые значения заключаются не в апострофы, а в двойные кавычки, как, например в MS Access.
Кроме этого, так же по-разному многие БД хранят дату и воспринимают дату. В том же самом MS Access, например значение даты требуется ограничить символами диез (#).


Сравнение значения столбца из одной таблицы со значением столбца из другой таблицы (внутренне соединение)

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

Если вы посмотрите на схему нашей БД, то увидите, что стрелка от поля ID таблицы товаров (Tovar) идет к полю Tovar_ID таблицы продаж (Sale).

У вас могут возникнуть два обоснованных вопроса.

Во-первых, почему мы «усложняем себе жизнь» и сделали две таблицы вместо одной? Ведь можно было наименование товаров, единицу измерения и цену в которые хранятся в отдельной таблице (Tovar), записывать сразу в таблицу продаж (Sale)?
Во-вторых, почему мы в таблицу продаж (Sale) проставляем не само наименование товаров, а значение поля ID из таблицы товаров?

Будем отвечать на эти вопросы по порядку.

В принципе ответ на первый вполне очевиден. Для примера будем рассматривать какой-либо один товар, ну, например, пусть это будет - рубашка, с ID = 2. Поскольку наименование товара по количеству всего одно, а его продаж много, то в таблице продаж (Sale) просто-напросто дублировалась бы информация, о единице измерения и цене этой рубашки. Причем дублировалась бы столько раз, сколько раз были произведены продажи этой рубашки. Или, если бы поменялась цена товара, то нам необходимо было бы изменять цену во всех записях продаж для данного товара. Исходя из этого, мы вынесли повторяющуюся информацию о товаре в отдельную таблицу.

Теперь рассмотрим второй вопрос. Представим, что мы вместо ID этого товара, записываем его наименование. Но вдруг у нас возникла необходимость переименовать наименование этого товара? Тогда нам придется менять это наименование во всех продажах этого товара, в таблице продаж (Sale).
Как этого избежать? Для этого существует внешний ключ (в нашем случае они он же является и первичным колючем). По сути, им может быть любое поле или набор полей, уникально идентифицирующее запись в таблице. Но мы будем использовать ID, так как это обусловлено хорошим стилем, а так же как я уже сказал, если вдруг измениться наименование товаров, чтобы не изменять его и в таблице продаж. И теперь, мы можем без боязни и осложнения изменять наименование товара, сколько нам заблагорассудиться.

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

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

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

<имя столбца таблицы 1> <оператор> <имя столбца таблицы 2>

Пример: Выдать все записи о расходе товаров из таблицы продаж (Sale), и для каждого товара его единицу измерения (Unit), цену (Price) и само наименование товара (NameTovar) из таблицы товаров (Tovar).
SQL
SELECT Sale.*, Tovar.Unit, Tovar.Price, Tovar.NameTovar
FROM Sale, Tovar
WHERE Sale.Tovar_ID = Tovar.ID

Результат запроса:
ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale Sum_Sale Unit
Price
NameTovar
1
2
1
15
12.01.2003
750
шт.
50
Рубашка
2
2
2
20
12.01.2003
1000
шт.
50
Рубашка
3
2
3
40
12.01.2003
2000
шт.
50
Рубашка
4
2
4
25
12.01.2003
1250
шт.
50
Рубашка
5
5
5
500
12.01.2003
1500
кг.
3
Мука
6
5
6
100
13.01.2003
300
кг.
3
Мука
7
5
7
5500
13.01.2003
16500
кг.
3
Мука
8
5
8
1000
13.01.2003
3000
кг.
3
Мука
9
5
9
250
13.01.2003
750
кг.
3
Мука
10
1
10
400
13.01.2003
4000
шт.
10
Носки
11
1
11
300
13.01.2003
3000
шт.
10
Носки
12
2
12
30
14.01.2003
1500
шт.
50
Рубашка
13
2
 
75
14.01.2003
3750
шт.
50
Рубашка
14
4
 
800
14.01.2003
5600
кг.
7
Колбаса
15
4
 
600
14.01.2003
4200
кг.
7
Колбаса
16
4
 
155
14.01.2003
1085
кг.
7
Колбаса
17
5
 
95
14.01.2003
285
кг.
3
Мука


Должен обратить внимание на одно особенность на то, что при определении столбцов, водящих в результирующий набор данных, мы можем написать запрос следующим образом:
SQL
SELECT *
FROM Sale, Tovar
WHERE Sale.Tovar_ID = Tovar.ID

что идентично:
SQL
SELECT Sale.*, Tovar.*
FROM Sale, Tovar
WHERE Sale.Tovar_ID = Tovar.ID

В результате выберутся все столбцы из таблиц продажи товаров (Sale) и самих товаров (Tovar):

Результат запроса:
ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale Sum_Sale ID_1
NameTovar
Unit
Price
1
2
1
15
12.01.2003
750
2
Рубашка
шт.
50
2
2
2
20
12.01.2003
1000
2
Рубашка
шт.
50
3
2
3
40
12.01.2003
2000
2
Рубашка
шт.
50
4
2
4
25
12.01.2003
1250
2
Рубашка
шт.
50
5
5
5
500
12.01.2003
1500
5
Мука
кг.
3
6
5
6
100
13.01.2003
300
5
Мука
кг.
3
7
5
7
5500
13.01.2003
16500
5
Мука
кг.
3
8
5
8
1000
13.01.2003
3000
5
Мука
кг.
3
9
5
9
250
13.01.2003
750
5
Мука
кг.
3
10
1
10
400
13.01.2003
4000
1
Носки
шт.
10
11
1
11
300
13.01.2003
3000
1
Носки
шт.
10
12
2
12
30
14.01.2003
1500
2
Рубашка
шт.
50
13
2
 
75
14.01.2003
3750
2
Рубашка
шт.
50
14
4
 
800
14.01.2003
5600
4
Колбаса
кг.
7
15
4
 
600
14.01.2003
4200
4
Колбаса
кг.
7
16
4
 
155
14.01.2003
1085
4
Колбаса
кг.
7
17
5
 
95
14.01.2003
285
5
Мука
кг.
3



При выполнении оператора SELECT для каждой записи из таблицы Sale ищется запись в таблице Tovar, у которой значение в поле Tovar_ID совпадает со значением в поле ID текущей записи таблицы Sale.
При этом безразлично, в каком порядке перечислять таблицы в условии поиска, т.е. безразлично, какая из таблиц будет упомянута слева, а какая справа. Таким образом, следующие условия пока идентичны:
SQL
Sale.Tovar_ID = Tovar.ID
Tovar.ID = Sale.Tovar_ID


Такой способ соединения таблиц называется внутренним соединением.

При внутреннем соединении двух таблиц, логический порядок формирования результирующего НД можно представить себе следующим образом:
1. Из столбцов, которые представлены после слова SELECT, составляется декартово произведение путем сцепления результирующих столбцов каждой записи из первой таблицы (в нашем случае Sale) и результирующих столбцов записи из второй таблицы (Tovar).
2. Из получившегося НД отбрасываются все записи, не удовлетворяющие условию поиска WHERE.

Замечание: Определение «логический порядок формирования результирующего набора данных» употреблено не случайно. В проектировании данных всегда различаются два уровня – логический и физический. Логический уровень – это часто достаточно абстрактный уровень; физический уровень определяет действительно протекающие процессы, в большинстве случаев скрытые от взгляда, не лежащие на поверхности.

Поэтому, когда мы говорим о «логическом порядке выполнения запроса». Это подразумевает, что так нам легче понимать процессы, происходящие при выполнении внутреннего соединения; на самом же деле физические процессы, реально протекающие на сервере БД при выполнении запроса, могут не совпадать с нашим логическим представлением о них.
SQL-сервер при выполнении запроса всегда стремиться его оптимизировать, т.е. выполнить с максимальной быстротой при минимально возможных затратах ресурсов.

При выполнении оператора SELECT для каждой записи из таблицы Sale ищется запись в таблице Tovar, у которой значение в поле Tovar_ID совпадает со значением в поле ID текущей записи таблицы Sale.
При этом безразлично, в каком порядке перечислять таблицы в условии поиска, т.е. безразлично, какая из таблиц будет упомянута слева, а какая справа. Таким образом, следующие условия пока идентичны:
SQL
Sale.Tovar_ID = Tovar.ID
Tovar.ID = Sale.Tovar_ID



Предложение ORDER BY – определение сортировки

Набор данных, выдаваемый в результате выполнения команды SELECT, в общем случае возвращается в неотсортированном виде. Это удобно далеко не всегда. Определить, по каким полям необходимо отсортировать записи в результирующем НД, можно, указав после предложения, следующего за словом WHERE, предложение

ORDER BY <список столбцов>

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

Пример: Выдать все записи из таблицы продаж, отсортировав их по количеству продаж.
SQL
SELECT *
FROM Sale ORDER BY Number_sale

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
1
2
15
12.01.2003
750
2
2
20
12.01.2003
1000
4
2
25
12.01.2003
1250
12
2
30
14.01.2003
1500
3
2
40
12.01.2003
2000
13
2
75
14.01.2003
3750
17
5
95
14.01.2003
285
6
5
100
13.01.2003
300
16
4
155
14.01.2003
1085
9
5
250
13.01.2003
750
11
1
300
13.01.2003
3000
10
1
400
13.01.2003
4000
5
5
500
12.01.2003
1500
15
4
600
14.01.2003
4200
14
4
800
14.01.2003
5600
8
5
1000
13.01.2003
3000
7
5
5500
13.01.2003
16500


Пример: Выдать все записи из таблицы продаж, где сумма продаж больше или равно 3000 и отсортировав полученные результаты по дате продаж:
SQL
SELECT *
FROM Sale WHERE Sum_Sale > = 3000
ORDER BY Date_sale

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
7
5
5500
13.01.2003
16500
8
5
1000
13.01.2003
3000
10
1
400
13.01.2003
4000
11
1
300
13.01.2003
3000
13
2
75
14.01.2003
3750
14
4
800
14.01.2003
5600


Пример: Выдать все записи из таблицы продаж, отсортировав полученный результирующий НД сначала по дате, а затем по сумме продаж.
SQL
SELECT *
FROM Sale ORDER BY Date_sale, Sum_sale

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
1
2
15
12.01.2003
750
2
2
20
12.01.2003
1000
5
5
500
12.01.2003
1500
3
2
40
12.01.2003
2000
4
2
25
12.01.2003
1250
6
5
100
13.01.2003
300
9
5
250
13.01.2003
750
11
1
300
13.01.2003
3000
8
5
1000
13.01.2003
3000
10
1
400
13.01.2003
4000
7
5
5500
13.01.2003
16500
17
5
95
14.01.2003
285
16
4
155
14.01.2003
1085
12
2
30
14.01.2003
1500
13
2
75
14.01.2003
3750
15
4
600
14.01.2003
4200
14
4
800
14.01.2003
5600


Пример: Выдать все записи из таблицы продаж, отсортировав полученный результирующий НД сначала по дате, а затем по сумме продаж.
SQL
SELECT *
FROM Sale ORDER BY Date_sale, Sum_sale

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
1
2
15
12.01.2003
750
2
2
20
12.01.2003
1000
5
5
500
12.01.2003
1500
3
2
40
12.01.2003
2000
4
2
25
12.01.2003
1250
6
5
100
13.01.2003
300
9
5
250
13.01.2003
750
11
1
300
13.01.2003
3000
8
5
1000
13.01.2003
3000
10
1
400
13.01.2003
4000
7
5
5500
13.01.2003
16500
17
5
95
14.01.2003
285
16
4
155
14.01.2003
1085
12
2
30
14.01.2003
1500
13
2
75
14.01.2003
3750
15
4
600
14.01.2003
4200
14
4
800
14.01.2003
5600


Пример: Выдать все записи о расходе товаров из таблицы продаж (Sale), и для каждого товара его единицу измерения (Unit), цену (Price) и само наименование товара (NameTovar) из таблицы товаров (Tovar) отсортировав результаты, сначала по наименованию товаров, а затем дате продажи:
SQL
SELECT S.*, T.Unit, T.Price, T.NameTovar
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
ORDER BY T.NameTovar, S.Date_sale

Результат запроса:
ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale Sum_Sale Unit
Price
NameTovar
16
4
 
155
14.01.2003
1085
кг.
7
Колбаса
15
4
 
600
14.01.2003
4200
кг.
7
Колбаса
14
4
 
800
14.01.2003
5600
кг.
7
Колбаса
5
5
5
500
12.01.2003
1500
кг.
3
Мука
9
5
9
250
13.01.2003
750
кг.
3
Мука
6
5
6
100
13.01.2003
300
кг.
3
Мука
7
5
7
5500
13.01.2003
16500
кг.
3
Мука
8
5
8
1000
13.01.2003
3000
кг.
3
Мука
17
5
 
95
14.01.2003
285
кг.
3
Мука
10
1
10
400
13.01.2003
4000
шт.
10
Носки
11
1
11
300
13.01.2003
3000
шт.
10
Носки
4
2
4
25
12.01.2003
1250
шт.
50
Рубашка
3
2
3
40
12.01.2003
2000
шт.
50
Рубашка
2
2
2
20
12.01.2003
1000
шт.
50
Рубашка
1
2
1
15
12.01.2003
750
шт.
50
Рубашка
12
2
12
30
14.01.2003
1500
шт.
50
Рубашка
13
2
 
75
14.01.2003
3750
шт.
50
Рубашка


Сортировка данных по умолчанию

Полный формат предложения ORDER BY имеет следующий формат:

ORDER BY <список столбцов> [ASC|DESC]

Параметры ASC и DESC задают правила упорядочивания сортировки.

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

Параметр DESC - сортировка в порядке убывания.

Как уже говорилось, по умолчанию данные сортируются в порядке возрастания:
• Числовые значения выводятся, начиная с самых малых (например, с 1 по 999);
• Даты выводятся, начиная с самых ранних (например, дата 12.01.2002 предшествует дате 13.01.2003);
• Символьные значения выводиться в алфавитном порядке – например, от «A» до «Z» (соответственно от «А» до «Я»), от «a» до «z» (соответственно от «а» до «я»)
• Неопределенные значения при сортировке по возрастанию выводятся последними, а при сортировке по убыванию – первыми.

Пример: Выдать все продажи в таблице продаж (Sale) отсортированные по количеству продаж (Number_sale) по убыванию.

SQL
SELECT *
FROM Sale ORDER BY Number_sale DESC

Результат запроса:
ID
Tovar_ID
Number_Sale
Date_Sale
Sum_Sale
7
5
5500
13.01.2003
16500
8
5
1000
13.01.2003
3000
14
4
800
14.01.2003
5600
15
4
600
14.01.2003
4200
5
5
500
12.01.2003
1500
10
1
400
13.01.2003
4000
11
1
300
13.01.2003
3000
9
5
250
13.01.2003
750
16
4
155
14.01.2003
1085
6
5
100
13.01.2003
300
17
5
95
14.01.2003
285
13
2
75
14.01.2003
3750
3
2
40
12.01.2003
2000
12
2
30
14.01.2003
1500
4
2
25
12.01.2003
1250
2
2
20
12.01.2003
1000
1
2
15
12.01.2003
750



Устранение повторяющихся значений (приложение DISTINCT)

Довольно часто в результирующий НД необходимо включать не все записи с одинаковым значением какого-либо столбца (комбинации столбцов), а только одну из них. В этом случае после ключевого слова SELECT указывают ключевое слово DISTINCT

SELECT [DISTINCT | ALL] {* | <значение1> [, <значение2> …]}
FROM <таблица1> [, <таблица2> …]


Повторяющимися считаются записи, содержащие идентичные значения во всех столбцах результирующего НД.
Наоборот, если в результирующий запрос нужно включить все записи, после слова SELECT указывается слово ALL.

Примечание: Обычно нет необходимости использовать ALL явно, поскольку это значение действует по умолчанию.

Пример: Выдать даты всех отпущенных товаров из таблицы продаж:
SQL
SELECT DISTINCT Date_Sale
FROM Sale

Результат запроса:
Date_Sale
12.01.2003
13.01.2003
14.01.2003



Расчет значений результирующих столбцов на основе арифметических выражений

Иногда требуется изменить формат вывода данных, произвести вычисления или выполнить сценарии типа «что, если…». Сделать это можно, с помощью арифметических выражений. Арифметическое выражение может включать имена столбцов, числовые константы и арифметические операторы.

Арифметические операторы SQL:
+ сложение
- вычитание
* умножение
/ деление

Все они могут использоваться в любых предложениях команды SQL, за исключением предложения FROM.

Если арифметическое выражение содержит более одного оператора, сначала выполняются умножение и деление. Эти операторы в выражении имеют одинаковый приоритет, они выполняются слева на право. Для изменения порядка выполнения оператора можно использовать круглые скобки, выражения в скобках вычисляются первыми.

В основном арифметические выражения используются для расчета значений вычисляемых столбцов результирующего НД. Как видно из вышеприведенного, при их формировании следует придерживаться общих правил формирования арифметических выражений, принятых в алгоритмических языках (например, Pascal или C/C++). При этом в списке возвращаемых столбцов после слова SELECT вместо имени вычисляемого столбца указывается выражение:

SELECT [DISTINCT | ALL] {* | <столбец1> [, <выражение1> …]}
FROM <таблица1> [, <таблица2> …]


Пример: Выдать все записи о продажах товара из таблицы продаж Sale, для каждого товара рассчитать общую стоимость отпущенного товара, умножив количество проданных единиц (Number_sale) на стоимость товара (Price), взятую из таблицы товаров Tovar.

SQL
SELECT S.*, T.NameTovar, T.Price, S.Number_sale*T.Price
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID

Результат запроса:
ID Number_Sale Date_Sale NameTovar Price Number_Sale*Price
1
15
12.01.2003
Рубашка
50
750
2
20
12.01.2003
Рубашка
50
1000
3
40
12.01.2003
Рубашка
50
2000
4
25
12.01.2003
Рубашка
50
1250
5
500
12.01.2003
Мука
3
1500
6
100
13.01.2003
Мука
3
300
7
5500
13.01.2003
Мука
3
16500
8
1000
13.01.2003
Мука
3
3000
9
250
13.01.2003
Мука
3
750
10
400
13.01.2003
Носки
10
4000
11
300
13.01.2003
Носки
10
3000
12
30
14.01.2003
Рубашка
50
1500
13
75
14.01.2003
Рубашка
50
3750
14
800
14.01.2003
Рубашка
50
5600
15
600
14.01.2003
Колбаса
7
4200
16
155
14.01.2003
Колбаса
7
1085
17
95
14.01.2003
Мука
3
285


Как видно из таблицы, результат вычисления выражения S.Number_sale*T.Price для каждой записи таблицы продаж Sale записан в сгенерированный столбец, которому по умолчанию присвоено имя «Number_sale*Price». В случае, если необходимо присвоить имя столбцу, содержащему результаты вычисления выражения, это имя можно указать после выражения вслед за ключевым словом AS:

SELECT ... {* | <столбец1> [, <выражение1> …]}

Пример: Выдаваемому в предыдущем примере вычисляемому столбцу присвоить имя Summa

SQL
SELECT S.*, T.NameTovar, T.Price, S.Number_sale*T.Price AS Summa
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID

Результат запроса:
ID Number_Sale Date_Sale NameTovar Price Summa
1
15
12.01.2003
Рубашка
50
750
2
20
12.01.2003
Рубашка
50
1000
3
40
12.01.2003
Рубашка
50
2000
4
25
12.01.2003
Рубашка
50
1250
5
500
12.01.2003
Мука
3
1500
6
100
13.01.2003
Мука
3
300
7
5500
13.01.2003
Мука
3
16500
8
1000
13.01.2003
Мука
3
3000
9
250
13.01.2003
Мука
3
750
10
400
13.01.2003
Носки
10
4000
11
300
13.01.2003
Носки
10
3000
12
30
14.01.2003
Рубашка
50
1500
13
75
14.01.2003
Рубашка
50
3750
14
800
14.01.2003
Рубашка
50
5600
15
600
14.01.2003
Колбаса
7
4200
16
155
14.01.2003
Колбаса
7
1085
17
95
14.01.2003
Мука
3
285


Имя, которое мы присвоили нашему вычисляемому столбцу, называется псевдонимом столбца.

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


Использование оператора конкатенации и литерал

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

Иначе говоря, оператор конкатенации:
• Соединяет столбцы и символьные строки с другими столбцами;
• Изображается двумя вертикальными линиями (||).
• Создает столбец с результатом, представляющий символьное выражение.

Пример: Соединить столбцы имени товара (NameTovar) и единицу измерения (Unit) из таблицы товаров (Tovar) и присвоить результирующему столбцу имя MyColum:
SQL
SELECT T.NameTovar||T.Unit AS MyColum
FROM Tovar T


Результат запроса:
MyColum
Носкишт.
Рубашкашт.
Сахаркг.
Колбасакг.
Мукакг.
Сигаретыпач.


Литерал – это любой символ, выражение или число, включенные в SELECT список и не являющийся именем или псевдонимом столбца. Литерал выводиться для каждой возвращаемой строки. Литеральные строки в виде свободного текста можно включать в результаты запросов, они обрабатываются так же, как столбец из списка SELECT.
Символьные литералы и литералы с датами должны быть заключены в одиночные апострофы (‘ ‘); цифровые литералы в апострофы не заключаются.

Пример: В приведенный нами выше пример, мы между наименование товара и единицей измерения добавим следующую строку «, единица измерения - ».
SQL
SELECT T.NameTovar||’, единица измерения – ‘||T.Unit AS MyColum
FROM Tovar T


Результат запроса:
MyColum
Носки, единица измерения - шт.
Рубашка, единица измерения - шт.
Сахар, единица измерения - кг.
Колбаса, единица измерения - кг.
Мука, единица измерения - кг.
Сигареты, единица измерения - пач.



Агрегатные функции

Агрегатные функции предназначены для выдачи итоговых значений. К агрегатным функциям относятся функции:
COUNT (<выражение>) – подсчитывает число вхождений значения выражения во все записи результирующего НД;
SUM (<выражение>) – суммирует значение выражении;
AVG (<выражение>) – находит среднее значение выражения;
MAX (<выражение>) – определяет максимальное значение выражения;
MIN (<выражение>) – определяет минимальное значение выражения;

Если из группы одинаковых записей, надо учитывать только одну, перед выражением в скобках включают слово DISTINCT
SQL
COUNT (DISTINCT NameTovar)

Чаще всего в качестве выражения выступают имена столбцов.
Выражение может вычисляться по значениям нескольких таблиц.

• функции AVG и SUM применяются только к столбцам, с числовыми данными;
• функции MAX и MIN применяются к данным любого типа;

Должен заметить, что имеется два формата функции COUNT:
COUNT (<выражение>) – как мы уже отмечали, эта функция подсчитывает число вхождений значения выражения во все записи результирующего НД;
COUNT (*) – возвращает общее количество строк в таблице;

Пример: Подсчитать количество проданных товаров:

SQL
SELECT COUNT(DISTINCT T.NameTovar) AS Count_Tovar
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID

Результат запроса:
Count_Tovar
4


Пример: Вычислить общую стоимость отпущенных товаров.

SQL
SELECT SUM(S.Number_sale*T.Price) AS Gen_Summa
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID

Результат запроса:
Gen_Summa
50470



Использование группировок записей (предложение GROUP BY)

Часто требуется выдать агрегированные значения (минимум, максимум, среднее) не по всему результирующему НД, а по каждой из входящих в него групп записей, характеризующихся одинаковым значением какого-либо столбца.
Иначе говоря, до сих пор, мы рассматривали таблицу, как одну большую группу информации. Но иногда требуется разделить таблицу на более мелкие группы. В этом случае оператор SELECT после предложения WHERE вводиться предложение

GROUP BY столбец [, столбец1 …]

Предложение GROUP BY разбивает строки таблицы на группы.
При этом необходимо, чтобы один из столбцов результирующего НД был представлен агрегатной функцией.

• Если агрегатная функция задана в предложении SELECT, получить одноименно индивидуальный результат можно только в случае, если отдельный столбец указан в предложении GROUP BY. Если предложение GROUP BY со списком столбцов отсутствует, выдается сообщение об ошибке.
• Предложение WHERE позволяет исключать строки до их группировки.
• Список столбцов в предложении GROUP BY обязателен.
• Использование псевдонимов столбцов в предложении GROUP BY недопустимо.
• По умолчанию строки сортируются в порядке возрастания значений столбцов, заданных в предложении GROUP BY, изменить этот порядок можно с помощью предложения ORDER BY.
• Если используется приложение GROUP BY, все столбцы, указанные в предложении SELECT, к которым не применяется групповые функции, должны быть обязательно включены в предложение GROUP BY.
• Столбец, заданный в предложении GROUP BY, может отсутствовать в предложении SELECT.

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

SQL
SELECT T.NameTovar, SUM(S.Number_sale) AS Gen_Number_Sale
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY T.NameTovar

Результат запроса:
NameTovar
Gen_Number_Sale
Колбаса
1555
Мука
7445
Носки
700
Рубашка
205


Пример: Выдать общую сумму продажи товара по каждому из наименований товаров

SQL
SELECT T.NameTovar, SUM(S.Number_sale*T.Price) AS Gen_Sum
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY T.NameTovar

Результат запроса:
NameTovar
Gen_Sum
Колбаса
10885
Мука
22335
Носки
7000
Рубашка
10250


Пример: Выдать общую сумму продажи товара по каждому из наименований товаров на каждую дату

SQL
SELECT T.NameTovar, S.Date_sale, SUM (S.Number_sale*T.Price) AS Gen_Sum
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY T.NameTovar, S.Date_sale

Результат запроса:
NameTovar
Date_Sale
Gen_Sum
Колбаса
14.01.2003
10885
Мука
12.01.2003
1500
Мука
13.01.2003
20550
Мука
14.01.2003
285
Носки
13.01.2003
7000
Рубашка
12.01.2003
5000
Рубашка
14.01.2003
5250


Пример: Выдать количество проданных товаров на каждую дату

SQL
SELECT S.Date_sale, COUNT (DISTINCT S.Number_sale) AS Gen_Number_Sale
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY S.Date_sale

Результат запроса:
Date_Sale
Gen_Number_Sale
12.01.2003
5
13.01.2003
6
14.01.2003
6



Предложение HAVING – наложение ограничений на группировку записей

Подобно тому, как предложение WHERE используется для исключения строк, предложение HAVING используется для исключения групп. Т.е. если нужно в результирующем НД выдавать агрегатную функцию не по всем группам, а только по тем из них, которые отвечают некоторому условию, после предложения GROUP BY указывается предложение:

HAVING <условие поиска>

где условия поиска указывается по тем же правилам, что и условия поиска для предложения WHERE за важным исключением: в условии поиска предложения HAVING можно использовать агрегатные функции, чего нельзя делать в условиях поиска для WHERE.

На физическом уровне, большинство серверов обрабатывают предложение HAVING следующим образом:
• Строки группируются;
• К группе применяется агрегатная функция;
• Выводятся группы, удовлетворяющие условиям в предложении HAVING.

Предложение HAVING может предшествовать предложению GROUP BY, но исходя из вышеперечисленного, логичнее сделать предложение GROUP BY первым, поскольку образование групп и вычисление агрегатных функций происходит до того, как к группам применяется предложение HAVING.

Пример: Выдать минимальное количество единиц продажи товара для всех наименований товаров, для которых минимальное количество проданных товаров не меньше 200 единиц.

SQL
SELECT T.NameTovar, MIN(S.Number_sale) AS Min_Number_Sale
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY T.NameTovar
HAVING MIN(S.Number_sale) > = 200

Результат запроса:
NameTovar
Min_Number_Sale
Носки
300


Если мы не будем указывать:
SQL
HAVING MIN(S.Number_sale) > = 200

будут выданы все группы:

Результат запроса:
NameTovar
Min_Number_Sale
Колбаса
155
Мука
95
Носки
300
Рубашка
15


Можно указывать различные агрегатные функции для возвращаемого столбца и условия HAVING.

Пример: Выдать общее количество проданного товара (в единицах) для всех наименований товаров, у которых минимальное количество покупаемого товара не меньше 100 единиц.

SQL
SELECT T.NameTovar, SUM(S.Number_sale) AS Sum_Number_Sale
FROM Sale S, Tovar T
WHERE S.Tovar_ID = T.ID
GROUP BY T.NameTovar
HAVING MIN(S.Number_sale) > = 100

Результат запроса:
NameTovar
Sum_Number_Sale
Колбаса
1555
Носки
700


Замечание: Следует всегда помнить, чем условие HAVING отличается от условия WHERE:
• HAVING исключает из результирующего НД группы с результатами агрегированных значений.
• WHERE исключает из расчета агрегатных значений по группировкам записи, не удовлетворяющие условию.
• В условии поиска WHERE нельзя указывать агрегатные функции.

Пример: Выдать на каждую дату число отпусков товаров из таблицы продаж, в которых количество отпускаемых товаров больше или равно 800 единицам:

SQL
SELECT S.Date_sale, COUNT(*) AS Count_sale
FROM Sale S
WHERE S.Number_sale > = 800
GROUP BY S.Date_sale

Результат запроса:
Date_Sale
Count_Sale
13.01.2003
2
14.01.2003
1


Пример: Выдать даты отпусков товара, в которых количество отпускаемого товара больше или равно 800 единицам. В результирующий НД включить только те группы, по которым число таких отпусков товаров больше 1:

SQL
SELECT S.Date_sale, COUNT(*) AS Count_sale
FROM Sale S
WHERE S.Number_sale > = 800
GROUP BY S.Date_sale
HAVING COUNT(*) > 1

Результат запроса:
Date_Sale
Count_Sale
13.01.2003
2



Подведем краткий итог:

Мы рассмотрели пять агрегатных (их еще называют групповыми) функций:

COUNT– подсчитывает число вхождений значения во все записи результирующего НД;
SUM – суммирует значение;
AVG – находит среднее значение;
MAX – определяет максимальное значение;
MIN – определяет минимальное значение;

Предложение GROUP BY позволяет создавать группы строк. Исключать группы можно с помощью предложения HAVING.
В операторе SELECT предложения HAVING и GROUP BY должны следовать за предложением WHERE. Предложение ORDER BY всегда должно быть последним.

Большинство серверов БД обрабатывают предложения в следующем порядке:
• Если имеется предложение WHERE, сервер выявляет строки-кандидаты.
• Сервер выявляет группы, заданные предложением GROUP BY.
• Предложение HAVING исключает из выходных данных группы, не удовлетворяющие критериям.


Замечание: Некоторые сервера БД (например, Oracle) позволяют осуществлять вложенные групповые функции, но только в два уровня.

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

SQL
SELECT MAX(AVG(S.Number_sale)) AS MAX_AVG_sale
FROM Sale S
GROUP BY S.Date_sale

Результат запроса:
MAX_AVG_Sale
8361,66666666667



ПРЕДЛОЖЕНИЕ WHERE: ЗАДАНИЕ СЛОЖНЫХ УСЛОВИЙ ПОИСКА

Ранее нами были рассмотрены простые варианты задания условий поиска в предложении WHERE (сравнение столбца с константой и внутреннее соединение). Однако условие поиска могут быть достаточно сложными (чем отчасти и объясняется такая мощная функциональность SQL запросов), чему собственно и способствует синтаксис оператора SELECT. Рассмотрим основные конструкции для построение сложных условий поиска.


Использование логических выражений

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

Пример: Выдать из таблицы продаж (Sale) все продажи товаров за 12.01.2003 и для каждого товара выдать его наименование из таблицы товаров (Tovar)

SQL
SELECT S.*, T.NameTovar
FROM Sale S, Tovar T
WHERE (S.Tovar_ID = T.ID) AND (S.Date_Sale = ’12.01.2003.’)

Результат запроса:
ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale Sum_Sale
NameTovar
1
2
1
15
12.01.2003
750
Рубашка
2
2
2
20
12.01.2003
1000
Рубашка
3
2
3
40
12.01.2003
2000
Рубашка
4
2
4
25
12.01.2003
1250
Рубашка
5
5
5
500
12.01.2003
1500
Мука


Пример: Выдать из таблицы продаж (Sale) все продажи товаров, осуществленные после 13.01.2003, где количество проданных товаров должно быть больше 100 единиц и меньше 1000 единиц, а также для каждого товара всю информацию, из таблицы товаров (Tovar). Кроме этого, результаты запроса должны быть отсортированы по количеству проданных единиц товара (Number_Sale)

SQL
SELECT S.*, T.*
FROM Sale S, Tovar T
WHERE (S.Tovar_ID = T.ID) AND (S.Date_Sale > = '13.01.2003.') AND (S.Number_sale > 100) AND (S.Number_sale < 1000)
ORDER BY S.Number_sale

Результат запроса:
ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale Sum_Sale ID_1
NameTovar
Unit
Price
16
4
 
155
14.01.2003
1085
4
Колбаса
кг.
7
9
5
9
250
13.01.2003
750
5
Мука
кг.
3
11
1
11
300
13.01.2003
3000
1
Носки
шт.
10
10
1
10
400
13.01.2003
4000
1
Носки
шт.
10
15
4
 
600
14.01.2003
4200
4
Колбаса
кг.
7
14
4
 
800
14.01.2003
5600
2
Рубашка
кг.
50



Сравнение столбца с результатом вычисления выражения

Условие поиска в предложении WHERE может быть сформулировано при помощи выражения:

<выражение> <оператор> <столбец>

Пример: (T.Price*S.Number_Sale = S.Sum_Sale)


Может использоваться и другой способ написания условия поиска:

<столбец> <оператор> <выражение>

Пример: (S.Number_sale > 100*10)

однако оно чаще всего применяется при использовании механизма вложенных подзапросов (вложенных операторов SELECT), речь о которых пойдет ниже. В этом случае результат вычисления выражения сравнивается с содержимым указанного столбца.

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

SQL
SELECT S.Number_Sale, S.Date_Sale, T.NameTovar, T.Unit, T.Price
FROM Sale S, Tovar T
WHERE (S.Tovar_ID = T.ID) AND ((S.Number_sale * T.Price) > 2000)

Результат запроса:
Number_Sale Date_Sale
NameTovar
Unit
Price
5500
13.01.2003
Мука
кг.
3
1000
13.01.2003
Мука
кг.
3
400
13.01.2003
Носки
шт.
10
300
13.01.2003
Носки
шт.
10
75
14.01.2003
Рубашка
шт.
50
800
14.01.2003
Колбаса
кг.
7
600
14.01.2003
Колбаса
кг.
7


Использование BETWEEN

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

<значение> [NOT] BETWEEN <значение1> AND <значение2>

Зарезервированное слово NOT инвертирует условие (т.е. значение не должно находиться в интервале между двумя заданными значениями).
Иначе говоря, с помощью ключевого слова BETWEEN можно проверять записи на вхождение в заданный диапазон значений. Диапазон имеет нижнюю и верхнюю границы.
Граничные значения, задаваемые с помощью BETWEEN, входят в диапазон (т.е. указываются включительно) Прежде необходимо задать нижнюю границу.

Пример: Выдать продажи, где количество проданного товара (в единицах) лежит в диапазоне 100…300.
SQL
SELECT S.*
FROM Sale S
WHERE S.Number_sale BETWEEN 100 AND 300

Результат запроса:
Number_Sale ID
Tovar_ID
Waybill_ID
Date_Sale Sum_Sale
100
6
5
6
13.01.2003
300
250
9
5
9
13.01.2003
750
300
11
1
11
13.01.2003
3000
155
16
4
 
14.01.2003
1085


Пример: Выдать все продажи, где сумма продаж находится в пределе с 1000 до 3000 и осуществленные с 13.01.2003 по 14.01.2003:
SQL
SELECT S.*
FROM Sale S
WHERE (S.Sum_sale BETWEEN 1000 AND 3000) AND (S.Date_sale BETWEEN '13.01.2003' AND '14.01.2003')
ORDER BY S.Date_sale, S.Number_sale

Результат запроса:
Date_Sale Sum_Sale ID
Tovar_ID
Waybill_ID
Number_Sale
13.01.2003
3000
11
1
11
300
13.01.2003
3000
8
5
8
1000
14.01.2003
1500
12
2
12
30
14.01.2003
1085
16
4
 
155



Ключевое слово IN (список значений)

Оператор IN используется для проверки на вхождение значений в список. Т.е. если нужно, чтобы значение какого-либо столбца (или результат вычисления некоторого выражения) совпадало с одним из дискретных значений в условии поиска указывается предложение

<значение> [NOT] IN (<значение1> [,<значение2>…])

Тогда в результирующий набор данных будут включены только те записи, для которых значение, стоящее слева от слова IN равно одному из значений, указанных в списке (<значение1> [,<значение2>…]).

Оператор IN может использоваться с данными любого типа. Если в значение списка входят символьные строки и даты, они должны быть заключены в апострофы (‘’);

Пример: Выдать сведения обо всех продажах, где количество проданного товара (в единицах) равно или 300, или 500, или 1000.
SQL
SELECT *
FROM Sale S
WHERE S.Number_Sale IN (300, 500, 1000)

Результат запроса:
Number_Sale ID
Tovar_ID
Waybill_ID
Date_Sale Sum_Sale
500
5
5
5
12.01.2003
1500
1000
8
5
6
13.01.2003
1500
300
11
1
11
13.01.2003
3000


Пример: Выдать сведения обо всех продажах, где сумма проданного товара не равна 1000, 3000, 1500, 2000 и 750.
SQL
SELECT *
FROM Sale S
WHERE S.Number_Sale NOT IN (1000, 3000, 1500, 2000, 750)

Результат запроса:
Sum_Sale ID
Tovar_ID
Waybill_ID
Number_Sale Date_Sale
1250
4
2
4
25
12.01.2003
300
6
5
6
100
13.01.2003
16500
7
5
7
5500
13.01.2003
4000
10
1
10
400
13.01.2003
3750
13
2
 
75
14.01.2003
5600
14
4
 
800
14.01.2003
4200
15
4
 
600
14.01.2003
1085
16
4
 
155
14.01.2003
285
17
5
 
95
14.01.2003


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


Использование UPPER
(преобразование символьных значений полей к верхнему регистру)


Функция UPPER(<значение>) используется для преобразования букв символьных значений (содержимого столбца, результат вычисления выражения) к заглавным буквам. Обычно эта функция используется в условие поиска, когда необходимо игнорировать возможную разницу в высоте букв. Функция UPPER может фигурировать как в списке столбцов результирующего НД, (т.е. после слова SELECT), так и в условии поиска в предложении WHERE. Т.е. иначе говоря, функция UPPER преобразует строку символов нижнего регистра или обоих регистров в символы верхнего регистра.

Чтобы наиболее полно отразить функциональность функции UPPER, давайте добавим в таблицу клиентов Clients, новое поле City. В которое мы запишем информацию из какого города клиент.
Таблица клиентов Clients:
ID
NameClients
Adres
City
1
ООО Евразия
ул. Ольшанского, 19
Екатеринбург
2
ООО Пертовка
ул. Петровка, 38
Москва
3
АО Центрснаб
ул. Заболотная, 8
Омск
4
ЗАО Геркулес
ул. Якиманка, 45
МОСКВА
5
АО Центр
м-н Молодежный, 20
Астана


Пример: Нам необходимо найти всех клиентов из Москвы. Однако, если вы заметили, в столбце City в одном случае имя города Москва, пишется как «Москва», а в другом случае, как «МОСКВА». Если мы попытаемся выполнить следующий запрос, то нам будет выдан только один клиент. Т.е. логически результирующий запрос будет не совсем полным:
SQL
SELECT *
FROM Clients WHERE City = ‘Москва’

Результат запроса:
ID
NameClients
Adres
City
2
ООО Пертовка
ул. Петровка, 38
Москва


Данная проблема решается приведением обоих составляющих условия поиска к одному общему виду.
SQL
SELECT *
FROM Clients WHERE UPPER(City) = ‘МОСКВА’

Результат запроса:
ID
NameClients
Adres
City
2
ООО Пертовка
ул. Петровка, 38
Москва
4
ЗАО Геркулес
ул. Якиманка, 45
МОСКВА


Можно сделать еще и просто приведение всех значения столбца City результирующего НД к верхнему регистру.
SQL
SELECT ID, NameClients, Adres, UPPER(City)
FROM Clients WHERE UPPER(City) = 'МОСКВА'

Результат запроса:
ID
NameClients
Adres
City
2
ООО Пертовка
ул. Петровка, 38
МОСКВА
4
ЗАО Геркулес
ул. Якиманка, 45
МОСКВА



Использование LIKE
(задание шаблонов сравнения строковых значений)


Иногда, точное искомое значение не известно. Оператор LIKE позволяет выбирать строки, соответствующие определенному символьному шаблону. Говоря простым языком, LIKE задает шаблоны сравнения строковых значений. Если необходимо, чтобы сравниваемое значение (значение столбца или результат вычисления строкового выражения) удовлетворяло шаблону, в условии поиска необходимо указать

<значение> [NOT] LIKE <шаблон> [ESCAPE <подшаблон>]

Такая операция поиска называется поиском по метасимволам (wildcard search). Для создания шаблона, могут использоваться два метасимвола:
«%» - представляет любую последовательность из нуля или более символов
«_» - Представляет любой одиночный символ

Иначе говоря, символ «%» (процент) используется для указания любого значения любой длины, а символ «_» (подчеркивание) для указания любого единичного случая.

Например:
LIKE ‘%ая’ - указывает, что сравниваемое значение должно оканчиваться символами «ая» (например «хорошая» или «неистребимая»).

LIKE ‘_аз’ - указывает, что сравниваемое значение может содержать всего 3 символа, из который первый символ может быть любым, а последние два только «аз» (например «раз» или «газ»).

Пример: Выбрать из таблицы клиентов (Clients) только клиентов, у которых форма собственности является АО (Акционерное общество).
SQL
SELECT *
FROM Clients WHERE NameClients LIKE ‘АО%’

Результат запроса:
ID
NameClients
Adres
City
3
АО Центрснаб
ул. Заболотная, 8
Омск
5
АО Центр
м-н Молодежный, 20
Астана


Метасимволы в шаблоне можно комбинировать.
Символы «%» и «_» можно комбинировать с литеральными символами. Следующий пример, показывает вывод всех наименований товаров, вторая буква в которых «о».

Пример: Требуется вывести все наименования товаров из таблицы Tovar, у которых вторая буква – «о».
SQL
SELECT *
FROM Tovar WHERE NameTovar LIKE ‘_о%’

Результат запроса:
ID
NameTovar
Unit
Price
1
Носки
шт.
10
4
Колбаса
кг.
7


Пример: Пусть необходимо выдать информацию о клиенте, имя которого забыли, и название улицы помним не точно, то ли Ольшанская, то ли Ольшанского, то ли Ольшаинского. Но точно помним, что название улицы начинается с «Ольша». Тогда нужно выполнить следующий запрос.
SQL
SELECT *
FROM Clients WHERE Adres LIKE ‘%Ольша%’

Результат запроса:
ID
NameClients
Adres
City
1
ООО Евразия
ул. Ольшанского, 19
Екатеринбург


Опция ESCAPE
Если поиск производиться не по метасимволам, а по действительным символам «%» и «_», необходимо использовать опцию ESCAPE. Или говоря иначе, ESCAPE <подшаблон> используется, если в предложении LIKE символы «%» и «_» должны использоваться в шаблоне, как обычные символы (без учета их специальных функций). В этом случае с помощью ESCAPE указывается символ, появление которого в шаблоне отменяет функцию следующего за ним символа («%» или «_»).
Например, в данном случае, выведутся все значения из поля Columns, которые, заканчиваются на символ «%»:
SQL
WHERE Columns LIKE ‘%/%’ ESCAPE ‘/’


Т.к. в шаблоне ‘%/%’ косая черта предшествует символу процента «%», (т.е который стоит после косой черты «/»), то он соответственно воспринимается не как метасимвол, а буквально.

В качестве значения опции ESCAPE можно использовать любой символ.
Также, в условие поиска (шаблоне) предложения LIKE, могут быть включены как алфавитные, так и цифровые символы.


Функция CAST (преобразование типов)

Иногда возникает потребность трактовать значение одно типа как значение другого типа. Например, использовать числовое значение как символьную строку, или наоборот. В этом случае применяют функцию CAST.

CAST (<значение> AS <тип данных>)

Функция CAST делает копию значения, преобразуя его к указанному типу данных. При этом важно не забывать о множестве типов данных, в которое может быть преобразовано данное значение.

Примечание: Я не буду подробно рассматривать в этой статье примеры использования функции CAST. Так как ее применение напрямую зависит от SQL-сервера (в частности от используемых в нем типов данных), с которым вы работаете в данный момент.

Примечание: в Oracle функция CAST вообще отсутствует. В место этого необходимо использовать однострочные функции TO_NAMBER, TO_DATE или TO_CHAR.


ПОДЗАПРОСЫ

Подзапрос – это команда SELECT, включенная в предложение другой команды SELECT. С помощью подзапросов можно создавать очень мощные команды из простых. Они очень полезны в тех случаях, когда выборка строк из таблицы осуществляется по условию, основанному на данных в этой же самой таблице.
Часто просто невозможно решить поставленную задачу путем использования одного запроса. Это также особенно актуально в тех случаях, когда при использовании условия поиска в предложении WHERE

<сравниваемое значение> <оператор> <значение, с которым сравнивать>

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

Внутренний подзапрос представляет собой также оператор SELECT и кодирование его предложений подчиняется тем же правилам, что и для основного оператора SELECT.

В общем случае оператор SELECT с подзапросом имеет вид:

SELECT ...
FROM ...
WHERE <сравниваемое значение> <оператор> (SELECT ... FROM ... WHERE ...)


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

Подзапрос можно использовать в следующих предложениях SQL команд:
WHERE
HAVING

Примечание: Такие сервера как Oracle, MS SQL, Interbase поддерживают использование подзапросов еще и в предложении FROM.

Подзапросы могут быть трех типов:
Однострочные подзапросы: запросы, в которых вложенная команда SELECT возвращает только одну запись (строку);
Многострочные подзапросы: запросы, в которых вложенные команда SELECT возвращает более одной записи;

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

Подзапросы могут быть вложены многократно.
Внешний и вложенный подзапросы могут выбирать данные из разных таблиц.

Теперь рассмотрим по отдельности каждый из типов подзапросов.


Однострочные подзапросы

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

= равно
> больше
>= больше или равно
< меньше
<= меньше или равно
<> не равно

Пример: Вывести все товары из таблицы товаров (Tovar), у которых единица измерения (Unit) такая же, как и у товара с наименованием «Сахар».

SQL
SELECT NameTovar, Unit
FROM Tovar WHERE Unit = (SELECT Unit FROM Tovar WHERE NameTovar = ‘Сахар’)

Результат запроса:
NameTovar
Unit
Сахар
кг.
Колбаса
кг.
Мука
кг.


Пример: Вывести все товары, у которых единица измерения такая же, как и у товара с наименованием «Мука», но имеют большую цену.
SQL
SELECT NameTovar, Unit, Price
FROM Tovar WHERE Unit = (SELECT Unit FROM Tovar WHERE NameTovar = ‘Мука’) AND Price > (SELECT Price FROM Tovar WHERE NameTovar = ‘Мука’)

Результат запроса:
NameTovar
Unit
Price
Сахар
кг.
5
Колбаса
кг.
7


Вышеприведенный пример состоит из трех блоков запроса – одного внешнего (главного) и двух вложенных подзапросов. Сначала выполняются вложенные блоки, их результаты – «кг.» и «3». Затем выполняется внешний блок. Для создания условий поиска он использует результаты вложенных запросов.

Можно получить данные в главном запросе, используя (агрегатную) групповую функцию во вложенном подзапросе, возвращающую одну строку.

Пример: Выдать все даты, из таблицы продаж (Sale), на которые приходиться максимальный отпуск товаров.
SQL
SELECT Number_sale, Date_sale
FROM Sale WHERE Number_sale = (SELECT MAX(Number_Sale) FROM Sale)

Результат запроса:
Number_Sale
Date_Sale
5500
13.01.2003


Примечание: Одна из самых распространенных ошибок, при написании однострочных подзапросов, - это когда однострочный подзапрос возвращает более одной строки. Т.е. когда используется однострочный оператор, с многострочным подзапросом. Прошу вас при написании таких запросов, обратить особое внимание, на данное обстоятельство.

Примечание: Еще одна из самых распространенных проблем – это когда внутренний запрос, не возвращает ни одной строки, иначе говоря, подзапрос не возвращает ни каких значений. В таких случаях, внешний запрос берет результаты подзапроса (неопределенное значение) и использует их. Естественно, что в данном случае, внешний запрос ни чего не возвращает.


Многострочные подзапросы

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

Многострочные операторы сравнения:

IN - Равно любому члену списка;
ANY - Сравнение значения с любым значением, возвращаемым подзапросом;
ALL - Cравнение значения с каждым значением, возвращаемым подзапросом.

Рассмотрим эти операторы более подробно.

В большинстве случаев, если подзапрос возвращает множество значений, используется оператор сравнения IN.

Например: Выбрать все продажи каких-либо товаров, которые в свое время был проданы на наибольшую сумму.
SQL
SELECT S.ID, S.Sum_sale, S.Number_sale, S.Date_sale, T.NameTovar
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID AND S.Tovar_ID IN (SELECT Tovar_ID FROM Sale WHERE Sum_Sale = (SELECT MAX(Sum_Sale) FROM SALE)) ORDER BY S.Sum_Sale DESC

Результат запроса:
Sum_Sale
NameTovar
Tovar_ID
Number_Sale Date_Sale
16500
Мука
5
5500
13.01.2003
16500
Колбаса
4
330
15.01.2003
5600
Колбаса
4
800
14.01.2003
4200
Колбаса
4
600
14.01.2003
3000
Мука
5
1000
13.01.2003
1500
Мука
5
500
12.01.2003
1085
Колбаса
4
155
14.01.2003
750
Мука
5
250
13.01.2003
300
Мука
5
100
13.01.2003
285
Мука
5
95
14.01.2003


Примечание: В результате выполнения «самого вложенного» подзапроса (SELECT MAX(Sum_Sale)…) нам возвращается максимальная сумма продажи товара (16500). Затем вложенный подзапрос (SELECT Tovar_ID ….) возвращает нам два значения (4,5) , т.е ID двух товаров у которых максимальная сумма продажи составила значение 16500. Иначе говоря, этот запрос можно было бы представить в следующей форме:
SQL
SELECT S.ID, S.Sum_sale, S.Number_sale, S.Date_sale, T.NameTovar
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID AND S.Tovar_ID IN (4, 5)


Использование ALL, ANY

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

<сравниваемое значение> {[NOT]} <оператор> {ALL|SOME|ANY} (<подзапрос>)

где подзапрос может возвращать более одного значения. Оператор определяет операцию сравнения (>, >=,<,<= и т.д). Отношение сравниваемого значения и значений, возвращаемых подзапросом устанавливаются многострочными операторами ALL и ANY (SOME).

Оператор ALL сравнивает значение с каждым значением, возвращаемым подзапросам.
>ALL - означает «больше, чем максимум»
<ALL - означает «меньше, чем минимум»
Иначе говоря, ALL определяет, что условие поиска истинно, когда сравниваемое значение находится в отношении, определяемым оператором, со всеми значениями, возвращаемыми подзапросом.
Например:
WHERE Column >ALL (SELECT Field FROM Table)
определяет, что текущее значение столбца Column должно быть больше всех значений в столбце Field из таблицы Table.

Пример: Выбрать все факты продажи товаров, в которых сумма проданного товара, превышает среднее значение:
SQL
SELECT S.ID, S.Sum_sale, S.Number_sale, S.Date_sale, T.NameTovar
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID AND S.Sum_sale > ALL (SELECT AVG(Sum_Sale) FROM SALE GROUP BY Tovar_ID)

Результат запроса:
ID
Sum_Sale Number_Sale Date_Sale
NameTovar
18
16500
330
15.01.2003
Колбаса
7
16500
5500
13.01.2003
Мука


Оператор ANY и его синоним SOME сравнивает значение с любым значением, возвращаемым подзапросом.
<ANY - означает «меньше, чем максимум»
>ANY - означает «больше, чем минимум»
=ANY – эквивалент IN
Т.е. Использование этого оператора ANY (или SOME) означает, что условие поиска истинно, когда сравниваемое значение находиться в отношении, определяемым оператором, хотя бы с одним значением, возвращаемым подзапросом.
Например:
WHERE Column >ANY (SELECT Field FROM Table)
Определяет, что текущее значение столбца Column должно быть больше хотя бы одного значения в столбце Field из таблицы Table.

Пример: Выбрать все факты продажи товаров, в которых сумма проданного товара, превышает среднее значение хотя бы одного товара:
SQL
SELECT S.ID, S.Sum_sale, S.Number_sale, S.Date_sale, T.NameTovar
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID AND S.Sum_sale > ANY (SELECT AVG(Sum_Sale) FROM SALE GROUP BY Tovar_ID)

Результат запроса:
ID
Sum_Sale Number_Sale Date_Sale
NameTovar
10
4000
400
13.01.2003
Носки
4
3750
75
14.01.2003
Рубашка
14
5600
800
14.01.2003
Колбаса
18
16500
330
15.01.2003
Колбаса
15
4200
600
14.01.2003
Колбаса
7
16500
5500
13.01.2003
Мука


Оператор NOT не может использоваться с операторами ANY и ALL.


Предложение HAVING с подзапросами

Подзапросы можно использовать не только в предложении WHERE, но и в предложении HAVING. Такой запрос выполняется в следующем порядке: сначала выполняется подзапрос, и затем его результаты возвращаются в предложение HAVING главного запроса. Обычно, HAVIGN используется, если в условиях поиска для вложенного запроса необходимо указать агрегатную функцию.

Пример: Определить товар, у которого средняя продажа больше, средней продажи других товаров, и среднее число продаж этого товара
SQL
SELECT T.NameTovar, AVG(S.Number_sale)
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID
GROUP BY T.NameTovar
HAVING AVG(S.Number_sale) >= ALL (SELECT AVG(Number_Sale) FROM SALE GROUP BY Tovar_ID)

Результат запроса:
NameTovar
AVG(S.Number_Sale)
Мука
1240,8333333333



Подведем краткий итог:

Подзапрос – это команда SELECT, включенная в предложение другой команды SQL. Подзапросы полезны в случаях, когда запрос основан на неизвестных критериях поиска.

Характеристики подзапросов:
• Могут передавать одну строку данных в главный запрос, содержащий однострочный оператор (=, <>, >, >=, <, <=);
• Могут передавать более одной строки данных в главный запрос, содержащий многострочный оператор (например, IN);
• Подзапросы обрабатываются первыми, а затем их результаты используются в предложении WHERE или HAVING;
• Могут содержать групповые(агрегатные) функции;

Указания по использованию подзапросов:
• Подзапрос должен быть заключен в скобки;
• Подзапрос должен находиться справа от оператора сравнения.
• Подзапрос не может содержать предложение ORDER BY. В команде SELECT может быть только одно предложение ORDER BY. Если предложение ORDER BY используется, оно должно быть последним в главной команде SELECT
• В однострочных подзапросах используются однострочные операторы.
• В многострочных подзапросах используются многострочные операторы.


Внешние соединения

Выше нами были рассмотрены внутренние соединения таблицы баз данных. Напомним, что внутреннее соединение имеют место, если в предложении WHERE указано условие:

<имя столбца тыблицы1> <оператор> <имя столбца таблицы2>

Например:
SQL
SELECT *
FROM Tovar T, Sale S
WHERE T.ID = S.Tovar_ID


В этом случае осуществляется декартово произведение таблиц 1 и 2, и затем, из полученного НД отбираются записи, удовлетворяющие условию поиска (т.е. T.ID = S.Tovar_ID)

Существует так же и другой вид соединения таблиц, называемый внешним соединением. Оно определяется в предложении FROM согласно спецификации

SELECT {* | <значение1> [, <значение2>..]}
FROM <таблица1> <вид соединения> JOIN <таблица2>
ON <условие поиска>


Внешнее соединение похоже на внутренне соединение, но в результирующий НД включаются также записи ведущей таблицы соединения, которые объединяются с пустым множеством записей другой таблицы. Какая из таблиц будет ведущей, определяет вид соединения:
LEFT – (левое внешнее соединение), когда ведущей является таблица1 (расположенная слева от вида соединения)
RIGHT – (правое внешнее соединение), когда ведущей является таблица2 (расположенная справа от вида соединения)

Проще всего и понятней, данную тему рассмотреть на примерах.
Рассмотрим две таблицы
1) Таблица факультетов.
ID
NameF
1
Юридический
2
Филологический


2) Таблица студентов.
ID
FIO
F_ID
Kurs
1
Иванов ИИ
1
3
2
Петров ПП
1
3
3
Сидоров СС
2
4
4
Пупкин ВВ
5

где в поле F_ID проставляется ID факультета.

Теперь, если мы выполним следующий запрос (реализующий внутреннее соединение)
SQL
SELECT *
FROM Students S, Fakult F
WHERE F.ID = S.F_ID

то получим следующие результаты:
Результат запроса:
ID
FIO
F_ID
Kurs
ID_1
Kurs
1
Иванов ИИ
1
3
1
Юридический
2
Петров ПП
1
3
1
Юридический
3
Сидоров СС
2
4
2
Филологический


Мы видим, что студент Пупкин Василий не попал в результирующий НД.
Это вполне объяснимо, так как у данного студента, в поле F_ID не стоит никакого значения, и следовательно, условие F.ID = S.F_ID не выполняется.

Ну а если же нам необходимо получить список всех студентов, с указанием их факультета? В этом случае нам необходимо использовать внешние соединения.
Например:
SQL
SELECT *
FROM Students S LEFT JOIN Fakult F ON F.ID = S.F_ID

Результат запроса:
ID
FIO
F_ID
Kurs
ID_1
Kurs
1
Иванов ИИ
1
3
1
Юридический
2
Петров ПП
1
3
1
Юридический
3
Сидоров СС
2
4
2
Филологический
4
Пупкин ВВ
5


Т.е. грубо говоря, порядок выполнения этого запроса следующий, выбираются все записи из ведущей таблицы Students, а затем, происходит соединение с таблицей Fakult по условию F.ID = S.F_ID, если же условие не соблюдается, то выполняется соединение с пустой записью.


UNION – объединение результатов выполнения нескольких операторов SELECT.

Иногда бывает необходимо объединять два или более результирующих НД, возвращаемых после выполнения двух или более оператора SELECT. Такое объединение производиться при помощи оператора UNION. Результирующие НД должны иметь одинаковую структуру, т.е. одинаковый состав возвращаемых столбцов. Если в результирующем НД имеется одна и та же запись, в сводном НД она дублироваться не будет.

Пример: Соединить результаты выполнения трех запросов.

1) Выбрать из таблицы товаров всю информаци по товару с наименование "Сахар"
SQL
SELECT * FROM Tovar WHERE NameTovar = ‘Сахар’

Результат запроса:
ID
NameTovar
Unit
Price
3
Сахар
кг.
5


2) Выбрать из таблицы товаров всю информаци по товарам у которых цена за единицу измерения меньше 5
SQL
SELECT * FROM Tovar WHERE Price < 5

Результат запроса:
ID
NameTovar
Unit
Price
5
Мука
кг.
3


3) Выбрать из таблицы товаров всю информаци по товарам, у которых единица измерения пачка "пач."
SQL
SELECT * FROM Tovar WHERE Unit = ‘пач.’

Результат запроса:
ID
NameTovar
Unit
Price
7
Сигареты
пач.
9


Произведем объединение трех результирующих наборов данных
SQL
SELECT * FROM Tovar WHERE NameTovar = 'Сахар'
UNION
SELECT * FROM Tovar WHERE Price < 5
UNION
SELECT * FROM Tovar WHERE Unit = 'пач.'

Результат запроса:
ID
NameTovar
Unit
Price
3
Сахар
кг.
5
5
Мука
кг.
3
7
Сигареты
пач.
9


Можно производить объединение результирующих НД из разных таблиц. Но как уже было сказано, важно чтобы эти результирующие НД имели одинаковую структуру.

Например: Выберем из таблицы товаров все наименования товаров с их единицей измерения, а из таблицы клиентов, выберем наименования клиентов, с городом, где они находятся, после чего объединим эти два результирующих НД.
SQL
SELECT NameTovar, Unit
FROM Tovar UNION
SELECT NameClients, City
FROM Clients

Результат запроса:
NameTovar
Unit
АО Центр
Астана
АО Центрснаб
Омск
ЗАО Геркулес
МОСКВА
Колбаса
кг.
Мука
кг.
Мышь
шт.
Носки
шт.
Пиво
бут.
Рубашка
шт.
Сахар
кг.
Сигареты
пач.
ООО Евразия
Екатеринбург
ООО Петровка
Москва



Использование IS NULL

Если требуется выдать все записи, в которых некоторый столбец (или результат вычисления выражения) имеет значение NULL, достаточно в условии поиска указать

<значение> IS [NOT] NULL

Пример: выбрать из таблицы студентов (Students) всех студентов, у которых не проставлен их факультет.
SQL
SELECT *
FROM Students WHERE F_ID IS NULL

Результат запроса:
ID
FIO
F_ID
Kurs
4
Пупкин ВВ
 
5



Работа с разными БД в одном запросе

В одном SQL запросе, можно использовать таблицы из разных БД. В данном случае имя таблицы указывается в формате

:ПсевдонимБД:ИмяТаблицы

Под псевдонимом БД понимается псевдоним BDE (алиас)

С помощью этой модели, можно объединять не только таблицы из однотипных, но разных БД. Но и таблицы из совершенно разнотипных БД. т.е. сделать выборку в одном запросе из таблицы БД Interbase и из таблицы БД Oracle.

Например, обратимся в одном запросе к таблицам БД InterBase (псевдоним «Inter») и Oracle (псевдоним «Ora»):
SQL
SELECT *
FROM “:Inter:TableInter” I, “:Ora:TableOra” O
WHERE I.ID = O.ID_Inter
Автор: Alexey Chernyavski
Сайт: www.pegas.vingrad.ru






Просмотров: 44567

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную