Почему простейший запрос в 1С выдает ошибку Переменная не определена или возвращает Неопределено?

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

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

Разбираем причину ошибки: почему не работает обращение к полю выборки?

Рассмотрим исходный код, который часто становится причиной недоумения. Разработчик пытается получить максимальный код из справочника, прибавить к нему единицу и вернуть результат. На первый взгляд, логика верна, но в коде пропущен критически важный шаг взаимодействия с объектом ВыборкаИзРезультатаЗапроса.

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

Для исправления ситуации необходимо использовать метод Следующий(). Этот метод выполняет сразу две функции: перемещает указатель на следующую (в данном случае — на первую и единственную) запись и возвращает Истина, если запись существует.

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


Функция НовыйКод()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    МАКСИМУМ(СКУД_Персонал.Код) + 1 КАК НовыйКод
        |ИЗ
        |    Справочник.СКУД_Персонал КАК СКУД_Персонал";
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    // Обязательный переход к первой строке результата
    Если Выборка.Следующий() Тогда
        Возврат Выборка.НовыйКод;
    Иначе
        Возврат Неопределено;
    КонецЕсли;
КонецФункции

Проблема «грязного чтения» и многопользовательский режим

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

  1. Первый пользователь запускает запрос, получает МАКСИМУМ(Код), равный 100, и вычисляет 101.
  2. В ту же секунду (до того, как первый пользователь нажал «Записать») второй пользователь запускает этот же запрос и тоже получает 101.
  3. При попытке записи у второго пользователя возникнет ошибка нарушения уникальности кода, либо (если уникальность не проверяется) в базе появятся дубли.

Именно об этом предупреждают опытные разработчики. Использование конструкции МАКСИМУМ + 1 вручную — это плохая практика для многопользовательских систем. Посмотрим на правильные альтернативы.

Как правильно генерировать новые коды в 1С?

Для обеспечения уникальности и стабильной работы системы рекомендуется использовать встроенные механизмы платформы. Разберем основные способы.

Способ 1. Метод УстановитьНовыйКод()

Это наиболее предпочтительный метод. Платформа 1С берет на себя все сложности: учитывает префиксы организации, префиксы узлов распределенной информационной базы (РИБ) и блокирует таблицу номеров на время генерации, что исключает дублирование.


НовыйОбъект = Справочники.СКУД_Персонал.СоздатьЭлемент();
// Платформа сама найдет максимум и добавит 1 с учетом префиксов
НовыйОбъект.УстановитьНовыйКод(); 
НовыйОбъект.Записать();

Способ 2. Использование автоматической нумерации

В свойствах справочника в конфигураторе можно установить флаг «Автонумерация». В этом случае код будет присвоен автоматически в момент записи объекта, если он не был заполнен вручную.

Обработка пустых значений (NULL) в запросах

Вернемся к нашему запросу. Что произойдет, если в справочнике еще нет ни одной записи? Функция МАКСИМУМ(Код) вернет значение NULL. В языке запросов 1С любая математическая операция с NULL (например, NULL + 1) также дает результат NULL. В итоге ваша функция вернет «пустоту» даже для первого элемента.

Проанализируем, как сделать запрос более отказоустойчивым с помощью функции ЕСТЬNULL:


Запрос.Текст = 
    "ВЫБРАТЬ
    |    ЕСТЬNULL(МАКСИМУМ(СКУД_Персонал.Код), 0) + 1 КАК НовыйКод
    |ИЗ
    |    Справочник.СКУД_Персонал КАК СКУД_Персонал";

В данном примере, если справочник пуст, функция ЕСТЬNULL заменит NULL на 0, после чего прибавление единицы даст корректный первый номер.

Важность типов данных: Строка против Числа

Посмотрим на еще один «подводный камень». В 1С коды справочников чаще всего имеют тип Строка. Это сделано для поддержки префиксов (например, "ЦБ-001").

Важно помнить: функция МАКСИМУМ для строк работает по правилам алфавитной сортировки, а не числовой. Если у вас есть коды "9" и "10", то "9" будет считаться больше, чем "10", потому что символ "9" идет позже символа "1".

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

  1. Коды имеют фиксированную длину и дополнены ведущими нулями (например, "00001", "00010"). В этом случае алфавитная сортировка совпадет с числовой.
  2. В поле кода нет лишних префиксов, которые могут помешать корректному поиску максимума.

Рекомендации по производительности

Когда мы используем МАКСИМУМ в запросе, СУБД должна быстро найти самое большое значение. Чтобы этот запрос не «тормозил» на базе из миллиона записей, поле Код должно быть индексировано. В стандартных справочниках 1С поле Код индексируется автоматически, но если вы используете произвольный реквизит для своей нумерации, обязательно проверьте свойство «Индексировать» в конфигураторе.

Подведем итог. Чтобы избежать ошибок в «простейших запросах», всегда проверяйте результат метода Следующий(), обрабатывайте возможные NULL через ЕСТЬNULL и, по возможности, доверяйте генерацию кодов стандартному методу УстановитьНовыйКод().

← На главную