Как устранить ошибку «Переменная не определена» при использовании условия вхождения в список в запросе 1С 7.7

Программист 1С v7.7
← На главную

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

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

Рассмотрим типичную ситуацию: разработчик создает объект СписокЗначений, наполняет его элементами справочника и пытается использовать в тексте запроса через оператор Условие. Однако система сообщает, что переменная списка не найдена. Основная причина кроется в том, как парсер запросов 1С 7.7 взаимодействует с контекстом модуля.

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

Для решения этой проблемы мы можем использовать несколько подходов:

  1. Объявление переменной в модуле: Если мы объявим Перем МойСписок; в самом верху модуля (модуля формы или модуля документа), она станет доступна всем процедурам и функциям этого модуля, включая внутренние механизмы объекта Запрос.
  2. Передача контекста: Если выполнение запроса происходит в глобальном модуле или другой функции, необходимо убедиться, что переменная передана как формальный параметр.
  3. Глобальные переменные: В крайних случаях (хотя это не рекомендуется правилами хорошего тона программирования) переменную можно объявить в Глобальном модуле с ключевым словом Экспорт.

Синтаксис условия вхождения в список

Важно помнить, что синтаксис 1С 7.7 отличается от 1С 8.x. В «семерке» не используется символ амперсанда (&) перед именем параметра в тексте запроса. Посмотрим на правильный пример формирования текста запроса:


МойСписок = СоздатьОбъект("СписокЗначений");
// Заполнение списка...
ТекстЗапроса = "
|Товар = Справочник.Товары.ТекущийЭлемент;
|Условие (Товар В МойСписок);
|";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    // Обработка результатов
КонецЕсли;

Если вы случайно добавите & перед МойСписок, как это делается в более современных версиях платформы, 1С 7.7 выдаст синтаксическую ошибку.

Оптимизация: Ссылки против Кодов

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


МойСписок.ДобавитьЗначение(МойСправочник.Код); 
// ... в запросе
|КодЭлемента = Документ.МойДокумент.Товар.Код;
|Условие (КодЭлемента В МойСписок);

Проанализируем, почему это плохо. Когда вы обращаетесь к Товар.Код в запросе, система вынуждена выполнять соединение (JOIN) таблицы документов с таблицей справочника, чтобы получить строковое значение кода для каждого товара. Если в документе тысячи строк, это существенно замедляет работу.

Правильный подход: использовать ссылки на объекты. Ссылка в 1С 7.7 — это внутренний идентификатор (ID), который хранится непосредственно в таблице документа. Сравнение идентификаторов происходит гораздо быстрее, чем сравнение строк. Рассмотрим правильный способ заполнения списка:


МойСправочник = СоздатьОбъект("Справочник.Товары");
МойСписок = СоздатьОбъект("СписокЗначений");

Если МойСправочник.НайтиПоКоду("284") = 1 Тогда
    МойСписок.ДобавитьЗначение(МойСправочник.ТекущийЭлемент());
КонецЕсли;

ТекстЗапроса = "
|Товар = Документ.Реализация.Товар;
|Условие (Товар В МойСписок);
|";

Нюансы метода НайтиПоКоду и лидирующие нули

При заполнении списка значений через поиск по коду, как в примере выше, часто возникает ошибка «элемент не найден». Выясним причину. В 1С 7.7 длина кода справочника фиксирована в метаданных. Если длина кода установлена, например, в 10 символов, а вы ищете код "284", поиск может завершиться неудачей, так как реальный код в базе выглядит как "0000000284".

Для корректного поиска рекомендуется использовать дополнение строки нулями или встроенные функции конфигурации (например, глПреобразоватьНомер в типовых решениях). Также всегда проверяйте результат выполнения метода НайтиПоКоду(), прежде чем добавлять значение в список, чтобы избежать попадания пустых значений, которые могут исказить результат запроса.

Особенности работы со списками в SQL-версии

Если ваша база данных работает на Microsoft SQL Server, следует учитывать еще один технический момент. При использовании условия В СписокЗначений движок 1С 7.7 преобразует это условие в SQL-запрос с оператором IN (...) или серией условий OR.

Если в вашем списке находятся тысячи элементов, результирующий SQL-запрос может стать слишком длинным, что приведет к ошибке переполнения буфера или отказу сервера базы данных. В таких случаях рекомендуется:

Итоги

Подведем итоги нашего исследования. Для того чтобы успешно использовать условие вхождения в список в запросе 1С 7.7, необходимо:

  1. Убедиться, что переменная СписокЗначений объявлена в области видимости модуля (лучше всего как переменная модуля).
  2. Использовать в списке именно объекты (ссылки ТекущийЭлемент()), а не строковые коды или наименования.
  3. Проверять успешность поиска элементов перед их добавлением в список.
  4. Избегать использования оператора & перед именами переменных в тексте запроса.

Соблюдение этих простых правил позволит вам писать надежный и быстрый код, избегая трудноуловимых ошибок исполнения.

← На главную