Как в СКД вывести две независимые табличные части одного документа без задвоения строк и итогов?

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

При разработке отчетов в системе компоновки данных (СКД) часто возникает задача вывести в один отчет данные из двух табличных частей одного документа. Если эти табличные части никак не связаны между собой прямыми ссылками, а объединены только реквизитами шапки (например, ссылкой на документ или подразделением), при неправильной настройке запроса или структуры компоновки происходит декартово перемножение строк. В результате данные задваиваются, а общие итоги рассчитываются некорректно.

Рассмотрим причину возникновения этой проблемы и разберем по шагам несколько рабочих способов ее решения.

Выясним причину искажения данных

Когда мы соединяем в одном запросе через ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ две табличные части документа по ссылке, платформа 1С на каждую строку из первой табличной части подтягивает все строки из второй. Если в первой таблице 3 строки, а во второй 4, результат запроса вернет 12 строк. Это и есть декартово произведение записей.

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

Способ 1. Использование одного запроса с ОБЪЕДИНИТЬ ВСЕ и разделением полей

Проанализируем первый подход. В одном наборе данных-запросе выбираются записи первой табличной части, а затем через оператор ОБЪЕДИНИТЬ ВСЕ — записи второй табличной части. При этом для уникальных колонок первой таблицы во второй части выборки подставляются NULL, и наоборот.

Рассмотрим пример текста запроса для документа с двумя табличными частями преподавателей и старших преподавателей:


ВЫБРАТЬ
	МотивацияПреподавателейПреподаватели.Сотрудник КАК Преподаватель,
	МотивацияПреподавателейПреподаватели.Ссылка.Подразделение КАК Подразделение,
	МотивацияПреподавателейПреподаватели.СреднийБалл КАК СреднийБаллПреподаватель,
	МотивацияПреподавателейПреподаватели.ОценкаПоБонусу КАК ОценкаПоБонусу,
	МотивацияПреподавателейПреподаватели.Начислено КАК НачисленоПреподаватель,
	МотивацияПреподавателейПреподаватели.СуммаБонусВопрос КАК СуммаБонусВопросПреподаватель,
	МотивацияПреподавателейПреподаватели.СуммаБонусов КАК СуммаБонусовПреподаватель,
	NULL КАК ПроцентПоложительныхРезультатов,
	NULL КАК НачисленоСтаршийПреподаватель,
	NULL КАК СтаршийПреподаватель,
	NULL КАК СуммаБонусВопросСтаршийПреподаватель,
	NULL КАК СуммаБонусовСтаршийПреподаватель
ИЗ
	Документ.МотивацияПреподавателей.Преподаватели КАК МотивацияПреподавателейПреподаватели

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

ВЫБРАТЬ
	NULL,
	МотивацияПреподавателейСтаршиеПреподаватели.Ссылка.Подразделение,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	МотивацияПреподавателейСтаршиеПреподаватели.ПроцентПоложительныхРезультатов,
	МотивацияПреподавателейСтаршиеПреподаватели.Начислено,
	МотивацияПреподавателейСтаршиеПреподаватели.Сотрудник,
	МотивацияПреподавателейСтаршиеПреподаватели.СуммаБонусВопрос,
	МотивацияПреподавателейСтаршиеПреподаватели.СуммаБонусов
ИЗ
	Документ.МотивацияПреподавателей.СтаршиеПреподаватели КАК МотивацияПреподавателейСтаршиеПреподаватели

Чтобы правильно вывести такие данные на макет и посчитать итоги, выполним следующие шаги:

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

Способ 2. Использование нескольких наборов данных и связей

Альтернативный и более прозрачный подход заключается в разделении запросов по разным наборам данных:

  1. Создадим НаборДанных1 (Запрос): выборка данных шапки документа (ссылка, подразделение, дата и др.).
  2. Создадим НаборДанных2 (Запрос): выборка записей из первой табличной части.
  3. Создадим НаборДанных3 (Запрос): выборка записей из второй табличной части.
  4. На вкладке «Связи наборов данных» свяжем НаборДанных2 с НаборДанных1 по полю Ссылка, а также НаборДанных3 с НаборДанных1 по полю Ссылка.

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

Способ 3. «Набор данных — Объединение»

Еще один способ — создание на вкладке «Наборы данных» элемента типа «Набор данных — Объединение». Внутрь этого объединения помещаются два отдельных набора данных-запроса (каждый для своей табличной части). В этом случае не нужно настраивать связи наборов по левому соединению, а платформа автоматически суммирует ресурсы по совпадающим полям на всех уровнях группировки.

Настройка расчета итогов и ресурсов

Разберем ситуации, когда требуется получить общие итоги по подразделению или документу, складывая показатели из двух табличных частей.

Если ресурсы первой и второй табличной части называются по-разному (например, СуммаБонусовПреподаватель и СуммаБонусовСтаршийПреподаватель), в настройках на вкладке «Ресурсы» мы можем добавить вычисляемый ресурс или задать произвольное выражение расчета итогов:

В колонке «Выражение» для общего итогового поля пишем:

Сумма(СуммаБонусовПреподаватель) + Сумма(СуммаБонусовСтаршийПреподаватель)

Таким образом, итог по подразделению будет корректно рассчитываться независимо от того, есть ли данные в первой, во второй или в обеих табличных частях одновременно.

← На главную