Почему запрос в 1С выдает разные результаты в консоли и в программном коде

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

Разработка сложных отчетов и механизмов выгрузки данных в 1С часто начинается с написания запроса в консоли. Это удобный инструмент, позволяющий быстро проверить логику соединений и правильность получения данных. Однако нередко программисты сталкиваются с досадной ситуацией: один и тот же запрос в консоли отрабатывает идеально, заполняя все колонки, а при выполнении в коде (в режиме «Предприятие») часть полей (например, цены или штрихкоды) оказывается пустой.

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

Разбор практического примера: Анализ запроса

Рассмотрим ситуацию, когда разработчик использует запрос с несколькими временными таблицами для получения данных о номенклатуре, её штрихкодах и актуальных ценах. Проблема заключается в том, что конечное левое соединение не «подцепляет» данные из правых таблиц при программном выполнении.

Типичная структура такого запроса выглядит следующим образом:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК НоменклатураСсылка,
    Номенклатура.Наименование КАК НоменклатураНаименование,
    Номенклатура.СтавкаНДС
ПОМЕСТИТЬ ВТ_Номенклатура
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка В ИЕРАРХИИ(&Ссылка);

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Штрихкоды.Владелец,
    Штрихкоды.Штрихкод
ПОМЕСТИТЬ ВТ_Штрихкод
ИЗ
    РегистрСведений.Штрихкоды КАК Штрихкоды
ГДЕ
    Штрихкоды.Владелец В (ВЫБРАТЬ ВТ_Номенклатура.НоменклатураСсылка ИЗ ВТ_Номенклатура);

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Цены.Номенклатура,
    Цены.Цена
ПОМЕСТИТЬ ВТ_Цены
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ТипЦен = &ВидЦены И Валюта = &Валюта) КАК Цены;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Номенклатура.НоменклатураНаименование,
    ВТ_Штрихкод.Штрихкод,
    ВТ_Цены.Цена
ИЗ
    ВТ_Номенклатура КАК ВТ_Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Штрихкод КАК ВТ_Штрихкод ПО ВТ_Номенклатура.НоменклатураСсылка = ВТ_Штрихкод.Владелец
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Цены КАК ВТ_Цены ПО ВТ_Номенклатура.НоменклатураСсылка = ВТ_Цены.Номенклатура

В консоли запросов такой код может возвращать полный набор данных, включая цену и штрихкод. Однако в коде колонки Цена и Штрихкод могут оказаться пустыми (содержать NULL). Разберемся, в чем могут быть причины.

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

Это самая распространенная причина, которая кажется очевидной, но часто пропускается при отладке. Рассмотрим, как параметры заполняются в консоли и в коде.

В консоли разработчик обычно выбирает значения визуально из списка. В коде же значения часто ищутся программно. Проанализируем ситуацию: если в коде параметр &Валюта ищется методом НайтиПоКоду("840"), а в справочнике такой код отсутствует или валюта помечена на удаление (и создана новая с другим внутренним идентификатором), запрос не выдаст ошибку. Он просто вернет пустую таблицу ВТ_Цены, так как ни одна запись не будет соответствовать пустой ссылке или битой ссылке в условии виртуальной таблицы СрезПоследних.

Рекомендация: Всегда проверяйте через отладчик, что именно попадает в Запрос.УстановитьПараметр(). Убедитесь, что передаваемая ссылка — это не Неопределено и не пустая ссылка неожиданного типа.

Причина №2: Влияние системы прав доступа (RLS)

Проанализируем ситуацию с точки зрения прав доступа. Консоль запросов чаще всего запускается под пользователем с полными правами (администратором). В этом случае механизм Row Level Security (RLS) отключен.

Когда тот же запрос выполняется в режиме «Предприятие» под обычным пользователем, платформа 1С неявно модифицирует текст запроса, добавляя условия фильтрации. Если у пользователя нет прав на просмотр цен определенного типа или штрихкодов конкретных групп номенклатуры, соответствующие временные таблицы просто окажутся пустыми. Левое соединение отработает штатно, но вместо данных вы получите пустоту.

Выясним причину, выполнив код в привилегированном режиме. Если данные появились — проблема в настройках прав доступа.

Причина №3: Особенности виртуальных таблиц и границ периода

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

  1. Если в параметр передана дата без времени ('2023-10-27 00:00:00'), то срез будет взят на начало дня. Если цена была установлена в полдень, она не попадет в результат.
  2. Для получения актуальных данных на текущий момент лучше использовать КонецПериода(ТекущаяДата(), ДЕНЬ) или вообще не указывать параметр даты, если нужен срез на "сейчас".

Также обратите внимание на условия внутри параметров виртуальной таблицы. В нашем примере фильтрация по валюте и типу цен происходит прямо в параметрах СрезПоследних. Это работает быстрее, чем использование ГДЕ, но если хотя бы один из параметров передан неверно (например, тип цены), вся виртуальная таблица вернет пустой результат.

Причина №4: Использование Менеджера временных таблиц

Если ваш запрос разбит на несколько частей в программном коде (несколько объектов Запрос), крайне важно использовать МенеджерВременныхТаблиц. Рассмотрим, как это работает:

В консоли весь текст запроса выполняется в одном контексте, и временные таблицы сохраняются между пакетами автоматически. В коде, если вы выполнили один запрос для создания ВТ_Номенклатура, а затем создали новый объект Запрос для получения цен, вторая часть «не увидит» временную таблицу из первой, если им не назначен общий МенеджерВременныхТаблиц.

Пример правильной инициализации:


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Далее выполнение пакетов запроса

Причина №5: Неявные преобразования типов при соединении

Разберем ситуацию, когда условия соединения кажутся одинаковыми, но работают по-разному. В 1С ссылка на объект — это сложный тип. Если в одной из временных таблиц поле ссылки случайно было приведено к строке или другому типу (что иногда случается при использовании сложных вложенных запросов или объединений), то в консоли механизм может «сгладить» это различие, тогда как SQL-сервер при реальном исполнении просто не сопоставит GUID ссылки и его строковое представление.

Всегда проверяйте типы полей во временных таблицах. Для этого можно использовать функцию ТИПЗНАЧЕНИЯ прямо в консоли, чтобы убедиться в однородности данных.

Алгоритм отладки «пустых» колонок

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

  1. Проверка параметров: Выведите в журнал регистрации или через Сообщить() значения всех параметров непосредственно перед Запрос.Выполнить().
  2. Выгрузка временных таблиц: В коде после выполнения запроса выгрузите каждую временную таблицу в отдельную таблицу значений (например, используя метод Запрос.ВыполнитьПакет()) и посмотрите их содержимое в отладчике. Так вы поймете, на каком этапе «теряются» данные.
  3. Тестирование под полными правами: Запустите обработку под пользователем с правами «Администратор системы». Если данные появились — ищите проблему в RLS.
  4. Сравнение текста: Скопируйте текст запроса из конфигуратора в консоль еще раз, но параметры заполните точно такими же значениями, какие вы увидели в отладчике (включая время в датах).

Таким образом, большинство проблем с «неработающими» соединениями сводятся к нюансам окружения и данных, а не к ошибкам самого движка запросов 1С. Системный подход к анализу каждого этапа формирования временных таблиц позволит вам быстро найти и устранить причину расхождения результатов.

← На главную