SeiOkami / OneS

Предложения по улучшению платформы
49 stars 3 forks source link

Язык запросов. Прошу возможность использовать выражения выбранных полей через указание их имен #212

Open tormozit opened 1 year ago

tormozit commented 1 year ago

https://partners.v8.1c.ru/forum/topic/2132138

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

Например:

ВЫБРАТЬ
    Остатки.Сумма КАК Сумма,
    Остатки.НДС КАК НДС,
    Остатки.Сумма+Остатки.НДС КАК СуммаВсего,
    ВЫБОР
        КОГДА СуммаВсего > 0
            0
        ИНАЧЕ
            0-СуммаВсего
    КОНЕЦ КАК Переплата
ИЗ Регистр.Остатки КАК Остатки
ГДЕ
    Переплата > 0

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

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

ВЫБРАТЬ
    Остатки.Сумма КАК Сумма,
    Остатки.НДС КАК НДС,
    Остатки.Сумма+Остатки.НДС КАК СуммаВсего,
    ВЫБОР
        КОГДА !СуммаВсего > 0
            0
        ИНАЧЕ
            0-!СуммаВсего
    КОНЕЦ КАК Переплата
ИЗ Регистр.Остатки КАК Остатки
ГДЕ
    !Переплата > 0

Реализация такого пожелания не сложная, по сути надо добавить препроцессор, который заменит !ИМЯ на определение этого имени.

tormozit commented 2 weeks ago

Можно сделать костыльную реализацию через схему запроса без доработки платформы. Для этого ссылки можно записывать в виде &Поле<ИмяПоля>. А перед выполнением запроса вызывать конвертацию

// Выполняет подмену ссылок на выбранные поля на их выражения в выражениях выбранных полей и отборе. Они должны быть записаны в виде &Поле<ИмяВыбраногоПоля>.
// https://github.com/SeiOkami/OneS/issues/212
// Минимальная версия платформы 8.3.23
// Параметры:
//   Запрос - Запрос -
Процедура ЗаменитьСсылкиПолей(Знач Запрос) Экспорт
    Схема = Новый СхемаЗапроса;
    Схема.УстановитьТекстЗапроса(Запрос.Текст);
    Для Каждого ЗапросПакета Из Схема.ПакетЗапросов Цикл
        Если ТипЗнч(ЗапросПакета) = Тип("ЗапросУничтоженияТаблицыСхемыЗапроса") Тогда
            Продолжить
        КонецЕсли;
        Для Каждого Оператор Из ЗапросПакета.Операторы Цикл
            ЗаменитьСсылкиВВыражениях(Оператор.ВыбираемыеПоля, ЗапросПакета, Оператор);
            //ЗаменитьСсылкиВВыражениях(Оператор.Группировка, ЗапросПакета, Оператор); // Не работает из-за ошибки платформы https://www.hostedredmine.com/issues/994651
            ЗаменитьСсылкиВВыражениях(Оператор.Отбор, ЗапросПакета, Оператор);
        КонецЦикла;
    КонецЦикла;
    Запрос.Текст = Схема.ПолучитьТекстЗапроса();
КонецПроцедуры

// .
// Параметры:
//   КоллекцияВыражений - Массив[ВыражениеСхемыЗапроса, Произвольный] - 
//   ЗапросПакета - ЗапросВыбораСхемыЗапроса - 
//   Оператор - ОператорВыбратьСхемыЗапроса - 
Процедура ЗаменитьСсылкиВВыражениях(Знач КоллекцияВыражений, Знач ЗапросПакета, Знач Оператор) Экспорт
    Для Каждого ВыражениеСхемыЗапроса Из КоллекцияВыражений Цикл
        Если ТипЗнч(ВыражениеСхемыЗапроса) = Тип("ВыражениеСхемыЗапроса") Тогда
            НовоеВыражение = ЗаменитьСсылкиПолейВыражения("" + ВыражениеСхемыЗапроса, Оператор, ЗапросПакета);
            КоллекцияВыражений[КоллекцияВыражений.Индекс(ВыражениеСхемыЗапроса)] = новый ВыражениеСхемыЗапроса(НовоеВыражение);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

// .
// Параметры:
//   Выражение - Строка -
//   Оператор - ОператорВыбратьСхемыЗапроса -
//   ЗапросПакета - ЗапросВыбораСхемыЗапроса -
// Возвращаемое значение:
//   Строка -
Функция ЗаменитьСсылкиПолейВыражения(Знач Выражение, Знач Оператор, Знач ЗапросПакета) Экспорт
    Ссылки = СтрНайтиВсеПоРегулярномуВыражению("" + Выражение, "&Поле(\w+)");
    Для Каждого Ссылка Из Ссылки Цикл
        ИмяПоля = Ссылка.ПолучитьГруппы()[0].Значение;
        ПолеРезультата = ЗапросПакета.Колонки.Найти(ИмяПоля);
        Если ПолеРезультата = Неопределено Тогда
            ВызватьИсключение СтрШаблон("Неверная ссылка на поле (%1)", Ссылка.Значение);
        КонецЕсли;
        ВыражениеЗамена = "(" + Оператор.ВыбираемыеПоля[ЗапросПакета.Колонки.Индекс(ПолеРезультата)] + ")";
        Выражение = СтрЗаменить(Выражение, Ссылка.Значение, ВыражениеЗамена);
    КонецЦикла;
    Возврат Выражение;
КонецФункции
KomAuras commented 2 weeks ago

[ОшибкаВоВремяВыполненияВстроенногоЯзыка] по причине: {(1, 1)}: Поле не найдено "Нет" <<?>>Нет + 1

tormozit commented 2 weeks ago

Исправил

PerlAmutor commented 2 weeks ago

Ты забыл удаление "мусора" после использования СхемыЗапроса, который сломает текст запроса если в нем есть условия построителя с фигурными скобками "{}"

Функция УдалитьМусорПослеСхемыЗапроса(Знач ТекстЗапроса) Экспорт

    Для НомерПоля = 1 По 20 Цикл
        ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрШаблон(" КАК Поле%1", Формат(НомерПоля, "ЧН=; ЧГ=")), "");
    КонецЦикла;

    Возврат ТекстЗапроса;

КонецФункции
tormozit commented 2 weeks ago

@PerlAmutor старайся сначала описывать (например в виде ссылки) проблему, а потом ее решение.

tormozit commented 2 weeks ago

Попытка преобразовать группировки таким методом через схему запроса столкнулась в ошибкой платформы https://www.hostedredmine.com/issues/994651