Как написать или использовать консоль запросов в 1С 7.7 без внешних компонент

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

Разработчики, работающие с legacy-системами на платформе 1С:Предприятие 7.7, регулярно сталкиваются с необходимостью отладки запросов. В отличие от современной платформы 1С 8.x, где консоль запросов и схема компоновки данных (СКД) встроены в систему, в версии 7.7 штатный инструментарий сильно ограничен. Большинство разработчиков привыкли использовать мощные внешние компоненты (ВК), такие как 1С++ (с ее мощным классом ODBCRecordset) или FormEx. Однако возникают ситуации, когда использование внешних библиотек (DLL) невозможно. Это может быть связано с политикой безопасности компании, работой в жестко ограниченных терминальных сессиях без прав администратора или необходимостью быстро запустить обработку на «чистой» конфигурации.

В этой статье мы подробно разберем, как реализовать консоль запросов для 1С 7.7 собственными силами без использования сторонних ВК. Мы рассмотрим два принципиально разных подхода: создание консоли для штатных («черных») запросов платформы и выполнение прямых SQL-запросов через системные механизмы COM/ADO.

Решение 1: Универсальная консоль штатных («черных») запросов

Штатные запросы в 1С 7.7 часто называют «черными» из-за их закрытости и невозможности гибко посмотреть промежуточный результат без вывода в печатную форму. Наша задача — написать обработку, которая принимает произвольный текст запроса, выполняет его, выгружает результат в универсальный объект ТаблицаЗначений и динамически строит отчет без предварительного создания жесткого макета.

Рассмотрим по шагам, как устроен этот механизм:

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

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


Процедура ВыполнитьЗапрос()
    // Создаем объект штатного запроса
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = СокрЛП(ТекстЗапросаПользователя);
    
    // Выполняем запрос
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Предупреждение("Ошибка выполнения запроса! Проверьте синтаксис.");
        Возврат;
    КонецЕсли;
    
    // Создаем таблицу значений для выгрузки результатов
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    
    // Выгружаем результаты запроса в ТЗ
    // Параметры метода Выгрузить: ТЗ, ФлагГруппировок (1 - с группировками, 0 - без), ФлагФункций (1 - выгружать функции)
    Запрос.Выгрузить(ТЗ, 1, 1);
    
    // Если таблица пустая, выводить нечего
    Если ТЗ.КоличествоКолонок() = 0 Тогда
        Предупреждение("Запрос не вернул колонок для отображения.");
        Возврат;
    КонецЕсли;
    
    // Инициализируем вывод в печатную форму (макет)
    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("УниверсальныйМакет"); // Здесь может быть пустой макет с одной ячейкой
    
    // Выводим шапку таблицы
    Таб.ВывестиСекцию("Шапка"); 
    
    // Динамически формируем колонки в печатной форме
    Для НомКол = 1 По ТЗ.КоличествоКолонок() Цикл
        ИмяКолонки = "";
        ТипКолонки = "";
        ШиринаКолонки = 0;
        ТЗ.ПолучитьПараметрыКолонки(НомКол, ТипКолонки, , , ИмяКолонки, ШиринаКолонки);
        
        // Используем метод ПрисоединитьСекцию для горизонтального наращивания колонок
        // В макете должна быть настроена одна вертикальная секция, например "Колонка"
        Таб.ПрисоединитьСекцию("СтрокаШапки|Колонка");
    КонецЦикла;
    
    // Выводим строки данных
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Для НомКол = 1 По ТЗ.КоличествоКолонок() Цикл
            ЗначениеЯчейки = ТЗ.ПолучитьЗначение(ТЗ.НомерСтроки, НомКол);
            // Записываем значение в область и присоединяем секцию данных
            Таб.ПрисоединитьСекцию("СтрокаДанных|Колонка");
        Loop;
    КонецЦикла;
    
    Таб.Опции(0, 0, 0, 0);
    Таб.Показать("Результат запроса");
КонецПроцедуры

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

Решение 2: Прямые SQL-запросы без ВК через COM (ADO)

Иногда возможностей штатного «черного» языка запросов 1С 7.7 критически не хватает (например, требуются сложные соединения таблиц, вложенные подзапросы или использование специфических функций СУБД). В этом случае можно обойтись без внешних компонент 1С, задействовав стандартные механизмы операционной системы Windows — технологию ActiveX Data Objects (ADO) через системные COM-объекты.

Разберем, как настроить подключение к базе данных (как к MS SQL Server, так и к файловой DBF) напрямую из кода 1С 7.7:


Процедура ВыполнитьПрямойЗапрос()
    // Создаем COM-объект подключения к БД
    Соединение = СоздатьОбъект("ADODB.Connection");
    Recordset = СоздатьОбъект("ADODB.Recordset");
    
    // Строка подключения для MS SQL Server
    // Замените параметры Server, Database, UID, PWD на ваши данные
    СтрокаПодключения = "Provider=SQLOLEDB;Data Source=ИмяСервера;Initial Catalog=ИмяБазыДанных;User ID=Пользователь;Password=Пароль;";
    
    // Для файловой базы DBF строка подключения настраивается через Microsoft OLE DB Provider for FoxPro:
    // СтрокаПодключения = "Provider=VFPOLEDB.1;Data Source=" + КаталогИБ() + ";Collating Sequence=MACHINE";
    
    Попытка
        Соединение.Open(СтрокаПодключения);
    Исключение
        Предупреждение("Не удалось подключиться к базе данных: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    ТекстSQL = СокрЛП(ТекстSQLЗапроса);
    
    Попытка
        // Выполняем SQL-запрос
        Recordset = Соединение.Execute(ТекстSQL);
    Исключение
        Предупреждение("Ошибка в тексте SQL-запроса: " + ОписаниеОшибки());
        Соединение.Close();
        Возврат;
    КонецПопытки;
    
    // Создаем Таблицу Значений для визуализации данных
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    
    // Создаем колонки в ТЗ на основе полей Recordset
    Для НомПоля = 0 По Recordset.Fields.Count - 1 Цикл
        ИмяПоля = Recordset.Fields(НомПоля).Name;
        ТЗ.НоваяКолонка(ИмяПоля);
    КонецЦикла;
    
    // Заполняем ТЗ данными из Recordset
    Пока Recordset.EOF() = 0 Цикл
        ТЗ.НоваяСтрока();
        Для НомПоля = 0 По Recordset.Fields.Count - 1 Цикл
            ТЗ.УстановитьЗначение(ТЗ.НомерСтроки, НомПоля + 1, Recordset.Fields(НомПоля).Value);
        КонецЦикла;
        Recordset.MoveNext();
    КонецЦикла;
    
    // Закрываем соединение
    Recordset.Close();
    Соединение.Close();
    
    // Выводим полученную ТЗ на форму или в универсальный макет
    ТЗ.ВыбратьСтроку();
КонецПроцедуры

Этот способ позволяет выполнять полноценные, быстрые и сложные запросы к базе данных без регистрации каких-либо сторонних DLL в операционной системе.

Главная проблема прямых запросов без ВК: Отсутствие метапарсера

Несмотря на изящество работы через чистое ADO, разработчик сталкивается с серьезной проблемой, которую на форумах называют «отсутствием метапарсера». Выясним причину этой проблемы подробнее.

В базе данных (будь то таблицы DBF или таблицы MS SQL) платформа 1С 7.7 хранит данные в обезличенном виде. Все понятные человеку объекты метаданных (справочники, документы, регистры) транслируются системой в буквенно-цифровые коды таблиц и полей. Без метапарсера (который встроен в специализированную ВК 1С++ и автоматически переводит запросы вида $Справочник.Номенклатура на язык понятный SQL) программисту приходится выполнять всю работу вручную.

Проанализируем основные сложности ручной сборки SQL-запросов через чистое ADO:

Лайфхак: Как преобразовать полученный из ADO ID в объект 1С

Если вы все же решили использовать прямое подключение через ADO и получили текстовый ID объекта (например, " 4A1 "), его можно превратить в полноценную ссылку 1С 7.7 без внешних компонент с помощью недокументированного метода ЗначениеИзСтрокиВнутр(). Посмотрим на пример:


Функция ПолучитьСсылкуИзID(ИмяМетаданных, ТекстовыйID)
    // ИмяМетаданных должно быть в формате, определяемом платформой, например "Справочник.Номенклатура"
    // Создаем внутреннее строковое представление объекта 1С 7.7
    // Строка имеет вид: {"B","0","0","0","0","0","   ID    "}
    СтрокаВнутр = "{""B"",""0"",""0"",""0"",""0"",""0"",""" + ТекстовыйID + """}";
    
    Попытка
        СсылкаНаОбъект = ЗначениеИзСтрокиВнутр(СтрокаВнутр);
        Возврат СсылкаНаОбъект;
    Исключение
        Возврат ПолучитьПустоеЗначение(ИмяМетаданных);
    КонецПопытки;
КонецФункции

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

Выводы и рекомендации

Разберем, какой подход лучше выбрать в зависимости от ваших задач:

Если вам требуется быстро проанализировать остатки, обороты или реквизиты справочников штатными средствами платформы — лучшим выбором будет написание динамической консоли штатных запросов (Решение 1). Она абсолютно безопасна, не требует понимания структуры базы данных на уровне СУБД и работает на любой конфигурации «из коробки».

Если перед вами стоит задача выполнения тяжелых, оптимизированных выборок, а использовать внешние компоненты категорически запрещено системными администраторами — используйте прямые запросы через COM/ADO (Решение 2). Но будьте готовы потратить время на расшифровку структуры таблиц в файле 1Cv7.DD / DDS и ручную сборку связей между таблицами.

← На главную