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

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

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

Причина 1. Особенности метода Выгрузить() и расход памяти сервера

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


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

Главный нюанс заключается в разнице между методами Выгрузить() и Выбрать():

  1. Метод Выгрузить() выполняет загрузку всех строк результата запроса целиком в оперативную память сервера (объект ТаблицаЗначений рабочего процесса rphost). Если выборка содержит десятки или сотни тысяч строк (например, срез последних по крупному регистру), рабочему процессу может не хватить выделенной памяти или сработать внутреннее ограничение платформы. В результате выгрузка сбрасывается или возвращает пустой объект.
  2. Метод Выбрать() создает объект ВыборкаИзРезультатаЗапроса, который считывает данные из СУБД порционно (в режиме потока) по мере вызова метода Следующий(). Это практически не нагружает оперативную память сервера.

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


&НаСервере
Процедура СформироватьЦеныНаСервере()
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	СтоимостьТоваровСрезПоследних.Стоимость КАК Стоимость,
		|	СтоимостьТоваровСрезПоследних.СтоимостьДопРасходы КАК СтоимостьДопРасходы,
		|	СтоимостьТоваровСрезПоследних.АналитикаУчетаНоменклатуры.Номенклатура КАК Номенклатура,
		|	СтоимостьТоваровСрезПоследних.АналитикаУчетаНоменклатуры.Характеристика КАК Характеристика
		|ИЗ
		|	РегистрСведений.СтоимостьТоваров.СрезПоследних(&ДатаЦены, ) КАК СтоимостьТоваровСрезПоследних";
		
	Запрос.УстановитьПараметр("ДатаЦены", Новый Граница(КонецДня(Объект.Дата), ВидГраницы.Включая));
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		// Обработка полученных строк потоком
		ОбработатьСтроку(Выборка.Номенклатура, Выборка.Стоимость);
	КонецЦикла;
	
КонецПроцедуры

Причина 2. Контекст исполнения и область видимости переменных

В приведенном выше примере процедура СформироватьЦеныНаСервере() объявляет локальную переменную РезультатЗапроса. Понятно, что даже если запрос отработает успешно, после завершения работы процедуры локальная переменная уничтожится во временной области памяти сервера.

В отличие от кода обработки, Консоль запросов принудительно связывает полученные данные с реквизитами своей формы для отображения пользователю. Для передачи результатов выборки из сервера на клиент в управляемом приложении необходимо помещать данные в коллекцию формы типа ДанныеФормыКоллекция (например, через ЗначениеВРеквизитФормы()) или использовать возврат значений через функции.

Причина 3. Использование объекта Граница для среза последних

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

Разберем пример создания параметра:


ДатаГраницы = КонецДня(Объект.Дата);
Запрос.УстановитьПараметр("ДатаЦены", Новый Граница(ДатаГраницы, ВидГраницы.Включая));

Причина 4. Влияние Безопасного режима и прав доступа (RLS)

Внешние обработки (файлы .epf) запускаются платформой в безопасном режиме (когда БезопасныйРежим() = Истина). В этом контексте платформа может автоматически накладывать ограничения на доступ к служебным регистрам и данным.

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


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

Подведем итоги

Если запрос работает в консоли, но возвращает 0 записей в обработке:

  1. Замените метод Выгрузить() на потоковую выборку Выбрать() с циклом Пока Выборка.Следующий() Цикл, чтобы избежать проблем с выделением памяти.
  2. Проверьте корректность передачи параметров даты и используйте объект Граница.
  3. Убедитесь, что полученные на сервере данные сохраняются в реквизиты формы, а не теряются вместе с локальными переменными процедуры.
  4. Учитывайте влияние безопасного режима внешних обработок и прав доступа RLS.
← На главную