При разработке отчетов и обработок в системе 1С программисты часто сталкиваются с задачей получения данных из регистров накопления за определенный интервал времени. Ошибка в выборе виртуальной таблицы или неправильное указание параметров может привести к некорректным результатам или крайне медленной работе программы. В этой статье мы подробно разберем, как правильно ограничить выборку данных по периоду, проанализируем типичные ошибки и рассмотрим эффективные методы решения подобных задач.
Рассмотрим ситуацию, с которой столкнулся автор темы. Изначально была попытка использовать виртуальную таблицу Остатки. Важно понимать фундаментальное отличие: таблица Остатки предназначена для получения «среза» данных на конкретный момент времени. У нее есть только один параметр периода — дата, на которую нужно рассчитать итоги. Если мы пытаемся наложить условие ГДЕ по дате документа на эту таблицу, мы совершаем методологическую ошибку.
Проанализируем пример кода, который не давал нужного результата:
ВЫБРАТЬ
РасчетыПоРаботамОстатки.Исполнитель,
РасчетыПоРаботамОстатки.Работа КАК Услуга,
ЗаказНарядУслуги.ДатаИВремяВыполнения КАК Выполнено
ИЗ
РегистрНакопления.РасчетыПоРаботам.Остатки(&Период, ) КАК РасчетыПоРаботамОстатки
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказНаряд.Услуги КАК ЗаказНарядУслуги
ПО РасчетыПоРаботамОстатки.ЗаказНаряд = ЗаказНарядУслуги.Ссылка
ГДЕ
ЗаказНарядУслуги.Ссылка.Дата >= &ДатаНачала
В данном случае система сначала получает все остатки на дату &Период, а затем пытается отфильтровать их по дате документа из табличной части. Если за указанный период движений не было, но остаток «висит» с прошлого года, он попадет в выборку, что противоречит задаче получить данные именно «за период».
Если нам необходимо видеть движения (обороты) внутри интервала времени и при этом знать остатки на начало и конец этого интервала, следует использовать таблицу ОстаткиИОбороты. Разберем по шагам, как правильно настроить параметры этой таблицы.
Синтаксис таблицы выглядит следующим образом: ОстаткиИОбороты(&НачалоПериода, &КонецПериода, &Периодичность, &МетодДополнения, &Условие). Посмотрим на исправленный вариант запроса:
ВЫБРАТЬ
РасчетыПоРаботамОстаткиИОбороты.Исполнитель КАК Исполнитель,
РасчетыПоРаботамОстаткиИОбороты.Работа КАК Услуга,
РасчетыПоРаботамОстаткиИОбороты.ЗаказНаряд КАК ЗаказНаряд,
РасчетыПоРаботамОстаткиИОбороты.СуммаКонечныйОстаток КАК Сумма
ИЗ
РегистрНакопления.РасчетыПоРаботам.ОстаткиИОбороты(&НачДата, &КонДата, , , ) КАК РасчетыПоРаботамОстаткиИОбороты
В этом примере параметры &НачДата и &КонДата жестко ограничивают данные регистра. Система не будет просматривать лишние записи, что значительно ускоряет выполнение запроса.
Одним из ключевых правил профессиональной разработки на 1С является установка условий именно в параметрах виртуальной таблицы, а не в секции ГДЕ. Проанализируем почему:
ГДЕ, система сначала выбирает все записи (или строит тяжелую таблицу), а потом «выбрасывает» лишнее.В коде часто встречается конструкция КонецДня(ДатаОкончания) + 1. Это делается для того, чтобы включить документы, записанные в самую последнюю секунду дня. Однако более изящным и правильным способом является использование объекта Граница. Рассмотрим пример кода на встроенном языке:
ГраницаКон = Новый Граница(КонецДня(Объект.ДатаОкончания), ВидГраницы.Включая);
Запрос.УстановитьПараметр("КонДата", ГраницаКон);
Объект Граница гарантирует, что в выборку попадут все движения, включая те, что были сделаны в последнюю секунду указанного периода, не прибегая к искусственному добавлению времени.
В обсуждении было замечено использование соединения с табличной частью документа: ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказНаряд.Услуги. Выясним, почему это может быть опасно. Табличные части документов могут быть огромными. Если вам нужно просто получить дату выполнения, как предложили в одном из сообщений, можно использовать обращение через точку:
РасчетыПоРаботамОстатки.ЗаказНаряд.ДатаИВремяВыполнения
Однако помните: каждое обращение через точку от ссылочного поля — это неявное левое соединение в SQL-запросе. Если таких полей много, запрос станет «тяжелым». Если производительность критична, рекомендуется предварительно выбрать данные из регистра во Временную таблицу, проиндексировать ее по полю ЗаказНаряд, и только потом соединять с основной таблицей.
Проанализируем ситуацию, когда запрос в консоли работает правильно, а в коде «не видит» начальную дату. Как выяснилось в ходе обсуждения, проблема часто кроется не в самом запросе, а в логике записи данных. При перепроведении документов в поле периода регистра может записываться дата фактического проведения, а не дата самого документа.
Совет: Всегда проверяйте, какие именно данные лежат в физической таблице регистра (через консоль запросов или просмотр движений документа), прежде чем искать ошибку в параметрах &НачДата и &КонДата. Если итоги регистра не актуальны, может потребоваться процедура «Пересчет итогов» в конфигураторе или через управление итогами в режиме предприятия.
Для правильного ограничения данных по периоду в 1С мы рекомендуем:
ОстаткиИОбороты, если нужен интервал, и Остатки, если нужен срез на момент.Граница для точного захвата конца периода.