Почему запрос в коде 1С возвращает пустые значения в ОБЪЕДИНИТЬ ВСЕ, хотя в консоли все работает корректно?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

Разработка сложных отчетов и механизмов в 1С часто сопровождается использованием объединений (ОБЪЕДИНИТЬ ВСЕ) и виртуальных таблиц регистров накопления. Одной из наиболее типичных и при этом трудноуловимых проблем является ситуация, когда в консоли запросов результат выглядит правильным, а при выполнении того же самого кода в конфигураторе часть данных (например, фактические данные из регистра) пропадает. Проанализируем эту ситуацию на примере задачи сопоставления плановых данных из документа и фактических затрат из регистра НезавершенноеПроизводство.

Разбор архитектуры запроса

Рассмотрим структуру запроса, с которым возникла проблема. Мы видим попытку объединить два источника данных: табличную часть документа ртТЭООбъекта (плановые показатели) и виртуальную таблицу ОстаткиИОбороты регистра накопления (фактические затраты). В первой части объединения выбираются данные из документа, а во второй — данные из регистра, после чего результат группируется по статьям затрат.


Запрос.Текст = 
    "ВЫБРАТЬ
    |    ИТОГ.СтатьиЗатрат,
    |    СУММА(ИТОГ.Площадь) КАК Площадь,
    |    ...
    |    СУММА(ИТОГ.Факт) КАК Факт,
    |    СУММА(ИТОГ.ПланФакт) КАК ПланФакт
    |ИЗ
    |    (ВЫБРАТЬ
    |        ртТЭООбъектаСтатьи.СтатьиЗатрат КАК СтатьиЗатрат,
    |        ...
    |        0 КАК Факт,
    |        ...
    |    ИЗ
    |        Документ.ртТЭООбъекта.Статьи КАК ртТЭООбъектаСтатьи
    |    ГДЕ
    |        ртТЭООбъектаСтатьи.Ссылка = &ТЭО
    |    
    |    ОБЪЕДИНИТЬ ВСЕ
    |    
    |    ВЫБРАТЬ
    |        НезавершенноеПроизводствоОстаткиИОбороты.СтатьяЗатрат,
    |        ...
    |        НезавершенноеПроизводствоОстаткиИОбороты.СтоимостьРасход,
    |        0
    |    ИЗ
    |        РегистрНакопления.НезавершенноеПроизводство.ОстаткиИОбороты КАК НезавершенноеПроизводствоОстаткиИОбороты
    |    ГДЕ
    |        НезавершенноеПроизводствоОстаткиИОбороты.Заказ = &ЗаказПокупателя
    |        И НезавершенноеПроизводствоОстаткиИОбороты.НоменклатурнаяГруппа = &ОбъектСтроительства) КАК ИТОГ
    |
    |СГРУППИРОВАТЬ ПО
    |    ИТОГ.СтатьиЗатрат";

Если в результате выполнения такого запроса колонка Факт остается нулевой, хотя мы точно знаем, что данные в регистре есть, это означает, что вторая ветка объединения возвращает пустой результат. Выясним основные причины, по которым это происходит.

Причина №1: Несоответствие типов параметров

Это самая распространенная причина "магических" расхождений. В консоли запросов программист часто выбирает параметры интерактивно, и система автоматически подставляет правильную ссылку. В коде же параметры передаются через переменные, в которых может оказаться объект другого типа.

Важный технический нюанс: В 1С запросы к СУБД выполняются строго по типам. Если в параметре &ОбъектСтроительства ожидается ссылка на справочник НоменклатурныеГруппы, а вы передаете ссылку на справочник Номенклатура, запрос не выдаст ошибку. Он просто попытается найти записи в регистре, где поле НоменклатурнаяГруппа равно переданной ссылке на номенклатуру. Поскольку типы не совпадают, СУБД вернет пустой результат для этой ветки объединения.

Проверим это в коде:


// Ошибка может быть здесь
Запрос.УстановитьПараметр("ОбъектСтроительства", ОбъектСтроительства); 
// Нужно убедиться, что ОбъектСтроительства — это именно НоменклатурнаяГруппа

Причина №2: Неправильная работа с виртуальными таблицами

Проанализируем использование виртуальной таблицы ОстаткиИОбороты. В исходном запросе условия по заказу и номенклатурной группе наложены в предложении ГДЕ. Это серьезная методическая ошибка.

Рассмотрим разницу:

  1. Условие в ГДЕ: Платформа сначала считывает и рассчитывает итоги по ВСЕМ записям регистра за указанный период (или за все время), и только потом фильтрует их. Это не только замедляет запрос, но и может приводить к странным результатам при работе с итогами.
  2. Условие в параметрах виртуальной таблицы: Фильтрация происходит на этапе обращения к индексам СУБД. Платформа выбирает только нужные данные.

Правильный вариант обращения к регистру должен выглядеть так:


ИЗ
    РегистрНакопления.НезавершенноеПроизводство.ОстаткиИОбороты( , , , , 
        Заказ = &ЗаказПокупателя И НоменклатурнаяГруппа = &ОбъектСтроительства) КАК НезавершенноеПроизводствоОстаткиИОбороты

Причина №3: Права доступа и RLS (Record Level Security)

Если в консоли запросов вы работаете под учетной записью администратора (полные права), а в режиме предприятия код выполняется под обычным пользователем, может сработать механизм RLS. Если на регистр НезавершенноеПроизводство наложены ограничения (например, пользователь может видеть затраты только по своему подразделению), то запрос в коде вернет только разрешенные данные, что может выглядеть как пустая таблица, если данных по текущему подразделению нет.

Методика пошаговой отладки запроса

Чтобы выяснить, почему объединение работает не так, как ожидается, пройдем по следующим шагам:

1. Изоляция ветвей объединения. Закомментируйте первую часть запроса и само ОБЪЕДИНИТЬ ВСЕ. Оставьте только выборку из регистра. Если запрос возвращает пустую таблицу — проблема в параметрах &ЗаказПокупателя или &ОбъектСтроительства.

2. Проверка типов в отладчике. В момент установки параметров запроса в коде воспользуйтесь табло или вычислите выражение, чтобы проверить тип значения. Например: ТипЗнч(ОбъектСтроительства). Сравните его с типом измерения в регистре.

3. Проверка записи данных. Убедитесь, что данные, которые вы пытаетесь выбрать, уже записаны в базу данных. Если вы формируете запрос при открытии нового (еще не записанного) документа и используете его ссылку в качестве параметра, то в базе данных по этой ссылке еще ничего не будет найдено.

4. Использование временных таблиц. Рассмотрим возможность переписать запрос с использованием временных таблиц. Это упрощает отладку, так как вы можете посмотреть промежуточное состояние данных через МенеджерВременныхТаблиц.


Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// ... выполнение первой части во временную таблицу План ...
// ... выполнение второй части во временную таблицу Факт ...
// ... итоговое объединение из временных таблиц ...

Логические ошибки при суммировании

Обратим внимание на важный момент в исходном запросе: СУММА(ИТОГ.ЦенаБезНДСДоговор). Проанализируем ситуацию: если по одной статье затрат в документе несколько строк, простое суммирование цены даст бессмысленное число. Обычно цена — это справочный показатель или результат деления суммы на количество. В группировках следует суммировать только аддитивные величины (количество, сумма, стоимость), а расчетные показатели вычислять уже в итоговой выборке или в ресурсах компоновки данных.

Выяснив причину (как в случае автора темы, где была перепутана Номенклатура с Номенклатурной группой), мы понимаем, что внимательность к типам данных — это ключевой навык при работе с метаданными 1С. Всегда проверяйте параметры запроса перед его выполнением, особенно если используете значения из реквизитов формы или объектов.

← На главную