Цитата:
Сообщение от
lev
1. выполнить цикл for по дата сору дважды, первый раз для того что вам нужно для проверки, второй раз, для непосредственно выполнения.
Поддерживаю! В одной своей задачке с целью предотвращения выгрузки в Excel гигантского количества данных - так что потом ни сохранить, а если и сохранить, то не открыть получившийся файл - не далее, как сегодня, влупил такой фрагмент с двойным пробегом:
X++:
cntAll=0; // первоначальный подсчёт записей
for ( common = gridDataSource.getFirst(1) ? gridDataSource.getFirst(1) : gridDataSource.cursor();
common ;
common = gridDataSource.getNext() )
{
cntAll++;
}
// эмпирически подобранная формула, исходя из размера файла примерно 20 МБ (грубо 20 млн. байт)
cntRecommended = decRound(20000000. / sumBytes * 4.,-2); // округляем до сотен
cntFrom = 1;
// если записей очень много, то предложение вывести в несколько подходов
if (cntAll > cntRecommended)
{
dialog = new Dialog('Слишком много записей для вывода');
dialogText = dialog.addText(strFmt('Запрошенная выборка содержит %1 записей. ' +
'Вывод такого количества записей за один раз может привести к проблемам ' +
'при сохранении и последующем открытии получившегося файла Excel.\n\n' +
'Однако, Вы можете выгрузить все данные несколькими порциями, ' +
'запуская процедуру выгрузки несколько раз ' +
'и каждый следующий раз увеличивая значения в полях "От записи" и "до записи" на размер порции. ' +
'Рекомендуемый сейчас размер порции - %2 записей. ' +
'Поэтому рекомендуется установить 1 и %2 для первой выгрузки, %3 и %4 - для второй и т.д.\n\n' +
'Вы также можете задавать границы порций, исходя из своих собственных соображений.\n\n' +
'ВАЖНО! Перед многоразовой выгрузкой следует отсортировать строчки таблицы заявок по возрастанию кодов заявок ' +
'и не менять этот порядок до окончания всего процесса! Если Вы не уверены, что уже выполнили такую сортировку - ' +
'нажмите "Отмена" и начните еще раз.'
, cntAll, cntRecommended, cntRecommended+1, cntRecommended*2));
dialogText.displayHeight(21);
dialogText.displayLengthValue(50);
dialog.addGroup('Вывести в Excel').columns(2);
dialogFrom = dialog.addFieldValue(Types::Integer, 1, 'От записи');
dialogTo = dialog.addFieldValue(Types::Integer, cntRecommended, 'до записи');
dialog.run();
if (! dialog.closedOk())
return;
cntFrom = dialogFrom.value();
cntTo = dialogTo .value();
}
cnt=0; // ПОВТОРНЫЙ (основной) ПРОБЕГ по датасорсу
for ( common = gridDataSource.getFirst(1) ? gridDataSource.getFirst(1) : gridDataSource.cursor();
common ;
common = gridDataSource.getNext() )
{
cnt++;
if (cntAll > cntRecommended)
{
if ((cnt < cntFrom) || (cnt > cntTo)) continue;
}
if (cnt mod 100 == 0) print strFmt('Уже выведены записи с %1 по %2', cntFrom, cnt);
.......................................
}
sumBytes - некоторый условный суммарный размер записи в байтах, подсчитанный по длинам строк, инты - 4 байта, даты и реалы - по 8, енумы - по длине максимальной метки. Литерал 4 (или 0.25) - экспериментально подобранный множитель, учитывающий отклонение теории от практики.
Вот какая картинка возникает через пару минут (отработка первого цикла) при выделении всех записей грида без фильтрации:
Возможно, не очень оптимально, но я доволен. И по мне - так лучше потратить лишние пару минут, чем ринуться сразу выводить 56 тыщ строк по 130 (!) колонок. С другой стороны, пользователи очень не часто пытаются вывести всё имеющееся и "наказываются" таким сообщением. Обычные же выборки по паре-тройке тысяч записей практически не раздражают своей недолгой продолжительностью (пусть и с двойным пробегом).