()
Вы говорите, как здорово и прекрасно засунуть отборы в функции, и одновременно показываете скрин с функциями которые модифицируют текст запроса через схему.
Что-то не могу понять, что Вы имеете в виду - дайте цитату/ссылку
Я кстати никакого ада не увидел, вполне себе читаемый код
Если запрос простой - то его изменение через "СхемуЗапроса" не сложно читается. Но текстовое изменение всё-равно будет более понятным.
Если запрос посложнее (ну хотя бы 10-20 запросов в пакете, с 3-4 уровнями вложениям и соединения) - и всё - это код становится адовым.
А уж какой ад писать такой код модификации - попробуйте сами - поймёте!
Это я ещё не стал упоминать подход из ЗУП (и EPR2) где ещё и куча временных таблиц - которые определяются в одном месте (одним текстом запроса), а используются в другом. Но тут редактирование через обработку строк не поможет. Только моя идея декларативной сборки.
Я думаю причина этого в том, что это тупо программный интерфейс конструктора запросов.
"СхемаЗапросов" отличный инструмент, чтобы перевести текст запроса в объектную модель (но первые версии и для этого были не пригодны - в общем случае). Отчасти неплохой инструмент, чтобы, собрать запрос "с нуля" (или часть запроса, которую легко конкатенировать (но не встраивать) в существующий), или чтобы что-то удалить из запроса. Но для изменения -
практически не годится. Поэтому конструктор запросов может использовать "СхемуЗапросов" только для преобразования в/из объектной модели. Но из объектной модели собрать запрос КУДА ПРОЩЕ именно через текст.
Ущербности "СхемыЗапросов" можно посвятит достаточно большую статью. Но, вот простой пример
Текст = "ВЫБРАТЬ
| Временная.Поле
|ИЗ
| Временная КАК Временная" ;
сз = Новый СхемаЗапроса();
сз.УстановитьТекстЗапроса(Текст); //Строка 0
сз.ПакетЗапросов[0].Операторы[0].ВыбираемыеПоля.Добавить("Временная.Поле2",1); //Строка 1
сз.ПакетЗапросов[0].Операторы[0].Отбор.Добавить("Временная.Поле2 = 1"); //Строка 2
Текст2 = сз.ПолучитьТекстЗапроса();
Показать
Ещё пару релизов назад "Строка 0" вообще не выполнилась бы.
Но и сейчас - на 8.3.19 не выполнится ни "Строка 1" ни "Строка 2":
Ошибка: Поле не найдено "Временная.Поле2 |
---|
{(1, 11)}: Поле не найдено "Временная.Поле2"
Временная.<<?>>Поле2 = 1
{ВнешняяОбработка.ВнешняяОбработка2.Форма.Форма.Форма(16)}: сз.ПакетЗапросов[0].Операторы[0].Отбор.Добавить("Временная.Поле2 = 1");
{ВнешняяОбработка.ВнешняяОбработка2.Форма.Форма.Форма(4)}: Команда1НаСервере();
по причине:
{(1, 11)}: Поле не найдено "Временная.Поле2"
Временная.<<?>>Поле2 = 1 |
Если глубоко покапать эту тему - то станет понятно, что не хватает вот такой инструкции (перед проблемными строками)
сз.ПакетЗапросов[0].Операторы[0].Источники[0].Источник.ДоступныеПоля.Добавить("Поле2");
Результат |
---|
ВЫБРАТЬ
Временная.Поле КАК Поле,
Временная.Поле2 КАК Поле2
ИЗ
Временная КАК Временная
ГДЕ
Временная.Поле2 = 1
Показать |
Обращу внимание на аргумент со значением 1 в строке "Строка 1" - это позиция добавляемого поля - именно в нё оно и будет добавлено - напишешь там 0 - затрёт существующее поле - напишешь больше 1 - добавит промежуточные поля со значениями NULL. Нужно ещё и позицию отслеживать (справедливости ради надо заметить, что этот аргумент можно опустить - и тогда поля добавляются в конец). А уж если надо вставить между существующими полями - всё - "пиши пропало"!
А теперь представьте как усложнится алгоритм - когда нужно будет так добавить сотни полей в десятки временных таблиц!
А уж как соединения добавляются...
А вот так идёт сборка с нуля
сз = Новый СхемаЗапроса();
пз = сз.ПакетЗапросов[0].Операторы[0];
//пз.Источники.Добавить("Временная"); //Строка 1
пз.Источники.Добавить(Тип("ОписаниеВременнойТаблицыСхемыЗапроса"),"Временная"); //Строка 2
пз.Источники[0].Источник.ДоступныеПоля.Добавить("Поле");
пз.Источники[0].Источник.ДоступныеПоля.Добавить("Поле2");
пз.ВыбираемыеПоля.Добавить("Временная.Поле");
пз.ВыбираемыеПоля.Добавить("Временная.Поле2");
пз.Отбор.Добавить("Временная.Поле2 = 1");
Текст2 = сз.ПолучитьТекстЗапроса();
Показать
Результат |
---|
ВЫБРАТЬ
Временная.Поле КАК Поле,
Временная.Поле2 КАК Поле2
ИЗ
Временная КАК Временная
ГДЕ
Временная.Поле2 = 1
Показать |
Строка "Строка 1" не работает (хотя строковые аргументы поддерживаются) - а "Строка 2" обязательна для работы с временными таблицами.
Временные таблицы нужно обязательно каждый раз описывать.
А если уже есть готовый подзапрос - который нужно встроить в новый? Такого функционала вовсе нет - переносить нужно будет поэлементно!
Вот так нужно создавать вложенный запрос:
сз = Новый СхемаЗапроса();
пз0= сз.ПакетЗапросов[0].Операторы[0];
пз = пз0.Источники.Добавить(Тип("ВложенныйЗапросСхемыЗапроса"),"Вложенная").Источник.Запрос.Операторы[0];
пз.Источники.Добавить(Тип("ОписаниеВременнойТаблицыСхемыЗапроса"),"Временная");
пз.Источники[0].Источник.ДоступныеПоля.Добавить("Поле");
пз.Источники[0].Источник.ДоступныеПоля.Добавить("Поле2");
пз.ВыбираемыеПоля.Добавить("Временная.Поле");
пз.ВыбираемыеПоля.Добавить("Временная.Поле2");
пз.Отбор.Добавить("Временная.Поле2 = 1");
пз0.ВыбираемыеПоля.Добавить("Вложенная.Поле");
пз0.ВыбираемыеПоля.Добавить("Вложенная.Поле2");
Текст2 = сз.ПолучитьТекстЗапроса();
Показать
Результат |
---|
ВЫБРАТЬ
Вложенная.Поле КАК Поле,
Вложенная.Поле2 КАК Поле2
ИЗ
(ВЫБРАТЬ
Временная.Поле КАК Поле,
Временная.Поле2 КАК Поле2
ИЗ
Временная КАК Временная
ГДЕ
Временная.Поле2 = 1) КАК Вложенная
Показать |
Главное - все источники описывать перед их применением и обращением к ним. Кому-то это покажется правильным, и с этим сложно не согласиться. Но в целом - всё очень заморочено - даже на таких простых примерах. Вложенных видов объектов(классов) модели "СхемаЗапроса" очень и очень много, и запутаться в них "как пить дать"!
Я не вижу реализации в данной модели получения данных
Не понял, что Вы не видете.
Если вы говорите, что написать обертку вокруг текущих запросов написать не сложно. Мне кажется, вы ошибаетесь.
Не то, чтобы совсем не сложно. Тут многое зависит от того, насколько глубоко будет происходить оптимизация - а ведь в ней вся суть и именно из-за неё будут хейтить идею адепты "чистых SQL запросов" (или просто - любители тонкой ручной настройки запросов). А оптимизаторы - это один из самых сложных блоков в любом компиляторе/кодогенераторе. Но - их развивать можно постепенно, сначала создать API взаимодействия, а потом уже оптимизировать внутренние процессы. Более того, для тонкой настройки можно вводить в конструкции Реквестов так называемые "Хинты" (подсказки - треования) - которые будут задавать определённый режим к обработке текущих Реквестов - например требующие создания промежуточного источника во временной таблице с определёнными индексами (такой подход есть и в расширенном SQL многих СУБД). Но в целом - эти "Хинты" - штука плохая - это крайняя мера - в идеале - оптимизатор сам должен это решать, опираясь на машинное обучение и статистику - делать такую оптимизацию уже совсем не просто - это уже уровень совершенно нового поколения платформы учета.
А декларативное формирование запросов 1С уже практиковала - до сих пор можете найти попытки, скажем, в УПП - где текст запроса формировался отчасти декларативно
Пример из Документ.РеализацияТоваровУслуг.ПодготовитьТаблицыДокумента |
---|
// Получим необходимые данные для проведения и проверки заполнения данные по табличной части "Товары".
СтруктураПолей = Новый Структура();
СтруктураПолей.Вставить("Номенклатура" , "Номенклатура");
СтруктураПолей.Вставить("ЕдиницаИзмерения" , "ЕдиницаИзмерения");
СтруктураПолей.Вставить("Цена" , "Цена");
СтруктураПолей.Вставить("Номенклатура" , "Номенклатура");
СтруктураПолей.Вставить("Услуга" , "Номенклатура.Услуга");
СтруктураПолей.Вставить("Набор" , "Номенклатура.Набор");
СтруктураПолей.Вставить("Комплект" , "Номенклатура.Комплект");
СтруктураПолей.Вставить("Количество" , "Количество * Коэффициент /Номенклатура.ЕдиницаХраненияОстатков.Коэффициент");
СтруктураПолей.Вставить("КоличествоДок" , "Количество");
СтруктураПолей.Вставить("Качество" , "Качество");
СтруктураПолей.Вставить("Склад" , "Склад");
СтруктураПолей.Вставить("ВидСклада" , "Склад.ВидСклада");
СтруктураПолей.Вставить("Сумма" , "Сумма");
СтруктураПолей.Вставить("СуммаДок" , "Сумма");
СтруктураПолей.Вставить("СтавкаНДС" , "СтавкаНДС");
СтруктураПолей.Вставить("НДС" , "СуммаНДС");
СтруктураПолей.Вставить("НДСДок" , "СуммаНДС");
СтруктураПолей.Вставить("ХарактеристикаНоменклатуры" , "ХарактеристикаНоменклатуры");
СтруктураПолей.Вставить("СерияНоменклатуры" , "СерияНоменклатуры");
СтруктураПолей.Вставить("ПроцентСкидкиНаценки" , "ПроцентСкидкиНаценки");
СтруктураПолей.Вставить("ПроцентАвтоматическихСкидок" , "ПроцентАвтоматическихСкидок");
СтруктураПолей.Вставить("УсловиеАвтоматическойСкидки" , "УсловиеАвтоматическойСкидки");
СтруктураПолей.Вставить("ЗначениеУсловияАвтоматическойСкидки" , "ЗначениеУсловияАвтоматическойСкидки");
СтруктураПолей.Вставить("КлючСтроки" , "КлючСтроки");
СтруктураПолей.Вставить("ТипНоменклатуры" , "Номенклатура.ВидНоменклатуры.ТипНоменклатуры");
СтруктураПолей.Вставить("ЗаказПокупателя" , "ЗаказПокупателя");
СтруктураПолей.Вставить("КоличествоВЕдиницахДокумента" , "Количество");
СтруктураПолей.Вставить("ПринадлежностьНоменклатуры" , "ПринадлежностьНоменклатуры");
Если СтруктураШапкиДокумента.ВедениеУчетаПоПроектам И НЕ ЗначениеЗаполнено(Проект) Тогда
СтруктураСложныхПолей=Новый Структура;
СтруктураСложныхПолей.Вставить("Проект", "ПроектыНоменклатуры.Проект");
Иначе
СтруктураСложныхПолей=Неопределено;
КонецЕсли;
// Дополним полями, нужными для регл. и упр. учета
ДополнитьСтруктуруПолейТабличнойЧастиТоварыУпр(СтруктураПолей);
ДополнитьСтруктуруПолейТабличнойЧастиТоварыРегл(СтруктураПолей);
РезультатЗапросаПоТоварам = УправлениеЗапасами.СформироватьЗапросПоТабличнойЧасти(ЭтотОбъект, "Товары", СтруктураПолей,СтруктураСложныхПолей);
Показать |
Это, конечно, жалкое зрелище, но идея правильная - странно, что отказались от развития.
Теперь пишут так (из EPR2)
Документ.РеализацияТоваровУслуг.ДанныеДокументаДляПроведения |
---|
функция ДанныеДокументаДляПроведения(Документ, Регистры, ДопПараметры = Неопределено) Экспорт
Если ДопПараметры = Неопределено Тогда
ДопПараметры = ПроведениеДокументов.ДопПараметрыИнициализироватьДанныеДокументаДляПроведения();
КонецЕсли;
Запрос = Новый Запрос;
ТекстыЗапроса = Новый СписокЗначений;
Если Не ДопПараметры.ПолучитьТекстыЗапроса Тогда
////////////////////////////////////////////////////////////////////////////
// Создадим запрос инициализации движений
ЗаполнитьПараметрыИнициализации(Запрос, Документ);
////////////////////////////////////////////////////////////////////////////
// Сформируем текст запроса
СформироватьСуммыДокументаВВалютахУчета(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаЗаказыКлиентов(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаСвободныеОстатки(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаОбеспечениеЗаказов(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаОбеспечениеЗаказовРаботами(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаДвиженияСерийТоваров(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаПереданнаяВозвратнаяТара(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаТоварыОрганизаций(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаТоварыПереданныеНаКомиссию(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаДатыПередачиТоваровНаКомиссию(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаТоварыОрганизацийКПередаче(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаТоварыКОформлениюОтчетовКомитенту(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаСебестоимостьТоваров(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаВыручкаИСебестоимостьПродаж(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаМатериалыИРаботыВПроизводстве(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаДвиженияНоменклатураНоменклатура(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаУслугиКОформлениюОтчетовПринципалу(Запрос, ТекстыЗапроса, Регистры);
ТекстЗапросаТаблицаРеестрДокументов(Запрос, ТекстыЗапроса, Регистры);
//++ НЕ УТКА
ТекстЗапросаТаблицаОтражениеДокументовВМеждународномУчете(Запрос, ТекстыЗапроса, Регистры);
//-- НЕ УТКА
РасчетСебестоимостиПроведениеДокументов.ОтразитьВМеханизмеУчетаЗатратИСебестоимости(Документ, Запрос, ТекстыЗапроса, Регистры);
ОтразитьВУчетеНДС(Запрос, ТекстыЗапроса, Регистры);
РеализацияТоваровУслугЛокализация.ДополнитьТекстыЗапросовПроведения(Запрос, ТекстыЗапроса, Регистры);
КонецЕсли;
ДобавитьТекстыОтраженияВзаиморасчетов(Запрос, ТекстыЗапроса, Регистры);
ОтразитьРезерв(Запрос, ТекстыЗапроса, Регистры);
ЗапланироватьОтгрузкуТоваров(Запрос, ТекстыЗапроса, Регистры);
ОформитьОтгрузкуТоваров(Запрос, ТекстыЗапроса, Регистры);
////////////////////////////////////////////////////////////////////////////
// Получим таблицы для движений
Возврат ПроведениеДокументов.ИнициализироватьДанныеДокументаДляПроведения(Запрос, ТекстыЗапроса, ДопПараметры);
КонецФункции
Показать |
Ну а функции как "ТекстЗапросаТаблицаТоварыОрганизаций" внутри имеют просто статический текст запроса (иногда с вариациями в виде закомментированных кусков).
Да ещё и возвращаемые вот так
ТекстыЗапроса.Добавить(ТекстЗапроса, ИмяРегистра);
Возврат ТекстЗапроса;
Такое через расширения дорабатывать не особо удобно.
Вообще - в новых типовых конфигурациях 1С постаралась на славу - чтобы доработка этих конфигураций превратилась в ад! Попробуйте просто добавить новый реквизит в документ - чтобы использовать его в движениях по регистру или просто для какого-то ветвления! Вот, возьмите функцию "ТекстЗапросаТаблицаТоварыОрганизаций" и в её тексте разместите дополнительный реквизит табличной части "Товары" - сделайте текстовым подходом и сделайте это через "СхемаЗапроса" - почувствуете разницу!
Кстати, эти вариация текстов запросов в виде закомментированных частей при работе через "СхемаЗапроса" ещё и
теряются! А при текстовой обработке - не теряются (но тут уже сложности в определении, где комментарий, а где нет - но это не большие сложности).
Текущее развитие идеи запросов в конфигурация 1С - это 100% тупик! И кромешный ад! И "СхемаЗапросов" - это один из демонов (или бесов) этого ада!