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