Имя: Пароль:
1C
1С v8
v8: динамический запрос.
0 zladenuw
 
28.02.13
13:51
Есть справочник который хранит показатели. если формула пустаю то передаем в запрос показатель как параметр. если же у параметра есть  формула. смотрим параметры формулы.
это сделал. вопрос только как сделать так. что если в формуле есть показатели. которые так же расчитываются. пока нет мысли как это сделать.

Вот запрос.


Функция ПостроениеЗапросаПоФормулеБюджета(Алгоритм,Год,МесяцК,МесяцН,Подразделение) Экспорт
    ТекстЗапросаОбщий = "";                        
    ТекстЗапросаОбщий2 = "";
    Если Алгоритм = Null или Алгоритм = Неопределено Тогда
        возврат 0;
    КонецЕсли;    
   
    Попытка
       Формула = Алгоритм.Формула;
       ПараметрыФормулы = Алгоритм.ПараметрыФормулы;
        Исключение
    Возврат 0;
    КонецПопытки;    
   
    Для каждого ПараметрФормулы из ПараметрыФормулы Цикл
       
           ТекстЗапроса = ПолучитьТекстЗапросаВложеннойФормулы(ПараметрФормулы);
           
        Если ПараметрыФормулы.Индекс(ПараметрФормулы)=0 тогда
            ТекстЗапросаОбщий = ТекстЗапроса;
        Иначе
            ТекстЗапросаОбщий2 = ТекстЗапросаОбщий2+",
            |("+ТекстЗапроса+")"+"КАК "+ПараметрФормулы.ПараметрИмя;
        КонецЕсли;    
    КонецЦикла;    
           
    ТекстПодмены = "ВЫБРАТЬ
                   |  ";
    ТекстПараметры = "";
    Для каждого ПараметрФормулы из ПараметрыФормулы Цикл
        Формула = СтрЗаменить(Формула,ПараметрФормулы.ПараметрИмя,"ЕстьNull("+ПараметрФормулы.ПараметрИмя+".Первонач"+",0)");
    КонецЦикла;
    ТекстПараметры = "("+Формула+") КАК "+"Итог";
    ТекстПоиска = "ВЫБРАТЬ
                       |    "+ПараметрыФормулы[0].ПараметрИмя+".Первонач";

    ТекстЗапросаОбщий = СтрЗаменить(ТекстЗапросаОбщий,ТекстПоиска,ТекстПодмены+ТекстПараметры);
    ТекстЗапросаОбщий =ТекстЗапросаОбщий+ТекстЗапросаОбщий2;
    ТекстЗапросаОбщий = ТекстЗапросаОбщий;
    Запрос = Новый Запрос(ТекстЗапросаОбщий);
    Для каждого ПараметрФормулы из ПараметрыФормулы Цикл
        Запрос.УстановитьПараметр(ПараметрФормулы.ПараметрИмя,ПараметрФормулы.ПараметрЗначение);
    КонецЦикла;
    Запрос.УстановитьПараметр("Год",Год);
    Запрос.УстановитьПараметр("МесяцК",МесяцК);
    Запрос.УстановитьПараметр("МесяцН",МесяцН);
    Запрос.УстановитьПараметр("Подразделение",Подразделение);
   
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        Возврат Выборка.Итог;
    КонецЦикла;      
    Возврат 0;
КонецФункции

Функция ПолучитьТекстЗапросаВложеннойФормулы(Параметр)
        ТекстЗапроса = "";
        Если ТипЗнч(Параметр.ПараметрЗначение) = Тип("Число") Тогда
            ТекстЗапроса = "ВЫБРАТЬ
            |    "+Параметр.ПараметрИмя+".Первонач
            |ИЗ
            |    (ВЫБРАТЬ
            |        СУММА(&"+Параметр.ПараметрИмя+") КАК Первонач) КАК "+Параметр.ПараметрИмя+"";
           
        ИначеЕсли ТипЗнч(Параметр.ПараметрЗначение) = Тип("СправочникСсылка.СтатьиДоходовИРасходов") Тогда
            ДоходРасход = ?(Параметр.Доход,"Доходы","Расходы");
            Доход = Параметр.Доход;
            ТекстЗапроса = "ВЫБРАТЬ
            |    "+Параметр.ПараметрИмя+".Первонач
            |ИЗ
            |    (ВЫБРАТЬ
            |        СУММА(ВЫБОР
            |                КОГДА ПланированиеБюджетаДоходыРасходы.Ссылка.Версия = 2
            |                    ТОГДА ПланированиеБюджетаДоходыРасходы.Сумма
            |                ИНАЧЕ 0
            |            КОНЕЦ) КАК Первонач,
            |        СУММА(ВЫБОР
            |                КОГДА ПланированиеБюджетаДоходыРасходы.Ссылка.Версия = 3
            |                    ТОГДА ПланированиеБюджетаДоходыРасходы.Сумма
            |                ИНАЧЕ 0
            |            КОНЕЦ) КАК Коррект
            |    ИЗ
            |        Документ.ПланированиеБюджета."+ДоходРасход+" КАК ПланированиеБюджетаДоходыРасходы
            |    ГДЕ
            |        ПланированиеБюджетаДоходыРасходы.Ссылка.Год = &Год
            |        И ПланированиеБюджетаДоходыРасходы.Ссылка.Месяц МЕЖДУ &МесяцН И &МесяцК
            |        И ПланированиеБюджетаДоходыРасходы.Ссылка.Проведен
            |        И ПланированиеБюджетаДоходыРасходы.ПравилоДДС.Код <> ""000000027""
            |        И ПланированиеБюджетаДоходыРасходы.Сумма <> 0
            |        И ПланированиеБюджетаДоходыРасходы.Статья = &"+Параметр.ПараметрИмя+"
            |        И ("+?(Доход,"","НЕ")+" ПланированиеБюджетаДоходыРасходы.Статья.Доход)) КАК "+Параметр.ПараметрИмя+"";
        ИначеЕсли НЕ ЗначениеЗаполнено(Параметр.ПараметрЗначение.Формула) Тогда
            ДоходРасход = ?(Параметр.Доход,"Доходы","Расходы");
            Доход = Параметр.Доход;
            ТекстЗапроса = "ВЫБРАТЬ
            |    "+Параметр.ПараметрИмя+".Первонач
            |ИЗ
            |    (ВЫБРАТЬ
            |        СУММА(ВЫБОР
            |                КОГДА ПланированиеБюджетаДоходыРасходы.Ссылка.Версия = 2
            |                    ТОГДА ПланированиеБюджетаДоходыРасходы.Сумма
            |                ИНАЧЕ 0
            |            КОНЕЦ) КАК Первонач,
            |        СУММА(ВЫБОР
            |                КОГДА ПланированиеБюджетаДоходыРасходы.Ссылка.Версия = 3
            |                    ТОГДА ПланированиеБюджетаДоходыРасходы.Сумма
            |                ИНАЧЕ 0
            |            КОНЕЦ) КАК Коррект
            |    ИЗ
            |        Документ.ПланированиеБюджета."+ДоходРасход+" КАК ПланированиеБюджетаДоходыРасходы
            |    ГДЕ
            |        ПланированиеБюджетаДоходыРасходы.Ссылка.Год = &Год
            |        И ПланированиеБюджетаДоходыРасходы.Ссылка.Месяц МЕЖДУ &МесяцН И &МесяцК
            |        И ПланированиеБюджетаДоходыРасходы.Ссылка.Проведен
            |        И ПланированиеБюджетаДоходыРасходы.ПравилоДДС.Код <> ""000000027""
            |        И ПланированиеБюджетаДоходыРасходы.Сумма <> 0
            |        И ПланированиеБюджетаДоходыРасходы.Статья.Вид = &"+Параметр.ПараметрИмя+"
            |        И ("+?(Доход,"","НЕ")+" ПланированиеБюджетаДоходыРасходы.Статья.Доход)) КАК "+Параметр.ПараметрИмя+"";
        Иначе
            ТекстЗапроса = ПолучитьТекстЗапросаВложеннойФормулы(Параметр);
        КонецЕсли;
       
        Возврат ТекстЗапроса;
КонецФункции
1 zladenuw
 
28.02.13
13:53
(1) вот тут цикл по вложенной формуле сделать ?
 Иначе
            ТекстЗапроса = ПолучитьТекстЗапросаВложеннойФормулы(Параметр);
        КонецЕсли;

Или как лучше ?
2 zladenuw
 
28.02.13
13:58
(1) на сколько я понимаю. мне нужно повторить полностью формирование запроса. сделать его вложенным и добавить к основному. получается что все формирование запроса копировать. или все таки может есть у кого то идеи ? может по другому надо ?  Может построителем будет лучше или нет ?
3 John D
 
28.02.13
13:59
По идее, рекурсия напрашивается...
4 zladenuw
 
28.02.13
14:00
(3) это уже понял. но все равно спасибо
5 zladenuw
 
28.02.13
14:54
есть загвостка. как определить или данное имя вложеного запроса уже используется ?

для показателей формулы могут содержать одинаковые символы.
например а и б. как во вложенных добавить префикс, количество вложенний не известно. и еще надо где то их запомнить и передавать в общий запрос для заполнение параметров.
6 zladenuw
 
28.02.13
14:56
(5) есть 1 показатель. который расчитывается по формуле а+б.
а расчитывается так же по вложенной формуле (а+б) как а и (а+б) как б.
7 MSII
 
28.02.13
14:57
(5) А ты передавай все нужные тебе данные в параметры функции.
8 НЕА123
 
28.02.13
15:01
почти офф.
может все это сначало в дерево значений сувать, а потом уж запрос делать.
9 zladenuw
 
28.02.13
15:02
(8) а подробней ?
10 zladenuw
 
28.02.13
15:05
пока сделал изварот. добавлю наименование показателя. но как то не по феншую :)
11 НЕА123
 
28.02.13
15:05
(9)
честно говоря, я не понял задачи(устал, плохо соображаю).
что-то аналогичное делал (не запрос). пока дерева не построил для наглядности, нихрена не получалось.
12 zladenuw
 
28.02.13
15:09
(11) есть справочник разделы бюджета, делаю запрос к 2 ТЧ документа. вывожу все в одну таблицу запроса . если нет формулы то вывожу в таблицу1. если есть формула то в таблицу 2.
вот пляски с дополнительными показателями.
13 zladenuw
 
28.02.13
15:11
(12) я думал не выбирать показатели где есть формула, тогда проблем нет. но начальник сказал, что бы можно было выбрать любой раздел. вот мучаюсь.
14 zladenuw
 
28.02.13
16:12
Сделал дерево.
http://ximage.ru/index.php?id=1362053287

Я так понимаю что нужно будет делать обход дерева. и на основание его строить запрос ? может все таки есть у кого примеры ?
15 zladenuw
 
28.02.13
16:18
(14) так красивее http://ximage.ru/index.php?id=1362053758

Думаю к Имени параметру добавлять число по нарастающей.
Но как быть дальше с запросом. делать подзапросы и выполнять а+б, для вложенной функции. или же формировать просто вложенные запросы. а потом вычитать уже по новой формуле где будет (а1+б1)-(а2+б2) так что ли ?
16 vde69
 
28.02.13
16:19
(14) дерево и динамический список жутко тормозят, на списке из 10к строк любое действие занимает около 5 минут, даже скролинг....

динамический список нормально работает только с иерхическими списками, но не с деревом
17 zladenuw
 
28.02.13
16:20
какой подход более правильный будет ?
Какое ограничение на количество вложенных запросов ?
Если что платформа 8.1.13..41
(16) так мне для отчета. я это дело в СКД подставую как вычисляемое поле. и вывожу во вторую таблицу.
18 vde69
 
28.02.13
16:21
19 zladenuw
 
28.02.13
16:24
http://ximage.ru/index.php?id=1362054229

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

(18)И как это поможет мне ?
20 zladenuw
 
28.02.13
16:27
(18) я дерево вывел для наглядности. и для хранение,заполнение параметров. так как не известно изначально сколько в показатели может быть вложенных формул.
+ надо где то хранить имена вложенных таблиц, из за того что в формуле могут быть повторение имен параметров.
21 zladenuw
 
28.02.13
16:29
(20) думаю использовать уровень дерева. тогда точно будут уникальные имена вложенных таблиц.
22 vde69
 
28.02.13
16:30
(20) да, это я тупанул, не вьехал в сабж...
23 zladenuw
 
28.02.13
16:31
(22) а можно как то в дереве узнать, какой уровень строки у нее или нет ?
24 zladenuw
 
28.02.13
16:45
(23) Мда. http://ximage.ru/index.php?id=1362055463
Все равно не так.
25 mishgan75
 
28.02.13
16:50
не надо казаться самым умным. Найди более простое(понятное) решение проблемы.
26 zladenuw
 
28.02.13
16:51
(25) ну так подскажи :)
27 vde69
 
28.02.13
16:59
(24) у тебя класический подход функционально програмирования, в принцепе нормально...

как вариант перейти к процедурному подходу, многим 1с никам будет более понятно
28 zladenuw
 
28.02.13
17:01
вот так заполняю дерево.
как мне проверить что владелец тот же и индекс его строки считать ненадо.


Процедура КнопкаВыполнитьНажатие(Кнопка)
   ДеревоПоказателей.Колонки.Очистить();
   СоздатьСтруктуруДерева(ДеревоПоказателей);
   
   ЗаполнитьДеревоПоказателей(ДеревоПоказателей,Алгоритм);
   
   ЭлементыФормы.ДеревоПоказателей.Значение = ДеревоПоказателей;
   ЭлементыФормы.ДеревоПоказателей.СоздатьКолонки();
КонецПроцедуры


Процедура ЗаполнитьДеревоПоказателей(Дерево,Показатель)
   СтрокаДерева = Дерево.Строки.Добавить();
   СтрокаДерева.Показатель = Показатель;
   СтрокаДерева.Формула = Показатель.Формула;
   Если Показатель.ПараметрыФормулы.Количество() > 0 Тогда
       Для каждого СтрПокФормулы из Показатель.ПараметрыФормулы цикл
           //
           СтрФормулы = СтрокаДерева.Строки.Добавить();
           ЗаполнитьПараметрамиФункции(СтрФормулы,СтрПокФормулы,);
       КонецЦикла;
       // Иначе
       //   СтрокаДерева.ЗначениеФормулы = Показатель.ЗначениеФормулы;
   КонецЕсли;      
КонецПроцедуры    

Процедура ЗаполнитьПараметрамиФункции(СтрокиФ,Показатель,пУровень = 0)
   Если Показатель.ПараметрЗначение.Формула = "" Тогда
       СтрокиФ.ПараметрФормулы =  Показатель.ПараметрИмя;
       СтрокиФ.ПараметрФормулыЗапрос =  Строка(СтрокиФ.Уровень()+пУровень)+Показатель.ПараметрИмя;
       СтрокиФ.ЗначениеФормулы =  Показатель.ПараметрЗначение;
       СтрокиФ.Доход =  Показатель.Доход;
       СтрокиФ.Расход =  Показатель.Расход;
       
   Иначе
       //Для каждого
       //ВложФормулаСтрока = СтрФормулы.Строки.Добавить();
       СтрокиФ.Показатель = Показатель.ПараметрЗначение;
       СтрокиФ.Формула = Показатель.ПараметрЗначение.Формула;
       Для каждого  СтрПокФормулы из Показатель.ПараметрЗначение.ПараметрыФормулы цикл
           СтрокиВложФ = СтрокиФ.Строки.Добавить();
           
           ЗаполнитьПараметрамиФункции(СтрокиВложФ,СтрПокФормулы,СтрокиФ.Строки.Индекс(СтрокиВложФ));
       КонецЦикла;
   КонецЕсли;    
   
КонецПроцедуры    
Процедура СоздатьСтруктуруДерева(Дерево)
   Дерево.Колонки.Добавить("Показатель");
   Дерево.Колонки.Добавить("Формула");
   Дерево.Колонки.Добавить("ПараметрФормулы");
   Дерево.Колонки.Добавить("ПараметрФормулыЗапрос");
   Дерево.Колонки.Добавить("ЗначениеФормулы");
   Дерево.Колонки.Добавить("Доход");
   Дерево.Колонки.Добавить("Расход");
КонецПроцедуры
29 zladenuw
 
28.02.13
17:08
(28) мда. надо было уровень брать с 0 уровня дерева,а не с его строк.с этим разобрался.

Теперь надо это чудо подставить в запрос. и потом подставить параметры :). вроде просто. вопрос как :)
30 zladenuw
 
28.02.13
17:10
(27) а чем плох или харош такой подход ? только как меня тут будут понимать или не только ?