Почему условие с отрицанием по субконто в параметрах виртуальной таблицы регистра бухгалтерии возвращает все записи и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке отчетов и обработок в 1С часто возникает необходимость выбрать проводки из регистра бухгалтерии с исключением определенной аналитики. Например, отобрать движения по счету учета товаров, исключив конкретный склад или группу складов. Однако при попытке наложить отрицание НЕ или <> на поле субконто непосредственно в параметре «Условие» виртуальной таблицы ДвиженияССубконто разработчики сталкиваются с неожиданным поведением: в результат попадают абсолютно все записи, включая те, которые требовалось исключить.

Разберем детально, почему это происходит на уровне платформы и СУБД, а также рассмотрим правильные способы построения таких запросов.

Рассмотрим исходный запрос, в котором накладывается прямое условие на совпадение склада:


ВЫБРАТЬ
    ХозрасчетныйДвиженияССубконто.СубконтоДт1 КАК Товар,
    ХозрасчетныйДвиженияССубконто.СубконтоДт2 КАК Партия,
    ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование КАК Склад,
    ХозрасчетныйДвиженияССубконто.КоличествоДт КАК КоличествоПоступило,
    ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоДт КАК Себестоимость
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
        &НачалоПериода,
        КОНЕЦПЕРИОДА(&КонецПериода, ДЕНЬ),
        Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ТоварыНаСкладах)
            И КоличествоДт > 0
            И СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой) КАК ХозрасчетныйДвиженияССубконто

Такой запрос отрабатывает ожидаемо: выбираются только те проводки, где третьим субконто выступает склад, наименование которого соответствует параметру. Однако если мы изменим условие на отрицание НЕ (СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой) или СубконтоДт3.Наименование <> &СкладСтрокой, результат запроса вернет все склады без исключения.

Причины некорректной работы отрицания в параметрах виртуальной таблицы

Проанализируем архитектуру хранения данных субконто и трансляцию запросов платформой «1С:Предприятие» в SQL:

  1. Особенность хранения строк субконто: В базе данных значения субконто для каждой проводки хранятся в отдельной таблице аналитики (отдельные строки для каждого вида субконто). При установке отбора в параметрах виртуальной таблицы платформа формирует условие проверки существования (EXISTS) записей в таблице субконто проводки. При прямом поиске (=, ПОДОБНО) проверяется наличие строки с требуемым значением. Но при использовании отрицания (НЕ, <>) условие превращается в поиск проводки, у которой существует хотя бы одна аналитика, не равная указанному значению. Поскольку у проводки по счету ТоварыНаСкладах есть субконто 1 (Номенклатура) и субконто 2 (Партия), их наименования не равны наименованию склада, и условие становится истинным для всех проводок.
  2. Документированное платформенное ограничение: В стандартах разработки и документации платформы зафиксировано правило: в параметрах виртуальной таблицы ДвиженияССубконто не допускается применение условий отрицания (НЕ) и неравенства (<>) к полям субконто и их реквизитам.
  3. Составной тип данных субконто: Поля СубконтоДт и СубконтоКт имеют составной ссылочный тип. Обращение через точку (СубконтоДт3.Наименование) порождает множество неявных левых соединений (LEFT JOIN) со всеми таблицами, входящими в составной тип. Поля несовпадающих типов возвращают NULL, что при отрицании в логике SQL приводит к некорректным результатам выборки.

Способ 1. Перенос условия в секцию ГДЕ (рекомендуемое решение)

Наиболее надежным и универсальным решением проблемы является перенос условия с отрицанием из параметров виртуальной таблицы в секцию ГДЕ основного запроса. В этом случае виртуальная таблица сначала формирует полную плоскую строку со всеми субконто проводки, а затем конструкция ГДЕ фильтрует полученный результат целиком.

Посмотрим на пример правильного запроса:


ВЫБРАТЬ
    ХозрасчетныйДвиженияССубконто.СубконтоДт1 КАК Товар,
    ХозрасчетныйДвиженияССубконто.СубконтоДт2 КАК Партия,
    ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование КАК Склад,
    ХозрасчетныйДвиженияССубконто.КоличествоДт КАК КоличествоПоступило,
    ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоДт КАК Себестоимость
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
        &НачалоПериода,
        КОНЕЦПЕРИОДА(&КонецПериода, ДЕНЬ),
        Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ТоварыНаСкладах)
            И КоличествоДт > 0) КАК ХозрасчетныйДвиженияССубконто
ГДЕ
    НЕ ХозрасчетныйДвиженияССубконто.СубконтоДт3.Наименование ПОДОБНО &СкладСтрокой

В таком варианте проводка проверяется целиком, и если в поле СубконтоДт3 указан склад, соответствующий строке &СкладСтрокой, вся строка будет корректно исключена из выборки.

Способ 2. Использование явного приведения типов через ВЫРАЗИТЬ

Если требуется оптимизировать обращение к реквизитам полей субконто и исключить лишние соединения таблиц в СУБД, поле составного типа следует типизировать с помощью оператора ВЫРАЗИТЬ. Это правило рекомендуется соблюдать как в секции ГДЕ, так и при формировании полей выборки:


ГДЕ
    НЕ ВЫРАЗИТЬ(ХозрасчетныйДвиженияССубконто.СубконтоДт3 КАК Справочник.Склады).Наименование ПОДОБНО &СкладСтрокой

Способ 3. Переход на ссылочные параметры

Сравнение строковых представлений и наименований через ПОДОБНО или = может приводить к ошибкам из-за неразрывных пробелов, опечаток или дублирующихся элементов справочника. Если данные передаются через COM-соединение или внешние источники, рекомендуется предварительно найти ссылку на объект (например, по наименованию или коду) и передавать в запрос конкретную ссылку:


ГДЕ
    ХозрасчетныйДвиженияССубконто.СубконтоДт3 <> &ИсключаемыйСклад

Если исключаемых объектов несколько, эффективнее передавать массив или список значений и использовать оператор НЕ В (&МассивСкладов) в секции ГДЕ.

Резюме: Никогда не используйте операторы отрицания (НЕ, <>, НЕ В) по полям субконто внутри параметров виртуальной таблицы ДвиженияССубконто. Ограничивайте в параметрах виртуальной таблицы только период, счет и положительные условия, а любые исключающие фильтры по субконто всегда выносите в секцию ГДЕ.

← На главную