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

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

При разработке отчетов в системе компоновки данных (СКД) часто возникает задача: сформировать список клиентов, приобретавших определенные группы или виды номенклатуры, и вывести их актуальные контактные данные (например, номера телефонов). Однако при прямом соединении документов продаж и контактной информации строки отчета начинают задваиваться. Разберем причины возникновения дублей и рассмотрим правильные варианты построения схемы компоновки данных.

Почему возникают дубли строк

Выясним причину появления повторяющихся данных в отчете. Задвоение строк возникает по двум основным факторам:

  1. Множественность документов и строк в них: если клиент совершил несколько покупок или в одной накладной присутствует несколько позиций нужного вида номенклатуры, обращение к табличной части документов РеализацияТоваровУслуг.Товары возвращает столько строк, сколько раз клиент встретился в табличной части.
  2. Структура контактной информации: в табличной части КонтактнаяИнформация (или одноименном регистре сведений) у каждого партнера хранится множество записей: юридический адрес, фактический адрес, несколько телефонов, email. Если не наложить жесткий фильтр на вид и тип контактной информации, при левом соединении одна строка клиента размножится на количество всех его контактов.

Способ 1. Использование временной таблицы и фильтрации контактной информации

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

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


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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ_Партнеры.Партнер КАК Партнер,
	ПартнерыКонтактнаяИнформация.НомерТелефона КАК НомерТелефона
ИЗ
	ВТ_Партнеры КАК ВТ_Партнеры
	ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
		ПО ВТ_Партнеры.Партнер = ПартнерыКонтактнаяИнформация.Ссылка
		И (ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон))
		И (ПартнерыКонтактнаяИнформация.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонПартнера))

Обратите внимание на важные условия в тексте запроса:

  1. Ключевое слово РАЗЛИЧНЫЕ в первом пакете гарантирует, что в таблицу ВТ_Партнеры попадут только уникальные ссылки на партнеров, независимо от количества накладных.
  2. Фильтры СКД помещены в фигурные скобки {}, что позволяет системе компоновки динамически управлять условиями отбора по датам и виду номенклатуры.
  3. В условии соединения со справочником контактной информации обязательно указываются Тип и конкретный Вид, чтобы исключить попадание адресов и прочих контактов.

Способ 2. Оптимальный вариант с использованием регистров накопления

В типовых конфигурациях (1С:ERP, Комплексная автоматизация, Управление торговлей) обращение напрямую к табличным частям документов не рекомендуется из соображений производительности. Проанализируем более быстрое и правильное решение с использованием виртуальных таблиц оборотов регистров накопления (например, ВыручкаИСебестоимостьПродаж.Обороты или Продажи.Обороты).

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
	ВыручкаИСебестоимостьПродажОбороты.Партнер КАК Партнер
ПОМЕСТИТЬ ВТ_Партнеры
ИЗ
	РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(
			&ПериодНачала,
			&ПериодОкончания,
			Авто,
			{АналитикаУчетаНоменклатуры.Номенклатура.ВидНоменклатуры.* КАК ВидНоменклатуры}) КАК ВыручкаИСебестоимостьПродажОбороты
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ_Партнеры.Партнер КАК Партнер,
	ПартнерыКонтактнаяИнформация.НомерТелефона КАК НомерТелефона
ИЗ
	ВТ_Партнеры КАК ВТ_Партнеры
	ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
		ПО ВТ_Партнеры.Партнер = ПартнерыКонтактнаяИнформация.Ссылка
		И (ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон))
		И (ПартнерыКонтактнаяИнформация.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонПартнера))

Способ 3. Разделение на два набора данных СКД со связями

Схему компоновки данных можно построить без объединения разнородных источников в один сложный запрос. Разберем по шагам, как настроить отчет через связанные наборы данных:

  1. Создаем НаборДанных_Продажи: запрос выбирает уникальных партнеров из регистра продаж с отбором по виду номенклатуры и периоду.
  2. Создаем НаборДанных_Контакты: запрос выбирает контактные данные из табличной части справочника или регистра сведений КонтактнаяИнформация с фильтрацией по типу Телефон.
  3. Настраиваем связь: на вкладке «Связи наборов данных» указываем источник НаборДанных_Продажи, приемник НаборДанных_Контакты, условие связи по полю Партнер = Ссылка (или Объект).

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

Что делать, если у одного клиента несколько номеров телефонов

Если у контрагента зарегистрировано несколько телефонов с одним и тем же видом контактной информации, простое левое соединение неизбежно размножит строки отчета. Рассмотрим два способа решения этой проблемы:

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

Важные нюансы при работе с контактной информацией

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

  1. Поля неограниченной длины: строковые поля контактной информации (например, Представление, АдресЭП) могут иметь неограниченную длину. Использование операторов РАЗЛИЧНЫЕ или СГРУППИРОВАТЬ ПО к таким полям вызовет ошибку СУБД. Для обхода ограничения всегда приводите строковые поля к фиксированной длине: ВЫРАЗИТЬ(ПартнерыКонтактнаяИнформация.Представление КАК Строка(250)).
  2. Хранение контактных данных в БСП: в зависимости от версии конфигурации и используемой редакции БСП, контактные данные могут храниться как в табличной части справочника Партнеры/Контрагенты, так и в независимом регистре сведений КонтактнаяИнформация. Если табличная часть пуста, замените источник данных на соответствующий регистр сведений.
← На главную