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