Как в запросе 1С убрать строки, в которых несколько колонок содержат NULL?

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

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

Постановка задачи

Представим ситуацию: у нас есть запрос к регистру бухгалтерии, который выводит данные по счетам, субконто и суммам. В результате вычислений или соединений у нас образуются три колонки (например, «ПрочиеВыплаты», «ОКЛАД», «СтрахВзносы»), которые во многих строках содержат NULL. Наша цель — вывести только те строки, в которых хотя бы в одной из этих колонок есть какое-либо значение. Если во всех трех колонках NULL, такая строка нам не нужна.

Вариант 1: Использование логического условия ГДЕ

Рассмотрим самый простой способ решения — добавление условия фильтрации непосредственно в текст запроса. Важно правильно использовать логические операторы ИЛИ и НЕ. Проанализируем правильную конструкцию:


ГДЕ
    НЕ Колонка1 ЕСТЬ NULL
    ИЛИ НЕ Колонка2 ЕСТЬ NULL
    ИЛИ НЕ Колонка3 ЕСТЬ NULL

Разберем, почему это работает: условие ЕСТЬ NULL проверяет поле на отсутствие значения. Инверсия НЕ ... ЕСТЬ NULL означает «поле заполнено». Используя оператор ИЛИ, мы указываем системе: «оставь строку, если заполнена первая колонка, ИЛИ вторая, ИЛИ третья». Если все три будут NULL, условие целиком вернет Ложь, и строка будет отсечена.

Существует альтернативная запись той же логики через закон де Моргана, которую иногда применяют для краткости:


ГДЕ
    НЕ (Колонка1 ЕСТЬ NULL И Колонка2 ЕСТЬ NULL И Колонка3 ЕСТЬ NULL)

Здесь мы говорим: «отсеки строки, где (первая И вторая И третья) одновременно являются NULL».

Вариант 2: Использование временных таблиц (Оптимальный подход)

Если ваши колонки являются результатом сложных вычислений через конструкцию ВЫБОР КОГДА ... ТОГДА, использование условий в секции ГДЕ того же самого запроса может сделать код нечитаемым и негативно сказаться на производительности. Рассмотрим подробнее подход с использованием временной таблицы.

Шаг 1: Поместим основной запрос с вычислениями во временную таблицу. Это позволит нам «зафиксировать» вычисленные значения.


ВЫБРАТЬ
    Движения.СчетДт,
    ВЫБОР
        КОГДА Движения.СчетДт = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ОсновноеПроизводство)
            ТОГДА "20 ПРЯМЫЕ РАСХОДЫ"
        ИНАЧЕ "ПРОЧЕЕ"
    КОНЕЦ КАК ВИД,
    ХозрасчетныйДвижения.Сумма КАК Сумма
ПОМЕСТИТЬ ВременнаяТаблицаДанных
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(&НП, &КП, ...) КАК Движения
;

Шаг 2: Вторым запросом выберем данные из временной таблицы, применив простое условие фильтрации к уже имеющимся полям.


ВЫБРАТЬ
    Т.СчетДт,
    Т.ВИД,
    Т.Сумма
ИЗ
    ВременнаяТаблицаДанных КАК Т
ГДЕ
    НЕ Т.ВИД ЕСТЬ NULL
    ИЛИ НЕ Т.Сумма ЕСТЬ NULL

Этот метод значительно упрощает отладку запроса в консоли и позволяет СУБД эффективнее строить план выполнения.

Важные нюансы работы с NULL в 1С

Проанализируем несколько критических моментов, которые часто упускают начинающие разработчики:

  1. Различие между NULL и «Пустой ссылкой»: Помните, что NULL — это полное отсутствие данных (например, при ЛЕВОЕ СОЕДИНЕНИЕ, когда в правой таблице нет соответствия). «Пустая ссылка» же является конкретным значением типа СправочникСсылка. Если ваша колонка содержит пустую ссылку, условие ЕСТЬ NULL на ней не сработает. В этом случае нужно использовать проверку: ГДЕ Поле <> ЗНАЧЕНИЕ(Справочник.ИмяСправочника.ПустаяСсылка).
  2. Функция ЕСТЬNULL: Если вы хотите не просто отфильтровать строки, а заменить NULL на осмысленное значение (например, на 0 для чисел), используйте ЕСТЬNULL(Поле, 0).
  3. Производительность (SARGability): Использование условий ИЛИ вместе с NULL часто приводит к тому, что СУБД не может использовать индексы таблиц (Full Table Scan). Если данных очень много (миллионы строк), старайтесь максимально фильтровать данные еще на этапе обращения к виртуальным таблицам (в параметрах условий), а не в итоговом ГДЕ.
  4. Группировка: Если вы используете СГРУППИРОВАТЬ ПО, помните, что все значения NULL будут собраны в одну группу. Это можно использовать для «схлопывания» пустых данных.

Пример итогового решения

Посмотрим на пример законченного кода, который объединяет вычисления и фильтрацию через временную таблицу, чтобы исключить строки с пустыми выплатами:


////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВременнаяТаблица.СчетДт КАК СчетДт,
    ВременнаяТаблица.Сумма КАК Сумма,
    ВременнаяТаблица.ПрочиеВыплаты КАК ПрочиеВыплаты,
    ВременнаяТаблица.ОКЛАД КАК ОКЛАД,
    ВременнаяТаблица.СтрахВзносы КАК СтрахВзносы
ИЗ
    ВременнаяТаблица КАК ВременнаяТаблица
ГДЕ
    (НЕ ВременнаяТаблица.ПрочиеВыплаты ЕСТЬ NULL)
    ИЛИ (НЕ ВременнаяТаблица.ОКЛАД ЕСТЬ NULL)
    ИЛИ (НЕ ВременнаяТаблица.СтрахВзносы ЕСТЬ NULL)

Подведем итог: для эффективного удаления «пустых» строк (содержащих NULL) в нескольких колонках, мы рекомендуем использовать временные таблицы для вычисления этих колонок, а затем применять фильтр ГДЕ НЕ Поле ЕСТЬ NULL с оператором ИЛИ. Это обеспечивает баланс между производительностью запроса и читаемостью кода программного продукта.

← На главную