Средства разработки приложений

         

Access


Проблемы отчетов в ACCESS Сергей Гущенко,

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

Выходные документы в СУБД проектируются с помощью механизма отчетов. В MS Access этот механизм имеет массу возможностей, позволяющих создавать выходные документы без обращения к программированию на встроенном языке VBA. Однако не все задачи можно решить таким путем.

Рассмотрим пример. Допустим, есть таблица "TELEFKOD" телефонных кодов с 528-ю записями, начало которой имеет следующий вид:

NPP GOROD KOD_TEL OBLAST
1 Авдеевка 06236 Донецкая
2 Акимовка 06131 Запорожская
3 Александрия 05235 Кировоградская
4 Александровка 06269 Донецкая
5 Александровка 05269 Кировоградская
6 Алушта 06560 Крым

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

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

В этом отчете названия колонок (шапка таблицы) размещены в верхнем колонтитуле, в качестве номера по порядку используется поле "NPP", в нижнем колонтитуле указывается номер страницы и добавлено Примечание отчета с количеством выводимых записей и примером подписей. Модуль класса пустой (то есть никаких программных кодов на языке VBA нет). Распечатывается такой отчет без проблем. Но могут возникнуть претензии к размещению Примечания. По умолчанию его свойство Не разрывать имеет значение "Да". (рис. 2).

Это означает: если всё Примечание не помещается на последней странице строк с данными, то оно будет целиком перенесено на следующую.
Но не всегда такое решение допустимо - особенно если печатается финансовый документ. Поэтому можно поменять значение этого свойства на "Нет" - тогда Примечание будет начинаться сразу после вывода последней записи. Это решает рассматриваемую проблему, но не до конца. Может возникнуть ситуация, когда одна подпись (например, Директора) окажется на одной странице (последней с данными), а другая перенесется на следующую,- тоже плохо. Более приемлемым решением в этом случае - с небольшой высотой Примечания - было бы его размещение полностью на отдельной странице, но так, чтобы к нему сверху автоматически добавлялись несколько последних строк с данными. И вот тут без обращения к VBA уже не обойтись. Вариантом решения этой задачи может оказаться следующий текст Модуля класса с кодами обработки событий:

Option Compare Database Option Explicit Dim I1 As Integer, KolZap As Integer, KolZ As Integer Dim dd As Database, zap As Recordset, Private Sub Report_NoData (Cancel As Integer) MsgBox (" А нету записей!") Cancel = True End Sub Private Sub Report_Open (Cancel As Integer) Set dd = CurrentDb Set zap = dd. OpenRecordset (" TELEFKOD", dbOpenDynaset) If Not zap. BOF Then zap. MoveLast KolZap = zap. RecordCount End If zap. Close KolZ = 0 End Sub Private Sub ВерхнийКолонтитул_Format (Cancel As Integer, FormatCount As Integer) Me![EndStr1]. Visible = False I1 = 0 End Sub Private Sub ОбластьДанных_Format (Cancel As Integer, FormatCount As Integer) I1 = I1 + 1 KolZ = Me. CurrentRecord If I1 > 39 Then If KolZap - KolZ < 3 Then Me![EndStr1]. Visible = True End If End If End Sub Во-первых, здесь по ходу дела задействовано интересное свойство Report_NoData - обработка ситуации, когда в таблице-источнике данных нет записей. Текст процедуры почти стандартен, строка Cancel = True приводит к прекращению печати отчета.

Во-вторых, в Области данных установлен элемент управления Конец страницы (рис. 3), действие которого контролируется в модуле класса.



При форматировании каждой новой страницы его "видимость" отключается (Me![EndStr1]. Visible = False). Включается же при форматировании Области данных - при наступлении определенного условия, которое состоит из двух частей. Первая контролирует область листа, на котором Примечание уже не может разместиться полностью. В данном отчете опытным путем определено, что такой момент возникает после печати 39-й строки (If I1 > 39 Then). Целочисленной переменной, в которой учитывается номер печатаемой строки, является I1.
При форматировании верхнего колонтитула она обнуляется, а при форматировании каждой новой строки данных ее значение увеличивается на 1. Но этого мало - требуется еще определить, что выводятся последние строки. Это делается через две другие переменные: KolZ, в которую заносится номер текущей записи в печатаемой таблице (KolZ = Me. CurrentRecord) и KolZap, в которой хранится общее количество записей, рассчитываемое при открытии отчета (KolZap = zap. RecordCount). В конечном итоге, если возникает ситуация печати последних двух записей в зоне листа, где уже не может полностью разместиться Примечание, то они печатаются вместе с ним на следующей странице (рис. 4).



Но в этом примере есть и ошибка - итоговое поле для подсчета количества записей в Примечании отчета насчитало 528 записей. А последний Номер по порядку значится как "529". Такая ситуация возможна в случае, если в качестве номера по порядку выводится поле, имеющее тип Счетчик, а в процессе заполнения таблицы были выполнены удаления записей (в примере была удалена одна запись). Поэтому в качестве поля порядкового номера в отчете лучше использовать свободное поле, не связанное с исходной таблицей. В качестве данных для такого поля надо установить значение "=1" и указать вариант Для всего в параметре Сумма с накоплением (рис. 5 - вид в Конструкторе и рис. 6 - при предварительном просмотре).

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


Это также делается через свободное поле (рис. 7), но его заполнение выполняется в модуле класса. Под него объявляется новая переменная, например: Dim NStrP As Integer. Она должна обнуляться при форматировании верхнего колонтитула и заполняться при форматировании области данных, например:



Private Sub ВерхнийКолонтитул_Format (Cancel As Integer, FormatCount As Integer) ….. NStrP = 0 End Sub Private Sub ОбластьДанных_Format (Cancel As Integer, FormatCount As Integer) ….. NStrP = NStrP + 1 Me![NSTR1] = NStrP End Sub


Последним вариантом учета строк рассмотрим нумерацию в группе. Access позволяет сортировать и группировать данные прямо при выводе. Эти настройки выполняются в Конструкторе через диалоговое окно Сортировка и группировка (вызывается по команде меню Вид) - рис. 8. Для создания группировки по какому-либо полю этого окна, его (поле) надо выбрать в списке (в примере - поле OBLAST) и указать "Да" в параметре Заголовок группы. Здесь же можно установить сортировку для других полей без группировки по ним (в примере - по полю GOROD). Вывод порядкового номера в группе производится в "свободном" поле, в параметре Данные которого указано "=1", но Сумма с накоплением установлена Для группы. Фрагмент результата показан на рис. 9.

Следующей проблемой может оказаться размещение в нижнем колонтитуле промежуточных сумм по какому-либо полю. Такая ситуация часто возникает в финансовых документах - например, при распечатке ведомости на зарплату. На первый взгляд, сделать это можно по технологии, рассмотренной ранее: объявляется переменная, обнуляется при форматировании верхнего колонтитула и заполняется при форматировании области данных. Но поскольку результат должен быть занесен в "свободное" поле, размещенное в другом разделе (в Нижнем колонтитуле), сумма окажется неправильной - ведь процесс форматирования некоторых разделов "отчетов" в Access может повторяться!!! Это является особенностью технологии подготовки "отчетов" - нужно помнить об этом при программировании.


В частности, в рассматриваемом примере заполнение переменной для промежуточной суммы (SumStr) можно выполнять не при форматировании области данных, а при отработке свойства печати области данных (ОбластьДанных_Print), в которой можно проконтролировать ситуацию - будет печататься лист с этими данными или нет. И именно в зависимости от результатов контроля должно быть заполнено поле, расположенное в нижнем колонтитуле. Допустим, оно имеет имя SumS, а переменная, в которой накапливается значение на странице,- SumStr. Тогда текст кода подобной процедуры будет иметь следующий вид:

Private Sub ОбластьДанных_Print (Cancel As Integer, PrintCount As Integer) 'PrintCount = 0 - страница не печатается, ' = 1 - будет печататься SumStr = SumStr + NStrP If PrintCount = 1 Then Me![SumS] = SumStr End Sub
Подобная же ситуация может возникнуть при попытке использовать Подчиненный отчет, который чаще всего вставляется в Примечание отчета или в Примечание группы. Если в нем требуется указывать какое-то расчетное значение (например, тот же номер на странице), то оно может оказаться неправильным, так как такой отчет будет форматироваться несколько раз (рис. 10).

Для решения проблемы команду заполнения поля № строки на странице Подчиненного отчета надо переместить из обработки события Форматирования в обработку события Печать раздела Область данных, например:

Private Sub ОбластьДанных_Print (Cancel As Integer, PrintCount As Integer) NStrP = NStrP + 1 Me![NSTR1] = NStrP SumStr = SumStr + NStrP If PrintCount = 1 Then Me![SumS] = SumStr End Sub

Содержание раздела