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

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

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

Разбор типичной ошибки в алгоритме вывода данных

Рассмотрим фрагмент кода, с которым возникла проблема. Программист пытается выбрать данные из регистра накопления ЗарплатаКВыплате, соединяя их с табличной частью документа НачислениеЗарплаты. Однако, даже если запрос находит данные, в итоговом табличном документе отображается либо пустота, либо только последняя найденная запись.

Первая и самая очевидная ошибка кроется в алгоритме обхода выборки. Посмотрим на исходный код:


Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    ОбластьЗначенияТаблицы.Параметры.Месяц = Выборка.Месяц;
    ОбластьЗначенияТаблицы.Параметры.Начислено = Выборка.Начислено;
    ОбластьЗначенияТаблицы.Параметры.НДФЛ = Выборка.НДФЛ;
    ОбластьЗначенияТаблицы.Параметры.Удержано = Выборка.Удержано;
    ОбластьЗначенияТаблицы.Параметры.Итого = Выборка.Итого;
КонецЦикла;
ТабДок.Вывести(ОбластьЗначенияТаблицы);

В данном примере метод ТабДок.Вывести(ОбластьЗначенияТаблицы) расположен вне цикла. Это означает, что программа перебирает все строки, последовательно перезаписывая параметры области макета, и только после окончания перебора выводит одну-единственную (последнюю) строку. Чтобы отчет формировался корректно, вывод каждой строки должен происходить непосредственно внутри цикла.

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


Пока Выборка.Следующий() Цикл
    // Заполняем параметры области из текущей записи выборки
    ОбластьЗначенияТаблицы.Параметры.Заполнить(Выборка); 
    // Если имена параметров в макете совпадают с именами полей в запросе, 
    // можно использовать метод Заполнить() для сокращения кода.
    
    ТабДок.Вывести(ОбластьЗначенияТаблицы); // Выводим текущую строку в отчет
КонецЦикла;

Проблема пустого результата: Внутреннее соединение и RLS

Если после исправления цикла отчет все равно остается пустым, причину следует искать в самом тексте запроса или в настройках прав доступа. В рассматриваемом случае запрос использует ВНУТРЕННЕЕ СОЕДИНЕНИЕ регистра с табличной частью документа:


ИЗ РегистрНакопления.ЗарплатаКВыплате КАК ЗарплатаКВыплате
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.НачислениеЗарплаты.НДФЛ КАК НачислениеЗарплатыНДФЛ
ПО ЗарплатаКВыплате.ДокументОснование = НачислениеЗарплатыНДФЛ.Ссылка

Проанализируем риски такого подхода:

  1. Отсечение данных: ВНУТРЕННЕЕ СОЕДИНЕНИЕ (Inner Join) исключает из результата все записи, для которых не найдено соответствие во второй таблице. Если в регистре ЗарплатаКВыплате есть запись, но в документе НачислениеЗарплаты по какой-то причине пуста табличная часть НДФЛ, такая строка вообще не попадет в выборку. Рекомендуется использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы видеть все движения по регистру, даже если аналитика по НДФЛ отсутствует.
  2. Дублирование сумм: Если в табличной части документа у одного сотрудника несколько строк по НДФЛ (например, разные ставки), то при соединении сумма из регистра «размножится». Это приведет к неверным итогам в отчете.
  3. Влияние RLS: Часто проблема скрывается в механизме ограничений доступа на уровне записей (RLS). Если у пользователя настроены права доступа только по определенным организациям, 1С неявно добавляет условия в запрос. Если в параметрах запроса передана организация, на которую у пользователя нет полных прав, запрос вернет 0 строк без каких-либо предупреждений. Как выяснилось в обсуждении, именно фильтр по Организации блокировал вывод данных. Попробуйте выполнить запрос под пользователем с полными правами, чтобы исключить влияние RLS.

Работа с составными типами данных

В запросе автора используется обращение через точку: ЗарплатаКВыплате.ДокументОснование.Начислено. Это является критической ошибкой производительности, особенно если поле ДокументОснование имеет составной тип данных (может содержать ссылки на разные виды документов).

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

Как оптимизировать:

Проверка периодов и типов параметров

Еще один важный момент — передача параметров даты. В коде автора используется НачалоМесяца(ДатаНачала) и КонецМесяца(ДатаОкончания). Это правильный подход для работы с регистрами накопления, где ПериодВзаиморасчетов обычно фиксируется на начало месяца.

Проанализируем ситуацию в отладчике. Если на точке останова Выборка.Следующий() в табло отображается «Ошибка чтения значения», это не всегда означает ошибку в коде. Часто это штатное поведение отладчика 1С до того момента, пока курсор выборки не перешел к первой записи. Чтобы убедиться в наличии данных, используйте метод Выборка.Количество() или выгрузите результат запроса в таблицу значений: ТЗ = Запрос.Выполнить().Выгрузить();. Если таблица пуста — ищите проблему в условиях ГДЕ.

Итоговый пример исправленного кода

С учетом всех разобранных нюансов, представим оптимизированный вариант решения задачи:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Зарплата.Сотрудник КАК Сотрудник,
|	Зарплата.Организация КАК Организация,
|	Зарплата.ПериодВзаиморасчетов КАК Месяц,
|	Зарплата.СуммаКВыплате КАК Итого,
|	ВЫРАЗИТЬ(Зарплата.ДокументОснование КАК Документ.НачислениеЗарплаты).Начислено КАК Начислено,
|	ЕСТЬNULL(НДФЛ.Налог, 0) КАК НДФЛ
|ИЗ
|	РегистрНакопления.ЗарплатаКВыплате КАК Зарплата
|		ЛЕВОЕ СОЕДИНЕНИЕ Документ.НачислениеЗарплаты.НДФЛ КАК НДФЛ
|		ПО Зарплата.ДокументОснование = НДФЛ.Ссылка
|ГДЕ
|	Зарплата.ПериодВзаиморасчетов МЕЖДУ &ДатаНачала И &ДатаОкончания
|	И Зарплата.Организация = &Организация
|	И Зарплата.Сотрудник = &Сотрудник";

Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(Объект.ДатаНачала));
Запрос.УстановитьПараметр("ДатаОкончания", КонецМесяца(Объект.ДатаОкончания));
Запрос.УстановитьПараметр("Организация", Объект.Организация);
Запрос.УстановитьПараметр("Сотрудник", Объект.Сотрудник);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    ОбластьЗначенияТаблицы.Параметры.Заполнить(Выборка);
    ТабДок.Вывести(ОбластьЗначенияТаблицы);
КонецЦикла;

Использование ЛЕВОЕ СОЕДИНЕНИЕ гарантирует, что данные по выплатам не пропадут из отчета, даже если по ним не зафиксирован НДФЛ в документе. А вызов метода Вывести() внутри цикла обеспечит корректное построчное формирование отчета.

← На главную