Времена вычисления формул и проходы отчета

Оценить
(1 голос)

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

Однако простое размещение формул в этих разделах вовсе необязательно гарантирует то, что они на самом деле будут вычисляться в этом разделе или в процессе логического “форматирования” отчета (во время которого сначала выводится заголовок группы, затем — разделы подробностей этой группы, после чего — нижний колонтитул группы и так далее). Чтобы стало понятнее, давайте рассмотрим пример. На рис. 5.18 показан отчет, в котором для подсчета “текущей суммы” используется переменная. Эта переменная накапливает суммы заказов в каждом разделе подробностей по мере выполнения отчета.

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

CurrencyVar MonthlyTotal := MonthlyTotal + {Order.Order Amount}

На рис. 5.19 показан тот же самый отчет, только теперь он разбит на группы по дате размещения заказа (Order Date), причем в качестве типа сортировки была выбрана опция for each month (для каждого месяца). Времена вычисления формул и проходы отчета

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

 

лось, поскольку каждый пользователь отчета будет по-своему просматривать месяцы. Соответственно, значение переменной промежуточной суммы “Monthly Total” должно быть сброшено в каждом заголовке группы с помощью следующей формулы:

CurrencyVar MonthlyTotal := О

Однако, даже поместив эту формулу в заголовок группы отчета, нужного результата мы все равно не получим.

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

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

В целом Crystal Reports разбивает процесс обработки отчета на три прохода, во время которых определенные типы формул вычисляются автоматически (табл. 5.5).

Времена вычисления формул и проходы отчета

В большинстве случаев вы можете довериться Crystal Reports в определении того, на каком проходе должна вычисляться та или иная формула. Однако явным исключением является случай, когда в формуле используются переменные. Если формула просто объявляет переменную или объявляет переменную и присваивает ей в качестве значения литерал или константу, Crystal Reports будет вычислять эту формулу на проходе “во время считывания записей”, поскольку на этом проходе отсутствуют ссылки на поля базы данных или функции сводок. Если переменной в качестве значения присваивается значение из базы данных, Crystal Reports будет вычислять эту формулу на проходе “перед считыванием записей” (таким образом, эта формула станет формулой первого прохода). Только если формула содержит какие-нибудь функции сводок или промежуточных сумм, Crystal Reports будет автоматически вычислять эту формулу на проходе “во время распечатки записей” (то есть будет рассматривать ее как формулу второго прохода).

Такое используемое по умолчанию поведение может приводить к весьма необычным результатам, как в предыдущем примере с подсчетом текущей суммы. Для того чтобы подсчитать текущую сумму, эта формула ссылается на поле Order Amount (Стоимость заказа) базы данных и поэтому вычисляется на первом проходе (во время считывания записей). Из-за этого текущая сумма была подсчитана перед началом разбиения отчета на группы. Однако, после того как отчет был разбит на группы на основе поля Order Date, порядок записей в отчете изменился и стал, естественно, отличаться от порядка, в котором эти записи хранятся в базе данных, вследствие чего значения текущих сумм перестали отображаться в логическом порядке. Еще больше усложнило дело то, что формула, сбрасывающая значение переменной текущей суммы в ноль, вообще не ссылалась ни на какие поля из базы данных, поэтому она стала трактоваться Crystal Reports как простая формула и была выполнена только один раз, в самом начале обработки отчета, вместо того, чтобы выполняться в начале каждой группы.

Используя в формуле переменные, вы, возможно, захотите, чтобы формула вычислялась на каком-нибудь другом проходе, а не на том, который применяется по умолчанию. Сделать это вы можете, просто изменив время вычисления формулы. Чтобы изменить время вычисления, в качестве первого оператора добавьте в формулу оператор времени вычисления. В списке Function Tree, который отображается в окне редактора Formula Editor, имеется раздел Evaluation Time (Время вычисления). Разверните этот раздел, и вы увидите несколько операторов времени вычисления функций, которые в принципе не нуждаются в отдельных пояснениях.

Времена вычисления формул и проходы отчета

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

WhilePrintingRecords;

CurrencyVar MonthlyTotal := MonthlyTotal + {Orders.Order Amount}

Внимание! He удивляйтесь, если не сможете вставить промежуточные суммы, сводки или итоговые суммы в формулу второго прохода. Когда вы щелкнете на этом типе формулы в разделе подробностей, промежуточные суммы, сводки и итоговые суммы не будут доступны в выпадающих и контекстных меню, поскольку промежуточные суммы, сводки и итоговые суммы вычисляются на проходе “во время распечатки записей ". Если формула уже вычисляется на этом проходе, вы не сможете создать по ней сводку или вычислить итоговую сумму.

Теперь, чтобы формула, сбрасывающая значение текущей суммы в ноль, вычислялась во время форматирования групп, а не только в момент начала выполнения отчета, также переведите ее на проход “во время печати записей” (WhilePrintingRecords):

WhilePrintingRecords;

CurrencyVar MonthlyTotal := О

Одной из функций определения времени вычисления, которая может потребовать пояснений, является EvaluateAfter (Вычислить после); эта функция принимает только один аргумент — имя другой формулы. Она вынуждает формулу вычисляться после другой формулы, когда эти формулы вычисляются на одном и том же проходе или находятся в одном и том же разделе отчета. Поскольку Crystal Reports автоматически вычисляет формулы, которые содержат другие формулы, в правильном порядке, вы нечасто будете пользоваться этой функцией. Тем не менее, у вас может возникнуть необходимость применять ее с формулами, которые содержат переменные.

Когда Crystal Reports вычисляет две формулы, которые содержат одну и ту же переменную и находятся в одном и том же разделе отчета, порядок их вычисления непредсказуем. Для примера давайте рассмотрим следующую ситуацию: вы помещаете в нижний колонтитул группы сразу две формулы. Первая из этих формул отображает значения переменных (предполагается, что их значения были установлены в других формулах, размещенных в разделе подробностей):

WhilePrintingRecords;

CurrentVar BonusAmount;

StringVar HigestCustName;

DateTimeVar DateBonusReached;

"Наибольший заказ с бонусом " + ToText(BonusAmount) +

" был размещен заказчиком " + HigestCustName + " дата: " +

ToText(DateBonusReached, "M/d/yy")

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

CurrentVar BonusAmount := 0;

StringVar HigestCustName := "";

DateTimeVar DateBonusReached := DateTime(0, 0,0);

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

EvaluateAfter ({@Bonus Show});

CurrentVar BonusAmount := 0;

StringVar HigestCustName := "" ;

DateTimeVar DateBonusReached := DateTime(0, 0,0);

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

Совет. Как только вы начнете добавлять формулы, которые вычисляют и обнуляют переменные, вы столкнетесь с появлением в разделах подробностей и заголовках групп нулей или другой ненужной информации. Вы не можете удалить формулы из этих разделов, поскольку тогда они не будут вычисляться должным образом. Чтобы скрыть их, просто подавите их отображение, воспользовавшись для этого кнопкой Suppress (Подавить), доступной в панели инструментов форматирования, или установив флажок Suppress (Подавить) на вкладке Common (Общие) редактора Format Editor. После того как вы сделаете это, формулы будут отображаться только на вкладке Design, а на вкладке Preview или в каких- нибудь других выводимых отчетом данных — нет.

Случаи, когда не следует пользоваться переменными

Часто, узнав, как правильно пользоваться теми или иными “специфическими” функциональными возможностями, люди начинают применять их сверх меры! И хотя эти возможности ускоряют процесс обработки, не потребляя слишком много памяти и ресурсов, когда используются в разумных пределах, “перебор” также не допускается. Обнаружив возможность использовать переменную, прежде всего, внимательно проанализируйте отчет — возможно, в нем уже существует более простой и быстрый способ решения для этой же задачи.

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

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

Формула @Bonus Calc помещается в раздел подробностей и подавляется:

WhilePrintingRecords;

NumberVar CountCustomer;

NumberVar CountReport; ,

If {Order.Order Amount] > 1000 Then (CountCustomer := CountCustomer + 1;

CountReport := CountReport + 1)

Формула @Show Group Bonus помещается в нижний колонтитул группы:

WhilePrintingRecords;

NumberVar CountCustomer;

"This customer had " + ToText(CountCustomer, 0) + " bonus orders."

Формула @Reset Group Bonus помещается в заголовок группы и подавляется:

WhilePrintingRecords;

NumberVar CountCustomer := 0;

Формула @Show Report Bonus помещается в нижний колонтитул отчета:

WhilePrintingRecords;

NumberVar CountCustomer;

"This report had " + ToText(CountReport, 0) + " bonus orders."

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

If {Order.Order Amount] > 1000 Then 1

Времена вычисления формул и проходы отчета

После того, как вы поместите эту формулу в раздел подробностей, она будет возвращать числовую константу 1 всегда, когда стоимость заказа превосходит $1000. Если стоимость заказа меньше $1000, она возвратит 0 (поскольку эта формула числовая и в ней нет конструкции Else, она всегда будет возвращать значение 0, когда проверка If будет неудачной (false)). Далее вам останется только вставить в формулу промежуточную сумму по группе и итоговую сумму по отчету для вычисления итоговых сумм по группам и по отчету.

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

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

Совет. Многие типы формул, проиллюстрированные в этой главе, входят в состав демонстрационных отчетов, которые доступны на сайте www. CrystalBook. сот. Для получения более подробной информации о том, как реализуются эти и другие подобные формулы, зайдите на этот сайт и в строке поиска введите “Formulas.RPT” или “BONUS.RPT”.

 

Библиотеки пользовательских функций
Поля текущих сумм
Crystal Reports предлагает формулы
Студия Formula Workshop
Эксперт Formula Expert

Добавить комментарий


Защитный код
Обновить