Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
68
Добавлен:
23.11.2017
Размер:
96.26 Кб
Скачать

10.2.1. Ограничения на запросы с группировкой

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

Следует учитывать также ограничения на элементы списка возвращаемых столбцов. Все элементы этого списка должны иметь одно значение для каждой группы строк. Это означает, что возвращаемым столбцом может быть: 1) константа; 2) агрегатная функция, возвращающая одно значение для всех строк, входящих в группу; 3) столбец группировки, который, по определению, имеет одно и то же значение во всех строках группы; 4) выражение, включающее в себя перечисленные выше элементы.

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

SELECT NOM,FIO,SUMD,COUNT(ID) FROM PERSON,HAVE_D WHERE PERSON.NOM=HAVE_D.NOM GROUP BY NOM

В этом запросе список возвращаемых столбцов содержит помимо столбца группировки NOM также столбцы FIO и SUMD, не указанные в предложении GROUP BY. Чтобы не нарушать ограничение, необходимо просто включить эти два столбца в предложение GROUP BY:

SELECT NOM,FIO,SUMD,COUNT(ID) FROM PERSON,HAVE_D WHERE PERSON.NOM=HAVE_D.NOM

GROUP BY NOM,FIO,SUMD

10.2.2. Условия поиска групп

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

SELECT ADR,AVG(SUMD) FROM PERSON GROUP BY ADR HAVING COUNT(*)>1

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

Условие поиска, используемое в предложении HAVING, применяется не к отдельным строкам, а к группе в целом. Это значит, что в условие поиска может входить: 1) константа; 2) агрегатная функция, возвращающая одно значение для всех строк, входящих в группу; 3) столбец группировки, имеющий, по определению, одно и то же значение во всех строках группы; 4) выражение, включающее в себя перечисленные выше элементы.

На практике условие поиска в предложении HAVING всегда должно включать в себя как минимум одну агрегатную функцию. Если это не так, то условие поиска можно переместить в предложение WHERE.

10.3. Вложенные запросы на чтение

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

Возможность применения одного запроса внутри другого и была причиной появления слова "структурированный" в названии SQL (структурированный язык запросов).

Понятие вложенного запроса играет важную роль в SQL по торем причинам: 1) оператор языка SQL с вложенным запросом зачастую является самым естественным способом выражения запроса, так как он лучше всего соответствует словесному описанию запроса; 2) вложенные запросы облегчают написание операторов SELECT, поскольку они позволяют разбивать запросы на части (т.е. на запрос и вложенные запросы), а затем складывать эти части вместе; 3) существуют запросы, которые нельзя сформулировать, не прибегая к помощи вложенных запросов.

Вложенным, или подчиненным, запросом, называется запрос, содержащийся в предложении WHERE или HAVING другого оператора.

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

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

Если известен размер S самого доходного источника, то запрос выражается достаточно просто:

SELECT NOM,FIO FROM PERSON WHERE SUMD<S

К сожалению, в таком виде оператор SELECT не может быть выполнен из-за некорректного условия поиска, содержащего величину S. Однако, эту величину можно легко вычислить таким оператором:

SELECT MAX(MONEYS) FROM PROFIT

Этот оператор следует использовать вместо величины S в качестве вложенного запроса:

SELECT NOM,FIO FROM PERSON WHERE SUMD<(SELECT MAX(MONEYS) FROM PROFIT)

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

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

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

  1. Таблица результатов вложенного запроса всегда состоит из одного столбца, т.е. список возвращаемых столбцов должен иметь только один элемент.

  2. Во вложенный запрос не может входить предложение ORDER BY.

  3. Вложенный запрос не может быть запросом на объединение нескольких различных операторов SELECT; допускается использование только одного оператора SELECT.

  4. Имена столбцов, используемые во вложенном запросе, могут являться ссылками на столбцы таблиц главного (внешнего) запроса.

Чтобы проиллюстрировать последнее из перечисленных отличий, рассмотрим следующий запрос: определить адреса квартир, жители которых не могут оплачивать коммунальные услуги. Условно принимаем, что коммунальные услуги оплачиваются из расчета 60 руб. за квадратный метр (в год).

Таблица результатов формируется оператором

SELECT ADR FROM FLAT WHERE SKV*60>(SELECT SUM(SUMD) FROM PERSON WHERE FLAT.ADR=PERSON.ADR)

Столбец (или поле) FLAT.ADR во вложенном запросе является примером внешней ссылки. Внешняя ссылка представляет собой имя столбца, принадлежащего таблице, указанной в предложении FROM главного запроса, и не входящего ни в одну из таблиц, перечисленных в предложении FROM вложенного запроса.

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

Процедура выполнения связанного подзапроса состоит из следующих шагов:

  1. выбрать строку из таблицы, имя которой указано в главном запросе; это текущая строка кандидат (в примере это строка таблицы FLAT с полем ADR);

  2. выполнить вложенный запрос с учётом значений, содержащихся в текущей строке-кандидате (в примере это значение поля FLAT.ADR, в соответствии с которым из таблицы PERSON выбираются сведения о жителях конкретной квартиры и вычисляется сумма их доходов);

  3. вычислить условие поиска главного запроса с учётом результатов вложенного запроса, выполненного на шаге 2; если вычислено значение TRUE, то текущая строка-кандидат включается в таблицу результатов;

  4. повторять шаги 1-3 для следующей строки-кандидата, пока не будут проверены все строки таблицы, указанной в главном запросе.

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