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

Публикация № 1390402

Разработка - Универсальные функции

Схема запроса запрос модели SQL текучий интерфейс

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

Оглавление

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

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

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

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

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

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

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

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

Метка

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

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

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

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

Поле, Есть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, переход по ссылкам из состава.

 

Скачать файлы

Наименование Файл Версия Размер
Модель запроса: конфигурация

.cf 106,45Kb
0
.cf v1.0.2 106,45Kb Скачать
Модель запроса: расширение

.cfe 36,89Kb
0
.cfe v1.0.2 36,89Kb Скачать
Конструктор модели запроса

.epf 10,36Kb
0
.epf v1.0.2 10,36Kb Скачать
Конструктор схемы запроса

.epf 12,46Kb
0
.epf v2.0.0.5 12,46Kb Скачать
Все файлы одним архивом

.zip 85,21Kb
2
.zip v1.0.2 85,21Kb 2 Скачать

Специальные предложения

Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. artbear 1295 01.03.21 11:32 Сейчас в теме
Хороший результат получается с текучим интерфейсом.

проще и нагляднее.

есть небольшие приятные фишки - не нужно указывать поля таблицы-параметра, поля вложенной таблицы

но главный вопрос так и остается - в чем плюсы подобного построения запроса перед непосредственным текстом запроса?
3. kalyaka 666 01.03.21 12:05 Сейчас в теме
(1)Преимущество в объектной модели запроса проявляется тогда, когда текст запроса получается алгоритмическим образом. Обычно это требуется для динамических запросов, что-то типа СКД, но не для отчетов, а для работы с данными. Например в этой публикации есть решение для параметризированных отборов данных, где требуется "подхватить" исходный запрос из динамического списка и добавить к нему дополнительные условия через соединения или отбор.

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

Даже статические запросы имеет смысл строить через объектную модель. Во первых решение может развиваться и статический запрос вероятно будет меняться, во вторых сложные запросы в алгоритмах можно представить семантически в более простом виде. Запрос, построенный алгоритмически лучше рефакторится, т.к. здесь нет ограничений, накладываемых синтаксисом построения текста запроса.
2. karpik666 3214 01.03.21 11:55 Сейчас в теме
Спасибо, за подробное описание. Однако схема запроса подходит для мелкой доработки типовых запросов, чтобы не лезть в сам текст запроса. Если же сам текст формируется "с нуля" через схему запроса. то периодически поддерживать такую разработку - это ад.
4. kalyaka 666 01.03.21 12:24 Сейчас в теме
(2)На самом деле я сторонник именно построения с нуля, чем модификации. Дело в том, что при построении запроса видна последовательность, а когда модифицируется существующий запрос, то могут быть очень не очевидные последствия. Например удаление поля в первом запросе может изменить текст запроса по всем запросам пакета. Для точечных исправлений предложенное здесь решение врятли будет хорошо работать. Тут больше подойдет слоган: "хочешь изменить запрос - построй его заново" :) Ну или можно достроить
5. karpik666 3214 01.03.21 12:31 Сейчас в теме
(4) вы используете такой вариант построения в командной разработке? Самое забавное начинается, когда схему просят модифицировать через год после реализации задачи.
6. kalyaka 666 01.03.21 14:44 Сейчас в теме
(5)Использую. То что вы пишете можно к любому плохо написанному коду отнести. Вопрос в том, какой сделать выбор сейчас, что бы потом не было так больно🙂 А вся проблема в том, что программирование неразрывно связано со сложностью моделирования объекта предметной области. И здесь по любому будет компромисс. Одним из действенных способов борьбы со сложностью является метод абстракций. Однако палка о двух концах🙂

Вот вам пример. Нужно инициализировать массив числами от 1 до 10. Какой вариант вы предпочтете: поэлементная инициализация или функция с параметрами начала и конца? В приложении к тексту запроса примерно тот же выбор.
7. karpik666 3214 01.03.21 15:01 Сейчас в теме
(6) пример не подходит, потому что не применим к реальным задачам, не припомню ни разу, чтобы требовался массив чисел. Идея я вашу понял, но такая абстракция только усложняет понимание, что конкретно делает запрос, да и последующий рефакторинг тоже, также странно, что подход вы относите к хорошо написанному коду. Мне больше понятна абстракция, которая сделана например в конфигурации ЗУП 3, когда ты вызываешь функцию с параметрами, и получаешь итоговый запрос, таким образом разработчику не нужно знать, где именно расположены данные, а только знать, какие данные ты можешь получить.
8. kalyaka 666 01.03.21 15:31 Сейчас в теме
(7)Практический пример. Делаете вы обработку со статическим запросом и с параметрами. Через какое-то время оказывается, что у запроса переменное число параметров. Параметры не только в секции ГДЕ, но и в параметрах виртуальной таблицы. Создавать запрос через склейку текста или обратиться к его модели?

Кстати я посмотрел как там устроено в ЗУПе. Я об этом писал в статье, что в типовых решениях схема запроса используется наравне с работой с текстом. Текст используется в качестве шаблонов для быстрой инициализации схемы. Так что компромисс такой: шаблоны в виде текста, построение запроса с помощью схемы.
9. karpik666 3214 01.03.21 15:40 Сейчас в теме
(8) чтобы запрос доработать, надо понять, что конкретно он делает, обычно задача поступает, когда либо ты ее не разрабатывал с нуля, либо так давно, что уже и не помнишь, и какое-то время нужно уделить на чтение уже созданного кода. Плюс такое изменение параметров довольно частный случай, возможно понадобится полностью переписать запрос, так как целиком поменялась логика работы, и в таком случае гораздо удобней использовать именно конструктор запросов, а не смотреть на его абстракцию.

Кстати я посмотрел как там устроено в ЗУПе. Я об этом писал в статье, что в типовых решениях схема запроса используется наравне с работой с текстом. Текст используется в качестве шаблонов для быстрой инициализации схемы. Так что компромисс такой: шаблоны в виде текста, построение запроса с помощью схемы.

Да, там используется схема запросов, однако для разработчика, это черный ящик, он не должен задумываться, как там все работает, в него закидываются параметры, а на выходе получается итоговый текст запроса, с таким же успехом можно динамически строить запрос, склеивая из кусков текста, конечный программист все равно это не увидит.
10. JohnyDeath 299 01.03.21 17:40 Сейчас в теме
Очень красиво, лаконично и удобно получилось. Спасибо!
Опробуем в бою
11. Yashazz 3732 02.03.21 17:34 Сейчас в теме
Ну, сомнительна мне польза таких экзерсисов... Типовые всё равно идут по пути строкового конструирования и запихивания во временные, с передачей менеджера ВТ. Поэтому для типовых всё это мало применимо. А свои тем более проще текстом - так оно нагляднее, чем любой код.
Darklight; zqzq; +2 Ответить
12. Ish_2 1061 02.03.21 23:19 Сейчас в теме
(11)
Ну, сомнительна мне польза таких экзерсисов...


Автор в (3) уже обосновал применение "СхемыЗапроса".
Я бы добавил пример когда без "СхемыЗапроса" никак не обойтись.

Допустим, в текущей конфигурации 1с мы должны обрабатывать произвольные запросы к данным ( в синтаксисе запросов 1с) ,поступающие из других приложений 1с или НЕ 1с, используя http-сервис.
Тогда процедура общего модуля в качестве входных параметров имеет :
- строковую переменную "ТекстЗапроса"
- соответствие "ПараметрыЗапроса".
Внутри этой процедуры мы не можем сразу написать :
Запрос= Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.Выполнить()
Нам нужно как минимум перед выполнением проверить "ТекстЗапроса" на синтаксис.
Далее , используя объект "СхемаЗапроса" , возможны некоторые проверки и исправления текста запроса.
( ну, например, у меня в конкретном решении удаляются из запроса поля выборки с типами "ДвоичныеДанные" ,"Тип")

Без объекта "СхемаЗапроса" такая функциональность была бы невозможна.
14. Darklight 27 04.03.21 17:21 Сейчас в теме
Данный комментарий основан на очень давнем моём опыте знакомства со Схемой запроса – а появилась она очень давно, и я тогда возлагал на неё очень большие надежды.
Насколько я знаю "СхемаЗапроса" - та ещё дрянь (пробовал пользоваться года три-четыре назад, тогда желание дальше пользоваться быстро пропало - у данного инструмента пять фундаментальных проблем:
1. Очень ограниченный API на изменения – банально даже поиска нормального даже в линейном списке нет (сейчас – смотрю, что некоторые средства поиска всё-таки появились), не говоря уже о поиске нужной точки изменения во всём запрос (сейчас искать можно только через глубокий рекурсивный перебор всех узлов) - от того конструкции работы с этим объектом просто монструозные - с кучей вложенных циклов или с рекурсией (сейчас, с появление методов «Найти» и «НайтиПоПсевдониму» - правда не везде, и не так как хотелось бы (поиск в глубину, поиск всех, сложно-составной поиск), циклов стало чуть поменьше); и даже если создавать свой хелперский API - всё равно – все банальные операции выливаются в десятки строк кода. В 98% гораздо проще просто обработать текст банальными текстовым функциями. А надёжность - да почти не пострадает (будет на уровне 50% в обоих случаях) - тут просто проблемы уже глубже лежат - внутри самого синтаксиса запросов. API очень нелогичный и запутанный – в нём сложно разбираться и применять его (всё гораздо хуже чем API СКД).

2. Работать можно только очень строго последовательно - т.е. если надо добавить поле - то нужно сначала добавить источник этого поля (если его нет), а чтобы его добавить - нужно добавить все прочие источники, от которых он зависит, и настроить соединения (при этом нельзя переносить готовые источники из других схем). А когда доходит до временных таблиц – так вообще просто жесть какая-то при работе выходит(сейчас, смотрю, тут многое доработали, но всё-равно всё выглядит очень топорно и неудобно).

3. Шаг влево - шаг в право - и всё - сразу ошибка при вызове метода (было бы куда удобнее – если бы встроенный вариатор терпимее относился к ещё недостроенным/неоткорректированным тексам запросов, оставляя проверку хотя бы до момента получения итогового текста запроса). От того вносить правки в запросы - ОЧЕНЬ сложно и громоздко - приходится думать минимум на три шага вперёд и "бегать" по всему API данного объекта и его производных. От того код модификации получается крайне запутанным и трудно воспринимаемым. Ну, а если исходный запрос вообще ещё требует постобработки (да хотя бы банальной сборки из нескольких частей-подзапросов и временных таблиц, а в конфигурациях такое бывает частенько) - то в схему его либо вообще не загрузить, либо если и загрузить - то по выходу потеряются все "управляющие комментарии" (или "фигурные" расширения языка запросов - да хоть для СКД).

4. Если к с запросу написан алгоритм модификации его через схему запроса. А потом у исходного запроса изменится структура – банально – добавиться ещё одна выборка «объединить», или новые поля, или ещё одно вложение – то с большой долей вероятности алгоритм модификации такого запроса перестанет работать (ибо вряд ли его будут составлять так – чтобы он аккуратно рекурсивно выискивал все места, где нужна модификация, строго по именам/выражениям(а уж если изменятся части выражений – то вообще труда) – скорее всего будет банальная адресация по числовым индексам). Да, если запрос модифицируется текстово – то он тоже может перестать работать – но вероятность этого, как я считаю (при правильном подходе к модификации текста) – куда ниже (было бы ещё куда ниже – если бы конструктор запроса позволял больше возможностей по вставке точек интеграции и не удалял псевдонимы в объединяемых запросах).

5. Доступность: "Сервер, толстый клиент, внешнее соединение". Может не так уж принципиально, но порой тексты запросов формируются на клиенте, а потом только передаются на сервер для выполнения (или устанавливаются в интерактивные объекты)

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

Простой пример 1: Модифицируем запрос из временной таблицы (ТЗ) объединение с другим запросом из временной таблицы (ТЗ2)
Текст = "ВЫБРАТЬ ТЗ.А ИЗ ТЗ КАК ТЗ"; //Раньше бы такой текст не прокатил бы, сейчас работает
	Сз = Новый СхемаЗапроса();
	Сз.УстановитьТекстЗапроса(Текст);
	Пз = Сз.ПакетЗапросов[0];
	Оператор = Пз.Операторы.Добавить();
	Оператор.ТипОбъединения = ТипОбъединенияСхемыЗапроса.ОбъединитьВсе;
	ист = Оператор.Источники.Добавить(Тип("ОписаниеВременнойТаблицыСхемыЗапроса"),"ТЗ2","ТЗ").Источник;
	ист.ДоступныеПоля.Добавить("А"); //Вот так нужно определять все поля временной таблицы вне схемы (заранее создать отдельно «ОписаниеВременнойТаблицыСхемыЗапроса» нельзя – нет конструктра)
ист.ДоступныеПоля.Добавить("Б"); //Ещё одно поле для второго примера
	Оператор.ВыбираемыеПоля.Добавить("ТЗ.А");
Показать

А теперь если нужно сделать агрегацию этих запросов по полю «А»:
Пз2 = Сз.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса"));
	Оператор = Пз2.Операторы.Добавить();
	Вложеный = Оператор.Источники.Добавить(Тип("ВложенныйЗапросСхемыЗапроса"),"Вложенный").Источник.Запрос;
	Вложеный.Операторы.Удалить(0); //Удалим автоподарочек - пустой оператор - только тут он не удалится (сначала надо добавить другие операторы)
	Вложеный.Операторы.Добавить(Пз.Операторы[0]); //Спасибо за возможность копирования, ранее её не было
	Вложеный.Операторы.Добавить(Пз.Операторы[1]);
	Вложеный.Операторы.Удалить(0); //Удалим автоподарочек - пустой оператор
	Оператор.ВыбираемыеПоля.Добавить("СУММА(Вложенный.А)");//Не знаю как тут добавить псевдоним поля
	Пз2.Операторы.Удалить(0); //Удалим автоподарочек - пустой оператор
	Сз.ПакетЗапросов.Удалить(0);
	Текст = Сз.ПолучитьТекстЗапроса();
	
	//Получим вот такой запрос
	Текст  = "
	         |ВЫБРАТЬ
	         |	СУММА(Вложенный.А) КАК А
	         |ИЗ
	         |	(ВЫБРАТЬ
	         |		ТЗ.А КАК А
	         |	ИЗ
	         |		ТЗ КАК ТЗ
	         |	
	         |	ОБЪЕДИНИТЬ ВСЕ
	         |	
	         |	ВЫБРАТЬ
	         |		ТЗ.А
	         |	ИЗ
	         |		ТЗ2 КАК ТЗ) КАК Вложенный";
Показать

Вот столько запутанных операторов надо для простого действия – а если нужно собрать запрос на сотни строк (про тысячи я говорить не буду – это уже сложная автоматизация, а не ручные модификации) из десятков таблиц?
Был бы нормальный API – то можно было бы сделать так (не претендую на самый удачный API – просто набросал на скорую руку)
КСЗ_1 = Новый КонструкторСхемыЗапроса("ВЫБРАТЬ ТЗ.А ИЗ ТЗ КАК ТЗ");
	КСЗ_2 = КСЗ_1.Скопировать();
	КСЗ_2.Пакеты[0].Операторы[0].Таблицы[0].Источник.ПутьКДанным= "ТЗ2";
	КСЗ = Новый КонструкторСхемыЗапроса("ВЫБРАТЬ СУММА(Вложенный.А) КАК А"); //Игнорирует, что источника "Вложенный" ещё нет
	ВложеннаяТаблица = КСЗ.Пакеты[0].Выборка[0].Таблицы.Добавить(Тип("ВложенныйЗапросСхемыЗапроса"),"Вложенный"));
	ВложеннаяТаблица.Выборка.Добавить(КСЗ_1.Пакеты[0].Операторы[0]);
	ВложеннаяТаблица.Выборка.Добавить(КСЗ_2.Пакеты[0].Операторы[0]);
	Текст = КС3.ПолучитьТекстЗапроса();
Показать


Простой пример 2: Нужно в готовый запрос добавить таблицу («ЗначенияСвойствОбъектов») левым соединением и выбрать из неё поле значения (за основу возьмём предыдущий итоговый запрос, но левое соединение и выбор поля нужно добавить только к выборке из таблицы ТЗ2 – а в ТЗ1 должно быть NULL, и поле нужно пробросить вверх – сделав по нему группировку). Но только в том, случае – если этой таблицы и этого поля там ещё нет. Будем так же считать, что мы не знаем как и где точно расположена таблица «ТЗ2» в исходном запросе – в какой выборке и является ли она источником или соединением (но, всё-таки, для простоты – будем считать, что общая структура вложенности запросов остаётся как предыдущем примере)
Сз = Новый СхемаЗапроса();
	Сз.УстановитьТекстЗапроса(Текст); //Предыдущий текст
	ВерхнийЗапрос = Сз.ПакетЗапросов[0];
	ВложенныйЗапрос = ВерхнийЗапрос.Операторы[0].Источники[0].Источник.Запрос;
	Операторы = ВложенныйЗапрос.Операторы;
	//Считаем, что мы не знаем в каком из объединяемых запросов находится нужная нам таблица "ТЗ2"
	//ПозицияПоля = 0; //При объединении нужно праивльно соблюдать порядок полей - будем вставлять в начало (если получится)
	ПозицияПоля = -1; //Пока нет позиции
	Если ВложенныйЗапрос.Колонки.Найти("Аналитика")=неопределено Тогда 
		//Только если нужного поля ещё нет
		Для каждого Оператор из Операторы Цикл
			Источник = Оператор.Источники.НайтиПоИмени("ТЗ2"); //Спасибо хоть за какую-то возможность поиска - ранее её не было
			//Если Источник=неопределено Тогда //Приходилось перебрать вручную
			//	Для каждого СтрокаИсточник из Оператор.Источники Цикл 
			//		Если ТипЗнч(СтрокаИсточник.Источник)=Тип("ОписаниеВременнойТаблицыСхемыЗапроса") 
			//		     И СтрокаИсточник.Источник.ИмяТаблицы = "ТЗ2"
			//		Тогда
			//			Источник = СтрокаИсточник.Источник;
			//			прервать;
			//		КонецЕсли;
			//	КонецЦикла
			//КонецЕсли;			
			Если Источник=неопределено Тогда //В этой выборке нет ТЗ2
				//Оператор.ВыбираемыеПоля.Добавить("НЕОПРЕДЕЛЕНО",ПозицияПоля);
				//Вставить в начало не просто - предыдущая строка перетирает поле "А"
				Позиция = Оператор.ВыбираемыеПоля.Количество(); //Это обязательно
				НовоеПоле = Оператор.ВыбираемыеПоля.Добавить("НЕОПРЕДЕЛЕНО", Позиция);
				Если ПозицияПоля=-1 Тогда 
					ПозицияПоля = Оператор.ВыбираемыеПоля.Индекс(НовоеПоле); //какое-то извращение
				КонецЕсли;
			Иначе
				ИмяТаблицы = "РегистрСведений.ЗначенияСвойствОбъектов";
				ПсевдонимТаблицы = "ЗначенияСвойствОбъектовСвойство1";
				//Упрощённая модель поиска (операется на фиксированный псевдоним;
				//иначе был бы дикий перебор с анализом необъектного условия соединения)
				Если Операторы[0].Источники.НайтиПоПсевдониму(ПсевдонимТаблицы) = неопределено Тогда
					Если Источник.Источник.ДоступныеПоля.Найти("Б")=неопределено Тогда 
						//У внешней временной таблицы это обычная ситуация
						Источник.Источник.ДоступныеПоля.Добавить("Б");
					КонецЕсли;
					//или через "одно место": ВложенныйЗапрос.ДоступныеТаблицы[4].Состав[0]
					//поиск там тоже есть, но такой же - по имени
					Ист = Оператор.Источники.Добавить(ИмяТаблицы,ПсевдонимТаблицы); 
					УсловиеСоединения=ПсевдонимТаблицы+".Свойство = &Свойство1 
										    |И "+ПсевдонимТаблицы+".Объект = ТЗ.Б"; 
					//Условия соединений до сих пор не имеют объектной модели API
					Источник.Соединения.Добавить(Ист,УсловиеСоединения);
				//Иначе - таблица есть, но поля для колонки "Аналитика" всё-равно нет - будем добавлять
				КонецЕсли;
				//Оператор.ВыбираемыеПоля.Добавить("Свойство1.Значение",ПозицияПоля);
				Позиция = Оператор.ВыбираемыеПоля.Количество(); //Это обязательно
				НовоеПоле  = Оператор.ВыбираемыеПоля.Добавить(ПсевдонимТаблицы+".Значение", Позиция);
				Если ПозицияПоля=-1 Тогда
					ПозицияПоля = Оператор.ВыбираемыеПоля.Индекс(НовоеПоле); //какое-то извращение
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		Если ПозицияПоля>=0 Тогда
			//Вот, как-то так надо размещать поле в заданной позиции (0 - начало)
			ВложенныйЗапрос.Колонки.Переместить(ПозицияПоля,0); 
			//А вот так придёся задать псевдоним новому полю
			ВложенныйЗапрос.Колонки[0].Псевдоним = "Аналитика"; 
		КонецЕсли;
	КонецЕсли;
	Если ВерхнийЗапрос.Колонки.Найти("Аналитика")=неопределено Тогда
		//Удивительно - группировка добавится автоматически
		НовПоле = ВерхнийЗапрос.Операторы[0].ВыбираемыеПоля.Добавить("Аналитика"); 
		Позиция = ВерхнийЗапрос.Операторы[0].ВыбираемыеПоля.Индекс(НовПоле);
		ВерхнийЗапрос.Колонки.Переместить(Позиция,0);
	КонецЕсли;

	Текст = Сз.ПолучитьТекстЗапроса();
Показать


Вроде бы очень простая задача – а сколько запутанного алгоритма пришлось наваять – новичок тут утонет (хе – а это хорошая задача для теста на собеседовании – небось я там сам вверху ошибок поналяпал – ну по-придираться там точно много де можно). И это всего одна таблица и одно поле – а если нужно было бы их несколько вставлять, а условия интеграции были бы чуть посложнее тривиальной привязки к заданным именам и псевдонимам?
Всё-таки алгоритм изменения запроса с целью добавления новой таблицы и поля должен быть проще и понятнее – вот как-то так
КСЗ = Новый КонструкторСхемыЗапроса(Текст);
	ВерхнийЗапрос = КСЗ.Пакеты[0];
	ВложенныйЗапрос = ВерхнийЗапрос.НайтиТаблицуПоПсевдониму("Вложенный"); //Считаем, что он всегда есть
	//таблица может быть любой, как внутри секци "ИЗ", так и внутри секции "СОЕДИНЕНИЕ"
	//Поиск выше делается последовательно по всем операторам-выборки пакета
	//Иначе нужно коретизировать оператор КСЗ_2.Пакеты[0].Оператор[0].Таблицы.НайтиПоПсевдониму
	КолонкаАналитика = ВложенныйЗапрос.Колонки.НайтиПоПсведониму("Аналитика");
	Если КолонкаАналитика=неопределено 
		//Создадим описание источника (вот так, коли в 1С нет статических методов встроенных классов)
		ИсточникТ32 = КСЗ.СоздатьОписаниеИсточника("ТЗ2",Тип("ВременнаяТаблицаСхемыЗапроса")); 
		Иерархически = Истина;
		ТаблицаТ32 = ВложенныйЗапрос.НайтиТаблицуПоИсточнику(ИсточникТ32,Иерархически);
		//Поиск выше делается последовательно по всем операторам-выборки запроса, 
		//с заходов во все подзапрсы (вложенные и соединения)
		//Ещё можно было бы найти сразу все МассивТ32 = ВложенныйЗапрос.НайтиТаблицы(ПараметрыОтбора,Иерархически)
		Если ТаблицаТ32 <> неопределено Тогда
			ИсточникСвойство1 = КСЗ.СоздатьОписаниеИсточника("РегистрСведений.ЗначенияСвойствОбъектов",
																		Тип("ДоступнаяТаблицаСхемыЗапросов"));
			ТаблицаСвойство1 = КСЗ.СоздатьОписаниеТаблицы(ИсточникСвойство1);
			УсловиеСвойство1 = КСЗ.СоздатьОписаниеУсловия(ТаблицаСвойство1, 
																	"$ТаблицаИсточник",
																	"Свойство",
																	КСЗ.СоздатьОписаниеПараметраЗапроса("Свойство1");
			ТаблицаСвойство1.УсловияСоединений.Добавить(УсловиеСвойство1);
			УсловиеСвойство1 = КСЗ.СоздатьОписаниеУсловия(ТаблицаСвойство1, 
																	"$ТаблицаИсточник",
																	"Объект",
																	"$ТаблицаПриемник",
																	"Б");
			ТаблицаСвойство1.УсловияСоединений.Добавить(УсловиеСвойство1);
			//Выше хитрый приём - создаём описание таблицы, с заданными условиями на соединение
			//Теперь можно найти таблицу, которая будет не только с данным источником данных
			//Но и иметь определённые условия применения (в данном случае - любого соединения
			//Тем самым мы не операемся на псевдоним, а ищем именно правильное назначение
			//Среди таблиц-соединений к нашей целевой табоицы "ТЗ2
			ТаблицаТ32.Соединения.НайтиТаблицу(ТаблицаСвойство1);
			Если Таблица = неопределено Тогда
				//Не нашли - добавим - у нас уже всё есть				
				ТаблицаСвойство1 = ТаблицаТ32.Соединения.ДобавитьЛевоеСоединение(ТаблицаСвойство1); 
				//Соединение - это тоже Таблица
			Иначе
				ТаблицаСвойство1 = Таблица; //Используем реально найденную таблицу
			КонецЕсли;
			КолонкаЗначениеИсточник = ТаблицаТ32.ДопустимыеКолонки.НайтиПоПсевдониму("Значение");
			КолонкаЗначение = КСЗ.СоздатьОписаниеКолонкиТаблицы(КолонкаЗначениеИсточник);
			КолонкаЗначение.Псевдоним = "Аналитика";
			//Для однозначной трактовки переданных значений
			ЗначениеНеопределено = КСЗ.СоздатьОписаниеВыражения("НЕОПРЕДЕЛЕНО"); 
			ЗначениеПоумолчанию = ЗначениеНеопределено;
			//Тут Владелец - это запрос - владелец данной таблицы (а не Оператор этого запроса)
			Колонка = ТаблицаТ32.Владелец.Колонки.Найти(КолонкаЗначение.Псевдоним);
			Если Колонка = неопределено Тогда
				//Колонки нет
				Позиция = 0; //Самая первая колонка
				//Добавим новую колонку в запрос владелец (источники все внутри КолонкаЗначение)
				Колонка = ТаблицаТ32.Владелец.Колонки.Вставить(Позиция, КолонкаЗначение, ЗначениеПоумолчанию);
				//ЗначениеПоумолчанию - позволяет сразу указать значение для других операторов выборки запроса
				//Если нужно было бы вставить для разных операторов объединения специфические значения поля
				//то их нужно было бы заполнить в специальной коллекции типа "КомплексноеОписаниеКолонки"
				//И передавть в один из методов добавления/обнволения колонки
				//Ну или обрабатывать Колонку по её полям для каждой таблицы - заменяя нужные поля методом "Обновить
			Иначе
				//Метод Обновить позволяет обновить поля  существующей комплексной колонки - для заданной таблицы
				//Не изменяя поля дргух таблиц (других операторов объединения)
				Колонка = ТаблицаТ32.Владелец.Колонки.Обновить(Колонка, КолонкаЗначение
			КонецЕсли
			
			//Осталось самое хитрое - протолкнуть созданную колонку "Аналитика" наверх
			//Например во ВложенныйЗапрос
			Если ТаблицаТ32.Владелец <> ВложенныйЗапрос Тогда
				Позиция = 0; //Самая первая колонка
				Пробросить = КС3.Перечисления.РежимПроброскиКолонки.ПроброситьВверх; //А ещё можно вниз
				КолонкаАналитика = ВложенныйЗапрос.Колонки.Вставить(Позиция, Колонка,,,Пробросить); 
				//Вот таквот просто - Колонка - определена где-то воложенной таблице
				//Но если добавлять её во родительскую таблицу - то она будет автоматически проброшена вверх
				//От своего источника до приёмника (если это, возможно, конечно) - иначе - вернёт 
			Иначе
				КолонкаАналитика = Колонка;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ВерхнийЗапрос.Колонки.НайтиПоПсевдониму("Аналитика")=неопределено 
		//Можно было бы пробросить сразу сюда - но для разнообразия добавим вручную
		Позиция = 0
		//Можно было бы так
		//Пробросить = КС3.Перечисления.РежимПроброскиКолонки.ПроброситьВверх; //А ещё можно вниз
		//ВерхнийЗапрос.Вставить(Позиция, НоваяКолонка,,,Пробросить);
		//Но сделаю по-другому - просто найдту доступную колонку во вложенном запросе 
		//(если он сразу внутри верхнего запроса) - это просто демонстрация альтернативного подхода
		КолонкаАналитикаИсточник = ВерхнийЗапрос.ДопустимыеКолонки.НайтиПоПсевдониму("Аналитика");
		КолонкаАналитика = КСЗ.СоздатьОписаниеКолонкиТаблицы(КолонкаЗначениеИсточник);
		ТаблицаТ32.Владелец.Колонки.Вставить(Позиция, КолонкаАналитика
	КонецЕсли;
Показать


Может получилось так же громоздко (даже если убрать все комментарии) – зато, на мой взгляд, куда нагляднее и мощнее типового подхода.
А ещё все эти таблицы можно было бы откреплять от одной схемы и легко добавлять в другие схемы, без изменений или с изменениями – увеличивая повторяемость кода
ДругойКСЗ = Новый КонструкторСхемыЗапроса();
ДругойКСЗ.Пакеты[0].Таблицы.Добавить(ТаблицаТ32.Скопировать(ДругойКСЗ));


А если бы ещё в запросах можно было бы прикреплять точки интеграции (и не тупые управляющие комментарии как в типовых конфигурациюя) – чтобы при анализе схемы запроса можно было бы на них оператся – вообщен круто было бы
Текст  = "
	         |ВЫБРАТЬ
	         |	СУММА(Вложенный.А) КАК А
	         |ИЗ
	         |	(ВЫБРАТЬ
	         |		ТЗ.А КАК А
	         |	ИЗ
	         |		ТЗ КАК ТЗ ИНТЕГРАЦИЯ(Точка1)
	         |	
	         |	ОБЪЕДИНИТЬ ВСЕ
	         |	
	         |	ВЫБРАТЬ
	         |		ТЗ.А
	         |	ИЗ
	         |		ТЗ2 КАК ТЗ ИНТЕГРАЦИЯ(Точка2)) КАК Вложенный";
КСЗ = Новый КонструкторСхемыЗапроса(Текст);
Точка2 = КСЗ.НайтиТочкуИнтеграции(Точка2);
Если ТипЗнч(Точка2.Владелец)=Тип("ТаблицаСхемыЗапроса") И Точка2.Псевдоним = "ТЗ2") Тогда
	ТаблицаТЗ2 = Точка2.Владелец;
	//И далее алгоритм обработки
КонецЕсли;
Показать


Эх, мечты мечты….
Но нештатную библиотеку «РаботаСоСхемойЗапроса» и «МодельЗапроса» изучить конечно будет любопытно – хотя как-то всё тут не привычно (хотя и напоминает мной горячо любимый LINQ – как-то всё сложновато (возможно и моё, вышеприведённое, предложение люди тоже назовут сложным) – наверное, это просто в статье очень сложно и ненаглядно преподносится материал (хотя визуально статья оформлена очень хорошо)

P.S.
За ошибки в тексте в коде алгоритимов прошу прощения
16. kalyaka 666 06.03.21 11:51 Сейчас в теме
(14) 1. глубокая модификации пакета запросов ненадежна. В случае работы с текстовыми шаблонами по хорошему нужен парсер, а это уже практически схема запроса. При работе со схемой велика вероятность, что изменения в одном запросе пакета затронут все остальные. Даже если работать аккуратно, то в процессе модификации могут возникать промежуточные состояния схемы, после которых схема может не вернуться в точности в первоначальное состояние. Например могут поменяться псевдонимы полей, может исчезнуть соединение и не восстановиться и т.д.
Поэтому я для себя сделал вывод: можно модифицировать только путем достраивания последнего запроса пакета: добавление связей, полей, условий. Можно также безопасно копировать оператор выбрать для достраивания запроса путем добавления объединений. Для такого рода модификаций у меня как раз есть функции (пока только в библиотеке): КопияОператора, ЗаменитьИсточник, УдалитьПоле, ВыражениеПоля и т.д.

2. согласен. По поводу "нельзя переносить готовые источники из других схем", то это вопрос необходимости, можно и добавить :)

3. это проблема промежуточных состояний схемы. Схема всегда должна быть валидна.

4. не всегда, например в следующей подсистеме происходит обволакивание любых условий в группу И для любых запросов. Т.е. Устойчивый алгоритм написать можно именно как раз за счет использования схемы.

По примеру 1 приведу иллюстрацию в модели запроса. Я предпочитаю использовать временные таблицы вместо вложений (с вложениями тоже можно):
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("ПолеА",  ОбщегоНазначения.ОписаниеТипаСтрока(10));
Таблица.Колонки.Добавить("ПолеБ",  ОбщегоНазначения.ОписаниеТипаЧисло(15, 2));

МодельЗапроса = Общий.МодельЗапроса();
МодельЗапроса.ЗапросПакета().Поместить("ВТ_1").Выбрать().Источник("&Таблица", "Таблица", Таблица).Поле("*");
МодельЗапроса.ЗапросПакета().Поместить("ВТ_2").Выбрать().Источник("&Таблица", "Таблица", Таблица).Поле("*");
МодельЗапроса.ЗапросПакета().Поместить("ВТ_12")
	.Выбрать()
		.Источник("ВТ_1")
		.Поле("ПолеА")
		.Поле("ПолеБ", "СуммаПоПолюБ_1")
		.Поле("0", "СуммаПоПолюБ_2")
	.ОбъединитьВсе()
		.Источник("ВТ_2")
		.Поле("ПолеА")
		.Поле("0", "СуммаПоПолюБ_1")
		.Поле("ПолеБ", "СуммаПоПолюБ_2");
МодельЗапроса.ЗапросПакета().Источник("ВТ_12")
	.Сумма("СуммаПоПолюБ_1")
	.Сумма("СуммаПоПолюБ_2")
	.Поле("*");
Показать
, что эквивалентно тексту запроса:
ВЫБРАТЬ
	Таблица.ПолеА КАК ПолеА,
	Таблица.ПолеБ КАК ПолеБ
ПОМЕСТИТЬ ВТ_1
ИЗ
	&Таблица КАК Таблица
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Таблица.ПолеА КАК ПолеА,
	Таблица.ПолеБ КАК ПолеБ
ПОМЕСТИТЬ ВТ_2
ИЗ
	&Таблица КАК Таблица
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ВТ_1.ПолеА КАК ПолеА,
	ВТ_1.ПолеБ КАК СуммаПоПолюБ_1,
	0 КАК СуммаПоПолюБ_2
ПОМЕСТИТЬ ВТ_12
ИЗ
	ВТ_1 КАК ВТ_1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ВТ_2.ПолеА,
	0,
	ВТ_2.ПолеБ
ИЗ
	ВТ_2 КАК ВТ_2
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	СУММА(ВТ_12.СуммаПоПолюБ_1) КАК СуммаПоПолюБ_1,
	СУММА(ВТ_12.СуммаПоПолюБ_2) КАК СуммаПоПолюБ_2,
	ВТ_12.ПолеА КАК ПолеА
ИЗ
	ВТ_12 КАК ВТ_12

СГРУППИРОВАТЬ ПО
	ВТ_12.ПолеА
Показать
Теперь модифицируем его. Скажем текст запроса был получен и к нему добавлено условие:
ТекстЗапроса = МодельЗапроса.ПолучитьТекстЗапроса();
МодельЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);
МодельЗапроса.Отбор("СУММА(ВТ_12.СуммаПоПолюБ_1) = СУММА(ВТ_12.СуммаПоПолюБ_2)");
, на выходе получим:
ВЫБРАТЬ
	СУММА(ВТ_12.СуммаПоПолюБ_1) КАК СуммаПоПолюБ_1,
	СУММА(ВТ_12.СуммаПоПолюБ_2) КАК СуммаПоПолюБ_2,
	ВТ_12.ПолеА КАК ПолеА
ИЗ
	ВТ_12 КАК ВТ_12

СГРУППИРОВАТЬ ПО
	ВТ_12.ПолеА

ИМЕЮЩИЕ
	СУММА(ВТ_12.СуммаПоПолюБ_1) = СУММА(ВТ_12.СуммаПоПолюБ_2)
Показать
19. Yashazz 3732 08.03.21 18:08 Сейчас в теме
(16) Схема всегда должна быть валидна? Чего это вдруг? Схема должна быть валидна в момент применения, а до того хоть полуоборванная и кривая.
Darklight; +1 Ответить
22. kalyaka 666 09.03.21 11:22 Сейчас в теме
(19) я исхожу их требования для объекта СхемаЗапроса в платформе.
20. Darklight 27 09.03.21 10:06 Сейчас в теме
(16)
1.
глубокая модификации пакета запросов ненадежна

Всё определяется лишь возможностями API движка. Я, вот, привёл примеры того, как легко делать вполне надёжную глубокую модификацию. И эти примеры я построил на коленке за час. А если подумать над этой задачей подольше - можно и что-то более изящное придумать.
Но....
Во-первых, для глубокой модификации лучше работать через точки интеграции, которые заранее заданы в запросе (пример приводил)
Во-вторых, запросы вообще лучше не модифицировать. Тут в корне нужна иная модель их построения - более декларативная (намекну на типовой "ПостроительЗапроса", но, всё-таки, я имею в виду ещё более продвинутый API, с несколько иным подходом к использованию). Когда запрос изначально собирается по частям из абстрактных частей - которые обретаю целостность и текстовое представление только в момент выполнения. Это особенно актуально на фоне расширений конфигурации 1С - когда модификации вносятся совершенно в других конфигурациях (расширениях) в других блоках программного кода. Но это кардинальные изменения вообще в принципы построения запросов - и это не приемлемо для запросов, которые изначально не применят такую методику.
В-третьих. Моё мнение такое - что для повышения надёжности и производительности - большая часть модификации должна осуществляться статически при компиляции - т.е. развиваться должно макропрограммирование и, опять-же, декларативное программирование, когда - все команды (которые статически определены) по внесению изменений (первичному построению) запроса выполняются ещё при конфигурировании (компиляции) - и можно сразу проконтролировать итоговый результат (а в идеале ещё и выполнить юнит-тесты). Да даже модификация с ветвлением, по возможности, должна быть статической - просто можно сразу сгенерировать несколько версий запроса (и тоже прогнать их по юниттестам), и динамически только выбирать нужный готовый запррос. Да, даже с абстрактными/неполными (на стадии компиляции) полями - при желании, можно было бы тоже готовить условно статические тексты запросов и контролировать их общий синтаксис и частично выполнение (где в рантайме просто делать простую автоподстановку нужных полей - это ещё ПостроительЗапроса умел делать).

Но - такие радикальные изменения, сложны в реализации, особенно без поддержки со стороны платформы, и особенно со стороны типовых конфигураций. В 1С Предприятие 8.x вряд ли стоит ждать таких новаций :-(

В случае работы с текстовыми шаблонами по хорошему нужен парсер, а это уже практически схема запроса

Конечно нужен - нужна полноценная объектная модель всего запроса. "СхемаЗапроса" её даёт, но её API ужасен, и да - он теряет комментарии. К счастью, язык запросов не такой уж сложный - чтобы сделать к нему свой парсер

3. Вот не считаю, что схема всегда должна быть валидна. Её валидность можно было бы проверять только в момент финальной сборки (или отдельным методом). Всё-таки, когда со схемой идёт работа через объектную модель, очень сложно внести в неё совсем уж несовместимые изменения – их, возможно, и стоит пресекать сразу. В остальном – запрос в схеме – это не более чем вложенный набор коллекций простых элементов – и его можно модифицировать как угодно – пока дело не дойдёт до финальной сборки и кодогенерации.
4. Ну, во-первых, я всё-таки говорил про типовой объект «СхемаЗапроса»
А во-вторых…

ТекстЗапроса = МодельЗапроса.ПолучитьТекстЗапроса();
МодельЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);
МодельЗапроса.Отбор("СУММА(ВТ_12.СуммаПоПолюБ_1) = СУММА(ВТ_12.СуммаПоПолюБ_2)");

Честно, не могу понять – как тут определяется правильное место в пакете запросов.
Что здесь «ВТ_12»? Это временная таблица или псевдоним таблицы данных? Или поле? Ведь внутри запроса и то и другое имя может встречаться не один раз раз.
В-третьих, добавлять что-то новое – куда проще, чем вносить изменения в существующее.
Да , и в приведённом примере внести такую модификацию текстом – так же просто (и так же не надёжно при изменении структуры исходного запроса) – не показано ни одного преимущества!

А вот это я вообще не могу понять зачем?

ТекстЗапроса = МодельЗапроса.ПолучитьТекстЗапроса();
МодельЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);
23. kalyaka 666 09.03.21 11:33 Сейчас в теме
(20)
не могу понять – как тут определяется правильное место в пакете запросов
Место определяется последним запросом пакета и последним оператором выбрать.

В этом примере я хотел продемонстрировать как можно начать схему в одном месте и затем продолжить в другом. При этом функции ПолучитьТекстЗапроса() и УстановитьТекстЗапроса() по сути выполняют роль сериализации в текст и восстановления из текста для объекта схемы запроса.
в приведённом примере внести такую модификацию текстом – так же просто
Однако при работе с текстом необходимо определить наличие раздела ИМЕЮЩИЕ. Хотя конечно, можно использовать продвинутую библиотеку, которая это сделает и добавить условие будет также просто, как и в представленном примере. Но последнее означает, что просто добавить условие удобнее, чем перед этим анализировать текст.
24. Darklight 27 09.03.21 13:35 Сейчас в теме
(23)Продолжить в другом месте - вообще никогда не было проблемой. Вот внести изменения где-то внутри - вот это всегда проблема!
Поэтому в (14) я и привёл такие банальные и популярные задачи такой модификации - которые не очень сложно решаются без подходящего API (и все нынешние методики внесения таких изменений нестабильны, при изменении структуры исходного текста запроса). Поэтому там же я привёл своё виденье API для более простого, понятного и стабильного внесения таких изменений не в конец!

Последний абзац вообще не понял
25. kalyaka 666 09.03.21 14:04 Сейчас в теме
(24)Ок, осталось дождаться появления таких удобных АПИ. Или, возможно, механизм представлений из ЗУП вполне себе удобный механизм и его можно взять в качестве образца в своих разработках.
Последний абзац вообще не понял
это я про то, что есть выбор: либо работать с текстом, либо вызвать метод.
17. Yashazz 3732 08.03.21 18:04 Сейчас в теме
(14) Целиком поддерживаю каждый пункт, просто мне категорически не под силу сейчас накатать вдумчивый анализ и критику, подобные этой. Со всем этим сталкивался, после чего желание пользоваться схемой запроса пропало напрочь. Сугубо декларативный инструмент смешали с обрабатываемой базой, данными, их структурой и типами. АПИ СКД действительно в разы более проработанная, гибкая, терпимая (вплоть до наплевательского отношения к метаданным - известные "мёртвые" поля с красными крестами не мешают компоновать декларацию). Так что спасибо за детальный разбор. Надеюсь, теперь яснее, почему мне польза сего сомнительна.
13. JohnyDeath 299 03.03.21 09:11 Сейчас в теме
(11) Я как раз типовые запросы подправляю именно схемой, чтобы не вкарячивать в середину огромного запроса свои доп поля и условия. Соответственно обновление на новый релиз проходит намного быстрей
15. Darklight 27 04.03.21 17:45 Сейчас в теме
(13)Несколько раз так пробовал - очень тяжело (но тогда ещё сам объект "СхемаЗапроса" был менее развит по API - и работа с ним было очень мучительно).

Пока предпочитаю встраиваться в тексты типовых запросов через СтрЗаменить - т.е. ищу подходящий кусочек кода в запросе, и этой функцией после текста запроса его заменяю на него же + мои добавки. Ещё мощная функция "СтрНайти" - для обработки текста запроса частями (позволяет разбивать его на блоки). Всё бы ничего только два момента:
1. Бывают проблемы с группировками, запросами объединениями и условиями - потому что в них нет псевдонимов.
2. Бывает проблемы с табуляцией - к сожалению нет поиска вхождения символов строки без учета табуляции - а порой бывает нужно обрабатывать именно такие участки - где присутствует шатающаяся табуляция

А со схемой запроса в такого рода задачах - это тоже - правильно спозиционироваться в место - где нужно внести доработки - нормальных средств поиска нет.
И когда запросы слишком комплексные - то обычно и однотипные исправления требуются сразу в нескольких местах - и всех их находить - ну очень неудобно. Чаще всего - банально обработать текст - гораздо проще. И обычно такая текстовая обработка хорошо переживает дальнейшее "развитие запроса" (его последующие типовые и не типовые модификации, которые меняют его структуру)
18. Yashazz 3732 08.03.21 18:07 Сейчас в теме
(15) Пробуй потоковым чтением, там поиск и разбивка на фрагменты удобнее; ну и регулярные выражения, чтоб ловить всякую табуляцию и иную ересь. И да, опять же целиком согласен.
21. Darklight 27 09.03.21 10:14 Сейчас в теме
(18)Можете привести пример с потоковым чтением и разбивкой на фрагменты - что-то я пока не соображу что Вы имеете в виду?
Регулярные выражения - мощная штука, жаль не входят в платформу 1С Предприятие, и порой - сами регулярные выражения становятся достаточно сложными при использовании и дальнейшем сопровождении (опять же - в силу отсутствия со стороны платформы поддержки конструкторов, анализаторов, отладчиков). Особенно это всё усложняется при обновлении конфигурации - когда надо понять - нужно ли вносить изменения (и какие) в алгоритм модификации - когда видишь, что типовой запрос изменился (и не видишь нюансы изменения именно в табуляции)
Оставьте свое сообщение

См. также

Программное создание динамического списка на управляемой форме. (Динамическое создание динамического списка). Готовая процедура + обработка - демонстрационный пример Промо

Практика программирования Универсальные функции v8::УФ 1cv8.cf Абонемент ($m)

Если у вас возникает необходимость на форму влиять динамически и создавать элементы управляемой формы программно, а особенно хотите вывести программно (динамически) динамический список, вам будет интересна эта процедура. Процедура включает также возможность формирования своей командной панели (а-ля снятие галочки "Автозаполнение" у стандартной командной панели списка).

1 стартмани

19.01.2018    63423    rpgshnik    31    

Библиотека программного изменения формы (УФ)

Инструментарий разработчика Работа с интерфейсом Универсальные функции v8 1cv8.cf Абонемент ($m)

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

1 стартмани

07.08.2020    5294    BuriyLesha    17    

Сохранение настроек колонок

Практика программирования Работа с интерфейсом Универсальные функции v8 Абонемент ($m)

Сохранение настроек колонок табличных полей. Получение имени формы из модуля формы. Для обычных форм.

1 стартмани

10.07.2020    1187    Arc    1    

Универсальные функции: разложение произвольной строки адреса в структуру

Практика программирования Универсальные функции v8 1cv8.cf Абонемент ($m)

Процедуры и функции раскладывают произвольную строку адрес в структуру по ключевым словам.

1 стартмани

30.12.2019    4701    vik070777    10    

Многопоточность. Универсальный «Менеджер потоков» (фреймворк) с отслеживанием зависимости объектов Промо

Практика программирования Математика и алгоритмы Универсальные функции Производительность и оптимизация (HighLoad) v8 1cv8.cf Россия Абонемент ($m)

Восстановление партий, расчет зарплаты, пакетное формирование документов или отчетов - теперь все это стало доступнее. * Есть желание повысить скорость работы медленных алгоритмов! Но... * Нет времени думать о реализации многопоточности? * о запуске и остановке потоков? * о поддержании потоков в рабочем состоянии? * о передаче данных в потоки и как получить ответ из потока? * об организации последовательности? Тогда ЭТО - то что надо!!!

26.05.2017    50288    DarkAn    86    

Работа с графической схемой в объектной модели DOM

Универсальные функции v8 v8::УФ Абонемент ($m)

Пример кода для работы с графической схемой в объектной модели DOM, платформа 8.3.12.

1 стартмани

04.06.2019    8186    botokash    19    

Корректировка движений документа

Универсальные функции v8 1cv8.cf Абонемент ($m)

Корректировка движений документа после его проведения по типовому алгоритму.

1 стартмани

26.05.2019    5558    rutadmeen    0    

Программное формирование картинки в 1С:Предприятие 8.3.9 (ПотокВПамяти / ЗаписьДанных)

Универсальные функции v8 1cv8.cf Абонемент ($m)

В статье представлен код программного формирования картинки (двоичные данные) без всяких внешних компонент, без формирования строки Base64, используя лишь встроенные механизмы 1С предприятие 8.3.9 (объекты ПотокВПамяти и ЗаписьДанных). Сам по себе код формирования картинки не несёт ничего нового. Всё описано в википедии. Захотелось попробовать новые методы, но никак не доходитили руки. В приложении обработка практически с этим же кодом.

1 стартмани

16.05.2019    10129    yku    11    

Ускорение для Клиент-Банка Промо

Банковские операции Обмен с банком Универсальные функции Банковские операции v8 1cv8.cf Абонемент ($m)

У вас много платежей и клиент-банк долго их читает? Есть проверенная практикой идея, как это ускорить.

1 стартмани

08.10.2012    23902    Yashazz    15    

Альтернатива внешним печатным формам. ЗУП 3.1

Печатные формы документов Универсальные функции Зарплата Практика программирования Зарплата Разработка v8 v8::СПР ЗУП3.x Абонемент ($m)

Как в ЗУП 3.1.8 отказаться от внешних печатных форм и расширением увеличить количество полей, доступных при редактировании макетов, для изменения печатных форм Т1, Т5, Т8 и аналогичные пользователями.

1 стартмани

30.01.2019    15086    Mogilnikova    3    

Использование подсистемы БСП "Заполнение объектов"

Практика программирования Универсальные функции БСП (Библиотека стандартных подсистем) v8 v8::УФ 1cv8.cf Россия Абонемент ($m)

Применение механизмов БСП для добавления новых команд заполнения к формам различных объектов. Использование расширений конфигурации для доработки. Шаблоны для реализации собственных команд заполнения.

1 стартмани

23.11.2018    27072    ids79    23    

Доработка функции ОбщегоНазначения.ЗаменитьСсылки для автоматической чистки или свёртки табличных частей

Универсальные функции v8 Абонемент ($m)

Стандартная обработка по замене дублей ругается на документ с неуникальными строками. Предполагается, что их нужно либо а) удалить, либо б) свернуть. Я немного модифицировал код функции ОбщегоНазначения.ЗаменитьСсылки, встроив в него вызов процедуры, переопределяемой в модуле менеджера соответствующего документа. И в этом модуле менеджера мы уже сами определяем - удалить или свернуть. Ну и вообще там чего хошь можно с этой коллекцией сделать - сам же ж процедуру пишешь...

1 стартмани

12.09.2018    4260    albert.goncharov    0    

Сохранение реквизитов и табличных частей объектов в XML Промо

Обмен через XML Универсальные функции v8 1cv8.cf Абонемент ($m)

Пример того, как можно сохранять и загружать объекты 1С методами встроенных объектов ЗаписьXML и ЧтениеXML.

1 стартмани

25.11.2011    22387    saiten    21    

Пропорциональное распределение в запросе

Универсальные функции Практика программирования v8 1cv8.cf Абонемент ($m)

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

1 стартмани

28.06.2018    12318    invertex    8    

Заполнение справочника с изображениями элементами по умолчанию

Практика программирования Обмен через XML Универсальные функции v8 Абонемент ($m)

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

1 стартмани

26.03.2018    8831    Kim1C    0    

Проверка таблицы на дублирование строк (ТаблицаЗначений, ТабличнаяЧасть) и получение массива таких строк

Практика программирования Универсальные функции v8 1cv8.cf Абонемент ($m)

Функция для проверки дублирования строк в ТаблицеЗначений или ТабличнойЧасти. Также, если необходимо, возвращает массив задублированных строк (можно обработать).

1 стартмани

05.02.2018    11731    uri1978    27    

Работа с кодами - числами, датами, кодами справочников, номерами документов, идентификаторами в 1С и в других базах данных

Универсальные функции v8 1cv8.cf Россия Абонемент ($m)

Поддерживается преобразование Кодов на основе Алфавитов, в том числе ''блочных" кодов - состоящих из блоков (подстрок) одинаковой длины (например: 8, 16, 32-битные коды, Хэши и т.п.). Функции доступны на Клиенте и на Сервере. Демо-примеры сделаны на управляемых формах. Тестировалось на платформах серии 8.3.10.

1 стартмани

28.11.2017    7635    newold2    1    

Размеры управляемой формы

Практика программирования Работа с интерфейсом Универсальные функции v8 1cv8.cf Абонемент ($m)

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

1 стартмани

08.10.2017    28339    json    9    

Пример универсальной функции для создания схемы компоновки данных

Практика программирования Универсальные функции v8::СКД 1cv8.cf Россия Абонемент ($m)

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

1 стартмани

12.01.2017    34006    dbachinsky    32    

Функция преобразования промежутка времени в строку

Универсальные функции v8 1cv8.cf Россия Абонемент ($m)

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

1 стартмани

23.09.2016    10143    vovant    1    

1С 8.2 переключение раскладки клавиатуры (с помощью dynwrap.dll)

Разработка внешних компонент Универсальные функции v8 Абонемент ($m)

Функция для автоматического переключения раскладки клавиатуры. (с помощью dynwrap.dll) Дабы не переключать каждый раз (при вводе информации в разных полях) с "Rus" на "Eng", можно эту работу возложить на функцию.

1 стартмани

22.05.2013    15348    Serg23ru    24    

Конвертер Даты из числового формата Excel

Загрузка и выгрузка в Excel Универсальные функции v8 1cv8.cf Абонемент ($m)

Столкнувшись с проблемой загрузки в 1С из Excel Даты-Времени в числовом формате к удивлению не нашел нигде подобных формул. Может потому что они уж слишком банальны, а может потому что они "тайное знание посвященных". В общем, эта обработка пример конвертации Excel <=> 1C

1 стартмани

17.04.2013    19200    vova196    5    

Точка Актуальности для 1С 8

Практика программирования Универсальные функции v8 УТ10 Абонемент ($m)

Все знают, что такое ТА для 1с 7.7 И этот механизм отсутствует в 1С 8. Но многие бухгалтера привыкли к нему. Почему бы тогда его не реализовать?

1 стартмани

18.12.2012    20966    Sykoku    28    

Ограничение на проведение реализаций по группе доступности складов в УТ 10.3

Практика программирования Универсальные функции Учет ТМЦ Учет ТМЦ v8 УТ10 Абонемент ($m)

В стандартной конфигурации УТ 10.3, настройка "группы доступности складов" не накладывает ограничения на продажи с определённых складов. Группа доступности складов позволяет наложить ограничение лишь на автоматическое размещение товаров в заказе покупателей, т.е. менеджер может вручную выбрать размещение и совершить продажу. Данная доработка исправляет эту ситуацию.

12.04.2012    12517    pusix    8    

Синхронизация с сервером 1С во внешнем соединении

Внешние источники данных Универсальные функции v8 1cv8.cf Абонемент ($m)

Позволяет установить время удаленного SQL-сервера на компьютере при выполнении обмена через Внешнее соединение

1 стартмани

27.09.2011    13601    sml    6    

Как превратить линейно-периодический отчёт в многолинейно-периодический (в платформах 8.х)

Универсальные функции Анализ учета v8 1cv8.cf Абонемент ($m)

Навеяно http://infostart.ru/public/90001/ - решение на основе пользовательских полей в СКД

1 стартмани

27.09.2011    17207    e.kogan    35