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