Как устранить задвоение строк в запросе 1С при выборе адреса электронной почты?

Программист 1С v8.3 (Управляемые формы) Сфера услуг, туризм и социальный сектор
← На главную

При разработке отчетов или выборок в системе 1С программисты часто сталкиваются с неприятным эффектом: при добавлении в запрос поля с адресом электронной почты или телефоном количество строк в результате внезапно увеличивается. Это явление называется «задвоением» (или размножением) записей. Рассмотрим подробнее, почему это происходит и как правильно составить запрос, чтобы получить корректные данные.

Почему происходит задвоение строк?

Прежде чем переходить к коду, проанализируем ситуацию с точки зрения логики базы данных. Когда мы используем ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) между основной таблицей (например, списком студентов или физических лиц) и таблицей контактной информации, система ищет совпадения по заданному условию. Если для одной записи в основной таблице в подчиненной таблице находится несколько записей, SQL-движок создаст отдельную строку для каждого совпадения.

В случае с контактной информацией в 1С причин может быть несколько:

  1. Несколько видов контактной информации: У одного физлица могут быть записаны и Email, и телефон, и фактический адрес. Если не указать фильтр по виду, запрос вернет по одной строке на каждый тип контакта.
  2. Дублирование записей одного вида: В базе могут физически присутствовать две записи с типом «Email», например, если данные загружались из разных источников.
  3. История изменений: Если контактная информация хранится в периодическом регистре сведений, без использования среза последних или среза на конкретную дату запрос выберет всю историю изменения адреса.
  4. Табличные части документов: Если вы обращаетесь к табличной части КонтактнаяИнформация документа (например, «Анкета абитуриента»), то для одного человека может существовать несколько таких документов, и каждый создаст дубль в выборке.

Решение 1: Фильтрация по конкретному виду контактной информации

Самый простой и очевидный способ исправить ситуацию — добавить в условие соединения жесткий фильтр по виду контактной информации. Выясним причину: если нам нужен только Email, мы должны явно сказать об этом системе.

Разберем пример кода, который исправляет ошибку:


ЛЕВОЕ СОЕДИНЕНИЕ Документ.АнкетаАбитуриента.КонтактнаяИнформация КАК АнкетаАбитуриентаКонтактнаяИнформация
    ПО ДвижениеКонтингентаСрезПоследних.Студент.ФизЛицо = АнкетаАбитуриентаКонтактнаяИнформация.Ссылка.ФизЛицо
    И АнкетаАбитуриентаКонтактнаяИнформация.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.EmailАбитуриента)

В данном случае добавление условия АнкетаАбитуриентаКонтактнаяИнформация.Вид = ... отсекает все остальные типы контактов (телефоны, адреса), оставляя только электронную почту. Однако, если у одного абитуриента в базе заведено два разных Email, задвоение сохранится. Рассмотрим, как решить эту проблему более фундаментально.

Решение 2: Использование временных таблиц и группировок

Проанализируем ситуацию: профессиональным подходом в 1С считается предварительная подготовка данных. Чтобы гарантированно получить одну строку на одного человека, лучше всего вынести получение контактной информации в отдельную временную таблицу с использованием группировки. Это исключит влияние любых дублей в исходных данных.

Посмотрим на пример реализации такого подхода:


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

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

Использование функции МАКСИМУМ вместе с конструкцией СГРУППИРОВАТЬ ПО гарантирует, что даже если у пользователя введено пять адресов почты, в результирующую таблицу попадет только один (алфавитно первый или последний). Это «золотой стандарт» разработки на 1С для предотвращения размножения строк.

Решение 3: Проверка статуса данных (Пометка удаления и проведение)

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

Рассмотрим по шагам, что нужно добавить в секцию ГДЕ или в условие соединения:

  1. Проверка на пометку удаления: НЕ АнкетаАбитуриентаКонтактнаяИнформация.Ссылка.ПометкаУдаления.
  2. Проверка на проведение (если это документ): АнкетаАбитуриентаКонтактнаяИнформация.Ссылка.Проведен.
  3. Проверка на актуальность: если в системе есть регистр КонтактнаяИнформация, всегда отдавайте предпочтение ему, а не табличным частям документов.

Решение 4: Работа с виртуальными таблицами

Если данные берутся из регистров сведений, важно правильно использовать виртуальные таблицы. При выполнении соединения с СрезПоследних крайне желательно передавать параметры (дату и условия фильтрации) непосредственно в параметры виртуальной таблицы, а не в общее условие ГДЕ. Это не только ускоряет запрос, но и помогает избежать логических ошибок при сопоставлении данных на разные моменты времени.

Важный момент: если вы видите, что запрос «тормозит» или выдает странные результаты при большом количестве ЛЕВОЕ СОЕДИНЕНИЕ, попробуйте разбить его на несколько этапов с использованием временных таблиц, как мы разобрали выше. Это упрощает отладку: вы всегда сможете посмотреть содержимое временной таблицы и понять, на каком этапе «просочились» лишние строки.

Таким образом, для победы над задвоением необходимо: четко ограничивать Вид контактной информации, использовать СГРУППИРОВАТЬ ПО для выбора единственного значения и следить за чистотой данных (исключать помеченные на удаление записи).

← На главную