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