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