Пустой запрос 1С: как проверить результат через Пустой()

Дата: 21.09.2026 07:06:43
Запросы
Язык запросов
РезультатЗапроса
Пакетный запрос
Отладка
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Любые

Пустой запрос 1С нужно обрабатывать отдельной веткой кода: отчёт должен написать «Нет данных», обработка не должна создавать пустой документ, а печатная форма не должна открываться чистым листом. Проверить, что результат запроса пустой, можно одним вызовом РезультатЗапроса.Пустой(). Ниже разобрано, когда этого метода достаточно, чем он отличается от Следующий() и Количество(), как проверять пакетный запрос и где искать причину, если запрос пустой, а данные в базе точно есть.

Как проверить, что результат запроса пустой

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

&НаКлиенте
Процедура ЗаполнитьТовары(Команда)

	Если Не ЗначениеЗаполнено(Объект.КонецПериода)
		Или Объект.НачалоПериода > Объект.КонецПериода Тогда
		ПоказатьПредупреждение(, "Укажите корректный период.");
		Возврат;
	КонецЕсли;

	Если Не ЗаполнитьТоварыНаСервере() Тогда
		ПоказатьПредупреждение(, "За выбранный период проведённых продаж нет.");
	КонецЕсли;

КонецПроцедуры

&НаСервере
Функция ЗаполнитьТоварыНаСервере()

	Объект.Товары.Очистить();

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

	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Ложь;
	КонецЕсли;

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

	Возврат Истина;

КонецФункции

Имена объектов в примере условные. Документ РеализацияТоваровУслуг с табличной частью Товары есть в УТ 11 и БП 3.0, но состав колонок в них отличается. Реквизиты НачалоПериода, КонецПериода и табличную часть Товары у обработки вы создаёте сами.

Разбор ключевых строк

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

Пустой(), Следующий() или Количество(): что выбрать

Проверить результат запроса на пустоту можно несколькими способами, и они не взаимозаменяемы:

СпособЧто делаетКогда подходит
РезультатЗапроса.Пустой()Отвечает только на вопрос, есть ли записиРанний выход или сообщение «нет данных» до обработки
Если Выборка.Следующий() Тогда … Иначе …Переходит к первой записи; Ложь — записей нетЗапрос возвращает одну строку: цену, остаток, последний документ
Выборка.Количество()Возвращает число записей выборкиНужно само число: для индикатора прогресса или текста «найдено N документов»
РезультатЗапроса.Выгрузить().Количество()Выгружает весь результат в таблицу значений и считает строкиТолько если таблица значений всё равно нужна дальше

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

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
	Цена = Выборка.Цена;
Иначе
	Цена = 0;
КонецЕсли;

Если нужен только факт существования — есть ли у контрагента хоть один непроведённый документ, есть ли движения по складу за месяц, — ограничьте запрос конструкцией ВЫБРАТЬ ПЕРВЫЕ 1. Пустой() ответит так же, но СУБД не придётся отдавать тысячи строк, которые никто не прочитает.

ВЫБРАТЬ ПЕРВЫЕ 1
	ИСТИНА КАК ЕстьДанные
ИЗ
	Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
	Реализация.Контрагент = &Контрагент
	И НЕ Реализация.Проведен
	И НЕ Реализация.ПометкаУдаления

Агрегатная функция без группировки

Запрос с СУММА, МАКСИМУМ или КОЛИЧЕСТВО без СГРУППИРОВАТЬ ПО возвращает одну строку, даже если под условие не попал ни один документ: в поле суммы будет NULL, в поле количества — 0. Пустой() для такого результата вернёт Ложь. Здесь проверяют не результат, а значение: агрегат оборачивают в ЕСТЬNULL() и сравнивают с нулём уже в коде.

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

Пакетный запрос: проверка каждого результата

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

Функция ДанныеДляПечати(МассивДокументов) Экспорт

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

	Результаты = Запрос.ВыполнитьПакет();
	// Результаты[0] — служебный результат ПОМЕСТИТЬ, данных документов в нём нет.
	РезультатШапки = Результаты[1];
	РезультатТоваров = Результаты[2];

	Если РезультатШапки.Пустой() Тогда
		Возврат Неопределено; // среди переданных нет ни одного проведённого документа
	КонецЕсли;

	Данные = Новый Структура;
	Данные.Вставить("Шапки", РезультатШапки.Выгрузить());
	Данные.Вставить("Товары", РезультатТоваров.Выгрузить());
	Возврат Данные;

КонецФункции

Для запроса с ПОМЕСТИТЬ в массиве лежит не содержимое временной таблицы, а служебный результат: одна строка с полем Количество, где записано число помещённых записей. Пустой() для него вернёт Ложь даже при нуле записей. Поэтому пустоту временной таблицы проверяют либо по этому числу, либо, что нагляднее, по результату следующего запроса, который из неё читает. Как устроены временные таблицы и пакеты, подробно описано в статье про таблицы запроса.

В длинном пакете индексы легко перепутать при правке текста. На время отладки пройдите по массиву циклом и выведите, что вернул каждый запрос:

Результаты = Запрос.ВыполнитьПакет();
Для Индекс = 0 По Результаты.ВГраница() Цикл
	Результат = Результаты[Индекс];
	Если Результат = Неопределено Тогда
		Сообщить(СтрШаблон("Запрос %1: результата нет", Индекс + 1));
	ИначеЕсли Результат.Пустой() Тогда
		Сообщить(СтрШаблон("Запрос %1: пусто", Индекс + 1));
	Иначе
		Сообщить(СтрШаблон("Запрос %1: записей %2", Индекс + 1, Результат.Выбрать().Количество()));
	КонецЕсли;
КонецЦикла;

Для запросов с ПОМЕСТИТЬ цикл покажет одну запись — ту самую служебную строку. Проверка на Неопределено страхует от элементов без результата, например от запросов УНИЧТОЖИТЬ. СтрШаблон() доступна с платформы 8.3.6; в конфигурациях на БСП 3.x вместо Сообщить() в серверном коде принято вызывать ОбщегоНазначения.СообщитьПользователю().

Пустой запрос 1С, хотя данные в базе есть

Запрос выполнился без ошибки, но вернул пусто. Обычно причина в одном из пунктов таблицы:

ПричинаКак выглядитЧто сделать
Параметр равен Неопределено или значению другого типаВ форме не заполнен реквизит; в параметр передали строку вместо ссылки или ссылку на другой справочникВывести параметры перед выполнением (код ниже), не выполнять запрос с незаполненными обязательными параметрами
Конец периода без времени&КонецПериода = 31.01.2026 0:00:00 — документы 31 января в выборку не попадают, а при одинаковых датах начала и конца результат пустойПередавать КонецДня() от даты окончания
Внутреннее соединениеОтбрасываются строки без пары во второй таблице: товар без цены, документ без движенийВременно заменить на ЛЕВОЕ СОЕДИНЕНИЕ и посмотреть, где появился NULL
Условие на правую таблицу левого соединения в ГДЕГДЕ Цены.Цена > 0 отсекает строки, где цены нет, и левое соединение работает как внутреннееПеренести условие в ПО (ЛЕВОЕ СОЕДИНЕНИЕ ... ПО Товары.Номенклатура = Цены.Номенклатура И Цены.Цена > 0) или явно пропустить NULL в ГДЕ: (Цены.Цена > 0 ИЛИ Цены.Цена ЕСТЬ NULL)
Сравнение с NULL через «=»ГДЕ Поле = NULL не выполняется ни для одной строкиПисать Поле ЕСТЬ NULL
Срез последних на слишком раннюю датуЦены установлены 10-го числа, запрос на 5-е — строки нетСверить период среза с датой первой записи регистра
Ограничение доступа на уровне записейПод администратором данные есть, под пользователем — пусто: с РАЗРЕШЕННЫЕ недоступные записи молча отбрасываютсяПроверить запрос под учётной записью этого пользователя и его права
Отбор по проведениюТестовые документы записаны, но не проведеныПроверить условия на Проведен и ПометкаУдаления

Если параметр не установлен совсем, пустого результата не будет — запрос упадёт с ошибкой «Не задано значение параметра». Коварнее вариант, когда параметр установлен, но в нём Неопределено: ошибки нет, строк тоже нет.

Как быстро найти причину

  1. Выведите параметры запроса с типами — процедура ниже. Часто причина видна уже здесь: Неопределено, пустая дата или ссылка не на тот справочник.
  2. Перенесите текст и параметры в консоль запросов. Их удобно взять в отладчике: остановитесь на строке Запрос.Выполнить() и посмотрите Запрос.Текст и Запрос.Параметры через «Вычислить выражение».
  3. В консоли убирайте условия из ГДЕ по одному, пока не появятся строки. Последнее убранное условие и есть причина.
  4. Замените внутренние соединения на левые и выведите поля присоединённых таблиц: колонка из NULL покажет таблицу, в которой не нашлось пары.
  5. В пакете проверяйте временные таблицы по одной: поставьте после подозрительной ВЫБРАТЬ * ИЗ ВТИмя и выполните пакет до этого места.

Процедура для первого шага. Её можно положить в серверный общий модуль и вызвать перед Запрос.Выполнить() на время отладки:

Процедура ВывестиПараметрыЗапроса(Запрос) Экспорт

	Для Каждого ОписаниеПараметра Из Запрос.НайтиПараметры() Цикл

		Имя = ОписаниеПараметра.Имя;
		Если Не Запрос.Параметры.Свойство(Имя) Тогда
			Сообщить(СтрШаблон("&%1 - не установлен", Имя));
			Продолжить;
		КонецЕсли;

		Значение = Запрос.Параметры[Имя];
		Если Значение = Неопределено Тогда
			Представление = "Неопределено";
		ИначеЕсли ТипЗнч(Значение) = Тип("Массив") Тогда
			Представление = СтрШаблон("массив, элементов: %1", Значение.Количество());
		Иначе
			Представление = Строка(Значение);
		КонецЕсли;

		Сообщить(СтрШаблон("&%1 = %2 [%3]", Имя, Представление, Строка(ТипЗнч(Значение))));

	КонецЦикла;

КонецПроцедуры

НайтиПараметры() возвращает все параметры из текста запроса, а Запрос.Параметры — структура с тем, что реально установлено. Сравнение сразу показывает забытый параметр или опечатку в имени. Дата выводится со временем, так что конец периода в 0:00:00 тоже заметен.

Типичные ошибки

  • Запрос на клиенте. Новый Запрос в процедуре с директивой &НаКлиенте в тонком клиенте даёт ошибку «Тип не определен (Запрос)». Проверку пустоты переносите в серверную функцию.
  • Потерянная первая строка. Сначала Если Выборка.Следующий() Тогда для проверки, потом Пока Выборка.Следующий() Цикл — цикл начнётся со второй записи. Для проверки берите Пустой(), а если Следующий() уже вызван, обработайте текущую запись до цикла или вызовите Выборка.Сбросить().
  • NULL вместо «нет данных». Запрос с агрегатом без группировки вернул строку, Пустой() вернул Ложь, а сложение с полем падает с ошибкой «Преобразование значения к типу Число не может быть выполнено». Решение — ЕСТЬNULL() в тексте запроса.
  • Двойное выполнение. Если Запрос.Выполнить().Пустой(), а затем снова Запрос.Выполнить().Выбрать() — два обращения к базе вместо одного. Результат сохраняйте в переменную.
  • Пустой() у результата ПОМЕСТИТЬ. Всегда Ложь: там служебная строка с количеством. Проверяйте запрос пакета, который читает временную таблицу.
  • Временная таблица из другого запроса. Без общего МенеджерВременныхТаблиц второй запрос не видит таблицу первого. Это ошибка «Таблица не найдена», а не пустой результат.

Частые вопросы

Чем Пустой() отличается от Выборка.Количество() = 0?

Ответ одинаковый, но Пустой() не создаёт выборку и сразу читается как намерение: данных нет — выходим. Количество() берите, когда само число нужно дальше.

Как проверить, что временная таблица пустая?

В пакете — по полю Количество результата запроса с ПОМЕСТИТЬ или по результату запроса, который из неё выбирает. Если таблица хранится в менеджере временных таблиц между запросами, выполните отдельный ВЫБРАТЬ ПЕРВЫЕ 1 из неё с тем же менеджером и проверьте Пустой().

Почему запрос с СУММА() не пустой, хотя документов нет?

Агрегатная функция без СГРУППИРОВАТЬ ПО всегда возвращает одну строку, при отсутствии данных сумма в ней — NULL. Используйте ЕСТЬNULL(СУММА(...), 0) и проверяйте значение, а не пустоту результата.

Можно ли вызвать Пустой() на клиенте?

В тонком и веб-клиенте — нет: объекты Запрос и РезультатЗапроса доступны только на сервере, в толстом клиенте и во внешнем соединении. Выполните запрос в серверной функции и верните на клиент Булево или нужные значения.

Запрос пустой только у одного пользователя. Что проверить?

Ограничение доступа на уровне записей (запрос с РАЗРЕШЕННЫЕ отбрасывает недоступные строки без ошибки) и параметры, которые берутся из настроек пользователя. Проще всего повторить запрос в консоли под его учётной записью.

Когда проще заказать

Если отчёт или обработка молча ничего не выводит, а разбирать чужой запрос на десяток соединений некогда, отдайте задачу программисту. Разместить задачу на площадке можно бесплатно, оценку пришлют в течение рабочего дня. Исправление и доработка запросов входят в услугу по отчётам и обработкам 1С.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.