Оглавление:
- Объектная модель запроса
- Объект "Модель запроса"
- Примеры работы с моделью
- Обработка "Конструктор модели запроса"
- Состав и установка
- Зависимости
Объектная модель запроса
Варианты работы
Поддержка объектной модели запроса позволяет повысить уровень абстракции при работе с запросами SQL. Теперь запрос SQL перестал быть просто текстом, это уже составной объект, в котором можно независимо работать с разными его частями: с источниками и их полями, с отборами и связями, с запросами в составе пакета и их колонками и т.д.
Ниже представлен типовой пример запроса и его объектное представление в разных вариантах:
- Программная работа с запросами
- РаботаСоСхемойЗапроса
- МодельЗапроса
Пример исходного запроса:
ВЫБРАТЬ
ТоварныеЗапасыОстатки.Номенклатура КАК Товар,
ТоварныеЗапасыОстатки.МестоХранения КАК Склад,
ТоварныеЗапасыОстатки.КоличествоОстаток КАК КоличествоОстаток,
ВЫБОР
КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
ТОГДА "Достаточно"
ИНАЧЕ "Недостаточно"
КОНЕЦ КАК Состояние
ИЗ
РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки КАК ТоварныеЗапасыОстатки
ГДЕ
ТоварныеЗапасыОстатки.МестоХранения = &Склад
УПОРЯДОЧИТЬ ПО
Товар,
Склад,
КоличествоОстаток
ИТОГИ ПО
ОБЩИЕ,
Товар,
Склад
Код формирования схемы, предложенный 1С. Проверить работоспособность кода можно в конструкторе схемы запроса. Для проверки нужно вставить текст примера в поле "Текст модуля", затем вызвать команду "Получить текст запроса":
СхемаЗапроса = Новый СхемаЗапроса;
Пакет1 = СхемаЗапроса.ПакетЗапросов[0];
Оператор1 = Пакет1.Операторы[0];
// добавим источник в запрос
ТаблицаРегистра = Оператор1.Источники.Добавить("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки");
// добавим поля в запрос
ПолеТовар = Оператор1.ВыбираемыеПоля.Добавить("ТоварныеЗапасыОстатки.Номенклатура", 0);
ДоступноеПолеСклад = ТаблицаРегистра.Источник.ДоступныеПоля.Найти("МестоХранения");
ПолеСклад = Оператор1.ВыбираемыеПоля.Добавить(ДоступноеПолеСклад, 1);
ПолеКоличество = Оператор1.ВыбираемыеПоля.Добавить("КоличествоОстаток", 2);
ВыражениеВыбора = Новый ВыражениеСхемыЗапроса("ВЫБОР
|КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
| ТОГДА ""Достаточно""
| ИНАЧЕ ""Недостаточно""
|КОНЕЦ");
ПолеВыбора = Оператор1.ВыбираемыеПоля.Добавить(Строка(ВыражениеВыбора), 3);
// зададим псевдонимы
Результат = Пакет1.Колонки.Найти(ПолеКоличество);
Результат.Псевдоним = "КоличествоОстаток";
Результат = Пакет1.Колонки[1];
Результат.Псевдоним = "Склад";
Результат = Пакет1.Колонки.Найти(ВыражениеВыбора);
Результат.Псевдоним = "Состояние";
// добавим условие
Оператор1.Отбор.Добавить(Строка(ПолеСклад) + " = &Склад");
// добавим упорядочивание
Пакет1.Порядок.Добавить(ПолеТовар);
Пакет1.Порядок.Добавить("Склад");
Пакет1.Порядок.Добавить("КоличествоОстаток");
// зададим контрольные точки итогов
Пакет1.ОбщиеИтоги = Истина;
Пакет1.КонтрольныеТочкиИтогов.Добавить(ПолеТовар);
Пакет1.КонтрольныеТочкиИтогов.Добавить("Склад");
// зададим агрегатные функции для итогов
КолонкаКоличество = Пакет1.Колонки.Найти(ПолеКоличество);
Пакет1.ВыраженияИтогов.Добавить("Сумма(" + КолонкаКоличество.Псевдоним +")");
Формирование схемы с использованием библиотеки РаботаСоСхемойЗапроса:
Перем СхемаЗапроса, ОператорВыбрать;
// ЗАПРОС ПАКЕТА 0
ЗапросПакета = РаботаСоСхемойЗапроса.ЗапросПакета(СхемаЗапроса,,, ОператорВыбрать);
РаботаСоСхемойЗапроса.Источник(ОператорВыбрать, "РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки");
ОператорВыбрать.Отбор.Добавить("ТоварныеЗапасыОстатки.МестоХранения = &Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.Номенклатура", "Товар");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.МестоХранения", "Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.КоличествоОстаток");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВЫБОР
| КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
| ТОГДА ""Достаточно""
| ИНАЧЕ ""Недостаточно""
|КОНЕЦ", "Состояние");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "Товар");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "Склад");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "КоличествоОстаток");
РаботаСоСхемойЗапроса.Итог(ЗапросПакета, "Товар", "Товар", );
РаботаСоСхемойЗапроса.Итог(ЗапросПакета, "Склад", "Склад", );
ЗапросПакета.ОбщиеИтоги = Истина;
Формирование схемы через модель запроса. Данный код можно проверить в конструкторе модели запроса по аналогии с конструктором схемы в примере выше:
МодельЗапроса = Общий.МодельЗапроса()
;// ЗАПРОС ПАКЕТА. Остатки
МодельЗапроса.ЗапросПакета("Остатки")
.Выбрать()
.Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
.Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад")
// Измерения
.Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
.Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
// Ресурсы
.Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
.Поле("ВЫБОР
| КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
| ТОГДА ""Достаточно""
| ИНАЧЕ ""Недостаточно""
|КОНЕЦ", "Состояние")
.Порядок("Товар")
.Порядок("Склад")
.Порядок("КоличествоОстаток")
.Группировка("Товар")
.Группировка("Склад")
.ОбщиеИтоги()
;
В представленных примерах на мой взгляд самый аутентичный вариант - последний, с использованием объекта МодельЗапроса.
Схема запроса, библиотечный подход
Реализованный в платформе объект "Схема запроса" в полной мере представляет объектную модель запроса. У схемы запроса есть один существенный недостаток - его поведение при программном использовании повторяет таковое при интерактивной работе пользователя в конструкторе запросов. Это приводит к неожиданному результату, когда программное описание запроса не соответствует его реальному представлению. Более подробно об этом было написано в моей статье, а также предложено обходное решение на базе использования библиотеки "Работа со схемой запроса".
Еще в схеме запроса сильно не хватает средств для построения описания полей выборки по образцу (объект метаданных, таблица), а также операций по модификации и копирования составляющих объектов схемы. Эти возможности реализованы в библиотеке.
К сожалению, предложенный в платформе объект не избавляет от высокой степени избыточности характерной для текстов запросов. Так при работе с одной и той же таблицей в нескольких запросах требуется повторить ее описание несколько раз. Это приводит к большому объему повторного кодирования, что потенциально затрудняет дальнейшую модификацию и является источником ошибок. Кроме того, в предложенном варианте от 1С в коде используется большое количество промежуточных переменных и магических чисел.
Использование библиотеки "РаботаСоСхемойЗапроса" позволяет получать однозначный результат построения схемы запроса с использованием минимального количества промежуточных переменных текущего состояния. Дополнительные функции построения выборки по образцу (копия оператора, запрос из таблицы) позволяют быстро конструировать схему запроса на основе готовых структур (таблицы значений, коллекции данных формы, табличные части), и, таким образом, избавляют от избыточности. Функции модификации схемы позволяют делать уточнения структуры путем переопределения выражения полей или удаления лишних, замену источников данных, изменение параметров виртуальных таблиц, условий соединения и отборов. Библиотека позволяет генерировать условия связей полей соединения по простому списку или по условию вхождения кортежей исходной таблицы источника в кортежи указанной таблицы. Последнее доступно также для использования в условиях виртуальной таблице или в отборе.
Еще одна возможность библиотеки - сохранение метки на запрос в пакете. Она позволяет обращаться к результату запроса по имени. Эта возможность удобна, когда для обработки данных требуются результаты разных запросов из пакета. В традиционном подходе требуется кодировать обращение к результату по индексу запроса, однако такое решение ненадежно, т.к. изменение текста запроса может привести к изменению индекса результата. Кроме того именованный запрос позволяет внести в текст программы дополнительную семантику.
Работа с библиотекой позволяет существенно сократить объем кодирования и позволяет быстро создавать схемы запросов по шаблонам. А обращение к результату пакета по имени не только вносит дополнительную семантику тексту запроса, но и повышает надежность программы.
Контекст построения схемы запроса
Однако несмотря на все преимущества использовании библиотеки у нее есть существенный недостаток - необходимость работы с контекстом. Разные функции библиотеки требуют передачи разных контекстов: запрос пакета, оператор выборки, источник данных, соединение, поле и даже целиком объект схема запроса. Настоящий контекстный взрыв происходит при попытке описать таким образом построение вложенных запросов. Требование контекста приводит к необходимости использования переменных и к использованию большого количества параметров функций. По сути функции работают с разными состояниями объекта схемы запроса, характеризуемыми объектами контекста.
Пример текста запроса с двумя вложенными подзапросами:
ВЫБРАТЬ
ВложенныйЗапрос.Товар КАК Товар,
ВложенныйЗапрос.Склад КАК Склад,
ВложенныйЗапрос.КоличествоОстаток КАК КоличествоОстаток
ИЗ
(ВЫБРАТЬ
ВложенныйЗапрос.Товар КАК Товар,
ВложенныйЗапрос.Склад КАК Склад,
ВложенныйЗапрос.КоличествоОстаток КАК КоличествоОстаток
ИЗ
(ВЫБРАТЬ
ТоварныеЗапасыОстатки.Номенклатура КАК Товар,
ТоварныеЗапасыОстатки.МестоХранения КАК Склад,
ТоварныеЗапасыОстатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки КАК ТоварныеЗапасыОстатки
ГДЕ
ТоварныеЗапасыОстатки.МестоХранения = &Склад) КАК ВложенныйЗапрос) КАК ВложенныйЗапрос
Решение задачи построения схемы запроса с вложенными подзапросами при использованием библиотеки РаботаСоСхемойЗапроса:
Перем СхемаЗапроса, ОператорВыбрать;
////////////////////////////////////////////////////////////////////////////////
// ЗАПРОС ПАКЕТА 0
ЗапросПакета = РаботаСоСхемойЗапроса.ЗапросПакета(СхемаЗапроса,,, ОператорВыбрать);
ВложенныйЗапросЗапросПакета = РаботаСоСхемойЗапроса.Источник(ОператорВыбрать, РаботаСоСхемойЗапроса.ОписаниеВложенногоЗапроса(), "ВложенныйЗапрос").Источник.Запрос;
//{ Вложенный запрос ВложенныйЗапрос
ВложенныйЗапросОператорВыбрать = РаботаСоСхемойЗапроса.Оператор(ВложенныйЗапросЗапросПакета);
ВложенныйЗапросВложенныйЗапросЗапросПакета = РаботаСоСхемойЗапроса.Источник(ВложенныйЗапросОператорВыбрать, РаботаСоСхемойЗапроса.ОписаниеВложенногоЗапроса(), "ВложенныйЗапрос").Источник.Запрос;
//{ Вложенный запрос ВложенныйЗапросВложенныйЗапрос
ВложенныйЗапросВложенныйЗапросОператорВыбрать = РаботаСоСхемойЗапроса.Оператор(ВложенныйЗапросВложенныйЗапросЗапросПакета);
РаботаСоСхемойЗапроса.Источник(ВложенныйЗапросВложенныйЗапросОператорВыбрать, "РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки");
ВложенныйЗапросВложенныйЗапросОператорВыбрать.Отбор.Добавить("ТоварныеЗапасыОстатки.МестоХранения = &Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.Номенклатура", "Товар");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.МестоХранения", "Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.КоличествоОстаток");
//} Вложенный запрос ВложенныйЗапросВложенныйЗапрос
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.Товар");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.КоличествоОстаток");
//} Вложенный запрос ВложенныйЗапрос
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.Товар");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.КоличествоОстаток");
Тоже решение с моделью запроса:
МодельЗапроса = Общий.МодельЗапроса()
;// ЗАПРОС ПАКЕТА. ВложенныйЗапрос
МодельЗапроса.ЗапросПакета("ВложенныйЗапрос")
.Выбрать()
.ИсточникНачать("ВложенныйЗапрос")
.Выбрать()
.ИсточникНачать("ВложенныйЗапрос")
.Выбрать()
.Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
.Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад")
.Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
.Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
.Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
.ИсточникЗавершить()
.Поле("ВложенныйЗапрос.*")
.ИсточникЗавершить()
.Поле("ВложенныйЗапрос.*")
;
Сами объекты контекста тоже где то нужно сохранять. На практике для хранения минимального контекста используются переменные: СхемаЗапроса, ОператорВыбрать, СтруктураЗапроса. Но не все состояние хранится в переменных, частично состояние передается в функции по их псевдониму. Так, например, для описания соединения используются псевдонимы источников слева и справа.
Использование переменных само по себе является потенциальным источником ошибок, а необходимость передачи контекста в функции приводит к избыточности в тексте программы. Возможными решениями по избавлению от этих недостатков могут быть: использование для хранения контекста такого объекта как Структура или использование в качестве объекта Обработки.
Сохранение контекста в Структуре может сократить избыточность при вызове функций, однако не может устранить необходимость передачи данной структуры в качестве обязательного параметра при работе с функциями библиотеки.
Большего эффекта можно добиться, если контекст хранить в Обработке. В таком варианте любая функция библиотеки будет иметь гарантированный доступ ко всему необходимому контексту при работе со схемой запроса. Кроме того появляется интересная особенность - возможность использования текучего интерфейса с операторами построения схемы запроса.
Объект "Модель запроса"
Вопрос что делать с контекстом меня мучил уже давно, однако перспектива переписать всю библиотеку занова сдерживала меня. Если идти по пути использования Структуры для сохранения контекста, то переписывание библиотеки неизбежно, т.к. меняется интерфейс функций. Если же использовать Обработку как объект с инкапсуляцией состояния, то можно переиспользовать библиотеку за фасадом методов.
Удачной иллюстрацией подхода с инкапсуляцией состояния для меня стала публикация "Новый способ программной настройки условного оформления". Чем больше я думал над этим примером, тем больше перспектив я видел при использовании Обработок в качестве объектов с инкапсуляцией в приложении к различным задачам. И хорошим поводом попробовать новый подход стала реализация модели запроса.
Разработка модели потребовала относительно небольших усилий, так как является по сути фасадом над уже готовой библиотекой. Потребовалось реализовать методы фасада и полностью переписать конструктор модели.
Фасад модели был расширен за счет реализации части настроек схемы через вызов методов. Например для установки автопорядка был добавлен метод Автопорядок(), установки параметра виртуальной таблицы Период - Период("Месяц") и т.д. Использование методов для установки свойств позволяет не прерывать интерфейс вызова, реализуя текучий интерфейс.
В обработке интерактивного конструктора реализована модель построения кода в стиле текучего интерфейса. Текучий интерфейс позволяет избавиться от избыточного повторения имени объекта контекста и полностью сосредоточится на выполнении последовательности методов. Фактически через него реализуется DSL по построению модели запроса.
Примеры работы с моделью
Примеры для работы с моделью вы можете получить для своих запросов самостоятельно используя обработку "Конструктор модели запроса". Порядок работы с обработкой аналогичен из поставки библиотеки "Работа со схемой запроса".
Некоторые неочевидные возможности я рассмотрю подробнее. Для начала взгляните на пример текста запроса и вариант построения модели:
Пример текста запроса:
ВЫБРАТЬ
Таблица.Номенклатура КАК Номенклатура,
Таблица.Организация КАК Организация
ПОМЕСТИТЬ ВТ_ИЗМЕРЕНИЯ
ИЗ
&Таблица КАК Таблица
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ИЗМЕРЕНИЯ.Номенклатура КАК Номенклатура,
ВТ_ИЗМЕРЕНИЯ.Организация КАК Организация,
ЕСТЬNULL(ТоварныеЗапасыОстатки.МестоХранения, ЗНАЧЕНИЕ(Справочник._ДемоМестаХранения.ПустаяСсылка)) КАК Склад,
ЕСТЬNULL(ТоварныеЗапасыОстатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки(, (Организация) В (ВЫБРАТЬ РАЗЛИЧНЫЕ Организация ИЗ ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ)) КАК ТоварныеЗапасыОстатки
ПО (ВТ_ИЗМЕРЕНИЯ.Организация = ТоварныеЗапасыОстатки.Организация
И ВТ_ИЗМЕРЕНИЯ.Номенклатура = ТоварныеЗапасыОстатки.Номенклатура)
УПОРЯДОЧИТЬ ПО
Номенклатура,
Организация,
Склад
АВТОУПОРЯДОЧИВАНИЕ
Пример кода построения модели запроса с последующей обработкой результата запроса. Для проверки примера уберите секцию обработки результата или скопируйте текст в консоль кода:
Таблица = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей().ВыгрузитьКолонки("Организация,Номенклатура");
МодельЗапроса = Общий.МодельЗапроса()
;// Запрос пакета. ВТ_ИЗМЕРЕНИЯ
МодельЗапроса.ЗапросПакета().Поместить("ВТ_ИЗМЕРЕНИЯ")
.Источник(Таблица)
.Поле("*")
;// ЗАПРОС ПАКЕТА. Остатки
МодельЗапроса.ЗапросПакета("Остатки")
.Выбрать()
.Источник("ВТ_ИЗМЕРЕНИЯ")
.Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
.УсловиеВхождения("ВТ_ИЗМЕРЕНИЯ", "Организация")
.ЛевоеСоединение("ВТ_ИЗМЕРЕНИЯ", "ТоварныеЗапасыОстатки")
.Связь("Организация, Номенклатура")
.Поле("ВТ_ИЗМЕРЕНИЯ.*")
.Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад", "ЗНАЧЕНИЕ(Справочник._ДемоМестаХранения.ПустаяСсылка)")
.Поле("ТоварныеЗапасыОстатки.КоличествоОстаток", "Остаток", "0")
.Порядок("Номенклатура")
.Порядок("Организация")
.Порядок("Склад")
.Автопорядок()
;// Обработка результата
Сообщить(МодельЗапроса.ПолучитьТекстЗапроса());
МодельЗапроса.ВыполнитьЗапрос();
РезультатЗапроса = МодельЗапроса.Результат("Остатки");
Временная таблица из параметра по образцу
В следующем примере представлена возможность описания запроса выборки временной таблицы из таблицы значений. Сама выборка определяется в описании источника: вначале указано имя параметра (в обычном варианте здесь указывается имя таблицы), затем псевдоним и последним параметром - сама таблица значений (Табличная часть, Коллекция данных формы, Колонки).
На этапе построения схемы запроса таблица значений служит лишь образцом, необходимым для определения состава и типа колонок временной таблицы. В качестве образца могут быть следующие типы: Таблица значений, Коллекция данных формы, Табличная часть, Строка колонок через запятую, Массив или Колонки. Сами поля при этом перечислять не обязательно, достаточно использовать краткую форму - "*".
Описание источника временной таблицы:
.Источник(Таблица)
.Поле("*")
;
Вложенные подзапросы
Описание в качестве источника вложенного запроса является хорошей иллюстрацией, когда контекст, рекурсивно повторяющийся для каждого подзапроса, скрыт в модели.
Технически текущий контекст для каждого уровня вложенности сохраняется на стеке в операторе ИсточникНачать. По окончании описания подзапроса оператором ИсточникЗавершить из стека восстанавливается предыдущий контекст модели.
Таким образом количество уровней вложенности позапросов не ограничено моделью, а текст модели при этом выглядит самоподобно и не задействует переменных (см. примеры выше).
Рекурсивное описание подзапросов:
.ИсточникНачать("ВложенныйЗапрос")
.Выбрать()
.ИсточникНачать("ВложенныйЗапрос")
.Выбрать()
.Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
.Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад")
.Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
.Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
.Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
.ИсточникЗавершить()
.Поле("ВложенныйЗапрос.*")
.ИсточникЗавершить()
.Поле("ВложенныйЗапрос.*")
;
Метка
Обратите внимание на оператор создания второго запроса из пакета, в который передается имя запроса "Остатки". В дальнейшем это имя будет использовано в качестве метки, по которой будет извлечен результат запроса.
Определение метки на запроса и использование ее для получения результата:
МодельЗапроса.ЗапросПакета("Остатки");
…
РезультатЗапроса = МодельЗапроса.Результат("Остатки");
Параметры виртуальной таблицы
Во втором запросе пакета в качестве источника выступает виртуальная таблица остатков. Параметры таблицы можно задать сразу (см. описание оператора Источник) или в следующих операторах: Периодичность, НачалоПериода, КонецПериода, Период, Условие и т.д.
Соединение, связь
Обычно условие соединения описывается как связь полей таблицы слева и справа. Для быстрого описания такого рода условий используется оператор Связь, в параметры которого передается список полей. Если поля различаются, то указывается выражение вида "Поле слева = Поле справа", иначе просто достаточно указать Имя поля или полей через запятую.
Пример использования оператора Связь по полям Организация, Номенклатура:
.ЛевоеСоединение("ВТ_ИЗМЕРЕНИЯ", "ТоварныеЗапасыОстатки")
.Связь("Организация, Номенклатура")
Оператор условия: Условие, УсловиеСвязи, Отбор
Следущие операторы задают условия для разных контекстов. Оператор "Условие" относится к параметру виртуальной таблицы, "УсловиеСвязи" - условию соединения из секции ПО, "Отбор" - условию секции ГДЕ.
Расширение оператора условия - "%ОператорУсловия%Вхождения"
В данном примере используется расширение оператора Условие как УсловиеВхождения (см. аналоги: СвязьВхождения, ОтборВхождения - для задания условия соединения и секции ГДЕ соответственно). Такого вида условие предполагает следующий текст запроса:
"(%1) В (ВЫБРАТЬ РАЗЛИЧНЫЕ %2 ИЗ %3 КАК %3)”, где 1 - поля таблицы слева, 2 - поля таблицы справа, 3 - псевдоним таблицы справа.
Текст запроса вхождения:
(Организация) В (ВЫБРАТЬ РАЗЛИЧНЫЕ Организация ИЗ ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ)
Оператор вхождения для параметра виртуальной таблицы (СвязьВхождения, ОтборВхождения - для соединения и секции ГДЕ соответственно):
.УсловиеВхождения("ВТ_ИЗМЕРЕНИЯ", "Организация")
Поле, ЕстьNull, Агрегатные функции, Автономер
Описание полей указывается после описания источника, из которого эти поля могут быть выбраны. Формат оператора поля допускает опускать псевдоним, тогда псевдоним будет сгенерирован по-умолчанию. Также для поля допускается указать null значение в третьем параметре.
Выражение оператора эквивалентно тексту запроса ЕСТЬNULL(ТоварныеЗапасыОстатки.КоличествоОстаток, Остаток, 0):
.Поле("ТоварныеЗапасыОстатки.КоличествоОстаток", "Остаток", "0")
;
Для использования агрегатных функций можно использовать предопределенные операторы: Сумма, Количество, КоличествоРазличных, Максимум и Минимум. При этом система автоматически сформирует состав полей группировки.
И на последок - оператор Автономер(Псевдоним), который добавляет поле с функцией АВТОНОМЕРЗАПИСИ().
Обработка результата
Для получения результата запроса необходимо: установить параметры, выполнить запрос, обратиться к результату запроса.
Установка параметра - таблица значений, выполнение запроса, обращение к результату запроса по метке:
МодельЗапроса
.Параметр("Период", ТекущаяДата())
;
МодельЗапроса.ВыполнитьЗапрос();
РезультатЗапроса = МодельЗапроса.Результат();
Обработка "Конструктор модели запроса"
Интерактивная обработка позволяет генерировать код модели на основе текста запроса. Описание работы аналогично с Обработка "Конструктор схемы запроса".
Состав и установка
Состав
- общий модуль библиотеки РаботаСоСхемойЗапроса
- обработка МодельЗапроса, реализующая объектный интерфейс
- Внешняя обработка "Конструктор модели запроса" (отдельный проект)
- Внешняя обработка "Конструктор схемы запроса" (поставляется как есть)
Установка
Объединить с файлом конфигурации из Демо-базы:
- Установить режим объединения с приоритетом в файле
- Отметить по подсистемам файла:
- KASL->ОбщегоНазначения
- KASL->Модели->МодельЗапроса
- KASL->Конструкторы->КонструкторМодельЗапроса
- KASL->АТДМассив
Зависимости
- БСП 3 (есть несущественная зависимость на уровне общих функций)
- Общие модули из подсистемы KASL->ОбщегоНазначения
- Подсистема АТДМассив
Проект разрабатывается на EDT и выложен в общий доступ на github. Текущая версия платформы 1С 8.3.24.