Проверка результата запроса на пустоту во встроенном языке 1С 8.3
Содержание
Проверяет пустоту результата запроса метод Результат.Пустой() — он возвращает Истина, когда в выборке нет ни одной строки, и при этом не читает сами данные. Это самый быстрый способ, и в большинстве кода хватает именно его.
Остальные приёмы нужны, когда пустоты мало — требуется ещё и число строк, проверка на лету в отладчике или контроль пустой временной таблицы внутри пакета. Ниже — рабочие варианты с кодом и ловушка, из-за которой Пустой() иногда «врёт».
Почему запрос в 1С возвращает пустой результат
Пустая выборка — это не ошибка платформы, а штатный исход: условиям запроса просто ничего не соответствует. Типичные причины:
- 🔎 Условие в
ГДЕслишком жёсткое — не нашлось ни одной подходящей записи. - 🧩 В параметр попало не то значение — пустая ссылка,
Неопределено, лишние пробелы в строке. - 📅 Границы периода заданы так, что ни один документ в них не попадает (частая беда с моментом времени и концом дня).
- 🗑️ Помеченные на удаление записи отфильтрованы, а других нет.
- 🔐 Ограничения доступа (RLS) — пользователь физически не видит данные, которые есть в базе.
Отсюда простое правило: прежде чем «чинить» запрос, проверьте значения параметров. В девяти случаях из десяти в параметр уходит пустая ссылка или не та дата, а сам текст запроса корректен.
Проверить это можно в пару строк перед выполнением:
Если Не ЗначениеЗаполнено(Артикул) Тогда
Сообщить("Артикул не задан — запрос гарантированно вернёт пусто");
Возврат;
КонецЕсли;
ЗначениеЗаполнено() отсекает пустую ссылку, пустую строку и Неопределено одним вызовом. Если параметр заполнен, а результат всё равно пуст — значит, дело в условиях или данных, и дальше включаем способы проверки ниже.
Метод Пустой() — самая быстрая проверка
Объект РезультатЗапроса, который возвращает Запрос.Выполнить(), имеет метод Пустой(). Он отвечает на единственный вопрос — есть ли хоть одна строка:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &Артикул";
Запрос.УстановитьПараметр("Артикул", Артикул);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Сообщить("По артикулу " + Артикул + " ничего не найдено");
Возврат;
КонецЕсли;
Почему именно Пустой(), а не что-то другое:
- он не выгружает данные в память и не создаёт выборку — платформе достаточно узнать факт наличия строк;
- на больших результатах это заметно дешевле, чем
Выгрузить().Количество(); - читается однозначно — любой, кто откроет код, сразу поймёт замысел.
Если вам нужен только факт «есть/нет», добавьте в запрос ВЫБРАТЬ ПЕРВЫЕ 1. Платформа прекратит выборку после первой подходящей записи, и проверка Пустой() отработает ещё быстрее.
Подсчёт строк: когда важно не «есть ли», а «сколько»
Иногда одного факта мало — нужно именно количество. Здесь Пустой() не помощник, берём другие инструменты.
Через выборку. У объекта ВыборкаИзРезультатаЗапроса есть метод Количество() — он отдаёт число записей текущего уровня:
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Сообщить("Найдено строк: " + Выборка.Количество());
Через выгрузку в таблицу значений. Удобно, когда данные всё равно нужны дальше:
Таблица = Запрос.Выполнить().Выгрузить();
Если Таблица.Количество() = 0 Тогда
// пусто
КонецЕсли;
Через агрегат в самом запросе. Если нужна только цифра и вытаскивать строки незачем, пусть считает сервер СУБД:
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(*) КАК Кол
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &Артикул";
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
Если Выборка.Кол = 0 Тогда
// по условию ничего не нашлось
КонецЕсли;
Обратите внимание на последний пример — у него есть важная особенность, из-за которой на нём часто спотыкаются. Разберём её отдельно в разделе про ошибки.
Ещё один нюанс касается группировок. Если в выборке есть иерархия или итоги (ИТОГИ ПО), метод Количество() отдаёт число записей только текущего уровня обхода. Для подсчёта всех детальных строк либо обходите выборку с типом ОбходРезультатаЗапроса.Прямой, либо используйте Выгрузить() — таблица значений хранит плоский список без учёта группировок.
Результат.Пустой() — не читает данные, работает быстрее всего.Результат.Выбрать().Количество(), а если данные нужны дальше — Результат.Выгрузить().Количество().КОЛИЧЕСТВО(*) — считает сервер СУБД, в код приходит одно число.Shift+F9) с выражением Результат.Пустой().Проверка результата в отладчике и консоли запросов
Пока код пишется, не обязательно вставлять Сообщить() — результат удобно смотреть прямо в отладчике Конфигуратора.
Порядок такой:
- Поставьте точку останова (
F9) на строке послеЗапрос.Выполнить(). - Запустите в режиме отладки. Когда выполнение остановится, наведите курсор на переменную
Результат— во всплывающей подсказке платформа покажет свойства объекта. - Чтобы оценить пустоту явно, откройте окно «Вычислить выражение» (
Shift+F9) и наберитеРезультат.Пустой()— получитеИстинаилиЛожь. - Чтобы увидеть сами строки, в том же окне вычислите
Результат.Выгрузить()и раскройте полученную таблицу значений.
Когда нужно крутить текст запроса без правки кода, удобнее консоль запросов — внешняя обработка, которая выполняет произвольный текст и показывает результат таблицей. Пустой результат там виден сразу: таблица выводится без строк. Консоль входит в типовые инструменты разработчика; если её нет под рукой, подойдёт любая проверенная обработка того же назначения.
Отладка идёт по реальной базе. Если запрос не только читает, но и вызывает процедуры с изменением данных, запускайте его на копии, а не на рабочей базе.
Корректная обработка пустого ответа: почему Попытка не нужна
Здесь прячется главное недопонимание. Пустой результат не вызывает исключения. Конструкция Попытка … Исключение … КонецПопытки ловит ошибки — неверный текст запроса, недоступную таблицу, сбой соединения, — но не отсутствие строк. Оборачивать проверку пустоты в Попытку бессмысленно: ветка Исключение просто не сработает.
Цикл по пустой выборке тоже ничего не ломает — тело просто не выполнится ни разу:
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// при пустом результате сюда не зайдём ни разу — и это нормально
ОбработатьСтроку(Выборка);
КонецЦикла;
Поэтому правильный шаблон — не перехват ошибки, а явная проверка и понятное поведение по умолчанию:
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
// осмысленный ответ вместо тихого «ничего не произошло»
ВызватьИсключение "Не найдены строки для обработки по заданным условиям";
// или: вернуть пустой массив, значение по умолчанию, показать сообщение пользователю
КонецЕсли;
ВызватьИсключение здесь — ваше решение, а не поведение платформы: вы сами превращаете пустоту в ошибку, если по логике метода отсутствие данных недопустимо. А если допустимо — возвращаете пустую коллекцию или значение по умолчанию. Главное — не оставлять пустой результат необработанным: иначе дальше по коду вылезет Неопределено там, где ждали значение.
Пустые временные таблицы в пакете запросов
В пакетных запросах промежуточные данные складывают во временные таблицы через ПОМЕСТИТЬ. Бывает нужно проверить: а попало ли туда хоть что-нибудь, прежде чем строить на этой таблице следующий запрос.
Если временные таблицы живут в рамках одного пакета, достаточно проверить итоговую выборку, которая читает из нужной таблицы. Но когда таблицу надо переиспользовать между несколькими Выполнить(), её удерживают в менеджере временных таблиц:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВремОстатки
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки() КАК Остатки";
Запрос.Выполнить();
// отдельным запросом проверяем, что во временной таблице есть данные
Запрос.Текст =
"ВЫБРАТЬ
| ВремОстатки.Номенклатура
|ИЗ
| ВремОстатки КАК ВремОстатки";
Если Запрос.Выполнить().Пустой() Тогда
Сообщить("Остатков нет — следующий расчёт пропускаем");
Возврат;
КонецЕсли;
Тот же Пустой(), только применённый к выборке из временной таблицы. Это избавляет от лишних соединений с заведомо пустой таблицей в тяжёлых пакетах и делает код предсказуемым.
Частые ошибки при проверке на пустоту
Собрал промахи, на которых теряют время чаще всего:
Агрегат без группировки всегда даёт одну строку. Запрос с
КОЛИЧЕСТВО(*),СУММА()илиМАКСИМУМ()без секцииСГРУППИРОВАТЬ ПОвозвращает ровно одну строку даже по пустому источнику. ПоэтомуРезультат.Пустой()на таком запросе вернётЛожь, хотя данных нет. Проверять надо значение (Количество = 0,Сумма = NULL), а не пустоту выборки.Соединение превращает пустоту в строку с
NULL. ПриЛЕВОЕ СОЕДИНЕНИЕв результате появятся строки от левой таблицы, а поля правой будутNULL. Выборка не пустая, но «полезных» данных в ней нет — заворачивайте такие поля вЕСТЬNULL(Поле, 0)и проверяйте значение.Повторный проход по уже прочитанной выборке. После
Выбрать()и цикла указатель выборки стоит в конце. Если захотите пройти её снова, вызовитеВыборка.Сбросить(), иначе второй цикл не выполнится и покажется, будто данных нет.Пустой()путают с проверкой самого запроса. Метод оценивает результат, а не текст. Ошибку в тексте запроса или недоступный реквизит он не покажет — такие случаи ловятся исключением приВыполнить().
Сравнение способов проверки
Чтобы не держать всё в голове, вот сводка — что каждый способ проверяет и когда он уместен:
| Способ | Что отвечает | Читает данные | Когда брать |
|---|---|---|---|
Результат.Пустой() | есть строки или нет | нет | проверка факта «есть/нет» — по умолчанию |
Выборка.Количество() | сколько строк | да, формирует выборку | когда число строк нужно для логики |
Выгрузить().Количество() | сколько строк | да, в таблицу значений | когда данные всё равно обрабатываются дальше |
КОЛИЧЕСТВО(*) в запросе | число записей по условию | нет (считает СУБД) | нужна только цифра, строки не нужны |
Пустой() на временной таблице | пуста ли таблица пакета | нет | контроль промежуточного результата в пакете |
Вывод из таблицы простой: по умолчанию — Пустой(), и только когда нужна цифра или сами строки, переходите к подсчёту и выгрузке. Лишний раз выгружать данные ради проверки «есть/нет» не стоит.
Рекомендации: что выбрать и как не замедлить код
Коротко по делу:
- Нужен только факт «есть/нет» —
Пустой(), при желании сВЫБРАТЬ ПЕРВЫЕ 1. Не выгружайте данные ради одной проверки. - Нужно число строк —
Выборка.Количество()или отдельный запрос сКОЛИЧЕСТВО(*); не считайте строки циклом вручную. - Не вызывайте
Выполнить()дважды ради пустоты и ради данных — выполните один раз, результат положите в переменную и работайте с ней. - Проверяйте значения параметров перед запуском: пустая ссылка или сдвинутая на день дата дают пустой результат чаще, чем кажется.
- В клиент-серверном варианте запрос исполняется на сервере — проверку пустоты держите в серверном коде, не гоняя данные на клиент.
Частые вопросы
Чем `Пустой()` лучше, чем `Количество() = 0`?
Пустой() не выгружает строки — платформе достаточно узнать факт наличия данных. Количество() у выборки требует её сформировать, а Выгрузить().Количество() ещё и переносит данные в таблицу значений. Для простой проверки «есть/нет» Пустой() быстрее, особенно на больших результатах.Почему `Пустой()` возвращает `Ложь`, хотя строк в результате нет?
КОЛИЧЕСТВО, СУММА, МАКСИМУМ) без СГРУППИРОВАТЬ ПО. Такой запрос всегда отдаёт одну итоговую строку, даже по пустому источнику. Проверяйте значение поля, а не пустоту выборки.Нужно ли оборачивать проверку в `Попытка … Исключение`?
Попытка ловит сбои выполнения (неверный текст, недоступная таблица), а не отсутствие строк. Достаточно явной проверки Если Результат.Пустой() Тогда.Как проверить пустоту результата в системе компоновки данных (СКД)?
Количество(). Если формируете результат через ПроцессорВывода, пустой набор даст пустую область — ориентируйтесь на отсутствие выведенных строк, а не на пустоту исходного набора данных, который мог пройти группировку.Как быстрее всего убедиться, что данные вообще есть, не читая их?
ВЫБРАТЬ ПЕРВЫЕ 1 и вызовите Пустой(). Платформа остановит выборку после первой подходящей записи — для проверки на существование этого достаточно.