Проверка результата запроса на пустоту во встроенном языке 1С 8.3

· 9 мин

Содержание

Проверяет пустоту результата запроса метод Результат.Пустой() — он возвращает Истина, когда в выборке нет ни одной строки, и при этом не читает сами данные. Это самый быстрый способ, и в большинстве кода хватает именно его.

Остальные приёмы нужны, когда пустоты мало — требуется ещё и число строк, проверка на лету в отладчике или контроль пустой временной таблицы внутри пакета. Ниже — рабочие варианты с кодом и ловушка, из-за которой Пустой() иногда «врёт».

Почему запрос в 1С возвращает пустой результат

Пустая выборка — это не ошибка платформы, а штатный исход: условиям запроса просто ничего не соответствует. Типичные причины:

  • 🔎 Условие в ГДЕ слишком жёсткое — не нашлось ни одной подходящей записи.
  • 🧩 В параметр попало не то значение — пустая ссылка, Неопределено, лишние пробелы в строке.
  • 📅 Границы периода заданы так, что ни один документ в них не попадает (частая беда с моментом времени и концом дня).
  • 🗑️ Помеченные на удаление записи отфильтрованы, а других нет.
  • 🔐 Ограничения доступа (RLS) — пользователь физически не видит данные, которые есть в базе.

Отсюда простое правило: прежде чем «чинить» запрос, проверьте значения параметров. В девяти случаях из десяти в параметр уходит пустая ссылка или не та дата, а сам текст запроса корректен.

Проверить это можно в пару строк перед выполнением:

Если Не ЗначениеЗаполнено(Артикул) Тогда
    Сообщить("Артикул не задан — запрос гарантированно вернёт пусто");
    Возврат;
КонецЕсли;

ЗначениеЗаполнено() отсекает пустую ссылку, пустую строку и Неопределено одним вызовом. Если параметр заполнен, а результат всё равно пуст — значит, дело в условиях или данных, и дальше включаем способы проверки ниже.

Метод Пустой() — самая быстрая проверка

Объект РезультатЗапроса, который возвращает Запрос.Выполнить(), имеет метод Пустой(). Он отвечает на единственный вопрос — есть ли хоть одна строка:

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

Результат = Запрос.Выполнить();

Если Результат.Пустой() Тогда
    Сообщить("По артикулу " + Артикул + " ничего не найдено");
    Возврат;
КонецЕсли;

Почему именно Пустой(), а не что-то другое:

  • он не выгружает данные в память и не создаёт выборку — платформе достаточно узнать факт наличия строк;
  • на больших результатах это заметно дешевле, чем Выгрузить().Количество();
  • читается однозначно — любой, кто откроет код, сразу поймёт замысел.

Если вам нужен только факт «есть/нет», добавьте в запрос ВЫБРАТЬ ПЕРВЫЕ 1. Платформа прекратит выборку после первой подходящей записи, и проверка Пустой() отработает ещё быстрее.

Подсчёт строк: когда важно не «есть ли», а «сколько»

Иногда одного факта мало — нужно именно количество. Здесь Пустой() не помощник, берём другие инструменты.

Через выборку. У объекта ВыборкаИзРезультатаЗапроса есть метод Количество() — он отдаёт число записей текущего уровня:

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Сообщить("Найдено строк: " + Выборка.Количество());

Через выгрузку в таблицу значений. Удобно, когда данные всё равно нужны дальше:

Таблица = Запрос.Выполнить().Выгрузить();
Если Таблица.Количество() = 0 Тогда
    // пусто
КонецЕсли;

Через агрегат в самом запросе. Если нужна только цифра и вытаскивать строки незачем, пусть считает сервер СУБД:

Запрос.Текст =
    "ВЫБРАТЬ
    |    КОЛИЧЕСТВО(*) КАК Кол
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.Артикул = &Артикул";

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

Обратите внимание на последний пример — у него есть важная особенность, из-за которой на нём часто спотыкаются. Разберём её отдельно в разделе про ошибки.

Ещё один нюанс касается группировок. Если в выборке есть иерархия или итоги (ИТОГИ ПО), метод Количество() отдаёт число записей только текущего уровня обхода. Для подсчёта всех детальных строк либо обходите выборку с типом ОбходРезультатаЗапроса.Прямой, либо используйте Выгрузить() — таблица значений хранит плоский список без учёта группировок.

Что именно вам нужно проверить?

Проверка результата в отладчике и консоли запросов

Пока код пишется, не обязательно вставлять Сообщить() — результат удобно смотреть прямо в отладчике Конфигуратора.

Порядок такой:

  1. Поставьте точку останова (F9) на строке после Запрос.Выполнить().
  2. Запустите в режиме отладки. Когда выполнение остановится, наведите курсор на переменную Результат — во всплывающей подсказке платформа покажет свойства объекта.
  3. Чтобы оценить пустоту явно, откройте окно «Вычислить выражение» (Shift+F9) и наберите Результат.Пустой() — получите Истина или Ложь.
  4. Чтобы увидеть сами строки, в том же окне вычислите Результат.Выгрузить() и раскройте полученную таблицу значений.

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

Отладка идёт по реальной базе. Если запрос не только читает, но и вызывает процедуры с изменением данных, запускайте его на копии, а не на рабочей базе.

Корректная обработка пустого ответа: почему Попытка не нужна

Здесь прячется главное недопонимание. Пустой результат не вызывает исключения. Конструкция Попытка … Исключение … КонецПопытки ловит ошибки — неверный текст запроса, недоступную таблицу, сбой соединения, — но не отсутствие строк. Оборачивать проверку пустоты в Попытку бессмысленно: ветка Исключение просто не сработает.

Цикл по пустой выборке тоже ничего не ломает — тело просто не выполнится ни разу:

Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
    // при пустом результате сюда не зайдём ни разу — и это нормально
    ОбработатьСтроку(Выборка);
КонецЦикла;

Поэтому правильный шаблон — не перехват ошибки, а явная проверка и понятное поведение по умолчанию:

Результат = Запрос.Выполнить();

Если Результат.Пустой() Тогда
    // осмысленный ответ вместо тихого «ничего не произошло»
    ВызватьИсключение "Не найдены строки для обработки по заданным условиям";
    // или: вернуть пустой массив, значение по умолчанию, показать сообщение пользователю
КонецЕсли;

ВызватьИсключение здесь — ваше решение, а не поведение платформы: вы сами превращаете пустоту в ошибку, если по логике метода отсутствие данных недопустимо. А если допустимо — возвращаете пустую коллекцию или значение по умолчанию. Главное — не оставлять пустой результат необработанным: иначе дальше по коду вылезет Неопределено там, где ждали значение.

Пустые временные таблицы в пакете запросов

В пакетных запросах промежуточные данные складывают во временные таблицы через ПОМЕСТИТЬ. Бывает нужно проверить: а попало ли туда хоть что-нибудь, прежде чем строить на этой таблице следующий запрос.

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

МенеджерВТ = Новый МенеджерВременныхТаблиц;

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

// отдельным запросом проверяем, что во временной таблице есть данные
Запрос.Текст =
    "ВЫБРАТЬ
    |    ВремОстатки.Номенклатура
    |ИЗ
    |    ВремОстатки КАК ВремОстатки";

Если Запрос.Выполнить().Пустой() Тогда
    Сообщить("Остатков нет — следующий расчёт пропускаем");
    Возврат;
КонецЕсли;

Тот же Пустой(), только применённый к выборке из временной таблицы. Это избавляет от лишних соединений с заведомо пустой таблицей в тяжёлых пакетах и делает код предсказуемым.

Частые ошибки при проверке на пустоту

Собрал промахи, на которых теряют время чаще всего:

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

  • Соединение превращает пустоту в строку с NULL. При ЛЕВОЕ СОЕДИНЕНИЕ в результате появятся строки от левой таблицы, а поля правой будут NULL. Выборка не пустая, но «полезных» данных в ней нет — заворачивайте такие поля в ЕСТЬNULL(Поле, 0) и проверяйте значение.

  • Повторный проход по уже прочитанной выборке. После Выбрать() и цикла указатель выборки стоит в конце. Если захотите пройти её снова, вызовите Выборка.Сбросить(), иначе второй цикл не выполнится и покажется, будто данных нет.

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

Сравнение способов проверки

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

СпособЧто отвечаетЧитает данныеКогда брать
Результат.Пустой()есть строки или нетнетпроверка факта «есть/нет» — по умолчанию
Выборка.Количество()сколько строкда, формирует выборкукогда число строк нужно для логики
Выгрузить().Количество()сколько строкда, в таблицу значенийкогда данные всё равно обрабатываются дальше
КОЛИЧЕСТВО(*) в запросечисло записей по условиюнет (считает СУБД)нужна только цифра, строки не нужны
Пустой() на временной таблицепуста ли таблица пакетанетконтроль промежуточного результата в пакете

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

Рекомендации: что выбрать и как не замедлить код

Коротко по делу:

  • Нужен только факт «есть/нет» — Пустой(), при желании с ВЫБРАТЬ ПЕРВЫЕ 1. Не выгружайте данные ради одной проверки.
  • Нужно число строк — Выборка.Количество() или отдельный запрос с КОЛИЧЕСТВО(*); не считайте строки циклом вручную.
  • Не вызывайте Выполнить() дважды ради пустоты и ради данных — выполните один раз, результат положите в переменную и работайте с ней.
  • Проверяйте значения параметров перед запуском: пустая ссылка или сдвинутая на день дата дают пустой результат чаще, чем кажется.
  • В клиент-серверном варианте запрос исполняется на сервере — проверку пустоты держите в серверном коде, не гоняя данные на клиент.
Разбор пустого результата по шагам
Выполнено: 0 / 5

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

Чем `Пустой()` лучше, чем `Количество() = 0`?
Пустой() не выгружает строки — платформе достаточно узнать факт наличия данных. Количество() у выборки требует её сформировать, а Выгрузить().Количество() ещё и переносит данные в таблицу значений. Для простой проверки «есть/нет» Пустой() быстрее, особенно на больших результатах.
Почему `Пустой()` возвращает `Ложь`, хотя строк в результате нет?
Скорее всего, в запросе есть агрегатная функция (КОЛИЧЕСТВО, СУММА, МАКСИМУМ) без СГРУППИРОВАТЬ ПО. Такой запрос всегда отдаёт одну итоговую строку, даже по пустому источнику. Проверяйте значение поля, а не пустоту выборки.
Нужно ли оборачивать проверку в `Попытка … Исключение`?
Нет. Пустой результат — не ошибка и исключения не вызывает. Попытка ловит сбои выполнения (неверный текст, недоступная таблица), а не отсутствие строк. Достаточно явной проверки Если Результат.Пустой() Тогда.
Как проверить пустоту результата в системе компоновки данных (СКД)?
Выполните компоновку в коллектор (например, в таблицу значений) и проверьте её Количество(). Если формируете результат через ПроцессорВывода, пустой набор даст пустую область — ориентируйтесь на отсутствие выведенных строк, а не на пустоту исходного набора данных, который мог пройти группировку.
Как быстрее всего убедиться, что данные вообще есть, не читая их?
Добавьте ВЫБРАТЬ ПЕРВЫЕ 1 и вызовите Пустой(). Платформа остановит выборку после первой подходящей записи — для проверки на существование этого достаточно.