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

Базы данных. Практикум

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
1 Мб
Скачать

На первый взгляд кажется, что такое соединение противоречит предложенному эмпирическому правилу, однако это не так, поскольку перетащив таблицу «Виды доставки» (а это можно сделать, поместив указатель мыши на заголовок таблицы), получим стрелки, направлен- ные в одну сторону (рис. 8). Легко убедиться, что для соединений на рис. 5 такого эффекта перемещением таблиц добиться не удастся.

Рис. 8. Другое изображение правильного соединения с получением полезного результата

Вот, собственно, и все основные проблемы, связанные с соедине- нием таблиц для запроса.

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

4.2. Базовые примеры запросов

Начнем с построения сравнительно простого запроса-выборки, чтобы затем использовать его в различных ситуациях.

Пример 1. Построим запрос, который содержит информацию о выписанных по счетам товарах (рис. 9).

Рис. 9. Исходный запрос-выборка по заказанным товарам

41

Пояснений по этому запросу, наверное, не требуется. Все поля взяты из таблиц, кроме одного вычисляемого поля «Сумма». Это по- ле содержит стоимость каждой строки товара в счете, то есть произ- ведение цены товара на его количество.

Если вместо таблиц «Товарные счета» и «Товары по счетам» подставить очевидно аналогичные им таблицы товарных наклад- ных и товаров по ним (или предположить, что весь выписанный по счетам товар обязательно отпускается), то получим запрос, со- держащий сведения по продажам товаров. Поэтому в дальнейшем будем считать этот запрос основным источником сведений о про- дажах.

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

В противном случае можно в данный запрос добавлять таблицы «Виды оплаты», «Номенклатура товаров» и «Типоразмеры» и вклю- чать соответствующие поля в наш запрос. Можно также использо- вать подчиненные запросы.

Покажем, как это делается на частном примере.

Пример 2. Предположим, нас интересуют продажи товаров за на- личный расчет, скажем, за март 2008 г. Для этого в поле «Выписан» мы зададим условие

Вetween 01.03.2008Аnd 31.03.2008

Покупатели нас интересовать не будут, поэтому поле «Клиент» из запроса исключаем. Чтобы отобрать только продажи за наличный расчет, зададим в поле «Вид оплаты» числовое значение кода оплаты для наличного расчета (пусть у нас оно будет равно «1»).

Под именем «Товар» выведем коды товаров и их названия. По- скольку значения этих полей хранятся в таблице «Номенклатура то- варов», нам необходимо включить в запрос эту таблицу и создать вычисляемое поле:

Товар: [Номенклатура товаров]![Код товара] & " " & [Наименование товара]

Цена здесь также не нужна, и ее мы исключаем. В итоге получаем запрос, показанный на рис. 10.

42

Рис. 10. Модификация предыдущего запроса

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

В этом случае в строку «Условие отбора» для нашего вычисляе- мого поля «Товар» мы запишем условие

Like «Бинты»

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

На этом же запросе проиллюстрируем методические тонкости, связанные с сочетанием условий отбора. Запишем приведенное выше условие отбора для товаров не в строку «Условие отбора», а в строку под ней, которая называется «или». Результатом такого запроса бу-

дет таблица, содержащая все товары, проданные в ноябре, и все про-

дажи бинтов, содержащиеся в таблице.

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

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

43

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

4.3. Итоговые запросы

Итоговые запросы это инструмент для обобщения инфор- мации, хранящейся в базе данных. Обычный запрос-выборка позволяет только отображать некоторые записи, в лучшем слу- чае с помощью вычисляемых полей как-то скомбинировать информацию в каждой отдельной записи, однако получить не- кие укрупненные данные с его помощью нельзя. Рассмотрим приведенный на рис. 9 пример запроса-выборки. Каждая его строка содержит сведения о заказе конкретного товара. Как показано в примерах предыдущего раздела, достаточно легко отобрать только сведения о заказах одного выбранного товара, заказы товаров в определенный день или за определенный пе- риод, заказы по виду оплаты, и т.п.; однако любой такой за- прос будет содержать строки по отдельным товарам. Невоз- можно даже узнать сумму продаж за день или, скажем, по од- ному заказу. В таких ситуациях помогают итоговые запросы.

Итоговый запрос является запросом-выборкой, в котором все выводимые поля являются вычисляемыми, причем вычис- ления производятся не над отдельными значениями поля в ка- ждой записи, а над значениями в группах записей. Начнем с наглядного примера. Возвращаясь к выборке на рис. 9, исклю- чим из запроса все поля, кроме поля «Выписан», и зададим режим групповых операций, который, собственно, и создает итоговый запрос. Чтобы задать этот режим, надо выбрать по- зицию «Групповые операции» либо в меню Вид конструктора запросов, либо в контекстном меню, открывающемся при на- жатии правой кнопки мыши.

Бланк конструктора запроса будет после этого выглядеть сле- дующим образом (рис. 11).

44

Поле Выписан

Групповая операция: Группировка Сортировка:

Вывод на экран: Х Условие отбора:

или:

Рис. 11. Бланк конструктора запроса для выполнения группировки

Если просмотреть результат такого запроса, то это будет таблица из одного столбца, содержащая даты выписки счетов, причем каждая дата встречается в таблице ровно один раз, хотя, естественно, в один день могло выписываться и несколько счетов. Пока что ничего инте- ресного в этом нет, в конце концов, такую же таблицу можно было бы получить с помощью свойства «Уникальные записи».

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

Результат будет таким, как показано на рис. 12.

Поле: Групповая операция:

Сортировка: Вывод на экран: Условие отбора:

или:

Выписан

Сумма: [Цена] * [Количество]

 

 

 

 

Группировка

Sum

 

 

 

 

 

 

 

Х

Х

 

 

 

 

 

 

 

Рис. 12. Бланк конструктора запроса для выполнения групповых операций

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

Группировку можно проводить не только по полю из исходной таблицы, но и по вычисляемому полю. Если вместо поля «Выписан» в вышеприведенный запрос поставить вычисляемое поле «Месяц», записав в соответствующей ячейке Месяц:Month([Выписан]), то

45

результатом запроса будет сумма продаж по месяцам. В самом деле, группировка будет производиться по полю «Месяц» и в одну группу попадут все записи, относящиеся к данному месяцу. По ним и будет просуммировано поле «Сумма».

С помощью функции Format() и Datepart() можно выбирать лю- бой интересующий нас временной интервал: неделю, квартал и т.д.

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

А что произойдет, если задать в итоговом запросе не 2, а большее количество полей?

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

Если же задавать группировку по нескольким полям (а при задании в меню режима групповых операций все «стаскиваемые» в бланк поля из исходных таблиц необходимо пометить группировкой, и в бланке поменять их на другие групповые операции), то результат зависит от порядка, в котором эти поля расположены в бланке запроса.

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

меняться другие групповые операции.

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

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

Если имеется еще одно поле группировки, то эта группировка производится уже внутри предыдущих групп (по второму полю).

46

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

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

Поясним сказанное выше на примере.

Создадим итоговый запрос следующего вида (рис. 13):

Поле:

Выписан

Клиент

Сумма:[Цена]*[Количество]

Групповая операция:

Группировка

Группировка

Sum

Сортировка:

 

 

 

 

 

 

Вывод на экран:

 

 

 

Х

Х

Х

Условие отбора:

 

 

 

 

 

 

или:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 13. Бланк конструктора запроса для выполнения групповых операций при группировке по нескольким полям

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

Если же поменять поля «Выписан» и «Клиент» местами, то в вы- ходной таблице сначала будут идти записи с первым кодом клиента, причем каждая запись содержит дату и сумму продаж этой фирме за соответствующий день.

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

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

47

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

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

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

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

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

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

Такие сводки проще получать с помощью отчетов. Они будут гибче итоговых запросов.

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

Допустим, мы хотим проверить долги клиентов, получивших то- вар с отсрочкой платежа.

Информация об оплате хранится в таблице «Оплата». При отсроч- ке платежа деньги могут поступать в несколько приемов, так что данные по оплате за данный заказ надо суммировать по нескольким записям.

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

48

Тогда следующий итоговый запрос (рис. 14), на первый взгляд, как раз выведет то, что нам нужно. Мы положили, что оплата с от- срочкой платежа кодируется видом оплаты «3».

Рис. 14. Неправильно сформированный итоговый запрос

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

Если вы построите такой запрос на реальных или пробных дан- ных, то с удивлением обнаружите, что, хотя внешне все выглядит, как и ожидалось, полученные суммы по каждому счету и проплатам по нему будут в несколько раз больше действительных! Что же слу- чилось?

И здесь надо вспомнить, как создается итоговый запрос, а именно, сначала отбираются записи и только потом производятся групповые операции. Это означает, что сначала будет создан запрос-выборка, который имеет вид, показанный на рис. 15. Чтобы получить его, дос- таточно из предыдущего запроса убрать групповые операции.

49

Рис. 15. Запрос-выборка

Теперь давайте разберемся, как выглядит результат этого запроса. Для простоты предположим, что у нас есть один единственный заказ, а это означает, что в таблицах «Заказы» и «Товарные счета» ровно по одной строке. Заказ состоит из m позиций товара (то есть в таблице «Товары по счетам m строк), проплат за него выполнено, скажем, n (n строк в таблице «Оплата»).

Нетрудно убедиться, что результатом запроса в этом случае будет

прямое (декартово) произведение таблиц «Товары по счетам» и «Оп-

лата», (напомним, что для прямого произведения к каждой строке первой таблицы, дописывается поочередно каждая строка второй таблицы и общее число строк в результирующей таблице равно m × n.) Таким образом, сумма по каждому товару повторяется n раз, а каждая проплата m раз.

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

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

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

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]