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