При разработке и доработке отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с загадочным поведением системы: отчет прекрасно работал, выводил все строки, но стоило добавить всего одно новое поле из связанного набора данных в выбранные поля или в собственный макет оформления, как отчет становится абсолютно пустым. Данные просто исчезают без каких-либо ошибок или предупреждений.
В этой статье мы подробно разберем, почему возникает этот эффект, как внутренние механизмы оптимизации СКД влияют на связи наборов данных, и как решить эту проблему раз и навсегда с помощью правильной настройки ресурсов и запросов.
Проанализируем ситуацию, которая происходит в системе компоновки данных по умолчанию. Когда мы связываем два набора данных (например, «НаборДанных1» — основной запрос, и «НаборДанных2» — подчиненный запрос или выборка из регистра) на вкладке «Связи наборов данных», платформа 1С пытается объединить их по ключевым полям.
По умолчанию СКД связывает наборы данных по принципу левого соединения (LEFT JOIN). Это означает, что все записи из основного набора данных должны отображаться в отчете в любом случае, даже если для них не нашлось подходящих соответствий во втором (подчиненном) наборе данных. В этом случае в колонках второго набора мы должны увидеть простые пустые значения.
Однако поведение оптимизатора СКД меняется, если мы добавляем новое поле из подчиненного набора данных напрямую в выбранные поля отчета как обычный реквизит или измерение. В этот момент левое соединение наборов данных неявно для разработчика превращается во внутреннее соединение (INNER JOIN). Происходит это по следующим причинам:
Самый простой и быстрый способ вернуть пропавшие данные в отчет — это объявить добавленное поле подчиненного набора данных ресурсом в СКД. Разберем по шагам, почему это работает и как это правильно настроить.
В СКД расчет обычных полей и полей-ресурсов происходит на принципиально разных этапах компоновки:
СУММА, МАКСИМУМ, МИНИМУМ или СРЕДНЕЕ) рассчитываются уже после того, как сформирована основная структура отчета на базе родительского набора данных. СКД сначала выводит все строки главного набора, а затем для каждой строки пытается вычислить значение ресурса из подчиненного набора. Если данных для связи нет, ресурс возвращает пустое значение (NULL), но исходная строка отчета сохраняется и никуда не пропадает.Выполним настройку поля-ресурса по шагам:
Сумма(ИмяВашегоПоля). Если поле имеет тип Дата, Строка или Булево, используйте функцию Максимум(ИмяВашегоПоля) или Минимум(ИмяВашегоПоля).После этого вернитесь в настройки отчета на вкладку «Выбранные поля» и убедитесь, что новое поле теперь отображается со значком ресурса (обычно это синий или зеленый значок функции). Запустите отчет — данные основного набора вернутся на место, а в новой колонке отобразятся нужные значения либо пустые ячейки там, где данных во втором наборе не оказалось.
Связывание наборов данных непосредственно в СКД средствами платформы «1С:Предприятие» — это удобный инструмент, но он имеет два существенных недостатка: он работает медленнее, чем соединение таблиц на уровне СУБД, и часто приводит к непредсказуемому поведению оптимизатора (как в случае с пропавшими данными).
Если оба ваших набора данных являются запросами к одной и той же базе данных, мы настоятельно рекомендуем отказаться от связей наборов в СКД и объединить их в один пакетный запрос с использованием классического ЛЕВОЕ СОЕДИНЕНИЕ. Это гарантирует 100% стабильность вывода данных и существенно ускорит работу отчета.
Рассмотрим пример того, как переписать два связанных набора данных в один оптимальный пакетный запрос:
ВЫБРАТЬ
ПродажиОбороты.Контрагент КАК Контрагент,
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.СуммаОборот КАК СуммаПродаж
ПОМЕСТИТЬ ВТ_ОсновныеДанные
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ОсновныеДанные.Контрагент КАК Контрагент,
ВТ_ОсновныеДанные.Номенклатура КАК Номенклатура,
ВТ_ОсновныеДанные.СуммаПродаж КАК СуммаПродаж,
ЕСТЬNULL(ДополнительныеСведения.Значение, "Не указано") КАК ДополнительноеСвойство
ИЗ
ВТ_ОсновныеДанные КАК ВТ_ОсновныеДанные
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
ПО ВТ_ОсновныеДанные.Контрагент = ДополнительныеСведения.Объект
И ДополнительныеСведения.Свойство = &СвойствоКонтрагента
В данном примере мы применили функцию ЕСТЬNULL. Она позволяет сразу обработать ситуации, когда во второй таблице нет связанных данных, и заменить системное значение NULL на понятную пользователю пустую строку или значение по умолчанию. Такой подход полностью исключает «схлопывание» строк отчета.
Если объединить запросы невозможно (например, один из наборов данных является внешним набором — таблицей значений, передаваемой из кода), обратите внимание на настройки связей наборов данных в СКД.
На вкладке «Связи наборов данных» для каждой связи предусмотрен флаг «Обязательная связь»:
Если вы выводите новые поля в середину отчета, используя собственный макет шапки или группировки, всегда соблюдайте следующие правила:
Параметр вы можете использовать тип Текст со встроенными выражениями компоновки данных, чтобы более гибко обрабатывать пустые значения.Представление(ЕСТЬNULL(ИмяПоля, "—")).Применяя данные подходы, вы сможете легко диагностировать причины исчезновения строк в отчетах СКД и создавать надежные, быстродействующие отчеты со сложной структурой данных.