Как правильно объединить регистраторы и рассчитать остатки по нескольким счетам в СКД

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке сложных аналитических отчетов в схеме компоновки данных (СКД) часто возникает задача вывести в единую строку детализацию по разным счетам учета (например, тело займа, проценты, штрафы, госпошлины) в разрезе контрагентов, договоров и документов-регистраторов. Типичной ошибкой является попытка соединить несколько виртуальных таблиц ОстаткиИОбороты через ЛЕВОЕ СОЕДИНЕНИЕ и объединить полученные поля документов через конструкцию ВЫБОР КОГДА ... ТОГДА. Рассмотрим, почему данный подход ломает расчет итогов в СКД, и как правильно реализовать такой запрос.

Почему возникает ошибка при множественном соединении таблиц остатков и оборотов:

  1. Нарушение шкалы времени: Вычисляемое через ВЫБОР КОГДА поле Регистратор не распознается платформой 1С как истинная точка шкалы времени. Механизм компоновки данных не может сопоставить составной регистратор с периодичностью и переходит к простому суммированию начальных и конечных остатков, что приводит к некорректным цифрам.
  2. Декартово произведение и задвоение сумм: Соединение нескольких виртуальных таблиц только по измерениям (контрагент, договор) без привязки к периодам и регистраторам вызывает перемножение строк. Если по одному счету движение было в начале месяца, а по другому — в конце, левое соединение создаст дублирующие строки, где начальные и конечные остатки многократно продублируются.
  3. Отсутствие поля упорядочивания внутри секунды: Без реального регистратора и системного поля НомерСтроки платформа не может однозначно выстроить хронологию документов, проведенных в одну и ту же секунду.

Способ 1. Получение данных через единую виртуальную таблицу (рекомендуемый подход)

Разберем оптимальный вариант: вместо соединения нескольких виртуальных таблиц между собой мы обращаемся к таблице РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты ровно один раз. Необходимый список счетов передается в параметры виртуальной таблицы массивом, а разнесение сумм по соответствующим колонкам отчета выполняется внутри секции ВЫБРАТЬ с помощью условий.

Посмотрим на пример правильного текста запроса для набора данных СКД:


ВЫБРАТЬ
	_РасчетыСКонтрагентами.Контрагент КАК Контрагент,
	_РасчетыСКонтрагентами.ВыбДоговор КАК Договор,
	_РасчетыСКонтрагентами.Организация КАК Организация,
	_РасчетыСКонтрагентами.Ссылка КАК СудебноеДело
ПОМЕСТИТЬ ВТ_Основания
ИЗ
	Документ._РасчетыСКонтрагентами КАК _РасчетыСКонтрагентами
ГДЕ
	_РасчетыСКонтрагентами.Проведен = ИСТИНА
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ_Основания.Контрагент КАК Контрагент,
	ВТ_Основания.Договор КАК Договор,
	ВТ_Основания.Организация КАК Организация,
	ВТ_Основания.СудебноеДело КАК СудебноеДело,
	Хозрасчетный.Счет КАК Счет,
	Хозрасчетный.ПериодСекунда КАК ПериодСекунда,
	Хозрасчетный.Регистратор КАК Регистратор,
	Хозрасчетный.НомерСтроки КАК НомерСтроки,
	// Тело займа (Счет 58.03)
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетЗаймТело
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаНачальныйОстаток, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК СуммаТелаНачало,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетЗаймТело
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаОборотДт, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК СуммаТелаУвеличение,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетЗаймТело
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаОборотКт, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК СуммаТелаУменьшение,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетЗаймТело
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаКонечныйОстаток, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК СуммаТелаОкончание,
	// Проценты и штрафы (Счет 76.06)
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетПроцентыШтрафы
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаНачальныйОстаток, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК ПроцентыШтрафыНачало,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетПроцентыШтрафы
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаОборотДт, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК ПроцентыШтрафыУвеличение,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетПроцентыШтрафы
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаОборотКт, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК ПроцентыШтрафыУменьшение,
	ВЫБОР
		КОГДА Хозрасчетный.Счет = &СчетПроцентыШтрафы
			ТОГДА ЕСТЬNULL(Хозрасчетный.СуммаКонечныйОстаток, 0)
		ИНАЧЕ 0
	КОНЕЦ КАК ПроцентыШтрафыОкончание
ИЗ
	ВТ_Основания КАК ВТ_Основания
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(
				&НачалоПериода,
				&КонецПериода,
				Авто,
				,
				Счет В (&СписокСчетов),
				,
				(Субконто1, Субконто2) В
					(ВЫБРАТЬ
						ВТ.Контрагент,
						ВТ.Договор
					ИЗ
						ВТ_Основания КАК ВТ)
		) КАК Хозрасчетный
		ПО ВТ_Основания.Контрагент = Хозрасчетный.Субконто1
			И ВТ_Основания.Договор = Хозрасчетный.Субконто2

Способ 2. Объединение независимых выборок через ОБЪЕДИНИТЬ ВСЕ

Если специфика счетов требует разного состава субконто или раздельной логики условий, объединение таблиц через LEFT JOIN все равно недопустимо. В этом случае данные по каждому счету следует выбирать отдельными запросами и объединять их вертикально в единую таблицу с помощью оператора ОБЪЕДИНИТЬ ВСЕ.

Проанализируем структуру такого запроса:


ВЫБРАТЬ
	Хозрасчетный.Субконто1 КАК Контрагент,
	Хозрасчетный.Субконто2 КАК Договор,
	Хозрасчетный.Счет КАК Счет,
	Хозрасчетный.ПериодСекунда КАК ПериодСекунда,
	Хозрасчетный.Регистратор КАК Регистратор,
	Хозрасчетный.НомерСтроки КАК НомерСтроки,
	Хозрасчетный.СуммаНачальныйОстаток КАК СуммаТелаНачало,
	Хозрасчетный.СуммаОборотДт КАК СуммаТелаУвеличение,
	Хозрасчетный.СуммаОборотКт КАК СуммаТелаУменьшение,
	Хозрасчетный.СуммаКонечныйОстаток КАК СуммаТелаОкончание,
	0 КАК ПроцентыШтрафыНачало,
	0 КАК ПроцентыШтрафыУвеличение,
	0 КАК ПроцентыШтрафыУменьшение,
	0 КАК ПроцентыШтрафыОкончание
ИЗ
	РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , Счет = &СчетТела, , ) КАК Хозрасчетный

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	Хозрасчетный.Субконто1,
	Хозрасчетный.Субконто2,
	Хозрасчетный.Счет,
	Хозрасчетный.ПериодСекунда,
	Хозрасчетный.Регистратор,
	Хозрасчетный.НомерСтроки,
	0,
	0,
	0,
	0,
	Хозрасчетный.СуммаНачальныйОстаток,
	Хозрасчетный.СуммаОборотДт,
	Хозрасчетный.СуммаОборотКт,
	Хозрасчетный.СуммаКонечныйОстаток
ИЗ
	РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , Счет = &СчетПроцентов, , ) КАК Хозрасчетный

Настройка ролей полей в схеме компоновки данных

Чтобы система компоновки данных автоматически и безошибочно рассчитывала остатки в любых группировках (по контрагенту, договору, счету и регистратору), необходимо корректно заполнить колонку Роль на вкладке Наборы данных:

  1. Поля измерений: Для полей Контрагент, Договор и Счет укажем флаг Измерение со значением Истина. Без указания счета в качестве измерения расчет остатков по разным счетам в СКД будет некорректен.
  2. Поле периода: Для поля ПериодСекунда устанавливаем роль Период, порядковый номер 1 и тип периода Секунда.
  3. Поле регистратора: Для поля Регистратор выбираем роль Регистратор, а в колонке Дополнительные поля обязательно выбираем НомерСтроки. Это позволит упорядочивать документы внутри одной секунды.
  4. Ресурсы начальных и конечных остатков:
    • Для СуммаТелаНачало: тип остатка НачальныйОстаток, имя группы — СуммаТела.
    • Для СуммаТелаОкончание: тип остатка КонечныйОстаток, имя группы — СуммаТела.
    • Для оборотов (увеличение, уменьшение) флаги остатков не устанавливаются.

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

← На главную