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