Каталог решений - Модель запроса

Модель запроса

Модель запроса

В наличии

Работа с текстом запроса напрямую не позволяет просто обратиться к определенному полю, таблице или условию. Однако, работая со схемой, можно добавить к существующему условию новое или вообще включить его в состав другой группы. Как ни странно, в типовых решениях часто можно встретить код работы с текстом запроса наряду с использование схемы. Возможно появление удобной библиотеки или нового объектного подхода позволит отказаться от работы с текстом совсем, а код построения запроса будет аутентичен исходному запросу, но без избыточности и доступный для простой модификации.

Категория:

Описание

Оглавление

Объектная модель запроса

Варианты работы

Схема запроса, библиотечный подход

Контекст построения схемы запроса

Объект "Модель запроса"

Примеры работы с моделью

Временная таблица из параметра по образцу

Вложенные подзапросы

Метка

Параметры виртуальной таблицы

Соединение, связь

Оператор условия: Условие, УсловиеСвязи, Отбор

Расширение оператора условия — "%ОператорУсловия%Вхождения"

Поле, ЕстьNull, Агрегатные функции, Автономер

Обработка результата

Поставка


Объектная модель запроса

Варианты работы

Поддержка объектной модели запроса позволяет повысить уровень абстракции при работе с запросами SQL. Теперь запрос SQL перестал быть просто текстом, это уже составной объект, в котором можно независимо работать с разными его частями: с источниками и их полями, с отборами и связями, с запросами в составе пакета и их колонками и т.д.

Ниже представлен типовой пример запроса и его объектное представление в разных вариантах: предложенном 1С, с использованием библиотеки РаботаСоСхемойЗапроса, с использованием объекта МодельЗапроса.

ВЫБРАТЬ
    ТоварныеЗапасыОстатки.Номенклатура КАК Товар,
    ТоварныеЗапасыОстатки.МестоХранения КАК Склад,
    ТоварныеЗапасыОстатки.КоличествоОстаток КАК КоличествоОстаток,
    ВЫБОР
        КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
            ТОГДА "Достаточно"
        ИНАЧЕ "Недостаточно"
    КОНЕЦ КАК Состояние
ИЗ
    РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки КАК ТоварныеЗапасыОстатки
ГДЕ
    ТоварныеЗапасыОстатки.МестоХранения = &Склад
УПОРЯДОЧИТЬ ПО
    Товар,
    Склад,
    КоличествоОстаток
ИТОГИ ПО
    ОБЩИЕ,
    Товар,
    Склад

Пример исходного запроса

СхемаЗапроса = Новый СхемаЗапроса;
Пакет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.ВыраженияИтогов.Добавить("Сумма(" + КолонкаКоличество.Псевдоним +")");

Код формирования схемы, предложенный 1С. Проверить работоспособность кода можно в конструкторе схемы запроса. Для проверки нужно вставить текст примера в поле текст модуля конструктора, затем вызвать команду "получить текст запроса". 

Перем СхемаЗапроса, ОператорВыбрать;
//  ЗАПРОС ПАКЕТА 0
ЗапросПакета    = РаботаСоСхемойЗапроса.ЗапросПакета(СхемаЗапроса,,, ОператорВыбрать);
РаботаСоСхемойЗапроса.Источник(ОператорВыбрать, "РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки");
ОператорВыбрать.Отбор.Добавить("ТоварныеЗапасыОстатки.МестоХранения = &Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.Номенклатура", "Товар");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.МестоХранения", "Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ТоварныеЗапасыОстатки.КоличествоОстаток");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВЫБОР
|   КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
|       ТОГДА ""Достаточно""
|   ИНАЧЕ ""Недостаточно""
|КОНЕЦ", "Состояние");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "Товар");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "Склад");
РаботаСоСхемойЗапроса.Порядок(ЗапросПакета, "КоличествоОстаток");
РаботаСоСхемойЗапроса.Итог(ЗапросПакета, "Товар", "Товар", );
РаботаСоСхемойЗапроса.Итог(ЗапросПакета, "Склад", "Склад", );
ЗапросПакета.ОбщиеИтоги = Истина;

Формирование схемы с использованием библиотеки РаботаСоСхемойЗапроса

МодельЗапроса = Общий.МодельЗапроса();
//  ЗАПРОС ПАКЕТА. Остатки
МодельЗапроса.ЗапросПакета("Остатки");
МодельЗапроса.Выбрать()
    .Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
    .Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
    .Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
    .Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
    .Поле("ВЫБОР
    |   КОГДА ТоварныеЗапасыОстатки.КоличествоОстаток > 0
    |       ТОГДА ""Достаточно""
    |   ИНАЧЕ ""Недостаточно""
    |КОНЕЦ", "Состояние")
    .Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад");
МодельЗапроса.Порядок("Товар").Порядок("Склад").Порядок("КоличествоОстаток");
МодельЗапроса.Группировка("Товар").Группировка("Склад").ОбщиеИтоги();

Формирование схемы через модель запроса. Данный код можно проверить в конструкторе модели запроса по аналогии с конструктором схемы в примере выше.

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

Схема запроса, библиотечный подход

Реализованный в платформе объект "Схема запроса" в полной мере представляет объектную модель запроса. У схемы запроса есть один существенный недостаток — его поведение при программном использовании повторяет таковое при интерактивной работе пользователя в конструкторе запросов. Это приводит к неожиданному результату, когда программное описание запроса не соответствует его реальному представлению. Более подробно об этом было написано в моей статье, а также предложено обходное решение на базе использования библиотеки "Работа со схемой запроса".

Еще в схеме запроса сильно не хватает средств для построения описания полей выборки по образцу (объект метаданных, таблица), а также операций по модификации и копирования составляющих объектов схемы. Эти возможности реализованы в библиотеке.

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

Использование библиотеки "РаботаСоСхемойЗапроса" позволяет получать однозначный результат построения схемы запроса с использованием минимального количества промежуточных переменных текущего состояния. Дополнительные функции построения выборки по образцу (копия оператора, запрос из таблицы) позволяют быстро конструировать схему запроса на основе готовых структур (таблицы значений, коллекции данных формы, табличные части), и, таким образом, избавляют от избыточности. Функции модификации схемы позволяют делать уточнения структуры путем переопределения выражения полей или удаления лишних, замену источников данных, изменение параметров виртуальных таблиц, условий соединения и отборов. Библиотека позволяет генерировать условия связей полей соединения по простому списку или по условию вхождения кортежей исходной таблицы источника в кортежи указанной таблицы. Последнее доступно также для использования в условиях виртуальной таблице или в отборе.

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

Работа с библиотекой позволяет существенно сократить объем кодирования и позволяет быстро создавать схемы запросов по шаблонам. А обращение к результату пакета по имени не только вносит дополнительную семантику тексту запроса, но и повышает надежность программы.

Контекст построения схемы запроса

Однако несмотря на все преимущества использовании библиотеки у нее есть существенный недостаток — необходимость работы с контекстом. Разные функции библиотеки требуют передачи разных контекстов: запрос пакета, оператор выборки, источник данных, соединение, поле и даже целиком объект схема запроса. Настоящий контекстный взрыв происходит при попытке описать таким образом построение вложенных запросов. Требование контекста приводит к необходимости использования переменных и к использованию большого количества параметров функций. По сути функции работают с разными состояниями объекта схемы запроса, характеризуемыми объектами контекста.

ВЫБРАТЬ
    ВложенныйЗапрос.Товар КАК Товар,
    ВложенныйЗапрос.Склад КАК Склад,
    ВложенныйЗапрос.КоличествоОстаток КАК КоличествоОстаток
ИЗ
    (ВЫБРАТЬ
        ВложенныйЗапрос.Товар КАК Товар,
        ВложенныйЗапрос.Склад КАК Склад,
        ВложенныйЗапрос.КоличествоОстаток КАК КоличествоОстаток
    ИЗ
        (ВЫБРАТЬ
            ТоварныеЗапасыОстатки.Номенклатура КАК Товар,
            ТоварныеЗапасыОстатки.МестоХранения КАК Склад,
            ТоварныеЗапасыОстатки.КоличествоОстаток КАК КоличествоОстаток
        ИЗ
            РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки КАК ТоварныеЗапасыОстатки
        ГДЕ
            ТоварныеЗапасыОстатки.МестоХранения = &Склад) КАК ВложенныйЗапрос) КАК ВложенныйЗапрос

Пример текста запроса с двумя вложенными подзапросами

Перем СхемаЗапроса, ОператорВыбрать;
////////////////////////////////////////////////////////////////////////////////
//  ЗАПРОС ПАКЕТА 0
ЗапросПакета 	= РаботаСоСхемойЗапроса.ЗапросПакета(СхемаЗапроса,,, ОператорВыбрать);
ВложенныйЗапросЗапросПакета = РаботаСоСхемойЗапроса.Источник(ОператорВыбрать, РаботаСоСхемойЗапроса.ОписаниеВложенногоЗапроса(), "ВложенныйЗапрос").Источник.Запрос;
//{	Вложенный запрос ВложенныйЗапрос
ВложенныйЗапросОператорВыбрать = РаботаСоСхемойЗапроса.Оператор(ВложенныйЗапросЗапросПакета);
ВложенныйЗапросВложенныйЗапросЗапросПакета = РаботаСоСхемойЗапроса.Источник(ВложенныйЗапросОператорВыбрать, РаботаСоСхемойЗапроса.ОписаниеВложенногоЗапроса(), "ВложенныйЗапрос").Источник.Запрос;
//{	Вложенный запрос ВложенныйЗапросВложенныйЗапрос
ВложенныйЗапросВложенныйЗапросОператорВыбрать = РаботаСоСхемойЗапроса.Оператор(ВложенныйЗапросВложенныйЗапросЗапросПакета);
РаботаСоСхемойЗапроса.Источник(ВложенныйЗапросВложенныйЗапросОператорВыбрать, "РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки");
ВложенныйЗапросВложенныйЗапросОператорВыбрать.Отбор.Добавить("ТоварныеЗапасыОстатки.МестоХранения = &Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.Номенклатура", "Товар");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.МестоХранения", "Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросВложенныйЗапросЗапросПакета, ВложенныйЗапросВложенныйЗапросОператорВыбрать,, "ТоварныеЗапасыОстатки.КоличествоОстаток");
//}	Вложенный запрос ВложенныйЗапросВложенныйЗапрос
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.Товар");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.Склад");
РаботаСоСхемойЗапроса.Поле(ВложенныйЗапросЗапросПакета, ВложенныйЗапросОператорВыбрать,, "ВложенныйЗапрос.КоличествоОстаток");
//}	Вложенный запрос ВложенныйЗапрос
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.Товар");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.Склад");
РаботаСоСхемойЗапроса.Поле(ЗапросПакета, ОператорВыбрать,, "ВложенныйЗапрос.КоличествоОстаток");

Решение задачи построения схемы запроса с вложенными подзапросами при использованием библиотеки РаботаСоСхемойЗапроса

МодельЗапроса = Общий.МодельЗапроса();
//  ЗАПРОС ПАКЕТА. ВложенныйЗапрос
МодельЗапроса.ЗапросПакета("ВложенныйЗапрос").Выбрать()
    .ИсточникНачать("ВложенныйЗапрос")
        .Выбрать()
            .ИсточникНачать("ВложенныйЗапрос")
                .Выбрать()
                    .Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
                    .Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
                    .Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
                    .Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
                    .Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад")
            .ИсточникЗавершить()
            .Поле("ВложенныйЗапрос.*")
    .ИсточникЗавершить()
    .Поле("ВложенныйЗапрос.*");

Тоже решение с моделью запроса

Сами объекты контекста тоже где то нужно сохранять. На практике для хранения минимального контекста используются переменные: СхемаЗапроса, ОператорВыбрать, СтруктураЗапроса. Но не все состояние хранится в переменных, частично состояние передается в функции по их псевдониму. Так, например, для описания соединения используются псевдонимы источников слева и справа.

Использование переменных само по себе является потенциальным источником ошибок, а необходимость передачи контекста в функции приводит к избыточности в тексте программы. Возможными решениями по избавлению от этих недостатков могут быть: использование для хранения контекста такого объекта как Структура или использование в качестве объекта Обработки.

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

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

Объект "Модель запроса"

Вопрос что делать с контекстом меня мучил уже давно, однако перспектива переписать всю библиотеку занова сдерживала меня. Если идти по пути использования Структуры для сохранения контекста, то переписывание библиотеки неизбежно, т.к. меняется интерфейс функций. Если же использовать Обработку как объект с инкапсуляцией состояния, то можно переиспользовать библиотеку за фасадом методов.

Удачной иллюстрацией подхода с инкапсуляцией состояния для меня стала публикация "Новый способ программной настройки условного оформления". Чем больше я думал над этим примером, тем больше перспектив я видел при использовании Обработок в качестве объектов с инкапсуляцией в приложении к различным задачам. И хорошим поводом попробовать новый подход стала реализация модели запроса.

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

Фасад модели был расширен за счет реализации части настроек схемы через вызов методов. Например для установки автопорядка был добавлен метод Автопорядок(), установки параметра виртуальной таблицы Период — Период("Месяц") и т.д. Использование методов для установки свойств позволяет не прерывать интерфейс вызова, реализуя текучий интерфейс.

В обработке интерактивного конструктора реализована модель построения кода в стиле текучего интерфейса. Текучий интерфейс позволяет избавиться от избыточного повторения имени объекта контекста и полностью сосредоточится на выполнении последовательности методов. Фактически через него реализуется DSL по построению модели запроса.

Примеры работы с моделью

Примеры для работы с моделью вы можете получить для своих запросов самостоятельно используя обработку "Конструктор модели запроса". Порядок работы с обработкой аналогичен из поставки библиотеки "Работа со схемой запроса".

Некоторые неочевидные возможности я рассмотрю подробнее. Для начала взгляните на пример текста запроса и вариант построения модели:

ВЫБРАТЬ
    Таблица.Номенклатура КАК Номенклатура,
    Таблица.Организация КАК Организация
ПОМЕСТИТЬ ВТ_ИЗМЕРЕНИЯ
ИЗ
    &Таблица КАК Таблица
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ИЗМЕРЕНИЯ.Номенклатура КАК Номенклатура,
    ВТ_ИЗМЕРЕНИЯ.Организация КАК Организация,
    ЕСТЬNULL(ТоварныеЗапасыОстатки.МестоХранения, ЗНАЧЕНИЕ(Справочник._ДемоМестаХранения.ПустаяСсылка)) КАК Склад,
    ЕСТЬNULL(ТоварныеЗапасыОстатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
    ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки(, (Организация) В (ВЫБРАТЬ РАЗЛИЧНЫЕ Организация ИЗ ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ)) КАК ТоварныеЗапасыОстатки
        ПО (ВТ_ИЗМЕРЕНИЯ.Организация = ТоварныеЗапасыОстатки.Организация
                И ВТ_ИЗМЕРЕНИЯ.Номенклатура = ТоварныеЗапасыОстатки.Номенклатура)
УПОРЯДОЧИТЬ ПО
    Номенклатура,
    Организация,
    Склад
АВТОУПОРЯДОЧИВАНИЕ

Пример текста запроса

 

    Таблица = РегистрыНакопления._ДемоОстаткиТоваровВМестахХранения.СоздатьНаборЗаписей().ВыгрузитьКолонки("Организация,Номенклатура");
    МодельЗапроса = Общий.МодельЗапроса();
    //  Запрос пакета. ВТ_ИЗМЕРЕНИЯ
    МодельЗапроса.ЗапросПакета().Поместить("ВТ_ИЗМЕРЕНИЯ");
    МодельЗапроса.Выбрать()
        .Источник("&Таблица", "Таблица", Таблица).Поле("*");
    //  ЗАПРОС ПАКЕТА. Остатки
    МодельЗапроса.ЗапросПакета("Остатки");
    МодельЗапроса.Выбрать()
        .Источник("ВТ_ИЗМЕРЕНИЯ")
        .Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
        .УсловиеВхождения("ВТ_ИЗМЕРЕНИЯ", "Организация")
        .ЛевоеСоединение("ВТ_ИЗМЕРЕНИЯ", "ТоварныеЗапасыОстатки").Связь("Организация, Номенклатура")
        .Поле("ВТ_ИЗМЕРЕНИЯ.*")
        .Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад", "ЗНАЧЕНИЕ(Справочник._ДемоМестаХранения.ПустаяСсылка)")
        .Поле("ТоварныеЗапасыОстатки.КоличествоОстаток", "Остаток", "0");
    МодельЗапроса.Порядок("Номенклатура").Порядок("Организация").Порядок("Склад").Автопорядок();
    //  Обработка результата
    Сообщить(МодельЗапроса.ПолучитьТекстЗапроса());
    МодельЗапроса.Параметр("Таблица", Таблица);
    МодельЗапроса.ВыполнитьЗапрос();
    РезультатЗапроса = МодельЗапроса.Результат("Остатки");

Пример кода построения модели запроса с последующей обработкой результата запроса. Для проверки примера уберите секцию обработки результата или скопируйте текст в консоль кода.

 

Временная таблица из параметра по образцу

В следующем примере представлена возможность описания запроса выборки временной таблицы из таблицы значений. Сама выборка определяется в описании источника: вначале указано имя параметра (в обычном варианте здесь указывается имя таблицы), затем псевдоним и последним параметром — сама таблица значений (Табличная часть, Коллекция данных формы, Колонки).

На этапе построения схемы запроса таблица значений служит лишь образцом, необходимым для определения состава и типа колонок временной таблицы. В качестве образца могут быть следующие типы: Таблица значений, Коллекция данных формы, Табличная часть, Строка колонок через запятую, Массив или Колонки. Сами поля при этом перечислять не обязательно, достаточно использовать краткую форму — "*".

        .Источник("&Таблица", "Таблица", Таблица).Поле("*");

Описание источника временной таблицы

 

Вложенные подзапросы

Описание в качестве источника вложенного запроса является хорошей иллюстрацией, когда контекст, рекурсивно повторяющийся для каждого подзапроса, скрыт в модели.

Технически текущий контекст для каждого уровня вложенности сохраняется на стеке в операторе ИсточникНачать. По окончании описания подзапроса оператором ИсточникЗавершить из стека восстанавливается предыдущий контекст модели.

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

    .ИсточникНачать("ВложенныйЗапрос")
        .Выбрать()
            .ИсточникНачать("ВложенныйЗапрос")
                .Выбрать()
                    .Источник("РегистрНакопления._ДемоОстаткиТоваровВМестахХранения.Остатки", "ТоварныеЗапасыОстатки")
                    .Поле("ТоварныеЗапасыОстатки.Номенклатура", "Товар")
                    .Поле("ТоварныеЗапасыОстатки.МестоХранения", "Склад")
                    .Поле("ТоварныеЗапасыОстатки.КоличествоОстаток")
                    .Отбор("ТоварныеЗапасыОстатки.МестоХранения = &Склад")
            .ИсточникЗавершить()
            .Поле("ВложенныйЗапрос.*")
    .ИсточникЗавершить()
    .Поле("ВложенныйЗапрос.*");

Рекурсивное описание подзапросов

Метка

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

МодельЗапроса.ЗапросПакета("Остатки");
…
РезультатЗапроса = МодельЗапроса.Результат("Остатки");

Определение метки на запроса и использование ее для получения результата

Параметры виртуальной таблицы

Во втором запросе пакета в качестве источника выступает виртуальная таблица остатков. Параметры таблицы можно задать сразу (см. описание оператора Источник) или в следующих операторах: Периодичность, НачалоПериода, КонецПериода, Период, Условие и т.д.

 

Соединение, связь

Обычно условие соединения описывается как связь полей таблицы слева и справа. Для быстрого описания такого рода условий используется оператор Связь, в параметры которого передается список полей. Если поля различаются, то указывается выражение вида "Поле слева = Поле справа", иначе просто достаточно указать Имя поля или полей через запятую.

        .ЛевоеСоединение("ВТ_ИЗМЕРЕНИЯ", "ТоварныеЗапасыОстатки").Связь("Организация, Номенклатура")

Пример использования оператора Связь по полям Организация, Номенклатура

Оператор условия: Условие, УсловиеСвязи, Отбор

Следущие операторы задают условия для разных контекстов. Оператор "Условие" относится к параметру виртуальной таблицы, "УсловиеСвязи" — условию соединения из секции ПО, "Отбор" — условию секции ГДЕ.

 

Расширение оператора условия — "%ОператорУсловия%Вхождения"

В данном примере используется расширение оператора Условие как УсловиеВхождения (см. аналоги: СвязьВхождения, ОтборВхождения — для задания условия соединения и секции ГДЕ соответственно). Такого вида условие предполагает следующий текст запроса:

"(%1) В (ВЫБРАТЬ РАЗЛИЧНЫЕ %2 ИЗ %3 КАК %3)”, где 1 — поля таблицы слева, 2 — поля таблицы справа, 3 — псевдоним таблицы справа.

(Организация) В (ВЫБРАТЬ РАЗЛИЧНЫЕ Организация ИЗ ВТ_ИЗМЕРЕНИЯ КАК ВТ_ИЗМЕРЕНИЯ)

Текст запроса вхождения

        .УсловиеВхождения("ВТ_ИЗМЕРЕНИЯ", "Организация")

Оператор вхождения для параметра виртуальной таблицы (СвязьВхождения, ОтборВхождения — для соединения и секции ГДЕ соответственно)

 

Поле, ЕстьNull, Агрегатные функции, Автономер

Описание полей указывается после описания источника, из которого эти поля могут быть выбраны. Формат оператора поля допускает опускать псевдоним, тогда псевдоним будет сгенерирован по-умолчанию. Также для поля допускается указать null значение в третьем параметре.

        .Поле("ТоварныеЗапасыОстатки.КоличествоОстаток", "Остаток", "0");

Выражение оператора эквивалентно тексту запроса ЕСТЬNULL(ТоварныеЗапасыОстатки.КоличествоОстаток, Остаток,  0)

Для использования агрегатных функций можно использовать предопределенные операторы: Сумма, Количество, КоличествоРазличных, Максимум и Минимум. При этом система автоматически сформирует состав полей группировки.

И на последок — оператор Автономер(Псевдоним), который добавляет поле с функцией АВТОНОМЕРЗАПИСИ().

 

Обработка результата

Для получения результата запроса необходимо: установить параметры, выполнить запрос, обратиться к результату запроса.

    МодельЗапроса.Параметр("Таблица", Таблица);
    МодельЗапроса.ВыполнитьЗапрос();
    РезультатЗапроса = МодельЗапроса.Результат("Остатки");

Установка параметра — таблица значений, выполнение запроса, обращение к результату запроса по метке

Поставка

Подсистема включает библиотеку РаботаСоСхемойЗапроса. Есть несущественная зависимость от БСП на уровне общих функций.

Разработка проекта ведется в EDT с использованием возможностей последней платформы 8.3.18. При объединении сбросьте признак "Объединять свойства конфигурации". Для варианта с расширением установите режим совместимости согласно версии вашей платформы.

Состав:

Конфигурация или расширение

Общие модули: Общий, ОбщийКлиентСервер, РаботаСоСхемойЗапроса

Обработка: МодельЗапроса

Обработка «Конструктор модели запроса»

 

Проект выложен на github, переход по ссылкам из состава.

 

has been added to your cart:
Оформление заказа