Руководство пользователя по Optima:Дизайнер отчётов
Содержание
- 1 Введение
- 2 Работа с утилитой FastReport
- 3 Часть I. Примеры создания отчетов
- 4 Часть II. Справочник
- 4.1 SQL
- 4.1.1 Литералы
- 4.1.2 Оператор SELECT
- 4.1.2.1 Выборка всех строк
- 4.1.2.2 Выбор строк (предложение WHERE)
- 4.1.2.3 Сортировка результатов (фраза ORDER BY)
- 4.1.2.4 Использование обобщающих функций языка SQL
- 4.1.2.5 Группирование результатов
- 4.1.2.6 Ограничения на выполнение группирования (фраза HAVING)
- 4.1.2.7 Подзапросы
- 4.1.2.8 Ключевые слова ANY и ALL
- 4.1.2.9 Многотабличные запросы
- 4.1.3 Изменение содержимого базы данных
- 4.2 Встроенные переменные
- 4.1 SQL
Введение
В процессе работы постоянно необходимо выводить различную информацию на печать. Для этого в дистрибутиве Optima WIN™ поставляется набор отчетных документов для работы фирмы-производителя. Документы, как правило, формируются после расчёта изделия. Однако, на любом производстве есть своя специфика работы. В случае если стандартные отчеты вам по каким-либо причинам не подходят, можно отредактировать уже существующие отчеты или сформировать новые. Для этого в составе Optima WIN™ поставляется дизайнер отчетов FastReport. В данном руководстве даются только общие сведения о методике создания отчетов. Более полную информацию можно получить по адресу http://www.fastreport.ru.
Соглашения
В табл. 1 сведены все обозначения, используемые в данном руководстве.
Таблица 0.0. Соглашения данного руководства
Работа с утилитой FastReport
Для работы отчетами в Optima WIN™ используется утилита FastReport. В меню Документы приведены названия стандартных отчетов, поставляемых с Optima WIN™. Чтобы сформировать отчет, вызовите пункт меню с названием отчета. Утилита FastReport запустит выполнение шаблона, а затем перейдет в режим предпросмотра и покажет готовый отчет. Также можно использовать команду Выполнить отчет. При этом откроется стандартный диалог открытия файла, в котором надо выбрать шаблон, по которому будет оформляться отчет. Чтобы просмотреть ранее сохраненный готовый отчет, воспользуйтесь командой Открыть отчет.
Также возможно редактирование уже сформированного отчета. Для этого дважды щелкните по отчету. Произведенные изменения будут действовать только для уже сформированного документа и не затронут шаблон отчета.
Для создания нового шаблона отчета вам необходимо выполнить команду Дизайнер отчетов из меню Документы в программе Optima WIN™.
Интерфейс
При вызове дизайнера отчетов откроется окно Дизайнер (см. рис. 1).
Рис. 1. Главное окно программы.
Панель «Стандартная»
На данной панели располагаются кнопки управления объектами и документом в целом.
Рис. 2. Панель «Стандартная»
Кнопки управления шаблоном (Создать, Открыть, Сохранить) и кнопки редактирования объектов (Копировать, Вырезать, Отменить и пр.) имеют тот же смысл, что и в большинстве приложений в операционной системе Windows. В табл. 2 представлены дополнительные кнопки для управления отчетом.
Таблица 0.0. Кнопки панели «Стандартная»
Панель «Текст»
Данная панель предназначена для настройки атрибутов текста объектов.
Рис. 3. Панель «Текст»
Здесь можно указать шрифт текста, его размер, цвет, выравнивание и т. д. Работа с этой панелью аналогична работе с подобными панелями в иных текстовых редакторах.
Панель «Прямоугольник»
Панель предназначена для настройки оформления границ добавляемых объектов.
Рис. 4. Панель «Прямоугольник»
С помощью кнопок, расположенных на панели, вы можете включить отображение той или иной границы объекта, указать толщину и цвет рамки, а также указать цвет заливки объекта.
Панель «Объекты»
В зависимости от вида страницы, с которой вы работаете в данный момент, окно Объекты имеет разный вид. Для страницы отчета панель выглядит так, как изображено на рис. 5, а, для окна диалога — как на рис. 5, б.
Подробнее об объектах и их свойствах см. раздел «Работа с шаблонами».
Рис. 5. Панель «Объекты»
Объекты можно добавлять на лист шаблона или диалоговую форму. Для этого нажмите на кнопку на панели левой кнопкой мыши, затем поместите курсор мыши на лист шаблона или диалоговую форму в том месте, куда вы хотите поместить объект и нажмите еще раз левую кнопку мыщи.
Инспектор объектов
Инспектор объектов позволяет изменять свойства объектов. В верхней части окна есть выпадающий список, в котором можно выбрать тот объект, свойства которого вам надо изменить. После выбора объекта в инспекторе отображаются все свойства данного объекта.
Инспектор объектов можно скрыть или показать. Для этого используйте команду Инспектор из меню Сервис->Панели инструментов.
Опции
Настройка опций дизайнера отчетов происходит в окне Опции. Чтобы открыть это окно, вызовите команду Опции… из меню Сервис. Окно Опции состоит из двух закладок (см. рис. 6).
Рис. 6. Окно Опции
На закладке «Дизайнер» можно задать используемые единицы измерения (пикселы, миллиметры, дюймы), указать шаг сетки в точках. Также можно указать способ прорисовки объектов при их перемещении (или изменения размеров).
Опция Расположение страницы позволяет выбрать расположение страницы. Это удобно, если на экране присутствует инспектор объектов: таким образом можно задать взаимное расположение страницы и инспектора.
Если опция Цветные кнопки отключена, то все кнопки становятся черно-белыми; при наведении указателя мыши на кнопку она показывается в цвете.
Опция Показывать заголовки бэндов позволяет отключать заголовки у бэндов в целях экономии свободного места на странице.
Наконец, опция Редактирование после вставки управляет процессом вставки новых объектов. Если опция включена, каждый раз при вставке объекта будет показываться его редактор. При вставке большого количества пустых объектов опцию лучше отключать.
На закладке «Редактор» можно настроить шрифт для окна редактора текста. При включенной опции Использовать установки шрифта объекта шрифт в окне редактора текста будет соответствовать шрифту редактируемого объекта
Работа с шаблонами
Дизайнер FastReport может работать с двумя видами документов: шаблонами отчетов и готовыми отчетами.
Работа с готовыми отчетами будет рассмотрена позже. В этом разделе остановимся на шаблонах.
Шаблоны
Шаблон отчета не содержит данных. На этапе оформления шаблона задаются условия, по которым готовый отчет будет наполняться данными. Например, при оформлении шаблона можно использовать системную переменную [DATE], которая в готовом отчете будет заменена на текущую дату. В квадратных скобках указываются переменные и выражения. При формировании отчета выражения, заключенные в квадратные скобки, вычисляются и заменяются на полученный результат.
В дистрибутиве Optima WIN™ поставляется следующий набор шаблонов:
Таблица 0.0. Файлы шаблонов отчётов
Имя файла | Наименование отчета |
---|---|
RpByDate.frf | Отчет по статусам заказов. |
Spec.frf | Спецификация изделий. |
SpecOrd.frf | Спецификация заказа. |
ComOffer.frf | Коммерческое предложение. |
RpByOrd.frf | Отчёт по заказам. |
GlassOrd.frf | Заказ стеклопакетов. |
Needmat.frf | Заказ материалов. |
WinCompl.frf | Задание в цех. |
AllPrice.frf | Отчет, включающий все рассчитанные прайс-листы по системе профиля. |
OnePrice.frf | Текущий прайс-лист. |
PriseList.frf | Прайс-лист на изделие — отчет, получаемый после создания прайс-листа в построителе. |
Repeipt.frf | Приходные накладные. |
Supply.frf | Текущая приходная накладная. |
Expense.frf | Расходные накладные. |
Outlay.frf | Текущая расходная накладная. |
Needmatwh.frf | Недостающие материалы. |
Whcond.frf | Состояние склада. |
WinCalc.frf | Задание в цех — отчёт, получаемый после расчета изделия в построителе. |
RpByCust.frf | Карточка заказчика. |
RpByAllCust.frf | Список заказчиков. |
Optimize.frf | Лист раскроя профилей — отчет, получаемый во время оптимизации группы оптимизации или заказа. |
Sort.frf | Лист раскроя профилей оптимизированного заказа. |
Sortg.frf | Лист раскроя профилей оптимизированной группы оптимизации. |
Свойства шаблона
Опции
В FastReport можно задавать параметры шаблона. Для этого вызовите команду Параметры отчета… из меню Файл. В окне Параметры отчета можно выбрать принтер, на котором будет печататься готовый отчет, а также указать число этапов формирования готового отчета.
Если флаг Делать два прохода установлен, формирование отчета будет осуществляться в два этапа. На первом проходе отчет формируется, осуществляется его разбивка на страницы, но результат нигде не сохраняется. На втором проходе происходит обычное формирование отчета с сохранением результата в потоке.
Для чего нужно делать два прохода? Наиболее часто эта опция применяется, если в отчете имеется упоминание об общем количестве страниц, то есть информация вида Страница 1 из 15. Общее количество страниц подсчитывается на первом проходе и доступно через системную переменную [TOTALPAGES]. Часто эту переменную применяют в однопроходном отчете, в этом случае она возвращает 0.
Другая область применения — выполнение каких-либо вычислений на первом проходе и отображение результатов на втором. Например, в случае, когда необходимо отобразить в заголовке группы сумму, которая обычно подсчитывается и отображается в итоге группы. Такого рода вычисления связаны с использованием встроенного языка FastReport.
Словарь данных
Для каждого отчета можно создать собственный словарь данных, в котором может содержаться список переменных, список данных из БД а также список источников данных. Чтобы настроить словарь данных, воспользуйтесь командой Словарь данных… из меню Файл. Окно Словарь данных состоит из трех закладок.
На этой закладке вы создаете переменные, которые в дальнейшем сможете использовать при оформлении шаблона.
Рис. 7. Словарь данных, закладка «Переменные»
Прежде чем вы объявите переменную, необходимо создать категорию, в которую она будет входить. Для этого нажмите кнопку Новая категория . В области Переменные появится значок папки. Переменные будут лежать в этой категории. Для объявления переменной нажмите кнопку Новая переменная
.
Если вы хотите, чтобы переменная возвращала значение какого-либо поля из мастер-источника, выберите из выпадающего списка нужный источник данных. В списке под ним укажите поле, значение из которого будет возвращать переменная. Если переменная должна возвращать значение выражения, включите флаг Выражение и укажите формулу, по которой будет вычисляться значение.
Рис. 8. Словарь данных, закладка «Данные из БД»
На этой закладке вы указываете, какие данные можно будет использовать при оформлении отчета и составлении выражений. В поле Псевдоним можно указать имя, под которым будет отображаться поле.
Если список Данные и поля пуст, то при составлении выражений будет отображаться весь список данных.
Рис. 9. Словарь данных, закладка «Источники данных для бэндов»
Закладка по своему назначению похожа на предыдущую закладку, только здесь указывается список источников данных для бэндов.
Панель «Мастера»
На панели расположены кнопки для работы с мастер-источниками.
Кнопку Вставка полей БД в отчет удобно использовать, если необходимо вставить в отчет несколько полей. В окне Вставка полей БД выбираются поля, при этом FastReport сам создаст необходимое количество бэндов и расместит на них текст. Подробнее о бэндах см. стр. 16.
Кнопка Менеджер данных открывает окно Источники данных (см. рис. 10), в котором можно создавать статические источники данных.
Рис. 10. Окно Источники данных
Статический запрос создается на этапе оформления шаблона и в дальнейшем не меняется. Для создания статического запроса нажмите кнопку Новый запрос, при этом откроется окно Свойства запроса (см. рис. 11).
Рис. 11. Окно Свойства запроса
В поле Имя необходимо указать идентификатор, по которому можно будет обращаться к этому запросу. Поле Алиас или путь содержит путь к БД, с которой будет оперировать запрос или псевдоним уже подключенной БД. В поле Master-источник указывается мастер-источник для данного запроса. В редакторе Текст SQL необходимо создать SQL-запрос. Статические запросы также могут работать с параметрами. Подробнее о внешних параметрах SQL-запроса см. стр. 29.
После заполнения всех полей нажмите кнопку ОК.
Открытие шаблона
Чтобы открыть шаблон, вызовите команду Открыть из меню Файл или нажмите кнопку Открыть отчет на панели инструментов. В стандартном диалоге открытия файла укажите имя шаблона, который вы хотите открыть. Шаблоны хранятся в папке Reports, которая расположена в каталоге установки Optima WIN™ .
Сохранение шаблона
После завершения редактирования шаблона его необходимо сохранить. Для этого воспользуйтесь кнопкой Сохранить отчет на панели инструментов или командой Сохранить из меню Файл. В открывшемся диалоговом окне укажите имя шаблона и папку, в которой он будет располагаться.
Структура каталогов
Стандартные отчеты хранятся в папке Reports каталога установки Optima WIN™ . Также вы можете создавать свои шаблоны отчетов. Чтобы они были доступны в программе Optima WIN™ , необходимо сохранять их в папке Reports\Addition. Тогда в меню Документы->Дополнительно появятся дополнительные пункты, которые будут иметь название шаблона, сохраненного в папке.
Также в папке Reports\Addition можно создавать подпапки. При этом в пункте меню Документы->Дополнительно появятся подменю.
Лист отчета
Новый шаблон состоит из пустого листа. На любое место листа можно положить объекты, которые могут отображать разную информацию (текст, графика) и определять внешний вид отчета. Все объекты, которые могут быть расположены на листе отчета, представлены на панели Объекты.
Будем различать лист шаблона и страницу отчета. Лист шаблона определяет структуру страниц, создаваемых во время формирования отчета. Если данные невозможно вывести на одной странице, автоматически создается следующая. Ее структура будет определяться тем же листом шаблона. То есть, по одному листу шаблона может быть создано несколько страниц отчета. В одном отчете может быть несколько листов, для создания страниц с разным оформлением. Чтобы добавить еще один лист, нажмите кнопку Добавить страницу на панели инструментов.
Для любого листа шаблона можно настроить опции формирования. Для этого возпользуйтесь командой Параметры страницы… из меню Файл. На закладках «Бумага», «Источник», «Поля» осуществляется настройка листа отчета — размер бумаги, поля принтера и т. д. На закладке «Параметры» можно указать количество колонок на листе и расстояние между ними. Также можно включить опцию Печать на предыдущем листе. Если эта опция включена, то при наличии на предыдущем листе свободного места текущий лист начинает печататься на предыдущей странице.
Объекты и их свойства
Таблица 0.0. Компоненты панели «Объекты»
У каждого объекта есть набор свойств, который определяет внешний вид и поведение этого объекта. Изменение этих свойств происходит в инспекторе объектов. Все свойства можно разделить на четыре основные группы:
Таблица 0.0. Группы свойств объектов
Группа свойств | Описание |
---|---|
Булевые свойства | Могут принимать только значение True или False. Значение True означает, что свойство включено. False — свойство выключено. |
Перечислямые свойства | Данные свойства могут принимать фиксированное значение из приводимого списка. |
Числовые свойства | Могут принимать численные значения, вводимые с клавиатуры. |
Составные свойства | Состоят из нескольких подсвойств. В инспекторе объектов значение данного свойства заключено в скобки. При двойном щелчке но полю открывается редактор, в котором можно настроить все подсвойства. |
У всех объектов (за исключением объекта Секция) есть особое свойство — Memo. В этом свойстве хранится содержимое объекта. Кроме того, в окне редактирования Memo можно редактировать скрипт для объекта.
Объект «Бэнд»
Остановимся подробнее на объекте Секция (в дальнейшем будем называть его бэндом).
Бэнд представляет собой полосу серого цвета на листе. Поведение бэнда зависит от его типа. В табл. 6 приведен полный перечень бэндов и выполняемых ими функций.
Таблица 0.0. Перечень используемых бэндов
Название | Функция |
---|---|
Report title | Печатается один раз в начале отчета |
Report summary | Печатается один раз в конце отчета |
Page header | Печатается вверху на каждой странице |
Page footer | Печатается внизу на каждой странице |
Master header | Печатается в начале списка 1-го уровня |
Master data | Данные списка 1-го уровня |
Master footer | Печатается в конце списка 1-го уровня |
Detail header | Печатается в начале списка 2-го уровня |
Detail data | Данные списка 2-го уровня |
Detail footer | Печатается в конце списка 2-го уровня |
Subdetail header | Печатается в начале списка 3-го уровня |
Subdetail data | Данные списка 3-го уровня |
Subdetail footer | Печатается в конце списка 3-го уровня |
Overlay | Печатается на каждой странице нижним слоем |
Column header | Печатается в начале каждой колонки |
Column footer | Печатается в конце каждой колонки |
Group header | Заголовок группы |
Group footer | Печатается после группы |
Cross header, Cross data, Cross footer | Эта группа бэндов предназначена для создания отчетов с переменным количеством столбцов и разбивкой на страницы |
Child | Может быть прикреплен к любому из бэндов, кроме Page footer. При этом бэнд будет выводиться вместе с родительским. |
Редактор для дата-бэндов позволяет выбрать источник данных из списка доступных либо выбрать виртуальный источник данных. При выборе виртуального источника необходимо указать, из скольких записей он состоит. При формировании отчета бэнд с виртуальным источником будет напечатан столько раз, сколько записей было задано. Редактор для бэнда Group header позволяет ввести условие группировки. Остальные бэнды не имеют редакторов.
На бэнде можно располагать разные объекты — это означает, что объект располагается поверх серой полоски бэда. Тогда при оформлении готового отчета эти объекты будут вести себя так же, как и бэнд, на котором они расположены. Например, бэнд Report title располагается один раз в самом начале отчета. При этом все объекты, которые при оформлении шаблона лежали на бэнде, автоматически перенесутся в начало отчета, сохраняя заданное расположение. Бэнды вывода данных (Master data, Detail data и Subdetail data) повторяются со всем своим содержимым столько раз, сколько записей содержится в источнике данных, к которому привязан бэнд. При этом происходит смена текущей записи источника и объекты на бэнде могут отображать информацию из этой записи.
Для различных бэндов в испекторе объектов доступны различные свойства. Все они сгруппированы в табл. 7
Таблица 0.0. Свойства объекта «Бэнд»
Свойство | Описание |
---|---|
FormNewPage | После печати бэнда формирование отчета продолжается с новой страницы. Если опция включена у дата-бэнда, то новая страница будет сформирована после вывода всех подбэндов. |
OnFirstPage | Если опция отключена, то бэнд не будет выведен на первой странице |
OnLastPage | Если опция отключена, то бэнд не будет выведен на последней странице |
RepeatHeader | Эта опция доступна у бэндов Master header, Detail header, Subdetail header, Group header, Cross header. При включении дублирует бэнд на новой странице или колонке |
Breaked | Если бэнд не помещается целиком на странице, будут выведены только поместившиеся строки текста, а вывод остальных будет продолжен с новой страницы |
Stretched | Высота бэнда определяется максимальной высотой находящихся в нем объектов. У объектов также должна быть включена опция Stretched. |
Диалоговая форма
Шаблон отчета, помимо листов, может содержать диалоговые формы. Диалоговая форма используется, когда необходимо задать какие-либо данные при формировании готового отчета. Чтобы добавить диалоговую форму в шаблон, нажмите кнопку Добавить форму диалога на панели инструментов.
Объекты диалоговой формы, их свойства и методы
Как и на листе, на диалоговой форме можно разместить различные объекты. Эти объекты представлены в табл. 8.
Таблица 0.0. Компоненты панели «Объекты»
У каждого объекта есть свое имя. Это уникальный в пределах отчета идентификатор. Он отображается в поле Name. В отчете у вас может быть несколько таких объектов, поэтому рекомендуется задавать «говорящие» имена всем новым объектам.
Объекты диалоговой формы имеют свои свойства, которые также могут быть сведены к четырем группам, описанным в табл. 5.
Доступ к свойствам как диалоговой формы, так и листа отчета осуществляется с помощью точки после имени объекта. Например, доступ к тексту объекта Edit с именем Edit1 осуществляется следующим образом:
Edit1.Text
Таким обращением можно изменить текст, прочитать его и т. д. Например, следующий скрипт изменяет содержимое объекта:
Edit1.Text := 'Hello World!';
Кроме свойств у объектов есть методы — определенные операции, которые производятся над объектом. Например, чтобы выполнить SQL-запрос объекта Запрос с именем Query1, необходимо создать скрипт вида:
Query1.Open;
Скрипт — это программа на языке высокого уровня, которая является частью отчета. Скрипт позволяет выполнить обработку данных, которую невозможно сделать штатными средствами FastReport, например, скрыть ненужные данные в зависимости от какого-либо условия. Также используется для управления диалоговыми формами, входящими в состав отчета.
Скрипт создается для событий — действий, которые наступают при определенных условиях. У разных объектов существуют различные события.
Объекты данных
На данной странице перечисляются компоненты, которые позволяют создать подключения и формировать запросы к базе данных.
Таблица 0.0. Компоненты на панели «Объекты»
Режим предпросмотра
Созданный шаблон содержит переменные и различный код. Чтобы шаблон превратился в отчет, необходимо воспользоваться кнопкой Предварительный просмотр на панели инструментов. При этом выполняются все скрипты, написанные для различных объектов, вычисляются переменные, бэнды формируются необходимое количество раз и т. д. После выполнения всех операций откроется окно Предварительный просмотр, в котором содержится готовый отчет. В этом окне можно изменять масштаб отчета, искать какую-либо информацию, печатать отчет на принтере. Также можно сохранить этот отчет или открыть ранее сохраненный.
Изменение готового отчета
Иногда необходимо изменить уже готовый отчет без изменения шаблона. Например, это может потребоваться при однократном изменении логотипа или вводе дополнительного поля. Чтобы изменить уже готовый отчет, дважды щелкните левой кнопкой мыши в любом месте отчета при просмотре. Откроется окно дизайнера отчета. вы можете изменить оформление отчета, но не можете использовать переменные или создавать какой-либо скрипт. После завершения редактирования выйдите из окна. Все внесенные изменения будут относиться только к текущему отчету. Шаблон отчета изменен не будет.
Сохранение готового отчета
Чтобы сохранить готовый отчет, воспользуйтесь кнопкой Сохранить отчет в файле на панели инструментов. Готовый отчет имеет расширение .frp и может использоваться в дальнейшем.
В дистрибутиве Optima WIN™ поставляется специальная утилита для просмотра готовых отчетов ReportViewer.
Часть I. Примеры создания отчетов
В данном руководстве все отчеты, за исключением первого, будут состоять из диалоговой формы и собственно листа отчета. Описание методики создания отчетов будет разделено на описание создания диалоговой формы и листа отчета.
Создание пустого бланка
Создадим бланк листа замера. Бланк должен содержать название заказчика, фамилию замеряющего, а также информацию по нескольким изделиям: ширина, высота, цвет и т. д.
Для вывода заголовка отчета удобно использовать бэнд Report title. Бэнд такого типа отображается один раз в начале отчета.
Теперь добавьте объект Прямоугольник с текстом (в дальнейшем — Текст) так, чтобы он располагался поверх бэнда. Этот объект будет отображать заголовок отчета. Если опция Редактирование после вставки включена, откроется окно редактирования Memo объекта. Если выключена, дважды щелкните мышью по объекту. В окне редактора Memo объекта введите следующий текст:
Лист замера
В табл. 1 приведены некоторые свойства, которые мы будем использовать для создания текущего отчета.
Таблица 0.0. Свойства объекта «Текст»
Свойство | Описание |
---|---|
AutoWidth | Если свойство имеет значение True, то при печати отчета ширина объекта увеличивается по ширине содержащегося в объекте текста. |
BandAlign | Положение объекта на бэнде. Может быть равно одной из констант: baNone, baLeft, baRight, baCenter, baWidth, baBottom. |
Stretched | Если свойство имеет значение True, то при печати отчета высота объекта будет зависеть от общей высоты строк текста, содержащегося в объекте (при этом необходимо, чтобы это же свойство было включено у бэнда, на котором лежит объект). |
Произведем следующие настройки объекта Текст:
Полю BandAlign присвоим значение baWidth, чтобы объект растянулся по всей ширине страницы.
Настроим оформление заголовка. Для этого необходимо использовать кнопки на панели «Текст». Установите следующий стиль для заголовка: выравнивание по центру страницы, шрифт «Verdana», 18 pt, белый на сером фоне.
Обратите внимание, что после произведенных нами изменений, введенный текст полностью не виден в объекте. Измените размеры объекта мышью.
Добавьте еще один объект Текст. Расположите его на бэнде под названием отчета. В Memo введите
Заказчик:
Следующий Текст расположите рядом с ним. Включите отображение контура объекта кнопкой Все линии рамки на панели «Прямоугольник». Растяните объект в длину.
Заголовок отчета готов. Теперь при формировании отчета FastReport расположит бэнд Report title в самом верху первой страницы.
Рис. 1.1. Пример оформления заголовка отчета
Оформим итог отчета. Здесь должна содержаться информация об исполнителе и дата выполнения замера. Добавьте бэнд Report summary. Этот бэнд располагается после вывода всех данных. Расположите на бэнде шесть объектов Текст. У трех из них включите отображение контура. Для оставшихся трех в Memo введите следуюшие записи:
Замер произвел:
Дата:
Подпись:
Эти объекты будут служить подписями к пустым прямоугольникам.
Рис. 1.2. Пример оформления итога отчета
Теперь оформим содержимое отчета. Добавьте бэнд Master data. Этот бэнд может повторяться несколько раз по числу записей, выводимых из БД. Также можно вручную указать число повторов. В окне Источник данных, которое открывается по двойному щелчку левой кнопки мыши, выберите пункт Виртуальный. В поле Количество записей укажите число повтора бэнда.
Рис. 1.3. Пример оформления формы замера
Расположите на бэнде нужное число объектов Текст, настройте их оформление. Для изменения оформления контура объектов, цвета их заливки, толщины и цвета рамки используйте панель «Прямоугольник». Для изменения выравнивания текста внутри объекта, а также стиля выводимого текста, используйте панель «Текст». На рис. 1.3 приведено примерное оформление формы заказа для одного изделия. Так как объект Master data должен выводиться несколько раз, эта форма полностью повторится столько раз, сколько вы указали в поле Количество записей для бэнда Master data.
Для просмотра готового отчета воспользуйтесь кнопкой Предварительный просмотр на панели инструментов или соответствующей командой в меню Файл.
Рис. 1.4. Пример готового отчета
Создание одноуровневого отчёта
Создадим отчет, который будет выводить список заказов и цены на них в виде таблицы. Также под таблицей заказов будем выводить общее число заказов и их общую стоимость.
Диалоговая форма
Для построения отчета с использованием данных из БД необходимо создать запрос. Запросы могут быть двух видов: статические и динамические. В отличие от статических, динамические запросы можно изменять с помощью скрипта в процессе формирования отчета. Мы рекомендуем использовать динамические запросы. Создание статических запросов описано на стр. 12. Динамический запрос — это объект, который располагается на диалоговой форме шаблона.
Чтобы добавить в отчет диалог, нажмите на панели инструментов кнопку Добавить форму диалога .
На форму добавьте объект Запрос. Для этого щелкните мышью по кнопке на панели объектов, а затем на поле формы диалога (см. рис. 2.1). У объекта Запрос есть разные свойства. В данном отчете будут использоваться только некоторые из них. Их описание приведено в табл. 2.
Рис. 2.1. Диалоговое окно с объектом Запрос
Таблица 0.0. Свойства объекта Запрос
Поле | Описание |
---|---|
Database | В этом поле указывается БД, из которой будут извлекаться данные. Во всех примерах в руководстве необходимо устанавливать OrdGridsDM.IBDB. Это псевдоним базы данных, с которой работает Optima WIN™ 7.0. |
Name | В этом поле указывается уникальный идентификатор, по которому осуществляется доступ к объекту и его свойствам. |
SQL | Поле, в котором хранится SQL-запрос для выбора данных из БД, указанной в поле Database. По двойному щелчку на этом поле открывается окно Редактор SQL, в котором можно создать или отредактировать запрос. |
Каждый объект FastReport имеет уникальный в пределах отчета идентификатор. Он отображается в поле Name. Добавленный нами только что объект Запрос имеет имя Query1. В дальнейшем у вас может быть несколько таких объектов. Поэтому рекомендуется задавать «говорящие» имена всем новым объектам. Изменим имя запроса на qryOrders.
Для вывода заказов и цен на них необходимо в окне Редактор SQL составить запрос на языке SQL. Для этого дважды щелкните по полю SQL в инспекторе объектов. Введите текст запроса, который приведен ниже, и нажмите ОК .
SELECT ordno,
ord_price
FROM orders
WHERE ordno IS NOT NULL
Структура используемой БД такова, что в таблице ORDERS хранятся записи заказов и папок в дереве заказов. Различаются эти записи только значениями некоторых полей. В частности, у заказа в поле ORDNO хранится его номер. У папки это поле не заполнено. То есть, данный запрос возвращает только те записи из таблицы ORDERS, у которых заполнено поле ORDNO, то есть, заказы.
В результате запроса из таблицы заказов (ORDERS) будет сформирована таблица, состоящая из двух полей: ORDNO (номер заказа) и ORD_PRICE (стоимость заказа).
Мы все подготовили для создания отчета. Теперь приступим к его оформлению. Перейдите на страницу отчета.
Лист отчета
Оформим заголовок отчета.
Рис. 2.2. Пример оформления заголовка
Настроим вывод данных из БД. Настроим заголовок таблицы заказов. Добавьте бэнд Master header. Этот бэнд отображается один раз перед выводом данных первого уровня. Добавьте объект Текст на бэнд. В Memo введите:
Номер заказа
Растяните объект мышью так, чтобы полностью отображался текст.
Добавьте еще один объект Текст. В Memo укажите:
Стоимость заказа
Произведите такие же операции, как и с предыдущим объектом.
Рис. 2.3. Пример оформления заголовка таблицы заказов
Теперь выведем список заказов. Добавьте объект Бэнд. Установите переключатель Тип секции в положение Master data. Если в настройках FastReport стоит опция Редактирование после вставки, то автоматически откроется окно Источник данных. Если данная опция отключена, дважды щелкните по области бэнда. Укажите в качестве источника DialogForm._qryOrders — это запрос на диалоговой форме. При выводе на печать бэнд и все его содержимое будут повторены столько раз, сколько записей было возвращено в ответ на запрос.
Для вывода необходимой информации добавьте в отчет два объекта Текст так, чтобы они находились на этом бэнде. В Memo объектов укажите поле БД, которое будет отображать объект. Для этого нажмите кнопку Вставить поле БД . В открывшемся окне (см. рис. 2.4) выберите источник данных — это будет результат запроса DialogForm.qryOrders, а затем поле, которое будет отображать данный объект. Для вывода номера заказа это поле ORDNO, а цены на заказ — ORD_PRICE. Также можно воспользоваться мастером вставки полей БДв отчет.
Рис. 2.4. Вставка поля БД
Для правильного отображения таблицы выполните следующие настройки:
- Расположите эти объекты под соответствующими заголовками на Master head.
- В качестве обрамления укажите Все линии рамки.
- Растяните объекты так, чтобы их размеры совпадали с соответствующими заголовками.
- Включите у объектов и у бэнда Master data свойство Stretched.
Рис. 2.5. Оформление таблицы заказов
Выведем под таблицей заказов сообщение об общем числе заказов. Для этого добавим бэнд Master footer. Расположим на нем объект Текст. В Memo объекта введем следующий текст:
Всего заказов: [COUNT(MasterData1)]
Здесь мы использовали одну из агрегатных функций COUNT(<имя бэнда>). Эта функция возвращает количество повторов бэнда. В данном примере мы использовали идентификатор бэнда с данными MasterData1. Очевидно, что это имя не говорит о наполнении бэнда, поэтому в дальнейшем будем переименовывать все добавляемые объекты.
Для отображения общей стоимости заказов добавьте на объект Master footer еще один объект Текст. Воспользуемся агрегатной функцией SUM(<выражение>).
на сумму: [SUM([DialogForm.qryOrders."ord_price"])]
Функция SUM() просуммирует все значения из поля ORD_PRICE.
Рис. 2.6. Итог таблицы заказов
Для просмотра получившегося отчета воспользуйтесь кнопкой Предварительный просмотр.
Создание двухуровневого отчёта
Создадим двухуровневый отчет, в котором сначала будет выводиться номер заказа, а под ним список изделий, входящих в него.
В FastReport можно напрямую создавать трехуровневые отчеты. Для создания отчетов с более сложной структурой необходимо использовать вложенные отчеты.
Диалоговая форма
Добавьте в отчет диалоговую форму.
В данном отчете мы будем работать с двумя таблицами: списком заказов и списком изделий. Необходимо создать SQL-запрос для формирования каждой таблицы.
Для работы с таблицей заказов добавьте объект Запрос. В качестве исходной базы данных назначьте OrdGridsDM.IBDB. Измените имя объекта на qryOrders.
Создайте следующий SQL-запрос:
SELECT ordno,
orderid
FROM orders
WHERE ordno IS NOT NULL
В результате запроса будут возвращены поля ORDNO (номер заказа) и ORDERID (идентификатор заказа). Идентификатор заказа необходим для того, чтобы после номера заказа выводился список изделий, относящихся именно к этому заказу.
Добавьте на диалоговую форму еще один объект Запрос. Для него укажите используемую БД в поле Database инспектора объектов.
В поле DataSource укажите qryOrders. Это означает, что запрос qryOrders является для текущего запроса мастер-источником. Мастер-источник чаще всего используется для создания многоуровневых отчетов. Измените имя объекта qryWindows.
Для вывода списка изделий и их цен необходимо создать следующий SQL-запрос:
SELECT wn_name,
wn_price
FROM windows
WHERE orderid = :orderid
Данный запрос возвращает значение двух полей WN_NAME (номер изделия) и WN_PRICE (стоимость изделия) из тех записей в таблице WINDOWS, у которых идентификатор заказа совпадает с идентификатором заказа текущей записи из мастер-источника. В нашем случае запись :orderid указывает, что значение берется из соответствующего поля мастер-источника, к которому привязан запрос qryWindows. Подробнее работа с внешними параметрами будет рассмотрена в следующем примере.
Лист отчета
Перейдем на страницу отчета. Оформите заголовок отчета так, как это было описано в предыдущем разделе.
Для вывода списка заказов добавьте бэнд Master data. В качестве источника данных установите DialogForm._qryOrders.
На бэнде разместите объект Текст. Объект будет выводить номер заказа, поэтому для вывода данных из БД укажите поле ORDNO (см. рис. 2.4). В Memo объекта появится следующая запись.
[DialogForm.qryOrders."ordno"]
Разместите на листе отчета под бэндом Master data бэнд с типом секции Detail data. В качестве источника данных укажите DialogForm._qryWindows. Добавьте на бэнд два объекта Текст. Этот бэнд будет выводить данные второго уровня. В Memo объектов для вывода номера изделия укажите источник WN_NAME, а для цены на изделие — WN_PRICE.
Если вы хотите вывести список изделий как таблицу, проделайте операции по оформлению таблицы, рассмотренные в предыдущем примере. Для вывода заголовка перед данными второго уровня используйте бэнд Detail header. Этот бэнд должен располагаться над бэндом Detail data (но под бэндом Master data).
Рис. 3.1. Пример оформления шаблона отчета
Для просмотра получившегося отчета воспользуйтесь кнопкой Предварительный просмотр.
Рис. 3.2. Пример отчета
Изменение запроса при формировании отчета
Изменим предыдущий отчет: будем выводить только те заказы, дата оформления которых лежит в заданном промежутке времени. Кроме того, в таблице изделий добавим изображение изделия.
Диалоговая форма
Добавьте на диалоговую форму два объекта DateEdit. Измените имена на decDateBegin и decDateEnd.
Диалоговое окно не выводится в процессе формирования отчета, если на нем нет отображаемых объектов. Неотображаемыми являются объекты Запрос, Таблица и База данных. Однако в данном случае производится ввод даты. Поэтому для формирования отчета добавьте на форму две кнопки Button. У одной кнопки установите свойство ModalResult равным mrOk. При нажатии на эту кнопку диалоговое окно закроется и начнется формирование отчета. У другой кнопки установите свойство ModalResult равным mrCancel. Эта кнопка закроет диалоговую форму без последующего формирования отчета. Обе кнопки на форме будут иметь подписи Button. Чтобы изменить подписи, свойству Caption каждой из кнопок присвойте значения OK для кнопки со свойством ModalResult равным mrOk и Cancel для другой кнопки.
Ранее в SQL-запросе явно указывались поля, которые необходимо выбрать. Когда таких полей оказывается много, затруднительно переписывать их все. Поэтому изменим SQL-запрос для qryOrders на следующий:
SELECT *
FROM orders
При этом запрос выдаст все поля таблицы ORDERS. Но этого не достаточно. Необходимо, чтобы выдавались не все заказы, а только те, которые были оформлены в промежутке дат. SQL-запрос должен окончательно формироваться после закрытия диалоговой формы, то есть, после выбора граничных дат. Модификация запроса будет осуществляться с помощью скрипта.
Необходимо, чтобы SQL-запрос изменился после окончательного выбора дат, то есть, после закрытия диалогового окна по кнопке OK. У объекта Button есть событие OnClick, наступающее при нажатии на кнопку. Чтобы изменить SQL-запрос, необходимо создать следующий скрипт для этого события:
begin
qryOrders.SQL.Add('where ordno is not null and
ord_date between ''' +
[FORMATDATETIME('dd.mm.yyyy', [decBeginDate.Date])] +
''' and ''' +
[FORMATDATETIME('dd.mm.yyyy', [decEndDate.Date])] + '''');
end
Приведенный выше скрипт добавляет в SQL-запрос условие, которое будет выбирать только те даты оформления заказа, которые лежат в промежутке между датой, указанной в объекте decBeginDate, и датой, указанной в объекте decEndDate. При этом в скрипте используется встроенная функция [FORMATDATETIME(<формат>, <дата>)], которая преобразует переменную <дата> имеющую тип Date в строку, используя формат, указанный в строке <формат>. В скрипте строковые переменные заключаются одинарные кавычки. Если строковая переменная должна содержать кавычки, используется удвоение символа. В результате для дат 10.10.2005 и 12.10.2005 SQL-запрос примет следующий вид:
SELECT *
FROM orders
WHERE ordno IS NOT NULL
AND ord_date BETWEEN '10.10.2005' AND '12.10.2005'
SQL-запрос окончательно формируется после закрытия диалоговой формы с помощью скрипта. Однако можно обойтись и без скрипта. Для этого используем внешние параметры SQL-запроса. Для qryOrders создайте SQL-запрос:
SELECT *
FROM orders
WHERE ord_date BETWEEN date1 AND date2
В данном SQL-запросе date1 и date2 являются внешними параметрами. Синтаксис задания внешнего параметра любого SQL-запроса — :<имя_параметра>. Все параметры хранятся в свойстве Params SQL-запроса. Дважды щелкните левой кнопкой мыши по соответствующему полю в инспекторе объектов. При этом откроется окно qryOrders параметры. Каждый параметр по умолчанию указывает на поле из мастер-источника. В нашем случае необходимо задать другое значение этих параметров. Для параметра date1 установите переключатель в положение Значение и введите в поле
decDateBegin.Date
Для date2 проделайте те же операции и введите текст
decDateEnd.Date
При выполнении SQL-запроса вместо параметров date1 и date2 будут подставлены значения дат соответствующих объектов.
Обратите внимание, что в запросе не производится проверка на то, что поле ORDNO заполнено. Эта проверка не нужна, так как дата создания папки не хранится в БД.
В таблице qryWindows, как и в таблице qryOrders, понадобятся дополнительные поля. Поэтому в SQL-запросе для qryWindows выведем все поля таблицы WINDOWS:
SELECT *
FROM windows
WHERE orderid = :orderid
При этом запрос qryWindows вернет все поля таблицы WINDOWS.
Лист отчета
Перейдите на страницу отчета.
На бэнд данных второго уровня Detail data к уже существующим объектам добавьте объект Рисунок. В поле DataField инспектора объектов вручную введите [PICT]. Это внутренняя переменная, которая ссылается на изображение. Всего существует три переменных, которые ссылаются на различные изображения. Их описание приведено в табл. 3.
Таблица 0.0. Внутренние переменные, хранящие изображение
Переменная | Описание |
---|---|
[PICT] | Изображение изделия. |
[PICT&SIZE] | Изображение изделия со всеми размерами изделия. |
[PICT&SIZE&NAME] | Изображение изделия со всеми размерами, а также подписи проемов. |
[PICT&SIZE&NAME&GLASS] | Изображение изделия со всеми размерами, а также подписи проемов и артикулы заполнений. |
[PICT&SIZE&NAME&GLASS&COLOR] | Изображение изделия в цвете со всеми размерами, а также подписи проемов и артикулы заполнений. |
Чтобы указать источник данных для построения изображения, для события OnBeforePrint объекта Detail data необходимо добавить следующий код:
begin
SOURCE_INFO := [DialogForm.qryWindows."wn_packed"]
WINID := [DialogForm.qryWindows."windowid"]
end
При этом во внутреннюю переменную SOURCE_INFO передается информация об изделии в xml-формате. Затем происходит распаковка xml-строки и передача полученного изображения в переменные, описанные в табл. 3.
Для оформления таблицы проделайте следующие операции:
- Установите нужные вам размеры Рисунка. Включите Все линии рамки объекта соответствующей кнопкой на панели «Прямоугольник».
- Установите высоту бэнда Detail data таким образом, чтобы нижняя граница бэнда совпадала с нижней границей Рисунка. Включите у бэнда свойство Stretched.
- У объектов Текст, отображающих номер изделия и его стоимость, также включите свойство Stretched. Это необходимо для того, чтобы высота объектов была равна высоте бэнда, на котором они лежат, а следовательно, и высоте объекта Рисунок. Таким образом, получим таблицу, содержащую номер изделия, его стоимость и изображение.
Взаимодействие объектов между собой
Сформируем отчет, который будет выводить список изделий указываемого заказа. То есть, после запуска отчета, вы выбираете заказ, информация о котором вас интересует.
Диалоговая форма
В предыдущих отчетах уделялось много внимания оформлению листа отчета. На примере этого отчета рассмотрим более подробно оформление диалоговой формы.
Создайте диалоговую форму. В заголовке окна вы увидите надпись Form. В поле Caption испектора объектов введите Выбор заказа. Обратите внимание, что заголовок окна изменился.
Добавьте на форму Запрос. Измените имя объекта на qryOrders. Создайте следующий SQL-запрос:
SELECT *
FROM orders
WHERE ordno IS NOT NULL
Теперь необходимо вывести список с номерами всех существующих заказов. Добавьте два объекта ListBox. Измените имена объектов на lbOrdNo и lbOrderID. Первый объект нам необходим для вывода списка заказов. Второй объект — для вывода списка идентификаторов заказов. Добавьте на форму объект Label. Этот объект может отображать текст, то есть, удобен для создания подписей. Отображаемый объектом текст хранится в свойстве Caption. Измените содержимое поля на Заказы:. Расположите объект над объектом lbOrdNo. Разместите объекты, как показано на рисунке.
Сделаем так, чтобы при открытии формы в объекте lbOrdNo приводился весь список заказов, а в объекте lbOrderID — список идентификаторов заказов. Для события OnActivate диалоговой формы создайте следующий скрипт:
begin
qryOrders.Open;
qryOrders.First;
for i := 1 to qryOrders.RecordCount do
begin
lbOrdNo.Items.Add(qryOrders.Fields['ordno']);
lbOrderID.Items.Add(qryOrders.Fields['orderid']);
qryOrders.Next;
end;
end
При выполнении этого кода происходит следующее:
- Выполнение запроса. При этом получаем общий список заказов.
- Запуск цикла for, который будет повторен столько раз, сколько записей вернул запрос qryOrders, то есть, число заказов. В результате выполнения цикла в lbOrdNo будет выведен список всех номеров заказов из запроса qryOrders, а в lbOrderID — список всех идентификаторов этих заказов.
Если вы работаете с большим числом заказов, найти нужный вам будет затруднительно. Сделаем возможность отображения только тех заказов, которые лежат в какой-либо папке.
Добавьте еще один Запрос. Измените имя запроса на qryFolders и укажите используемую БД. Создайте SQL-запрос:
SELECT orderid,
node_title
FROM orders
WHERE node_title IS NOT NULL
У папки, в отличие от заказа, поле ORDNO не заполнено. Название папки хранится в поле NODE_TITLE. Таким образом, данный запрос возвращает только те записи из таблицы ORDERS, у которых заполнено поле NODE_TITLE, то есть, папки.
Добавьте на форму объект DBLookupComboBox. Этот объект позволяет выбрать значение в выпадающем списке. Выпадающий список состоит из записей, полученных из БД или запроса. Измените имя объекта на lcbFolders. У объекта DBLookupComboBox будем использовать следующие свойства:
Таблица 0.0. Свойства объекта DBLookupComboBox
Свойство | Описание |
---|---|
ListSource | Показывает список таблицу БД, откуда будут браться данные для формирования списка. Установите значение qryFolders. |
ListField | Указывает поле таблицы, которое будет отображаться в списке. |
KeyField | Указывает поле таблицы, в котором хранится идентификатор записи. Поле обязательно для заполнения. В нашем случае — это ORDERID. |
Установите в качестве источника данных в поле ListSource значение qryFolders, возвращающее список папок заказов.
В поле ListField выберите поле NODE_TITLE из запроса qryFolders, содержащее названия папок заказов.
В поле KeyField укажите поле ORDERID.
Добавьте объект Label на форму и расположите его над выпадающим списком. Измените содержимое поля Caption на Папка с заказами:.
Для события OnActivate диалоговой формы к существующему коду добавьте следующее:
begin
qryFolders.Open;
qryFolders.Fetchall;
end
Первая строка кода запустит выполнение запроса.
По умолчанию в выпадающем списке отображается только одна строка. Чтобы отобразить несколько строк, необходимо пролистать список. Это можно сделать вручную или програмно. Вторая строка приведенного кода не обязательна и позволяет пролистать значения списка програмно.
Теперь выпадающий список содержит названия всех папок из дерева заказов. Сделаем так, чтобы выводился список только тех заказов, которые лежат в выбранной папке. Для события OnClick объекта lcbFolders необходимо написать следующий код:
begin
qryOrders.SQL.Clear;
qryOrders.SQL.Add('select * from orders where ordno is not null
and parent_id = ' + STR(lcbFolders.Text));
ListBox1.Items.Clear;
ListBox2.Items.Clear;
qryOrders.Open;
qryOrders.First;
for i := 1 to qryOrders.RecordCount do
begin
ListBox1.Items.Add(qryOrders.Fields['ordno']);
ListBox2.Items.Add(qryOrders.Fields['orderid']);
qryOrders.Next;
end;
end
Разберем подробнее работу приведенного кода. Для начала необходимо полностью очистить SQL-запрос. Это осуществляется с помощью метода Clear объекта Запрос. Затем создается новый SQL-запрос с помощью метода Add. Этот запрос выбирает записи таблицы ORDERS, которые являются заказами и лежат в папке, указаной в объекте lcbFolders. Принадлежность папке проверяется сравнением идентификатора родительской папки (PARENT_ID), который есть у каждого заказа и идентификатора папки, которую выбрали в списке папок. Этот идентификатор хранится в поле Text объекта DBLookupComboBox. Чтобы не вызвать ошибки преобразования типов переменных, используется встроенная функция Str(<число>), которая преобразует число в строку.
Последние строки кода повторяют записанные в событии OnActivate диалоговой формы. Однако перед добавлением нового списка заказов необходимо удалить уже существующие записи. Это осуществляется с помощью метода Clear объекта ListBox.
Теперь вы можете выбрать папку в выпадающем списке, при этом вы увидите список заказов в данной папке.
Однако конечной целью данного отчета является список изделий выбранного заказа. Добавьте еще один Запрос. Измените имя на qryWindows. Укажите используемую дазу данных.
Добавьте два объекта Button. Как и в предыдущем отчете это будут кнопки OK и Cancel. Настройте кнопки так, как это было показано в предыдущем примере.
Для события OnClick кнопки OK создайте код:
begin
qryWindows.SQL.Clear;
qryWindows.SQL.Add('select * from windows where orderid = ' +
lbOrderID.Items[lbOrdNo.ItemIndex]);
end
Остановимся подробнее на обращении к объекту ListBox. У таких объектов в поле ItemIndex хранится номер выбранной строки. Доступ к любой строке можно получить обращением Items[<номер_строки>]. Таким образом, из списка, содержащего идентификаторы заказов берется строка с номером выбранной строки в списке заказов. Именно для того, чтобы можно было получить идентификатор заказа, мы и использовали в данном отчете объект lbOrderID.
Измените размеры окна так, чтобы объект lbOrderID не был виден (см рис. 5.1).
Рис. 5.1. Диалоговая форма отчета
Такой способ определения идентификатора записи требует двух объектов ListBox на каждый список. Если в отчете используется большое количество списоков, можно выводить название и идентификатор в одном объекте ListBox. Именно на таком принципе построен отчет needmat.frf.
Лист отчета
Оформление листа отчета не отличается от рассмотренных ранее отчетов, поэтому не будем его рассматривать подробно.
Добавьте бэнд Report title. Укажите номер заказа, отчет по которому вы выводите. Для этого в Memo объекта Текст введите
[DialogForm.qryOrders."ordno"]
Добавьте бэнд Master data. Расположите на нем нужное количество объектов Текст, укажите поля таблицы qryWindows, которые будут выводиться в данных объектах.
Для просмотра отчета воспользуйтесь кнопкой Предварительный просмотр.
Создание Cross-tab отчётов
В данном отчете выведем таблицу, которая будет содержать сумму стоимостей всех заказов по месяцам для каждого заказчика в БД. Под таблицей выведем диаграммы, показывающие долю каждого заказчика в общей стоимости заказов, а также общую сумму стоимостей заказов за каждый месяц.
Диалоговая форма
Для начала необходимо получить список всех заказчиков. Добавьте на форму объект Запрос. Измените имя объекта на qryCustomers, укажите используемую БД.
В базе данных Optima WIN™ информация о заказчиках и поставщиках хранится в одной таблице CONTRAGENTS. В таблице заказчиков CUSTOMERS хранятся только указатели, которые ссылаются на записи в таблице CONTRAGENTS. Таким образом, чтобы получить список заказчиков, необходимо создать следующий SQL-запрос:
SELECT *
FROM customers
INNER JOIN contragents
ON contragid = customerid
Этот запрос выполняется в два этапа: сначала в таблице CONTRAGENTS выбираются записи, на которые ссылаются указатели в таблице CUSTOMERS, а затем полученная таблица объединяется с таблицей CUSTOMERS. Результатом данного запроса будет весь список заказчиков, когда-либо заведенных в БД, в том числе будут указаны и удаленные заказчики. Во многих таблицах БД (CUSTOMERS, ORDERS и др,) информация не удаляется, а лишь помечается как удаленная. В таких таблицах в поле DELETED хранится дата удаления записи, а у неудаленных записей данное поле содержит NULL. Чтобы предотвратить вывод удаленных заказчиков, измените запрос на:
SELECT *
FROM customers
INNER JOIN contragents
ON contragid = customerid WHERE customers.deleted IS NULL
Добавьте еще один Запрос. Измените имя объекта на qryDates. Создайте следующий SQL-запрос:
SELECT DISTINCT Extract(month FROM ord_date) d_month,
Extract(year FROM ord_date) d_year
FROM orders
WHERE ordno IS NOT NULL
ORDER BY 2,
1
При выполнении SQL-запроса будет просмотрен каждый заказ в БД и возвращена таблица, все записи которой будут содержать два поля — месяц и год заказа. Модификатор distinct удалит повторяющиеся записи из таблицы. Таким образом запрос вернет список всех сочетаний месяц-год, в которые были оформлены заказы. Затем все записи будут упорядочены по возрастанию даты.
Добавьте Запрос, который будет работать с заказами. Измените его имя на qryOrders. Создайте SQL-запрос, который будет возвращать пустое поле SUMPRICE.
SELECT Sum(ord_price) sumprice
FROM orders
WHERE orderid IS NULL
Лист отчета
На этапе оформления шаблона отчета неизвестно, сколько столбцов должно быть в таблице. Чтобы построить подобную таблицу используются Cross-tab отчеты.
Для построения такого отчета прежде всего необходимо добавить несколько бэндов.
Добавьте бэнд Master header — он будет использоваться для вывода наименования столбцов таблицы. Затем добавьте бэнд Master data, в качестве источника данных укажите DialogForm._qryCustomers. Этот бэнд должен повториться столько раз, сколько записей было возвращено запросом qryCustomers, то есть один раз на каждого заказчика. Бэнд Master footer будет использоваться для подведения итогов в столбцах.
Добавьте бэнд Cross header. Он неоходим для вывода названия строк таблицы. Для вывода столбцов добавьте бэнд Cross data. В окне Источники данных необходимо указать источники для каждого пересечения этого бэнда с другим. В данном случае существует три бэнда, с которыми пересекается бэнд Cross data. Для всех секций эти источники одинаковы. Установите значение DialogForm._qryDates в поле Источник для всех бэндов. При этом бэнд повторится столько раз, сколько записей будет возвращено запросом qryDates.
Добавьте бэнд Cross footer. Он будет использоваться в дальнейшем для вывода общей суммы заказа для каждого заказчика.
В результате получится девять зон, образованных пересечением бэндов (см. рис. 6.1).
Рис. 6.1. Бэнды для построения таблицы
На пересечении бэндов Master data и Cross header разместите объект Текст, измените размеры бэндов и объекта Текст так, чтобы объект полностью лежал в пределах зоны, образованной пересечением бэндов. В Memo объекта Текст укажите:
[DialogForm.qryCustomer."co_name"]
При формировании отчета в этом поле будет выводиться название заказчика.
Объект Текст на пересечении бэндов Master footer и Cross header будет выводить название последней строки в таблице. В Memo объекта укажите необходимый текст, например, "Итого: ".
На пересечении бэндов Master header и Cross data разместите объект Текст. В Memo объекта укажите следующее:
[DialogForm.qryDates."d_month"].[DialogForm.qryDates."d_year"]
При формировании отчета отобразится запись даты типа mm.yyyy.
Для вывода стоимости заказов, совершенных заказчиком в какой-либо месяц, необходимо разместить Текст на пересечении бэндов Master data и Cross data. В Memo объекта укажите поле БД:
[DialogForm.qryOrders."sumprice"]
Так как стоимость заказов должна считаться динамически для каждого промежутка дат, создать запрос на этапе оформления диалоговой формы нельзя. Поэтому SQL-запрос необходимо создавать с помощью скрипта. Создайте скрипт в Memo объекта:
begin
qryOrders.Close;
qryOrders.SQL.Сlear;
qryOrders.SQL.Add('select coalesce(sum(o.ord_price), 0) sumprice
from orders o where
customerid = ' + STR([DialogForm.qryCustomer."customerid"]) +
' and extract(month from o.ord_date) = ' +
STR([DialogForm.qryDates."d_month"]) +
' and extract(year from o.ord_date) = ' +
STR([DialogForm.qryDates."d_year"]));
qryOrders.Open;
end
Этот скрипт создает SQL-запрос, который отбирает все заказы, у которых заказчиком является текущий заказчик в запросе qryCustomers, а месяц и год оформления заказа соответствуют текущим значениям запроса qryDates. Затем стоимости полученных заказов суммируются и передаются в поле SUMPRICE. Таким образом, в результате SQL-запроса возвращается одна запись в поле SUMPRICE, которая и выводится в Memo объекта Текст.
Для вывода суммы стоимостей всех заказов за определенный месяц разместите Текст на пересечении бэндов Master footer и Cross data. Чтобы получить сумму стоимостей, используйте агрегатную функцию SUM() и введите в Memo следующий текст:
[SUM([DialogForm.qryOrders."SUMPRICE"])]
Объект Текст на пересечении бэндов Master header и Cross footer будет выводить заголовок последнего в таблице столбца. В Memo объекта укажите необходимый текст, например, "Итого: ".
Для вывода суммы стоимостей всех заказов каждого заказчика разместите Текст на пересечении бэндов Master data и Cross footer. Используте агрегатную функцию SUM() и введите в Memo следующий текст:
[SUM([DialogForm.qryOrders."SUMPRICE"])]
Шаблон, по которому будет создаваться и заполняться данными таблица, готов (см. рис. 6.2).
Рис. 6.2. Шаблон таблицы данных
Для вывода графической информации добавьте бэнд Report summary, на нем разместите два объекта Диаграмма. Дважды щелкните кнопкой мыши по первому объекту. В открывшемся окне укажите Тип диаграммы. Для вывода суммы стоимостей всех заказов за каждый месяц построим вертикально ориентированную гистограмму. На закладке «Данные» в группе Имя объекта необходимо указать источники данных. В поле Для данных введите имя источника числовых данных. В нашем случае — Memo5. В поле Для подписи должно содержаться поле, откуда будут браться подписи для столбцов гистограммы. В нашем случае — Memo3. На закладке «Пометки» в группе Стиль выберите пункт Значение.
Чтобы показать долю каждого заказчика в общей стоимости заказов, воспользуемся круговой диаграммой. На тот же бэнд Report summary добавьте еще одну Диаграмму. Укажите необходимый Тип диаграммы. На закладке «Данные» укажите источники данных: Для данных — Memo7, Для подписи — Memo1. На закладке Стиль выберите пункт Процент.
Отчет готов. Для просмотра нажмите кнопку Предварительный просмотр.
Рис. 6.3. Пример Cross-tab отчета
Часть II. Справочник
Ниже приводятся справочные данные, полезные при составлении отчетов.
SQL
Данная глава посвящена описанию работы с SQL запросами при работе с дизайнером отчетов.
SQL-оператор состоит из зарезервированных слов, а также из слов определяемых пользователем. Зарезервированные слова являются постоянной частью языка SQL и имеют фиксированное значение. Их следует записывать в точности так, как это установлено, и нельзя разбивать на части для переноса из одной строки в другую. Слова, определяемые пользователям, задаются самим пользователем (в соответствии с определенными синтаксическими правилами) и представляют собой имена различных объектов базы данных — таблиц, столбцов, представлений индексов и т. д. Слова в операторе размещаются в соответствии с установленными синтаксическими правилами.
Большинство компонентов SQL-операторов не чувствительны к регистру. Это означает что могут использоваться любые буквы — как строчные так и прописные. Одним важным исключением из этого правила являются символьные литералы-данные, которые должны вводится точно так же, как были введены соответствующие им значения, хранящиеся в базе данных. Например, если в базе данных хранится значение фамилии 'Минеев', а в условии поиска указан символьный литерал 'МИНЕЕВ', то эта запись не будет найдена.
Поскольку язык SQL имеет свободный формат, отдельные SQL-операторы и их последовательности будут иметь более читабельный вид при использовании отступов и выравнивания. Рекомендуется придерживаться следующих правил:
- Каждая фраза в операторе должна начинаться с новой строки;
- Начало каждой фразы должно быть выровнено с началом остальных фраз оператора;
- Если фраза имеет несколько частей, каждая из них должна начинаться с новой строки с некоторым отступом относительно начала фразы, что будет указывать на их подчиненность;
В дальнейшем для определения формата SQL-операторов будет применяться следующая форма:
- Вертикальная черта | указывает на необходимость выбора одного из нескольких приведенных значений, например, a | b | c.
- Фигурные скобки определяют обязательный элемент, например, {a}.
- Квадратные скобки определяют необязательный элемент, например, [a].
- Многоточие … используется для указания необязательной возможности повторения конструкции, от нуля до нескольких раз, например {a|b} [,c…]. Эта запись означает что после a или b может следовать от нуля до нескольких повторений c разделенных запятыми.
Литералы
Прежде чем приступить к обсуждению SQL-операторов, необходимо выяснить, что означает такое понятие как «литерал». Литералы представляют собой константы, которые используются в SQL-операторах. Существуют различные формы литералов для каждого типа данных, которые поддерживаются SQL. Однако не углубляясь в детали можно указать лишь различия между литералами, которые следует заключать в одинарные кавычки, и теми, которые не следует. Все нецифровые значения данных всегда должны заключаться в одинарные кавычки. Вот пример использования литералов при помещении данных в таблицу:
INSERT INTO windcharge
(windchargeid,
namefactor,
chargefactor,
deleted,
userconst)
VALUES (1,
'A',
0.6,
NULL,
0)
Здесь литералами являются указанные в скобках после value значения полей.
Оператор SELECT
Оператор SELECT является наиболее сложной и чаще всего используемой командой языка SQL. Его назначение состоит в выборке и отображении данных одной или более таблиц базы данных. Общий вид оператора SELECT имеет следующий вид:
SELECT [DISTINCT | ALL] {* | [<имя_поля> [AS <новое_имя>]] [,…]}
FROM <имя_таблицы> [<псевдоним>] [,…]
[WHERE <условие>]
[GROUP BY <список_полей>] [HAVING <условие>]
[ORDER BY <список_полей>]
Здесь параметр <имя_поля> представляет собой имя поля или выражение из нескольких имен. Параметр <имя_таблицы> является именем существующей в базе данных таблицы или представления, к которым необходимо получит доступ. Необязательный параметр <псевдоним> — это сокращение, устанавливаемое для имени таблицы <имя_таблицы>. Обработка элементов оператора SELECT выполняется в следующей последовательности:
Таблица 0.0. Выполнение элементов оператора SELECT
Элемент | Описание |
---|---|
SELECT | Устанавливается, какие поля должны присутствовать в выходных данных |
FROM | Определяются имена используемой таблицы или нескольких таблиц |
WHERE | Выполняется фильтрация строк объекта в соответствие с заданными условиями |
GROUP BY | Образуются группы строк, имеющих одно и то же значение в заданном поле |
HAVING | Фильтруются группы строк объекта в соответствие с указанным условием |
ORDER BY | Определяется упорядоченность результатов выполнения оператора |
Порядок предложений и фраз в операторе SELECT не может быть изменен. Только два предложения оператора — SELECT и FROM — являются обязательными, все остальные предложения и фразы могут быть опущены. Операция SELECT является закрытой: результат запроса к таблице представляет собой другую таблицу. Существует множество вариантов записи данного оператора, что иллюстрируется приведенными ниже примерами.
Выборка всех строк
Для выбора всех записей из справочника контрагентов можно воспользоваться следующим запросом.
SELECT windchargeid,
namefactor,
chargefactor,
deleted,
userconst
FROM windcharge
В результате получим таблицу вида:
WINDCHARGEID | NAMEFACTOR | CHARGEFACTOR | DELETED | USERCONST |
---|---|---|---|---|
1 | A | 0.6 | 0 | |
2 | B | 0.96 | 1 | |
3 | C | 1.32 | 17.09.2005 | 2 |
5 | D | 1.56 | 3 |
Поскольку выборка всех имеющихся в таблице полей выполняется достаточно часто, в языке SQL определен упрощенный вариант записи значения «все поля» — вместо имени полей указывается символ звездочки *. Приведенный ниже пример представляет собой упрощенный вариант записи того же самого запроса:
SELECT *
FROM windcharge
Если же необходимо получить только определенные поля (например, название группы и коэффициент), то запрос будет выглядеть следующим образом:
SELECT namefactor,
chargefactor
FROM windcharge
Результат запроса:
NAMEFACTOR | CHARGEFACTOR |
---|---|
A | 0.6 |
B | 0.96 |
C | 1.32 |
D | 1.56 |
F | 2.08 |
Выведем список дат, когда заводились заказы. Для этого можно использовать запрос:
SELECT ord_date
FROM orders
Результат:
ORD_DATE |
---|
17.10.2004 0:00:00 |
01.09.2005 0:00:00 |
01.09.2005 0:00:00 |
16.09.2005 0:00:00 |
16.09.2005 0:00:00 |
16.09.2005 0:00:00 |
19.09.2005 0:00:00 |
19.09.2005 0:00:00 |
Как видно из примера оператор SELECT не исключает дублирующихся значений при выборке одного или нескольких полей. Для удаления из результирующей таблицы дублирующихся строк используется ключевое слово DISTICT:
SELECT DISTINCT ord_date
FROM orders
Результат:
ORD_DATE |
---|
01.08.2004 0:00:00 |
01.09.2004 0:00:00 |
17.10.2004 0:00:00 |
01.09.2005 0:00:00 |
16.09.2005 0:00:00 |
19.09.2005 0:00:00 |
В общем случае для создания вычисляемого поля в списке SELECT следует указать некоторое выражение языка SQL. В этих выражениях могут применяться операции сложения, вычитания, умножения и деления. При построении сложных выражений могут использоваться скобки. Для получения значения вычисляемого поля могут использоваться значения из нескольких полей таблицы, однако тип данных тех полей, которые входят в арифметическое выражение, обязательно должен быть цифровым.
SELECT ordno,
ord_price * 29.9 AS rus_price
FROM orders
Результат:
ORDNO | RUS_PRICE |
---|---|
Order2 | 20130.77 |
A32 | 6809.72 |
456218953 | 182.00 |
Order3 | 0.00 |
28949 | 8752.33 |
Выбор строк (предложение WHERE)
В приведенных выше примерах в результате выполнения оператора SELECT выбирались все строки указанной таблицы. Однако очень часто требуется тем или иным образом ограничить набор строк, помещаемых в результирующую таблицу запроса. Это достигается с помощью указания в запросе предложения WHERE. Оно состоит из ключевого слова WHERE, за которым следует перечень условий поиска, определяющий те строки, которые должны быть выбраны при выполнении запроса. Существует пять основных типов условия поиска.
- Сравнение — сравниваются результаты вычисления одного выражения с результатами вычисления другого выражения.
- Диапазон — проверяется, попадает ли результат вычисления выражения в заданное множество значений.
- Принадлежность к множеству — проверяется, принадлежит ли результат вычисления выражения заданному множеству значений.
- Соответствие шаблону — проверяется, отвечает ли некоторое строковое значение заданному шаблону.
- Значение NULL — проверяется содержит ли данное поле определитель NULL (неизвестное значение).
В языке SQL можно использовать следующие операторы сравнения:
Таблица 0.0. Операторы сравнения}
Оператор | Описание |
---|---|
= | равенство |
< | меньше |
> | больше |
< = | меньше или равно |
> = | больше или равно |
< > | не равно (стандарт ISO) |
Более сложные предикаты могут быть построены с помощью логических операторов AND, OR или NOT, а также с помощью скобок, используемых для определения порядка вычисления выражения (если это необходимо или желательно). Вычисление выражений в условиях выполняется по следующим правилам:
- Выражение вычисляется слева направо.
- Первыми вычисляются подвыражения в скобках.
- Операторы NOT выполняются до выполнения операторов AND и OR.
- Операторы AND выполняются до выполнения операторов OR.
Для устранения любой возможной неоднозначности рекомендуется использовать скобки.
SELECT wn_name
FROM windows
WHERE orderid = 2
Результат:
WN_NAME |
---|
A32-1 |
A32-3 |
A32-4 |
Наличие ключевого слова BETWEEN требует задания границ диапазона значений. Имеется и негативная версия проверки диапазона значений (NOT BETWEEN). В этом случае требуется, чтобы проверяемое значение лежало вне границ заданного диапазона. Наличие ключевого слова BETWEEN и соответствующей проверки лишь незначительно повышает выразительную мощность языка SQL, поскольку те же самые результаты могут быть достигнуты с помощью выполнения двух обычных проверок.
SELECT ordno,
ord_price,
ord_date
FROM orders
WHERE ord_date BETWEEN '20.05.2005' AND '17.08.2005'
Результат:
ORDNO | ORD_PRICE | ORD_DATE |
---|---|---|
456218953 | 182.00 | 16.06.2005 0:00:00 |
Order3 | 0.00 | 16.06.2005 0:00:00 |
28949 | 8752.33 | 29.07.2005 0:00:00 |
Проверка вхождения результата вычисления выражения в заданное множество организуется с помощью ключевого слова IN. При этом проверяется, соответствуют ли результат вычисления выражения одному из значений в предоставленном списке.
Существует и отрицательная версия этой проверки (NOT IN), которая используется для отбора любых значений, кроме тех, которые указаны в представленном списке. Как и в случае ключевого слова BETWEEN, условие IN незначительно повышает выразительную мощность языка SQL. Однако использование ключевого слова IN представляет собой более эффективный способ записи условий поиска, особенно если набор допустимых значений достаточно велик.
Сортировка результатов (фраза ORDER BY)
В общем случае строки в результирующей таблице SQL-запроса не упорядочены каким-либо определенным образом. Однако их можно требуемым образом отсортировать, для чего в оператор SELECT помещается фраза ORDER BY. Фраза ORDER BY включает список разделенных запятыми идентификаторов полей, по которым требуется упорядочить результирующую таблицу запроса. Идентификатор поля может представлять собой либо его имя, либо номер, который идентифицирует элемент списка SELECT его позицией в этом списке. Самый левый элемент списка имеет номер 1, следующий — номер 2 и т. д. Номера полей могут использоваться в тех случаях, когда поля, по которым следует упорядочить результат, являются вычисляемыми, а фраза AS с указанием имени этого поля в операторе SELECT отсутствует. Фраза ORDER BY позволяет упорядочить выбранные записи в порядке возрастания (ASC) или убывания (DESC) значений любого поля или комбинации полей, независимо от того, присутствуют эти поля в таблице результатов или нет.
SELECT ordno,
ord_price,
ord_date
FROM orders
WHERE ord_date BETWEEN '20.05.2005' AND '17.08.2005'
ORDER BY ord_date DESC
Результат:
ORDNO | ORD_PRICE | ORD_DATE |
---|---|---|
456218953 | 182.00 | 16.06.2005 0:00:00 |
Order3 | 0.00 | 16.06.2005 0:00:00 |
28949 | 8752.33 | 29.07.2005 0:00:00 |
Во фразе ORDER BY может быть указано и больше одного элемента. Главный ключ сортировки определяет общую упорядоченность строк результирующей таблицы. Если значения главного ключа сортировки во всех строках результирующей таблицы являются уникальными, нет необходимости использовать дополнительные ключи сортировки. Однако, если значения главного ключа не уникальны, в результирующей таблице будет присутствовать несколько строк с одним и тем же значением старшего ключа сортировки. В этом случае может оказаться желательным упорядочить строки с одним и тем же значением главного ключа по какому-либо дополнительному ключу сортировки. Если во фразе ORDER BY присутствуют второй и последующие элементы, то такие элементы называют младшими ключами сортировки.
SELECT ordno,
ord_price,
ord_date
FROM orders
WHERE ord_date BETWEEN '20.05.2005' AND '17.08.2005'
ORDER BY ord_date DESC,
ord_price ASC
Результат:
ORDNO | ORD_PRICE | ORD_DATE |
---|---|---|
Order3 | 0.00 | 16.06.2005 0:00:00 |
456218953 | 182.00 | 16.06.2005 0:00:00 |
28949 | 8752.33 | 29.05.2005 0:00:00 |
Использование обобщающих функций языка SQL
Стандарт ISO содержит определение следующих пяти обобщающих функций:
Таблица 0.0. Обобщающие функции
Функция | Описание |
---|---|
COUNT | Возвращает количество значений в указанном поле |
SUM | Возвращает сумму значений в указанном поле |
AVG | Возвращает усредненное значение в указанном поле |
MIN | Возвращает минимальное значение в указанном поле |
МАХ | Возвращает максимальное значение в указанном поле |
Все эти функции оперируют со значениями в единственном поле таблицы и возвращают единственное значение. Функции COUNT, MIN и МАХ применимы как к числовым, так и к нечисловым полям, тогда как функции SUM и AVG могут использоваться только в случае числовых полей. За исключением COUNT(*), при вычислении результата любых функций сначала исключаются все пустые значения, после чего требуемая операция применяется только к оставшимся конкретным значениям поля. Вариант COUNT(*) является особым случаем использования функции COUNT — его назначение состоит в подсчете всех строк в результирующей таблице, независимо от того, содержатся там пустые, дублирующиеся или любые другие значения.
SELECT Count(*)
FROM orders
Результат:
COUNT |
---|
24 |
Если до применения обобщающей функции необходимо исключить дублирующиеся значения, следует перед именем поля в определении функции поместить ключевое слово DISTINCT. Стандарт ISO допускает использование ключевого слова ALL с целью явного указания того, что исключение дублирующихся значений не требуется, хотя это ключевое слово подразумевается по умолчанию, если никакие иные определители не заданы. Ключевое слово DISTINCT не имеет смысла для функций MIN и МАХ. Однако его использование может оказывать эффект на результаты выполнения функций SUM и AVG, поэтому следует заранее обдумать, должно ли оно присутствовать в каждом конкретном случае. Кроме того, ключевое слово DISTINCT в каждом запросе может быть указано не более одного раза.
SELECT Min(ord_price),
Max(ord_price),
Avg(ord_price)
FROM orders
Результат:
MIN | MAX | AVG |
---|---|---|
0.00 | 765.56 | 91.13 |
Очень важно отметить, что обобщающие функции могут использоваться только в списке предложения SELECT и в составе предложения HAVING. Во всех других случаях использование этих функций недопустимо. Если список в предложении SELECT содержит обобщающие функции, а в тексте запроса отсутствует фраза GROUP BY, обеспечивающая объединение данных в группы, то ни один из элементов списка предложения SELECT не может включать каких-либо ссылок на колонки, за исключением случая, когда эта колонка используется как аргумент обобщающей функции. Например, следующий запрос является некорректным:
SELECT ordno,
Count(*)
FROM orders
Ошибка состоит в том, что в данном запросе отсутствует фраза GROUP BY, а обращение к полю ORDNO выполняется без применения обобщающей функции.
Группирование результатов
Приведенные выше примеры сводных данных подобны итоговым строкам, обычно размещаемым в конце отчетов. В итогах все детальные данные отчета сжимаются в одну обобщающую строку. Однако очень часто в отчетах требуется формировать и промежуточные итоги. Для этой цели в операторе SELECT может указываться фраза GROUP BY. Запрос, в котором присутствует фраза GROUP BY, называется группирующим запросом, поскольку в нем группируются данные, полученные в результате выполнения операции SELECT, после чего для каждой отдельной группы создается единственная суммарная строка. Поля, перечисленные во фразе GROUP BY, называются группируемыми полями. Стандарт ISO требует, чтобы предложение SELECT и фраза GROUP BY были тесно связаны между собой. При использовании в операторе SELECT фразы GROUP BY каждый элемент списка в предложении SELECT должен иметь единственное значение для всей группы. Более того, предложение SELECT может включать только следующие типы элементов:
- имена полей;
- обобщающие функции;
- константы;
- выражения, включающие комбинации перечисленных выше элементов.
Все имена полей, приведенные в списке предложения SELECT, должны присутствовать и во фразе GROUP BY — за исключением случаев, когда имя поля используется в обобщающей функции. Обратное правило не является справедливым — во фразе GROUP BY могут присутствовать имена полей, отсутствующие в списке предложения SELECT. Если совместно с фразой GROUP BY используется предложение WHERE, то оно обрабатывается первым, а группированию подвергаются только те строки, которые удовлетворяют условию поиска.
При проведении группирования все отсутствующие значения рассматриваются как равные. Если две строки таблицы в одном и том же группируемом поле содержат значения NULL и идентичные значения во всех остальных непустых группируемых полях, они помещаются в одну и ту же группу.
Например, необходимо определить количество заказов, оформленных в определенный день:
SELECT ord_date,
Count(*)
FROM orders
GROUP BY ord_date
Результат:
ORD_DATE | COUNT |
---|---|
17.10.2004 0:00:00 | 1 |
01.09.2005 0:00:00 | 2 |
16.09.2005 0:00:00 | 3 |
19.09.2005 0:00:00 | 2 |
Ограничения на выполнение группирования (фраза HAVING)
Фраза HAVING предназначена для использования совместно с фразой GROUP BY для задания ограничений, указываемых с целью отбора тех групп, которые будут помещены в результирующую таблицу запроса. Хотя фраза HAVING и предложение WHERE имеют сходный синтаксис, их назначение различно. Предложение WHERE предназначено для фильтрации отдельных строк, используемых для группирования или помещаемых в результирующую таблицу запроса, тогда как фраза HAVING используется для фильтрации групп, помещаемых в результирующую таблицу запроса. Стандарт ISO требует, чтобы имена полей, используемые во фразе HAVING, обязательно присутствовали в списке фразы GROUP BY или применялись в обобщающих функциях. На практике условия поиска во фразе HAVING всегда включают, по меньшей мере, одну обобщающую функцию, в противном случае эти условия поиска должны быть помещены в предложение WHERE и для отбора отдельных строк (Не забывайте, что обобщающие функции не могут использоваться в предложении WHERE).
Например, необходимо определить даты, когда было оформлено более пяти заказов:
SELECT ord_date,
Count(*)
FROM orders
GROUP BY ord_date HAVING Count(*) > 5
Фраза HAVING не является необходимой частью языка SQL — любой запрос, написанный с использованием фразы HAVING, может быть представлен в ином виде, без ее применения.
Подзапросы
Рассмотрим использование законченных операторов SELECT, внедренных в тело другого оператора SELECT. Внешний (второй) оператор SELECT использует результат выполнения внутреннего (первого) оператора для определения содержания окончательного результата всей операции. Внутренние запросы могут быть помещены в предложения WHERE и HAVING внешнего оператора SELECT — в этом случае они получают название подзапросов, или вложенных запросов. Кроме того, внутренние операторы SELECT могут использоваться в операторах INSERT, UPDATE и DELETE. Существует три типа подзапросов. Скалярный подзапрос возвращает значение, выбираемое из пересечения одного поля с одной строкой, то есть, единственное значение. В принципе, скалярный подзапрос может использоваться везде, где требуется указать единственное значение.
Определим список фурнитуры ROTO:
SELECT wn_name,
wn_price
FROM windows
WHERE orderid = (SELECT orderid
FROM orders
WHERE ordno = 'Order2')
Результат:
WN_NAME | WN_PRICE |
---|---|
Order2-1 | 673.27 |
Order2-2 | 0.00 |
Order2-3 | 412.34 |
Order2-4 | 0.00 |
Order2-7 | 1234.38 |
Строковый подзапрос возвращает значения нескольких полей таблицы, но в виде единственной строки. Строковый подзапрос может использоваться везде, где применяется конструктор строковых значений — обычно это предикаты.
Табличный подзапрос возвращает значения одного или больше полей таблицы, размещенные в более чем одной строке. Табличный подзапрос может использоваться везде, где допускается указывать таблицу — например, как операнд предиката IN.
К подзапросам применяются следующие правила и ограничения:
- В подзапросах не должна использоваться фраза ORDER BY, хотя она может присутствовать во внешнем запросе.
- Список в предложении SELECT подзапроса должен состоять из имен отдельных полей или составленных из них выражений — за исключением случая, когда в подзапросе используется ключевое слово EXISTS.
- По умолчанию имена полей в подзапросе относятся к таблице, имя которой указано в его предложении FROM. Однако допускается ссылаться и на поля таблицы, указанной во фразе FROM внешнего запроса, для чего используются квалифицированные имена полей.
- Если подзапрос является одним из двух операндов, участвующих в операции сравнения, то запрос должен указываться в правой части этой операции.
Ключевые слова ANY и ALL
Ключевые слова ANY и ALL могут использоваться с подзапросами, возвращающими один столбец чисел. Если подзапросу будет предшествовать ключевое слово ALL, условие сравнения считается выполненным только в том случае, если оно выполняется для всех значений в результирующем столбце подзапроса. Если записи подзапроса предшествует ключевое слово ANY, то условие сравнения будет считаться выполненным, если оно выполняется хотя бы для одного из значений в результирующем столбце подзапроса. Если в результате выполнения подзапроса будет получено пустое значение, то для ключевого слова ALL условие сравнения будет считаться выполненным, а для ключевого слова ANY — невыполненным. Согласно стандарту ISO дополнительно можно использовать ключевое слово SOME, являющееся синонимом ключевого слова ANY.
Многотабличные запросы
Все рассмотренные выше примеры имеют одно и то же важное ограничение: помещаемые в результирующую таблицу поля всегда выбираются из единственной таблицы. Однако во многих случаях этого оказывается недостаточно. Для того чтобы объединить в результирующей таблице поля из нескольких исходных таблиц, необходимо выполнить операцию соединения. В языке SQL операция соединения используется для объединения информации из двух таблиц посредством образования пар связанных строк, выбранных из каждой таблицы. Помещаемые в объединенную таблицу пары строк составляются по равенству входящих в них значений указанных полей.
Если необходимо получить информацию более чем из одной таблицы, то можно либо применить подзапрос, либо выполнить соединение таблиц. Если результирующая таблица запроса должна содержать поля из разных исходных таблиц, то целесообразно использовать механизм соединения таблиц. Для выполнения соединения достаточно в предложении FROM указать имена двух и более таблиц, разделив их запятыми, после чего включить в запрос предложение WHERE с определением полей, используемых для соединения указанных таблиц. Кроме того, вместо имен таблиц можно использовать назначенные им в предложении FROM псевдонимы (алиасы). В этом случае имена таблиц и назначаемые им псевдонимы должны разделяться пробелами. Псевдонимы могут использоваться с целью квалификации имен полей во всех тех случаях, когда возможно появление неоднозначности. Кроме того, псевдонимы могут использоваться как сокращения имен таблиц. Если для таблицы определен псевдоним, он может использоваться в любом месте, где требуется указание имени этой таблицы.
Составим список заказчиков:
SELECT cu.*,
ca.co_name,
ca.inn
FROM customers cu,
contragents ca
WHERE ca.contragid = cu.customerid
Результат:
CUSTOMERID | DELETED | CO_NAME | INN |
---|---|---|---|
3002 | ООО «Алиса» | 456853753875496 | |
3003 | 20.09.2004 | Сидоров П. В. | 753862165135796 |
3004 | Вирта | 224951373337954 |
Чаще всего многотабличные запросы выполняются для двух таблиц, соединенных связью типа 1:М (один ко многим). Пары строк, которые генерируются при выполнении запроса, представляют собой результат всех допустимых комбинаций строк дочерней и родительской таблиц. Таблица, содержащая внешний ключ, обычно является дочерней, как таблица, содержащая первичный ключ, всегда будет родительской. Для использования связи типа «родительская-дочерняя» в SQL-запросе необходимо указать условие поиска, в котором будут сравниваться внешний и первичный ключи.
Изменение содержимого базы данных
Язык SQL является полнофункциональным языком манипулирования данными, который может использоваться не только для выборки данных из базы, но и для изменения ее содержимого. Операторы модификации информации в базе данных не столь сложны, как оператор SELECT. Рассмотрим три оператора языка SQL, предназначенных для модификации содержимого базы данных:
- INSERT — предназначен для добавления данных в таблицу.
- UPDATE — предназначен для модификации уже помещенных в таблицу данных.
- DELETE — позволяет удалять из таблицы строки данных.
Добавление новых данных в таблицу (оператор INSERT)
Существует две формы оператора INSERT. Первая предназначена для вставки единственной строки в указанную таблицу. Эта форма оператора INSERT имеет следующий формат:
INSERT INTO <имя_таблицы>
[(<список_полей>)]
VALUES (<список_значений>)
Здесь параметр <имя_таблицы> может представлять либо имя таблицы базы данных, либо имя обновляемого представления. Параметр <список_полей> представляет собой список, состоящий из имен одного или более полей, разделенных запятыми. Параметр <список_полей> является необязательным. Если он опущен, то предполагается использование списка из имен всех полей таблицы, указанных в том порядке, в котором они были описаны в операторе CREATE TABLE. Если в операторе INSERT указывается конкретный список имен полей, то любые опущенные в нем поля должны быть объявлены при создании таблицы как допускающие значение NULL, за исключением случаев, когда при описании поля использовался параметр DEFAULT. Параметр <список_значений> (cписок значений данных) должен соответствовать параметру <список_полей>:
- количество элементов в обоих списках должно быть одинаковым;
- должно существовать прямое соответствие между позицией одного и того же элемента в обоих списках, поэтому первый элемент списка <список_значений> полагается относящимся к первому элементу списка <список_полей>, второй элемент списка <список_значений> — ко второму элементу списка <список_полей> и т. д.;
- типы данных элементов списка values должны быть совместимы с типом данных соответствующих столбцов таблицы.
Например, необходимо добавить новую группу ветровой нагрузки:
INSERT INTO windcharge
(windchargeid,
namefactor,
chargefactor,
deleted,
userconst)
VALUES (1,
'A',
0.6,
NULL,
0)
Другая форма оператора INSERT имеет следующий вид:
INSERT INTO <имя_таблицы1> (<список_полей1>)
SELECT <список_полей2>
FROM <имя_таблицы2>
Здесь параметры <имя_таблицы> и <список_полей> имеют тот же формат и смысл, что и при вставке в таблицу одной строки. Предложение SELECT может представлять собой любой допустимый оператор SELECT. Строки, вставляемые в указанную таблицу, в точности соответствуют строкам результирующей таблицы, созданной при выполнении вложенного запроса. Все ограничения, указанные выше для первой формы оператора INSERT, применимы и в этом случае.
Скопируем сетку фурнитуры для поворотного типа открывания из одной системы фурнитуры (с идентификатором 2) в другую (c идентификатором 7):
INSERT INTO rt_windsize
(windid,
typsize,
7,
wind_no,
price,
aheight,
awidth,
fordelete)
SELECT *
FROM rt_windsize
WHERE firmid = 2
AND wind_no = 3
Модификация данных в базе (оператор UPDATE)
Оператор UPDATE позволяет изменять содержимое уже существующих строк указанной таблицы. Этот оператор имеет следующий формат:
UPDATE <имя_таблицы>
SET <имя_поля1> = <значение1> [, <имя_поля2> = <значение2>...]
[WHERE <условие_отбора>]
Здесь параметр <имя_таблицы> представляет либо имя таблицы базы данных, либо имя обновляемого представления. В предложении SET указываются имена одного или более полей, данные в которых необходимо изменить. Предложение WHERE является необязательным. Если оно опущено, значения указанных столбцов будут изменены во всех строках таблицы. Если предложение WHERE присутствует, то обновлены будут только те строки, которые удовлетворяют условию поиска, заданному в параметре <условие_отбора>. Параметры значение представляют новые значения соответствующих столбцов и должны быть совместимы с ними по типу данных.
К примеру, заменим коэффициент ветровой нагрузки в группе A на 0.9:
UPDATE windcharge
SET chargefactor = 0.9
WHERE namefactor = 'A'
Удаление данных из базы (оператор DELETE)
Оператор DELETE позволяет удалять строки данных из указанной таблицы. Этот оператор имеет следующий формат:
DELETE
FROM <имя_таблицы>
[WHERE <условие_отбора>]
Как и в случае операторов INSERT и UPDATE, параметр <имя_таблицы> может представлять собой либо имя таблицы базы данных, либо имя обновляемого представления. Если предложение WHERE присутствует, из таблицы будут удалены только те строки, которые удовлетворяют условию отбора, заданному параметром <условие_отбора>. Но если параметр <условие_отбора> опущен, из таблицы будут удалены все существующие в ней строки.
Например, необходимо удалить группу ветровой нагрузки с идентификатором 1:
DELETE
FROM windcharge
WHERE windchargeid = 1
Сама по себе таблица с помощью оператора DELETE не удаляется. Если необходимо удалить не только содержимое таблицы, но и ее определение, следует использовать оператор DROP TABLE.
Встроенные переменные
При создании отчета может потребоваться различная информация о заказе или изделии, которую нельзя или сложно получить с помощью запросов. Эта информация передается из Optima WIN™ и хранится в различных переменных. В этом разделе представлены все переменные, которые могут понадобиться при составлении отчета. Чтобы использовать эти переменные, укажите их в Memo объекта (для текстовых переменных) или в поле DataField (для графических переменных). В табл. 8 представлены переменные, которые всегда содержат информацию о заказе, с которым в данный момент работает Optima WIN™.
Таблица 0.0. Переменные для работы с текущим заказом
Переменная | Описание |
---|---|
CURRORDER | Идентификатор текущего заказа (ORDERS.ORDERID) |
CURRWINDOW | Идентификатор текущего изделия (WINDOWS.WINDOWID) |
CURRCUSTOMER | Идентификатор заказчика текущего заказа (ORDERS.CUSTOMERID) |
CURRGRORDER | Идентификатор текущей группы оптимизации (GRORDERS.GRORDERID) |
PRICENAME | Наименование текущего рассчитанного прайс-листа (в построителе). Используется для изменения шаблона PriseList.frf |
CURREMPLOYEE | Возвращает ID текущего пользователя |
![]() |
Для установки значения CURRORDER в отчёте можно присвоить значение переменной ORDID.
Для установки значения CURRWINDOW в отчёте можно присвоить значение переменной WINID. |
В табл. 9 представлены переменные для работы с изделиями. Для этих переменных необходимо указывать источник данных. Так, например, прежде, чем использовать переменную WIDTHWIN необходимо указать изделие, ширину которого необходимо вывести. Это делается следующим образом: для бэнда, на котором располагается объект, в котором используется переменная, для события OnBeforePrint создайте скрипт вида:
begin
SOURCE_INFO := [DialogForm.<имя_запроса>."WN_PACKED"];
WINID := [DialogForm.<имя_запроса>."WINDOWID"];
end
Здесь запрос <имя_запроса> обращается к таблице WINDOWS.
Таблица 0.0. Переменные для работы с изделием
Переменная | Описание |
---|---|
WIDTHWIN | Ширина текущего изделия с учётом соединителей/расширителей. |
HEIGHTWIN | Высота текущего изделия с учётом соединителей/расширителей. |
SYSPROFID | Идентификатор системы профиля текущего изделия (R_FIRMPROFIL.FIRMID). |
SYSPROFWIN | Наименование системы профиля текущего изделия (R_FIRMPROFIL.FP_NAME). |
SYSFURNID | Идентификатор системы фурнитуры текущего изделия (R_FIRMFURN.FIRMID). |
SYSFURNWIN | Наименование системы фурнитуры текущего изделия (R_FIRMFURN.FP_NAME). |
COLORWIN | Наименование цвета текущего изделия в формате «Внешний/Внутренний». |
IZDELIE | Тип текущего изделия: «Окно» или «Дверь». |
IZDELIEITEMID | Идентификатор типа текущего изделия (R_ITEMSTYPE.ITEMSTYPEID). |
IZDELIEITEMNAME | Наименование типа текущего изделия (R_ITEMSTYPE.IT_NAME). |
AREA | Площадь текущего изделия (WINDOWS.WN_AREA). |
ALLAREA | Площадь текущего изделия c учётом кол-ва (WINDOWS.WN_AREA * WINDOWS.WN_AMOUNT). |
ORDERNO | Номер текущего заказа (ORDERS.ORDNO). |
WINDOWNO | Наименование текущего изделия (WINDOWS.WN_NAME). |
COLORIN | Идентификатор внутреннего цвета текущего изделия (COLORSPART.COLORSPARTID). |
COLOROUT | Идентификатор внешнего цвета текущего изделия (COLORSPART.COLORSPARTID). |
ARTRAM | Наименование артикула рамы текущего изделия (VIRTARTICULES.AR_ART). Артикул рамы, устанавливаемый по умолчанию. |
ARTSTV | Наименование артикула створки текущего изделия (VIRTARTICULES.AR_ART). Артикул створки, устанавливаемый по умолчанию. |
ARTIMP | Наименование артикула импоста текущего изделия (VIRTARTICULES.AR_ART). Артикул импоста, устанавливаемый по умолчанию. |
GLASSPACK | Наименования стеклопакетов текущего изделия (WINGLASS) разделенные «, » (GLASSPACKET.GL_PACKET) |
PICT | Рисунок изделия (только для объекта Рисунок). |
PICT&SIZE | Рисунок с размерами (только для объекта Рисунок). |
PICT&SIZE&NAME | Рисунок с размерами и номерами проемов
(только для объекта Рисунок). |
PICT&SIZE&NAME&GLASS | Рисунок с размерами, номерами проемов, артикулами стеклопакетов
(только для объекта Рисунок). |
PICT&SIZE&NAME&GLASS&COLOR | Рисунок в цвете с размерами, номерами проемов, артикулами стеклопакетов
(только для объекта Рисунок). |
В табл. 10 представлены переменные для работы с профилями изделий. Для события OnBeforePrint бэнда, на котором расположен объект, в котором используется переменная, создайте скрипт вида:
begin
SOURCE_SVARKA := [DialogForm.<имя_запроса>."WP_SVARKA"];
end
Запрос <имя_запроса> должен обращаться к таблице WINPROFILES.
Таблица 0.0. Переменные для работы с профилями
Переменная | Описание |
---|---|
PICTSECTION | Рисунок сечений (только для объекта Рисунок) |
PICTSVARKA | Рисунок с точками вставки импостов — сварка при сварном типе соединения и долбежки для дерева
(только для объекта Рисунок). |
PICTSVARKAFROMFALZ | Рисунок с точками вставки импостов относительно фальца
(только для объекта Рисунок). |
Для вывода информации о стеклопакете (таблица WINGLASS) необходимо использовать переменные, представленные в табл. 11. Для указания источника данных для события OnBeforePrint бэнда создайте скрипт:
begin
SOURCE:=[DialogForm.<имя_запроса>."WG_INFO"];
end
Таблица 0.0. Переменные для работы со стеклопакетами
Переменная | Описание |
---|---|
WIDTHGLASS | Ширина заполнения, установленного через переменную скрипта SOURCE. |
HEIGHTGLASS | Высота заполнения, установленного через переменную скрипта SOURCE. |
PICTGLASS | Рисунок стеклопакетов (только для объекта Рисунок). |
TYPGLASS | Тип геометрии заполнения, установленного через переменную скрипта SOURCE: 0 — прямоугольное, 1 — со скосами, 2 — арочное. |
DRAWGLASS | True, если заполнение непрямоугольное (установленного через переменную скрипта SOURCE) |
Для работы с конструкциями используются переменные, представленные в табл. 12. Для корректной работы создайте для события OnBeforePrint бэнда скрипт вида:
begin
IDCON := [DialogForm.<имя_запроса>."CONSTRID"];
end
Таблица 0.0. Переменные для работы с конструкциями
Переменная | Описание |
---|---|
PICT_CONSTR | Рисунок конструкции (только для объекта Рисунок). |
PICT_CONSTRSIZE | Рисунок конструкции с размерами (только для объекта Рисунок). |
Для вывода общих пользовательских параметров достаточно написать в квадратных скобках имя параметра — например [ЦВЕТ_ФУРНИТУРЫ] — при этом на бэнде должен быть скрипт вида:
- для изделия (запрос обращается к таблице WINDOWS):
- SOURCE_PARAM := [DialogForm.<имя_запроса>."PARAMS"]
- для заказа (запрос обращается к таблице ORDERS):
- SOURCE_PARAM := [DialogForm.<имя_запроса>."PARAMS"]
Для записи какой-либо информации в БД, например логотипа фирмы, и прочтения этой информации существуют функции SaveDialog и OpenDialog, имеющие следующий синтаксис:
SaveDialog(<идентификатор>, <расширение_файла>, '0');
Эта функция сохраняет в файл значение поля CT_BLOBVALUE таблицы CONSTANTS с идентификатором записи <идентификатор> и возвращает 1 при успехе;
OpenDialog(<имя_параметра>, <пояснение>, '0');
Данная функция вызывает стандартный диалог открытия окна, затем выбранный файл записывает в поле CT_BLOBVALUE таблицы CONSTANTS и возвращает идентификатор записи.