При разработке отчетов и обработок в 1С часто возникает необходимость выбрать проводки из регистра бухгалтерии с исключением определенной аналитики. Например, отобрать движения по счету учета товаров, исключив конкретный склад или группу складов. Однако при попытке наложить отрицание НЕ или <> на поле субконто непосредственно в параметре «Условие» виртуальной таблицы ДвиженияССубконто разработчики сталкиваются с неожиданным поведением: в результат попадают абсолютно все записи, включая те, которые требовалось исключить.
Разберем детально, почему это происходит на уровне платформы и СУБД, а также рассмотрим правильные способы построения таких запросов.
Рассмотрим исходный запрос, в котором накладывается прямое условие на совпадение склада:
ВЫБРАТЬ
ХозрасчетныйДвиженияССубконто.СубконтоДт1 КАК Товар,
ХозрасчетныйДвиженияССубконто.СубконтоДт2 КАК Партия,
ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование КАК Склад,
ХозрасчетныйДвиженияССубконто.КоличествоДт КАК КоличествоПоступило,
ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоДт КАК Себестоимость
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
&НачалоПериода,
КОНЕЦПЕРИОДА(&КонецПериода, ДЕНЬ),
Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ТоварыНаСкладах)
И КоличествоДт > 0
И СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой) КАК ХозрасчетныйДвиженияССубконто
Такой запрос отрабатывает ожидаемо: выбираются только те проводки, где третьим субконто выступает склад, наименование которого соответствует параметру. Однако если мы изменим условие на отрицание НЕ (СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой) или СубконтоДт3.Наименование <> &СкладСтрокой, результат запроса вернет все склады без исключения.
Проанализируем архитектуру хранения данных субконто и трансляцию запросов платформой «1С:Предприятие» в SQL:
EXISTS) записей в таблице субконто проводки. При прямом поиске (=, ПОДОБНО) проверяется наличие строки с требуемым значением. Но при использовании отрицания (НЕ, <>) условие превращается в поиск проводки, у которой существует хотя бы одна аналитика, не равная указанному значению. Поскольку у проводки по счету ТоварыНаСкладах есть субконто 1 (Номенклатура) и субконто 2 (Партия), их наименования не равны наименованию склада, и условие становится истинным для всех проводок.ДвиженияССубконто не допускается применение условий отрицания (НЕ) и неравенства (<>) к полям субконто и их реквизитам.СубконтоДт и СубконтоКт имеют составной ссылочный тип. Обращение через точку (СубконтоДт3.Наименование) порождает множество неявных левых соединений (LEFT JOIN) со всеми таблицами, входящими в составной тип. Поля несовпадающих типов возвращают NULL, что при отрицании в логике SQL приводит к некорректным результатам выборки.Наиболее надежным и универсальным решением проблемы является перенос условия с отрицанием из параметров виртуальной таблицы в секцию ГДЕ основного запроса. В этом случае виртуальная таблица сначала формирует полную плоскую строку со всеми субконто проводки, а затем конструкция ГДЕ фильтрует полученный результат целиком.
Посмотрим на пример правильного запроса:
ВЫБРАТЬ
ХозрасчетныйДвиженияССубконто.СубконтоДт1 КАК Товар,
ХозрасчетныйДвиженияССубконто.СубконтоДт2 КАК Партия,
ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование КАК Склад,
ХозрасчетныйДвиженияССубконто.КоличествоДт КАК КоличествоПоступило,
ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоДт КАК Себестоимость
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
&НачалоПериода,
КОНЕЦПЕРИОДА(&КонецПериода, ДЕНЬ),
Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ТоварыНаСкладах)
И КоличествоДт > 0) КАК ХозрасчетныйДвиженияССубконто
ГДЕ
НЕ ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой
В таком варианте проводка проверяется целиком, и если в поле СубконтоДт3 указан склад, соответствующий строке &СкладСтрокой, вся строка будет корректно исключена из выборки.
Если требуется оптимизировать обращение к реквизитам полей субконто и исключить лишние соединения таблиц в СУБД, поле составного типа следует типизировать с помощью оператора ВЫРАЗИТЬ. Это правило рекомендуется соблюдать как в секции ГДЕ, так и при формировании полей выборки:
ГДЕ
НЕ ВЫРАЗИТЬ(ХозрасчетныйДвиженияССубконто.СубконтоДт3 КАК Справочник.Склады).Наименование ПОДОБНО &СкладСтрокой
Сравнение строковых представлений и наименований через ПОДОБНО или = может приводить к ошибкам из-за неразрывных пробелов, опечаток или дублирующихся элементов справочника. Если данные передаются через COM-соединение или внешние источники, рекомендуется предварительно найти ссылку на объект (например, по наименованию или коду) и передавать в запрос конкретную ссылку:
ГДЕ
ХозрасчетныйДвиженияССубконто.СубконтоДт3 <> &ИсключаемыйСклад
Если исключаемых объектов несколько, эффективнее передавать массив или список значений и использовать оператор НЕ В (&МассивСкладов) в секции ГДЕ.
Резюме: Никогда не используйте операторы отрицания (НЕ, <>, НЕ В) по полям субконто внутри параметров виртуальной таблицы ДвиженияССубконто. Ограничивайте в параметрах виртуальной таблицы только период, счет и положительные условия, а любые исключающие фильтры по субконто всегда выносите в секцию ГДЕ.