Скачиваний:
60
Добавлен:
01.04.2014
Размер:
627.71 Кб
Скачать

Table-term

nonjoin- table-term

: := nonjoin-table-primary

| table-term INTERSECT [ ALL ]

[ CORRESPONDING [ BY ( column-commalist ) ] ]

table-primary

table-term

: := nonjoin-table-term

I join-table-expression

table -primary

: := nonjoin-table-primary

I join-table-expression

nonjoin-table -primary

: := TABLE table

| table-constructor

| select-expression

I ( nonjoin-table-expression )

table-constructor

: := VALUES row-constructor-commalist

row-constructor

: := scalar-expression

| ( scalar-expression-commalist )

I ( table-expression )

select-expression

: := SELECT [ ALL | DISTINCT ] select-item-commalist

FROM table-reference-commalist

[ WHERE conditional-expression ] [ GROUP BY column-commalist ]

[ HAVING conditional-expression ]

select-item

: := scalar-expression [ [ AS ] column ]

I [ range-variable . ] *

Рис. 8.1. BNF-грамматика для табличных выраженийSQL

• Если элемент выборки включает ссылку на итоговую функцию и выражение выборки не включает инструкцию group by (см. ниже), то ни один элемент выборки в инструк­ции select не может включать никаких ссылок на столбец таблицы T1, кроме такой, которая является ссылкой на аргумент (или часть аргумента) итоговой функции.

Случай 2. Элемент выборки имеет следующий вид:

[ range-variable . ] *

• Если уточнение (range-variable) опущено (т.е. элемент выборки представлен как неуточненный символ "*"), то этот элемент выборки должен быть только элемен­том выборки в инструкции select. Эта форма является сокращением для списка всех столбцов таблицы Т1 в порядке слева направо.

• Если уточнение включено (т.е. элемент выборки состоит из символа "*", уточненно­го именем переменной области значений R, записывается как "R.*" ), то этот эле­мент выборки представляет список всех столбцов таблицы, соответствующей пере­менной области значений R, в порядке слева направо. (Напомним, что имя таблицы может и часто будет использоваться как явная переменная области значений. Таким образом, элемент выборки часто будет иметь форму "T. *", а не "R. *".)

Инструкция FROM

Инструкция from записывается в виде

FROM tabIe-reference-commaIist

Список ссылок на таблицы (table-reference-commalist) не должен быть пустым. Пусть вычисление указанных табличных ссылок дает таблицы А, В,..., С. Тогда ре­зультат вычисления инструкции from будет таблицей, эквивалентной декартову произ­ведению таблиц А, В,..., С.

Замечание. Декартово произведение отдельной таблицы Т определяется как экви­валентное Т, т.е. оно, конечно, допустимо для инструкции from, содержащей просто отдельную табличную ссылку.

Инструкция WHERE

Инструкция where записывается в виде

WHERE conditional-expression

Пусть Т— результат вычисления предыдущей инструкции from. Тогда результатом инструкции where будет таблица, производная от Т и исключающая все строки, для ко­торых вычисление условного выражения (conditional-expression) не дает истину. Если инструкция where опущена, результатом будет просто Т.

Инструкция GROUP BY

Инструкция group by записывается в виде

GROUP BY column-commalist

Список столбцов (column-commalist) не должен быть пустым. Пусть Т— результат вы­числения предыдущих инструкций from и where (если они использовались). Каждый столбец, указанный в списке инструкции group by, должен быть представлен (не обя­зательно) уточненным именем столбца таблицы Т. А результатом этой инструкции будет сгруппированная таблица, т.е. набор групп строк, производных от таблицы Т с помощью концептуальной перегруппировки таблицы Т в минимальное количество таких групп, что в пределах одной группы все строки имеют одинаковое значение для комбинации столбцов, указанных в инструкции group by. Поэтому заметьте, что ре­зультат — это не совсем таблица. Однако инструкция group by никогда не применяет­ся без соответствующей инструкции select, которая преобразует этот промежуточный результат в правильную таблицу, поэтому нет ничего плохого в том, что временно мы отклонились от точной табличной структуры.

Если выражение выборки включает инструкцию group by, то есть ограничения на форму, которую может принимать инструкция select. Точнее, каждый элемент выбор­ки в инструкции select (включая любой такой, который подразумевается по сокраще­нию "*") должен быть однозначным в группе. Итак, каждый элемент выборки не должен включать никаких ссылок на какой-либо столбец таблицы T, не указанной в инструкции group by, кроме ссылок на аргументы или часть аргумента одной из итоговых функций — count, sum, avg, max или min, в результате выполнения которых некоторый набор скалярных значений группы сводится к единственному такому значению.

Инструкция HAVING

Инструкция having записывается в виде

HAVING conditional-expression

Пусть G (сгруппированная таблица) — результат выполнения предыдущей инструк­ции frcm, инструкции where (если она присутствует) и инструкции group by (если она есть). Если инструкции group by нет, то в качестве G берется результат выполнения предыдущей инструкции from или инструкции where и рассматривается как сгруппиро­ванная таблица, состоящая только из одной группы(///////); иначе говоря, в этом случае есть неявная концептуальная инструкция group by, которая указывает, что группируемых столбцов нет совсем. Результат инструкции having— это сгруппированная таблица, производная от G и исключающая все группы, для которых условное выражение не является истиной.

' Так сказано в стандарте SQL, хотя логичнее было бы сказать — не более одной группы, поскольку если с помощью инструкций FROM и WHERE будет вычислена пустая таблица, то не будет ни одной группы.

Замечание 1. Если инструкция having опущена, а инструкция group by присутствует, то результатом будет просто G. Если обе инструкции having и group by опущены, результатом будет "правильная", т.е. не сгруппированная, таблица T, вы­численная в соответствии с инструкциями where и from.

Замечание 2. Скалярные выражения инструкции having в каждой группе должны быть однозначными (так же как и скалярные выражения инструкции select, если при­сутствует инструкция group by, как обсуждалось выше).

Замечание 3. Стоит упомянуть, что инструкция having полностью излишняя, т.е. для любого выражения выборки, в котором используется эта инструкция, существует семантически эквивалентное выражение выборки, в котором она не используется (упражнение для читателя!).

Обширный пример

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

Для всех красных и голубых деталей, таких что поставляемое итоговое количе­ство определенных деталей больше 350 (исключая из итога все поставки, в которых количество не больше 200), получить номер детали, вес в граммах, цвет и макси­мальное поставляемое количество этих деталей.

SELECT P.P#,

'Weight in grams = ' AS TEXT1,

P.WEIGHT * 454 AS GMWT,

P.COLOR,

'Max quantity = ' AS TEXT2,

MAX ( SP.OTY ) AS MQY FROM P, SP

WHERE P.P# = SP.P#

AND ( P.COLOR = 'Red' OR P.COLOR = 'Blue’ )

AND SP.OTY > 200

GROUP BY P.P#, P.WEIGHT, P.COLOR

HAVING SUM ( SP.QTY ) > 350 ;

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

1. FROM: вычисление инструкции from дает новую таблицу, которая является декар­товым произведением таблиц Р и SP.

2. WHERE: результат шага 1 сокращается путем исключения всех строк, которые не удовлетворяют условию инструкции where. В данном примере исключаются строки, не удовлетворяющие условному выражению

P.P# = SP.P# AND

( P.COLOR = 'Red' OR P.COLOR = 'Blue' ) AND

SP.QTY > 200

3. GROUP BY: результат шага 2 группируется по значениям столбца или столбцов, перечисленных в инструкции group by. В данном примере это столбцы Р.Р#, P.WEIGHT и P.COLOR.

Замечание. Теоретически здесь было бы достаточно одного столбца Р.Р# в качест­ве группируемого, поскольку P.WEIGHT и P.COLOR однозначно определяются по номеру детали. Однако в SQL не учитывается этот момент, и если в инструкции group by опустить P.WEIGHT и P.COLOR, то, поскольку они упоминаются в инст­рукции select, будет сгенерирована ошибка.

4. HAVING: группы, не удовлетворяющие условию

SUM ( SP.QTY ) > 350,

из результата шага 3 исключаются.

5. SELECT: каждая группа в результате шага 4 генерирует отдельную строку ре­зультата следующим образом. Во-первых, из группы извлекаются номер детали, вес, цвет и максимальное количество поставки. Во-вторых, вес преобразуется в граммы. И, в-третьих, две литеральные строки "Weight in grams =" (вес в граммах) и "Max quantity ==" (максимальное количество) ставятся на соответствующее место в строке. Кстати, "соответствующее место в строке" предполагает, что столбцы таблицы в SQL расположены в порядке слева направо. Литеральные строки не имели бы смысла, если бы они не располагались в "соответствующих местах".

Окончательный результат выглядит следующим образом:

P#

TEXT1

GMWT

COLOR

TEXT2

MQY

P1

P2

P3

Weight in grams=

Weight in grams=

Weight in grams=

5448

5448

7718

Red

Blue

Blue

Max quantity=

Max quantity=

Max quantity=

300

400

400

И, наконец, необходимо осознать, что описанный алгоритм представляет только кон­цептуальное объяснение того, как вычисляется выражение select. Алгоритм, конечно, верный, в том смысле, что он обеспечивает правильный результат вычисления. Однако на практике он весьма неэффективен. Например, вычислять на первом шаге декартово про­изведение просто неуместно. Соображения, подобные этому, как раз и являются той при­чиной, по которой для реляционных систем требуется оптимизатор. Действительно, за­дача оптимизатора в системах SQL может быть охарактеризована как нахождение проце­дуры реализации, которая будет вырабатывать тот же результат, что и описанный выше концептуальный алгоритм, но более эффективно (об этом речь идет далее в книге).

Соседние файлы в папке Дейтл Введ в БД