Разработчики, работающие с legacy-системами на платформе 1С:Предприятие 7.7, регулярно сталкиваются с необходимостью отладки запросов. В отличие от современной платформы 1С 8.x, где консоль запросов и схема компоновки данных (СКД) встроены в систему, в версии 7.7 штатный инструментарий сильно ограничен. Большинство разработчиков привыкли использовать мощные внешние компоненты (ВК), такие как 1С++ (с ее мощным классом ODBCRecordset) или FormEx. Однако возникают ситуации, когда использование внешних библиотек (DLL) невозможно. Это может быть связано с политикой безопасности компании, работой в жестко ограниченных терминальных сессиях без прав администратора или необходимостью быстро запустить обработку на «чистой» конфигурации.
В этой статье мы подробно разберем, как реализовать консоль запросов для 1С 7.7 собственными силами без использования сторонних ВК. Мы рассмотрим два принципиально разных подхода: создание консоли для штатных («черных») запросов платформы и выполнение прямых SQL-запросов через системные механизмы COM/ADO.
Штатные запросы в 1С 7.7 часто называют «черными» из-за их закрытости и невозможности гибко посмотреть промежуточный результат без вывода в печатную форму. Наша задача — написать обработку, которая принимает произвольный текст запроса, выполняет его, выгружает результат в универсальный объект ТаблицаЗначений и динамически строит отчет без предварительного создания жесткого макета.
Рассмотрим по шагам, как устроен этот механизм:
Запрос и выполняет его.Проанализируем пример кода, реализующий этот алгоритм:
Процедура ВыполнитьЗапрос()
// Создаем объект штатного запроса
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = СокрЛП(ТекстЗапросаПользователя);
// Выполняем запрос
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Предупреждение("Ошибка выполнения запроса! Проверьте синтаксис.");
Возврат;
КонецЕсли;
// Создаем таблицу значений для выгрузки результатов
ТЗ = СоздатьОбъект("ТаблицаЗначений");
// Выгружаем результаты запроса в ТЗ
// Параметры метода Выгрузить: ТЗ, ФлагГруппировок (1 - с группировками, 0 - без), ФлагФункций (1 - выгружать функции)
Запрос.Выгрузить(ТЗ, 1, 1);
// Если таблица пустая, выводить нечего
Если ТЗ.КоличествоКолонок() = 0 Тогда
Предупреждение("Запрос не вернул колонок для отображения.");
Возврат;
КонецЕсли;
// Инициализируем вывод в печатную форму (макет)
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("УниверсальныйМакет"); // Здесь может быть пустой макет с одной ячейкой
// Выводим шапку таблицы
Таб.ВывестиСекцию("Шапка");
// Динамически формируем колонки в печатной форме
Для НомКол = 1 По ТЗ.КоличествоКолонок() Цикл
ИмяКолонки = "";
ТипКолонки = "";
ШиринаКолонки = 0;
ТЗ.ПолучитьПараметрыКолонки(НомКол, ТипКолонки, , , ИмяКолонки, ШиринаКолонки);
// Используем метод ПрисоединитьСекцию для горизонтального наращивания колонок
// В макете должна быть настроена одна вертикальная секция, например "Колонка"
Таб.ПрисоединитьСекцию("СтрокаШапки|Колонка");
КонецЦикла;
// Выводим строки данных
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
Для НомКол = 1 По ТЗ.КоличествоКолонок() Цикл
ЗначениеЯчейки = ТЗ.ПолучитьЗначение(ТЗ.НомерСтроки, НомКол);
// Записываем значение в область и присоединяем секцию данных
Таб.ПрисоединитьСекцию("СтрокаДанных|Колонка");
Loop;
КонецЦикла;
Таб.Опции(0, 0, 0, 0);
Таб.Показать("Результат запроса");
КонецПроцедуры
Этот подход избавляет разработчика от необходимости каждый раз рисовать новый макет под конкретный запрос. Программа автоматически адаптируется под структуру полей, возвращаемых штатным механизмом 1С 7.7.
Иногда возможностей штатного «черного» языка запросов 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:
1Cv7.DD (для DBF-версии) или 1Cv7.DDS (для SQL-версии), находящийся в корневом каталоге базы данных. Это обычные текстовые файлы, в которых описана структура. Например, справочник «Номенклатура» может физически называться таблицей SC433, а документ «Расходная накладная» — таблицей шапки DH1205 и табличной частью DT1205." 3Z "). В результате выполнения прямого запроса без ВК вы получите именно эти «сырые» строки. Чтобы преобразовать их обратно в объекты 1С (для возможности кликнуть по ячейке в отчете и открыть карточку), нужно применять сложные преобразования или использовать системную функцию получения объекта по его внутреннему идентификатору.15.05.2023 в SQL-таблице будет записана как 15.05.0023. При выборке через прямое ADO вам придется вручную прибавлять 2000 лет к полученным датам средствами SQL или кодом 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 и ручную сборку связей между таблицами.