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

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

В процессе совместной работы мы проанализируем, почему стандартный синтаксический подход вызывает ошибку компиляции запроса, рассмотрим наиболее эффективные обходные пути решения этой задачи и разберем практические приемы сопоставления данных для успешной отладки.

В чем суть проблемы: почему возникает ошибка?

Давайте подробно рассмотрим ситуацию, описанную автором темы. В коде инициализируется стандартный черный запрос, внутри которого разработчик пытается выполнить следующее присвоение:

|вКв = ВыбКвартира;

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

Когда же мы пишем вКв = ВыбКвартира;, где ВыбКвартира — это переменная модуля (например, реквизит диалога формы выбора), парсер запроса выдает ошибку. Он не умеет динамически «подставлять» статические внешние значения в качестве вычисляемых полей на уровне SQL-транслятора встроенного языка. Запрос работает исключительно с объектами базы данных.

Что же делать, если нам критически важно сопоставить «глазами» значение из базы данных и значение внешней переменной отбора, выгрузив их в одну Таблицу Значений? Давайте разберем по шагам рабочие и изящные решения.

Решение 1. Пост-обработка Таблицы Значений (Рекомендуемый способ)

Проанализируем самый простой, надежный и производительный способ решения данной задачи. Нам не нужно пытаться заставить транслятор запросов делать то, для чего он не предназначен. Вместо этого мы перенесем логику формирования сопоставимой колонки на уровень встроенного языка после выполнения запроса.

Рассмотрим по шагам, как это реализовать на практике:

  1. Уберем некорректное присвоение из текста запроса.
  2. Выгрузим чистый результат выполнения запроса в объект типа ТаблицаЗначений.
  3. Программно добавим новую колонку в полученную таблицу.
  4. Заполним всю новую колонку значением нашей внешней переменной с помощью метода Заполнить().

Посмотрим на пример программного кода, реализующего этот алгоритм:


// Создаем объект Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|//{{ЗАПРОС(НайтиЛС)
|Без итогов;
|ТекущийЭлемент = Справочник.ЛицевыеСчета.ТекущийЭлемент;
|Квартира = Справочник.ЛицевыеСчета.Квартира;
|Условие(Квартира = ВыбКвартира); // Временно можно закомментировать для отладки
|//}}ЗАПРОС
|";

// Выполняем запрос
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    // Создаем Таблицу Значений для выгрузки результатов
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    Запрос.Выгрузить(ТЗ, 1, 1);
    
    // Добавляем новую колонку для нашей внешней переменной
    ТЗ.НоваяКолонка("вКв");
    
    // Заполняем добавленную колонку значением внешней переменной ВыбКвартира
    ТЗ.Заполнить(ВыбКвартира, , , "вКв");
    
    // Выводим ТЗ на экран для визуального анализа и сравнения строк
    ТЗ.ВыбратьСтроку("Результат сопоставления данных");
КонецЕсли;

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

Решение 2. Тонкости отладки условий и сравнения типов

Часто программисты сталкиваются с ситуацией: без условия запрос возвращает множество строк, но как только включается Условие(Квартира = ВыбКвартира);, результат становится абсолютно пустым. Выясним причину, почему это происходит, ведь визуально значения могут казаться абсолютно идентичными.

В платформе 1С 7.7 существует жесткое разделение типов данных, о котором часто забывают:

Решение 3. Интерактивная отладка через внешнюю функцию

Мало кто знает, но в черных запросах 1С 7.7 есть потрясающая возможность использовать внешние функции модуля прямо внутри тела запроса в секции условий. Это позволяет построчно анализировать, какие именно данные обрабатывает запрос в цикле. Давайте воспользуемся этим приемом для вывода отладочной информации в окно сообщений.

Для начала создадим специальную отладочную функцию в модуле нашего отчета или обработки:


Функция ОтладитьСравнение(ЗначениеИзБазы)
    Сообщить("База: " + ЗначениеИзБазы + " (тип: " + ТипЗначенияСтр(ЗначениеИзБазы) + 
             ") | Отбор: " + ВыбКвартира + " (тип: " + ТипЗначенияСтр(ВыбКвартира) + ")");
    // Возвращаем 1, чтобы условие всегда считалось истинным и записи попадали в выборку
    Возврат 1; 
КонецФункции

Теперь внесем изменения в текст нашего запроса, временно заменив стандартное условие на вызов нашей функции:

|Условие(ОтладитьСравнение(Квартира) = 1);

Запустим выполнение запроса. При этом в окно сообщений построчно выведутся сравниваемые значения и их внутренние типы данных. Вы сразу увидите, например, что с одной стороны передается пустая ссылка, а с другой — строка или объект другого справочника. Это мощный инструмент для быстрого поиска логических ошибок в коде.

Альтернативный путь: Использование прямых SQL-запросов

Как справедливо заметил один из участников обсуждения на форуме, штатный механизм черных запросов в 1С 7.7 весьма ограничен по своей функциональности, скорости работы и возможностям отладки. В крупных корпоративных системах для решения подобных задач разработчики давно ушли от использования черных запросов в пользу прямых SQL-запросов к таблицам базы данных (используя внешние компоненты, такие как 1С++ и класс ODBCRecordset).

В прямом SQL-запросе ограничений черного запроса не существует в принципе. Там мы можем передавать параметры любого типа напрямую в тело запроса и конструировать результирующую выборку так, как нам удобно, выводя внешние переменные отдельными текстовыми или числовыми колонками.

Проанализируем пример концептуального SQL-запроса, решающего аналогичную задачу:


SELECT 
    ParentVal.descr as [Квартира],
    :ВыбКвартира as [вКв] -- Передаем внешнюю переменную как параметр напрямую в выборку
FROM 
    $Справочник.ЛицевыеСчета as ParentVal
WHERE 
    ParentVal.descr = :ВыбКвартира

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

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

← На главную