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