|
Подключение к базе данных 1С и выполнение SQL запросов на примере работы со справочниками. Часть 2.
В прошлой статье мы заполняли известные поля таблиц известными значениями. Теперь рассмотрим обратную задачу. Предположим, что нам требуется выбрать значения из таблиц. Написать и выполнить соответствующий SQL запрос мы уже сможем. В "Rainbow" есть методы позволяющие получить данные из выборки. Основная проблема
заключается в том, чтобы узнать, что же мы получили. Согласитесь, что от строки ' STU ' толку мало. Тот факт, что она находится в колонке справочника контрагента под названием "Ответственный менеджер" дает нам основание предполагать, что это идентификатор элемента справочника "Сотрудники", однако и этого пытливому
уму недостаточно. Конечно, можно сделать запрос к справочнику "Сотрудники" по этому идентификатору и получить нужные сведения (например фамилию), но в контексте работы в 1С удобнее было бы получить соответствующий агрегатный объект. Этим мы и займемся.
К сожалению "Rainbow" не содержит методов, позволяющих осуществить преобразование ID объекта в объект 1С. Придется позаботиться об этом самим. Идея заключается в использовании функции ЗначениеИзСтрокиВнутр. Параметром ей служит особым образом форматированная строка, которая однозначно идентифицирует любой агрегатный объект. Если Вы поэкспериментируете с обратной функцией
ЗначениеВСтрокуВнутр, применив ее к различным объектам и внимательно присмотревшись к полученным результатам, то у Вас есть шанс совершить деяние достойное Шампольона. Мы этот путь уже прошли и в результате предлагаем Вашему вниманию три функции восстанавливающие по виду объекта, по типу объекта и по идентификатору объекта собственно агрегатный объект.
//Вспомогательная функция для представления строки, представляющей
//идентификатор объекта в десятичном виде,
//в нужном формате
Функция глСтрокаФикс(Знач текстСтрока,Знач ФиксДлина,Назад = 1) Экспорт
Перем Инд, ДлинаТекстСтрока;
ФиксДлина = Число(ФиксДлина);
текстСтрока = СокрЛП(Строка(текстСтрока));
ДлинаТекстСтрока = СтрДлина(текстСтрока);
ДобавитьПробелов = ФиксДлина - ДлинаТекстСтрока;
Если ДобавитьПробелов = 0 Тогда
Возврат текстСтрока;
ИначеЕсли ДобавитьПробелов < 0 Тогда
текстСтрока = Сред(текстСтрока,1,ДлинаТекстСтрока - ДобавитьПробелов);
Иначе
Для Инд = 1 по ДобавитьПробелов Цикл
Если Назад = 1 Тогда
текстСтрока = текстСтрока + " ";
Иначе
текстСтрока = " " + текстСтрока;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Возврат текстСтрока;
КонецФункции
//Функция преобразующая идентификатор объект
//из тридцатишестиричного формата в десятичный
Функция глПреобразоватьID(Знач ID) Экспорт
ID = Прав(ID,9);
Стр1 = СокрЛП(Строка(objRainbowService.BaseToInt(НРег(Сред(ID,1,6)),36)));
Стр2 = ВРег(Сред(ID,7,3));
Стр3 = Сред(глСтрокаФикс(Стр1 + Стр2 + "'",14,0),1,13);
Возврат Стр3;
КонецФункции
//Самая главная функция.
//Принимает три параметра
//ТипОбъекта - Строка
//ВидОбъекта - Строка или готовый идентификатор вида объекта в десятичном
//формате
//IDОбъекта - идентификатор объекта
Функция глПолучитьОбъектПоID(ТипОбъекта,Знач ВидОбъекта,IDОбъекта) Экспорт
Если ТипОбъекта = "Справочник" Тогда
Если ТипЗначенияСтр(ВидОбъекта) = "Строка" Тогда
ВидОбъекта = Число(глПолучитьМетаIDОбъекта(Метаданные.Справочник(ВидОбъекта), 0));
КонецЕсли;
Если ТипЗначенияСтр(ВидОбъекта) = "Число" Тогда
стрНомер = СокрЛП(Строка(ВидОбъекта));
КонецЕсли;
стрКод = "B";
стрID = глПреобразоватьID(IDОбъекта);
ИначеЕсли ТипОбъекта = "Документ" Тогда
Если ТипЗначенияСтр(ВидОбъекта) = "Число" Тогда
стрНомер = СокрЛП(Строка(ВидОбъекта));
КонецЕсли;
стрКод = "O";
стрID = глSQLПреобразоватьID(IDОбъекта);
ИначеЕсли ТипОбъекта = "Перечисление" Тогда
Если ТипЗначенияСтр(ВидОбъекта) = "Строка" Тогда
ВидОбъекта = Число(глПолучитьМетаIDОбъекта(Метаданные.Перечисление(ВидОбъекта), 0));
КонецЕсли;
Если ТипЗначенияСтр(ВидОбъекта) = "Число" Тогда
стрНомер = СокрЛП(Строка(ВидОбъекта));
КонецЕсли;
стрКод = "E";
стрID = глПреобразоватьID(IDОбъекта);
КонецЕсли;
Результат = "{""" + стрКод + """,""0"",""0"",""" + стрНомер + """,""0"",""0"",""" + стрID + """}";
Попытка
Объект = ЗначениеИзСтрокиВнутр(Результат);
Исключение
Сообщить(ОписаниеОшибки(),"!!!");
Сообщить(">> Тип = '" + ТипОбъекта + "'","!");
Сообщить(">> Вид = '" + ВидОбъекта + "'","!");
Сообщить(">> ID = '" + IDОбъекта + "'","!");
Сообщить(">> Знач = " + Результат ,"!");
Возврат 0;
КонецПопытки;
Возврат Объект;
КонецФункции
Соберем все вместе в маленьком примере. Предположим нам надо выбрать из справочника контрагентов только тех у который определенный ответственный менеджер и которые находятся в определенном регионе.
Функция ПолучитьТЗКонтрагентовПоУсловию(ВыбМенеджер, ВыбРегион)
тзРезультат = СоздатьОбъект("ТаблицаЗначений");
тзРезультат.НоваяКолонка("Контрагенты", "Справочник.Контрагенты");
метаIDКонтрагента = Число(глПолучитьМетаIDОбъекта(Метаданные.Справочник("Контрагенты"), 0));
РеквизитОтвМенеждер = Метаданные.Справочник("Контрагенты").Реквизит("ОтветственныйМенеджер");
метаIDОтветственныйМенеджер = Число(глПолучитьМетаIDОбъекта(РеквизитОтвМенеджер, 0));
РеквизитРегион = Метаданные.Справочник("Контрагенты").Реквизит("Регион");
метаIDРегион = Число(глПолучитьМетаIDОбъекта(РеквизитРегион, 0));
IDМенеджера = глПолучитьIDОбъекта(ВыбМенеджер.ТекущийЭлемент(), 1);
IDРегиона = глПолучитьIDОбъекта(ВыбРегион.ТекущийЭлемент(), 1);
стрЗапрос =
"SELECT ID
|FROM SC" + метаIDКонтрагента + "
|WHERE
| SP" + метаIDОтветственныйМенеджер + " = " + IDМенеджера + "
| AND SP" + метаIDРегион + " = " + IDРегиона;
objSQLЗапрос = "";
глВыполнитьЗапрос(objSQLЗапрос, стрЗапрос);
//GotoNext - переход к следующей записи
objSQLЗапрос.GotoNext();
//IsOk - Возвращает 1, если есть выбранный элемент
Пока objSQLЗапрос.IsOK() <> 0 Цикл
тзРезультат.НоваяСтрока();
//GetString - получить строковое значение из выборки
текЗначение = objSQLЗапрос.GetString(0);
тзРезультат.Контрагенты = глПолучитьОбъектПоID("Справочник", метаIDКонтрагента, текЗначение);
objSQLЗапрос.GotoNext();
КонецЦикла;
//Close - закрытие выборки
objSQLЗапрос.Close();
objSQLЗапрос = "";
Возврат тзРезультат;
КонецФункции
Но несмотря на все достоинства у "Rainbow" присутствует ряд недостатков:
- Так как "Rainbow" работает с базой данных в контексте с 1С, то ошибка в SQL запросе приводит к системной ошибке самой 1С, и как следствие, закрытию программы.
- По этой же причине попытка обратится к SQL серверу при открытом объекте ODBCQuery (например, создать новый элемент справочника) вызовет системную ошибку 1С и ее закрытие.
- "Rainbow" не умеет корректно возвращать значения типа NUMERIC(n, m). Поэтому приходится в запросе выполнять преобразование к типу CHAR, а затем в 1С выполнять обратное преобразование.
- "Rainbow" не умеет обрабатывать ошибки в пакетном запросе. Т.е. если Вы выполняете пакет команд SQL, то вполне вероятна ситуация, при которой одна из первых команд не выполнится из-за ошибки (например, ошибка в вызываемой из пакета хранимой процедуре), а остальные будут выполняться далее. В этом случае никакой ошибки "Rainbow" не сгенерит, и чтобы узнать об успешности выполнения всех команд пакета Вам придется приложить ряд усилий.
Но перечисленные недостатки не отменяют основных преимуществ "Rainbow":
- Способность работать в монопольном режиме.
- Наличие средств работы с метаданными.
На сегодня все. Далее мы рассмотрим способы подключения к базе данных с использованием технологии ADODB.
|