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