При разработке отчетов и обработок в системе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью объединить в одной выборке итоговые остатки по счету и детальные обороты в разрезе корреспондирующих счетов. Основная сложность заключается в архитектуре виртуальных таблиц регистра бухгалтерии. Рассмотрим подробнее, почему стандартная таблица ОстаткиИОбороты не всегда подходит для решения таких задач и как правильно спроектировать запрос.
Разберем ситуацию: нам необходимо получить сальдо по счету 19.03 и одновременно увидеть оборот в связке Дебет 19.03 — Кредит 68.02. Посмотрим на возможности виртуальных таблиц:
КорСчет. В ней хранятся уже агрегированные данные по счету без учета того, «откуда» пришли деньги или «куда» ушли.КорСчет, но не предоставляет данных об остатках (сальдо).Выясним причину затруднения: попытка соединить эти таблицы напрямую (через ЛЕВОЕ СОЕДИНЕНИЕ) может привести к дублированию строк или некорректному расчету итогов, если по счету ведется сложный аналитический учет. Проанализируем наиболее грамотные подходы к решению этой задачи.
Профессиональная разработка в 1С предполагает использование оператора ОБЪЕДИНИТЬ ВСЕ вместо сложных соединений. Это позволяет избежать «раздувания» результата (картезианского произведения) и значительно повышает читаемость кода. Суть метода заключается в том, чтобы выбрать остатки в одной части запроса, а обороты — в другой, приведя их к общей структуре полей.
Рассмотрим пример построения такого запроса:
ВЫБРАТЬ
ВТ_Данные.Счет КАК Счет,
СУММА(ВТ_Данные.СальдоНач) КАК СальдоНач,
СУММА(ВТ_Данные.ОборотСКорр) КАК ОборотСКорр
ИЗ
(ВЫБРАТЬ
Т_Остатки.Счет КАК Счет,
Т_Остатки.СуммаОстатокДт КАК СальдоНач,
0 КАК ОборотСКорр
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , ) КАК Т_Остатки
ГДЕ
Т_Остатки.Счет = &Счет19
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т_Обороты.Счет КАК Счет,
0,
Т_Обороты.СуммаОборотДт
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(&НачДата, &КонДата, , Счет = &Счет19, , КорСчет = &Счет68, , ) КАК Т_Обороты) КАК ВТ_Данные
СГРУППИРОВАТЬ ПО
ВТ_Данные.Счет
Важный момент: Обратите внимание, что фильтрация по корреспондирующему счету 68.02 производится непосредственно в параметрах виртуальной таблицы Обороты. Это заставляет SQL-сервер выполнять отбор на этапе формирования временной таблицы в памяти, что существенно ускоряет выполнение запроса.
Если специфика задачи требует обязательного наличия полей в одной строке (например, для сложной математической обработки внутри запроса), мы можем использовать временные таблицы. Рассмотрим по шагам этот алгоритм:
ВТ_Остатки, куда помещаем сальдо из таблицы ОстаткиИОбороты.ВТ_Обороты, выбирая данные из таблицы Обороты с указанием конкретного КорСчета.Посмотрим на пример реализации связи:
ВЫБРАТЬ
ЕСТЬNULL(ВТ_Остатки.Счет, ВТ_Обороты.Счет) КАК Счет,
ЕСТЬNULL(ВТ_Остатки.СуммаКонечныйОстатокДт, 0) КАК Остаток,
ЕСТЬNULL(ВТ_Обороты.СуммаОборотДт, 0) КАК ОборотСКоррСчетом
ИЗ
ВТ_Остатки КАК ВТ_Остатки
ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Обороты КАК ВТ_Обороты
ПО ВТ_Остатки.Счет = ВТ_Обороты.Счет
И ВТ_Остатки.Субконто1 = ВТ_Обороты.Субконто1
При использовании соединений крайне важно использовать функцию ЕСТЬNULL. Если по счету есть остаток, но в выбранном периоде не было движений по конкретному корр. счету, запрос вернет NULL, что может привести к ошибкам в дальнейших вычислениях.
Проанализируем ситуацию с точки зрения нагрузки на систему. При работе с регистром бухгалтерии следует придерживаться следующих правил:
ПО (условие связи). Без индексов на больших базах запрос может «зависнуть».ГДЕ выполняется после получения всех данных, а параметры виртуальной таблицы (в скобках) — до. Всегда передавайте Счет и КорСчет в параметры.Хозрасчетный.ОборотыДтКт.Мы выяснили, что наиболее устойчивым и производительным методом получения сальдо и оборотов с корр. счетом является использование объединения (UNION ALL). Этот подход исключает потерю данных при отсутствии оборотов и позволяет прозрачно управлять структурой результата. Если же вам необходимо использовать соединение (JOIN), обязательно используйте временные таблицы с предварительной индексацией и тщательную обработку пустых значений через ЕСТЬNULL.