Версия для печати темы (https://pro1c.org.ua/index.php?s=f194226e10243797a0f79d84314a1534&showtopic=54021)

Нажмите сюда для просмотра этой темы в обычном формате

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7 _ Программирование в 1С Предприятие 7.7 _ Помогите понять принцип создания запросов в 1с 7.7 конф 7.7.00

Автор: ZUBR 08.09.19, 22:14

И снова здравствуйте! Уважаемые гуру, помогите, пожалуйста, разобраться в создании запросов. Хочу понять основные принципы и закрепить на практике. Вопросов будет несколько, но все по запросам. И все практические. Уважаемые Модераторы, прошу разрешить обсудить эти вопросы в одной теме. Думаю, так будет лучше. Они все будут касаться процедуры формирования запросов. Но если администрация сайта посчитает, что, все же, нужно по каждому вопросу создавать отдельную тему, я беспрекословно подчинюсь. Итак.
У меня есть РасходныеНакладные по ремонтам техники. В табличной части этих накладных есть есть Товары с реквизитом ВидТовара = Товар, а есть различные виды выполняемых работ, которые в справочнике числятся как товар с реквизитом ВидТовара = Услуга. Мне нужно в отчете по всем проведенным накладным просуммировать все виды работ. Без, собственно, товаров. Например, есть товар с видом Услуга, который называется "Чистка бойлера". Или "ЗаменаНагревателя". Ясно, что это работа. Поэтому этот товар имеет ВидТовара = Услуга. Остальные же товары, например, Выключатель, Прокладка и т.д. имеет ВидТовара = Товар. После многих попыток я пришел к следующему коду, который работает:


Процедура Сформировать()   
    НужныйТовар = Константа.НужныйТовар;
    ВидТовараУм = Константа.ВидТовараУм;
    
    ЗапросСуммы = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |ВидТовара = Справочник.Номенклатура.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (ВидТовара = ВидТовараУм);";
    ЗапросСуммы.Выполнить(ТекстЗапроса);
    Пока ЗапросСуммы.Группировка() = 1 Цикл
        СуммаУслуг = ЗапросСуммы.Сум;
        
    КонецЦикла;
Сообщить("Сумма:"+СуммаУслуг);

КонецПроцедуры


"Константа.ВидТовараУм" у меня в пользовательской программе выбран вид Услуга.

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

Автор: andrew76 09.09.19, 5:42

ZUBR @ Сегодня, 1:14 * ,

А ВидТовара

Цитата(ZUBR @ 09.09.19, 1:14) *
|Товар = Документ.РасходнаяНакладная.Товар; |ВидТовара = Справочник.Номенклатура.ВидТовара;


Наверное условие должно выглядеть как-то так :

|Товар = Документ.РасходнаяНакладная.Товар.ВидТовара;  //вместо  |ВидТовара = Справочник.Номенклатура.ВидТовара;
|Условие (ВидТовара = ВидТовараУм);";


В Вашем варианте получается,что обрабатываются все накладные,без учета условия.
Получается что СправочникНоменклатура и ДокументРасходнаяНакладная в этом запросе работают не в паре !

Попробуйте вот так :

Процедура Сформировать()   
    НужныйТовар = Константа.НужныйТовар;
    ВидТовараУм = Константа.ВидТовараУм;
    
    ЗапросСуммы = СоздатьОбъект("Запрос");

ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (ВидТовара = ВидТовараУм);";
    ЗапросСуммы.Выполнить(ТекстЗапроса);
    
Пока ЗапросСуммы.Группировка() = 1 Цикл
        СуммаУслуг = ЗапросСуммы.Сум;
КонецЦикла;

Сообщить("Сумма:"+СуммаУслуг);

КонецПроцедуры

Автор: ZUBR 09.09.19, 18:03

andrew76 @ Сегодня, 6:42 * , да, так как Вы предложили, работает. Интересно, что я вчера примерно так же пробовал сделать, но, видимо, какую-то мелочь прописал неправильно. Спасибо!

Автор: ZUBR 16.09.19, 23:05

Здравствуйте. Возникла необходимость посчитать стоимость услуг для отдельного инженера по выданным аппаратам. Для этого мне нужно ввести в текст запроса еще одно условие. Даже два. Не могу сформировать этот проклятущий запрос. Никак не въеду. Мне программа выдает ошибку, что агрегатное поле объекта ТекущийЭлемент не обнаружено. А, кроме того, я не могу вывести Сообщить, потому что выскакивает ошибка, что переменная Инженер не определена. Как это лучше сделать?(

Процедура Сформировать()   
    НужныйТовар = Константа.НужныйТовар;
    ВидТовараУм = Константа.ВидТовараУм;
    
    Спр = СоздатьОбъект("Справочник.Сотрудники");
    
    ЗапросСуммы = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (Инженер = Спр.ТекущийЭлемент);
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд));
    |Условие (ВидТовара = ВидТовараУм);";
    
    Спр.ВыбратьЭлементы();
      
      Пока Спр.ПолучитьЭлемент()=1 Цикл
    
    
                       ЗапросСуммы.Выполнить(ТекстЗапроса);
                           Пока ЗапросСуммы.Группировка() = 1 Цикл
                                                  СуммаУслуг = ЗапросСуммы.Сум;
        
                                                                          КонецЦикла;
                            Сообщить(Инженер+СуммаУслуг);
                                                    КонецЦикла;


КонецПроцедуры


Спасибо!

ZUBR @ Сегодня, 23:29 * , я с трудом разобрался. В общем, поставил дополнительное условие по статусам заказов, и запрос работает правильно. Но как сюда втулить инженера, не могу понять. Помогите посчитать эту сумму для инженера, который в документе и в справочнике. Спасибо.

Это работает. Что и как добавить для инженера?

Процедура Сформировать()   
    НужныйТовар = Константа.НужныйТовар;
    ВидТовараУм = Константа.ВидТовараУм;
    
    Спр = СоздатьОбъект("Справочник.Сотрудники");
    
    ЗапросСуммы = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд));
    |Условие (ВидТовара = ВидТовараУм);";
    
       ЗапросСуммы.Выполнить(ТекстЗапроса);
                         Пока ЗапросСуммы.Группировка() = 1 Цикл
                            СуммаУслуг = ЗапросСуммы.Сум;
                        КонецЦикла;

                           Сообщить(СуммаУслуг);
                  
КонецПроцедуры

Автор: ZUBR 17.09.19, 23:28

Все, решил. После долгих попыток код следующий:


Процедура Сформировать()   

    Спр = СоздатьОбъект("Справочник.Сотрудники");
    
    ЗапросСуммы = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (Инженер = Сотрудник);
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд));
    |Условие (ВидТовара = Перечисление.ВидыТоваров.Услуга);";
    
      Спр.ВыбратьЭлементы();
      
      Пока Спр.ПолучитьЭлемент()=1 Цикл
          
       Сотрудник = Спр.ТекущийЭлемент();
    
       
    ЗапросСуммы.Выполнить(ТекстЗапроса);
                         Пока ЗапросСуммы.Группировка() = 1 Цикл
                            СуммаУслуг = ЗапросСуммы.Сум;
                                                    КонецЦикла;
                       Сообщить(Сотрудник);
                       Сообщить(СуммаУслуг);
                      
                       КонецЦикла;
                  

КонецПроцедуры


Пока единственное, что я еще не понимаю в запросах - это Группировка. Где почитать? Что значит "Товар Без Групп".
Очевидно, что Группировка - мощный метод. Надо его знать! Если кто поможет - буду признателен. Ну, и о функциях тоже. Правила их создания. Вообще, конечно, запрос - мощная штука.

Автор: ZUBR 18.09.19, 1:10

Нашел неплохую статью по запросам. Не знаю, можно ли дать ссылку.

Автор: Vofka 18.09.19, 8:07

Цитата(ZUBR @ 18.09.19, 2:10) *
Нашел неплохую статью по запросам. Не знаю, можно ли дать ссылку.

Если это тематическая полезная информация, не реклама - то можно.

Автор: mut 18.09.19, 12:26

ZUBR @ Сегодня, 0:28 * ,

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

Автор: ZUBR 18.09.19, 23:30

mut @ Вчера, 13:26 * , хочу уточнить - правильно ли я понял, что "Без групп" к собственно Группировке отношения не имеет. То есть, Группировка - это не группы в справочниках? И Без групп можно писать отдельно?


Информация по запросам. С разрешения модератора.

https://pro1c.org.ua/redirect.php?http://anatoly4xs.narod.ru/manual/lang/lang0342.htm

Еще по запросам. Это начало
https://pro1c.org.ua/redirect.php?http://anatoly4xs.narod.ru/manual/lang/lang0341.htm#3130

Автор: ZUBR 19.09.19, 1:11

Теперь я дополнил текст запроса функцией Счетчик для подсчета количества сделанных систем. Запрос не работает. Выскакивает ошибка "Неожиданное выражение Счетчик()" и "Ошибка условия" во всех условиях, хотя я в условиях ничего не менял. Как правильно использовать функцию Счетчик?

Процедура Сформировать()   

    Спр = СоздатьОбъект("Справочник.Сотрудники");
    
    ЗапросСуммы = СоздатьОбъект("Запрос");
    ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Функция КолСис = Счетчик();
    |Группировка Товар Без Групп;
    |Условие (Инженер = Сотрудник);
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд));
    |Условие (ВидТовара = Перечисление.ВидыТоваров.Услуга);";
    
      Спр.ВыбратьЭлементы();
      
  Пока Спр.ПолучитьЭлемент()=1 Цикл
          
       Сотрудник = Спр.ТекущийЭлемент();
    
       
        ЗапросСуммы.Выполнить(ТекстЗапроса);
         Пока ЗапросСуммы.Группировка() = 1 Цикл
            СуммаУслуг = ЗапросСуммы.Сум;
            КолСис = ЗапросСуммы.КолСис;                      
        КонецЦикла;
        Сообщить(Сотрудник);
        Сообщить(СуммаУслуг);
        Сообщить(КолСис);
                      
    КонецЦикла;


Че-то глюкануло и стала такая картинка. Не имею возможности исправить. Модератор, исправьте, пожалуйста...

Автор: Макс1С 19.09.19, 13:37

ZUBR @ Сегодня, 2:11 * ,
Попробуйте

|Функция КолСис = Счетчик(Товар);


надо же сказать программе что мы будем считать )))

Макс1С @ Сегодня, 13:37 * ,
сорри, не досмотрел: через букву "ё"

|Функция КолСис = Счётчик(Товар);


В качестве примера предлагаю так переделать запрос:

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


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

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

Автор: ZUBR 19.09.19, 23:49

Даааа, ребята. Я в скобках Счетчика указывал и Товар, и Документ, и все равно запрос не работал, а то, что в слове Счётчик должна быть буква ЙО, а не Е, в голову не пришло! В этом моя основная ошибка. 32541510.gif 32541510.gif Тем не менее я вам всем благодарен за предложения по оптимизации запроса. Ваши критические советы очень мне помогают в изучении и освоении этого раздела! Очень интересно. Спасибо!

Автор: ZUBR 20.09.19, 0:54

Макс1С @ Вчера, 14:37 * , Ваш вариант более профессионален, чем мой. Но и в моем, и в Вашем варианте есть проблема. Для меня. Функция КолСис считает количество сделанных аппаратов по товарам с типом Услуга. Но в одном аппарате в расходной накладной может присутствовать несколько типов товаров вида Услуга. Например, инженер сделал 1 аппарат. Сделал Ремонт и Чистку. И функция КолСис выдает 2. А нужно, чтобы она выдала 1 - он сделал 1 аппарат. Я пробовал считать по документам. Все равно запрос 2 раза проходит документ и КолСис выдает 2. Как можно решить эту проблему? Можно ли поставить функции КолСис условие товар = ремонт, например? Хотя, в некоторых документах может быть чистка и не быть ремонта. Как заставить функцию считать даный аппарат только раз, не зависимо от количества проходов?

Автор: Макс1С 20.09.19, 8:29

ZUBR @ Сегодня, 1:54 * ,
Верно, условия для функции есть, просто вы не писали о таком условии раньше )))) Зато хороший опыт получился с разными примерами .

Можно попробовать так:

ЗапросСуммы = СоздатьОбъект("Запрос");
    ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |ТекДок = Документ.РасходнаяНакладная.ТекущийДокумент;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Функция КолСис = Счётчик(ТекДок) когда (ВидТовара = Перечисление.ВидыТоваров.Услуга);
    |Группировка Инженер;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд));";

Условие перенес в функцию, убрал группировку по товару - теперь он нам ни к чему, добавил переменную запроса "ТекДок" и счётчик именно по ней, т.е. считаем количество документов в которых есть услуги.
Остался нюанс с функцией Сум - если оставить так - будет выводить всю сумму документа, можно добавить такое же условие по услуге или так:
 |Функция СуммаУслуг = Сумма(СуммаСНДС)  когда (ВидТовара = Перечисление.ВидыТоваров.Услуга);
|Функция СуммаСистемы = Сумма(СуммаСНДС)  когда (ВидТовара = Перечисление.ВидыТоваров.Товар);




Автор: ZUBR 20.09.19, 23:58

Макс1С @ Вчера, 9:29 * , нет, результат такой же. Текущий документ считает столько раз, сколько товара с видом Услуга. Думаю, для подсчета количества надо делать отдельный запрос.

Автор: andrew76 21.09.19, 16:52

ZUBR @ Сегодня, 2:58 * ,

Цитата(ZUBR @ 21.09.19, 2:58) *
Например, инженер сделал 1 аппарат. Сделал Ремонт и Чистку. И функция КолСис выдает 2. А нужно, чтобы она выдала 1 - он сделал 1 аппарат.


Группировка в запросе по реквизиту Инженер.Вот и "склеивается" результат запроса.

Автор: Макс1С 22.09.19, 23:34

ZUBR @ 21.09.19, 0:58 * ,
Тогда так:
Добавим группировку по документу

 
|Группировка Инженер;
|Группировка ТекДок;

и посчитаем их не в запросе
    Пока ЗапросСуммы.Группировка(1) = 1 Цикл    // обходим первую по порядку группировку "Инженер"
        Сотрудник = ЗапросСуммы.Инженер;

        КвоДок = СоздатьОбъект("ТаблицаЗначений");
        КвоДок.НоваяКолонка ("Док");
        
        Пока ЗапросСуммы.Группировка(2) = 1 Цикл  
               КвоДок.НоваяСтрока();
               КвоДок.Док = ЗапросСуммы.ТекДок;
        КонецЦикла;
                КвоДок.Свернуть("Док");
                КвоСистем = КвоДок.КоличествоСтрок();
    КонецЦикла;

Автор: andrew76 23.09.19, 4:58

Может проще будет выгрузить весь запрос в Таблицу Значений, и далее свернуть (и просуммировать) по нужным колонкам ?

Автор: Макс1С 23.09.19, 8:41

andrew76 @ Сегодня, 5:58 * ,
Может и проще, но ТС в каждой новой теме добавляет вводные по частям для этой задачи, поэтому на этом этапе трудно сказать как лучше ))

Автор: ZUBR 23.09.19, 23:48

ТС решил сделать так:


Процедура Сформировать()
    
    ЗапросСуммыУслуг = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (Инженер = Сотрудник);
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));
    |Условие (ВидТовара = Перечисление.ВидыТоваров.Услуга);";
    
    
      Спр = СоздатьОбъект("Справочник.Сотрудники");
      Расх = СоздатьОбъект("Документ.РасходнаяНакладная");
      ТЗ = СоздатьОбъект("ТаблицаЗначений");
    
       ТЗ.НоваяКолонка ("Сотрудник");
       ТЗ.НоваяКолонка ("КолСис");   // количество систем
       ТЗ.НоваяКолонка ("ОР");   // стоимость основной работы
      ....................................................................................
          ....................................................................................
      

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

     ТЗ.ВыбратьСтроку();

КонецПроцедуры

Автор: andrew76 24.09.19, 5:09

ЗапросСуммыУслуг = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Док       = Документ.РасходнаяНакладная.ТекущийДокумент;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Группировка Док;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));
    |Условие (ВидТовара = Перечисление.ВидыТоваров.Услуга);";
    
    
    ТЗ = СоздатьОбъект("ТаблицаЗначений");      
    ТЗ.НоваяКолонка ("Сотрудник");
    ТЗ.НоваяКолонка ("КолСис");   // количество систем
    ТЗ.НоваяКолонка ("ОР");          // стоимость основной работы
      
    ЗапросСуммыУслуг.Выполнить(ТекстЗапроса);    

          
    Пока ЗапросСуммыУслуг.Группировка() = 1 Цикл
        ТЗ.НоваяСтрока();        
        ТЗ.Сотрудник=ЗапросСуммыУслуг.Инженер;
        ТЗ.ОР=ЗапросСуммыУслуг.СуммаСНДС;
        ТЗ.КолСис=1;
     КонецЦикла;

    ТЗ.Свернуть("Сотрудник","КолСис,ОР");

Автор: ZUBR 25.09.19, 0:52

andrew76 @ Вчера, 6:09 * ,
запрос считает неправильно. И суммы неправильно, и количество систем неправильно.
Мой гибридный код, приведенный ранее, считает все четко. Почему Ваш не считает, я так и не разобрался. Не знаю, как строится в данном случае группировка по документам... Думаю, причина в том, что при данных условиях выборки товара посчитать количество аппаратов в одном запросе программно невозможно. Остаюсь пока на своем варианте. Тем более, что мне нужно выбирать несколько параметров из справочника Сотрудники. Так что справочник мне все равно нужен. Благодарю Вас за участие!


Я благодарю Вас не в смысле прощаюсь, а просто благодарю. Если есть решение этих двух задач одним запросом, это будет интересно. Я пока не могу найти логического построения такого запроса. Короче, если суммировать услуги не по товару, а по видам товаров, тогда не получается вычислить количество систем. А если считать количество систем, тогда нужно суммировать по одному товару, а не по виду. То есть, в моем случае нужны, как минимум, два запроса. Во всяком случае, я так думаю.

Автор: andrew76 25.09.19, 5:19

ZUBR @ Сегодня, 3:52 * ,
Будем разбираться,раз такое дело.
Вот Ваш запрос ,без условия по Сотруднику.Попробуйте такой вариант.

ЗапросСуммыУслуг = СоздатьОбъект("Запрос");
ТекстЗапроса =
    "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Инженер = Документ.РасходнаяНакладная.Инженер;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));
    |Условие (ВидТовара = Перечисление.ВидыТоваров.Услуга);";

ТЗ = СоздатьОбъект("ТаблицаЗначений");      
       ТЗ.НоваяКолонка ("Сотрудник");
       ТЗ.НоваяКолонка ("КолСис");   // количество систем
       ТЗ.НоваяКолонка ("ОР");          // стоимость основной работы
      
ЗапросСуммыУслуг.Выполнить(ТекстЗапроса);    

          
    Пока ЗапросСуммыУслуг.Группировка() = 1 Цикл
        ТЗ.НоваяСтрока();        
        ТЗ.Сотрудник=ЗапросСуммыУслуг.Инженер;
        ТЗ.ОР=ЗапросСуммыУслуг.СуммаСНДС;
        ТЗ.КолСис=1;
     КонецЦикла;

ТЗ.Свернуть("Сотрудник","КолСис,ОР");

Автор: andrew76 25.09.19, 8:01

andrew76 @ Сегодня, 8:19 * ,

Если число Инженеров в выборке в моем варианте совпадает с Вашим отчетом,значит,где-то здесь в моём варианте проблема:

ТЗ.ОР=ЗапросСуммыУслуг.СуммаСНДС;
ТЗ.КолСис=1;


возможно так :
ТЗ.ОР=ЗапросСуммыУслуг.Сум;

Автор: ZUBR 25.09.19, 18:49

andrew76 @ Сегодня, 9:01 * , у меня в тестовом режиме два инженера. В Вашем варианте отчета отображается почему-то один. Правильность суммы забыл проверить. Наверное, свертка. Сейчас нет времени, посмотрю позже

Автор: ZUBR 25.09.19, 21:53

Я пытаюсь анализировать последний предложенный вариант, но не могу, потому что не понимаю до конца, что такое группировка. Вот если, например, Группировка Товар, и идет оператор

Пока ЗапросСуммыУслуг.Группировка() = 1 Цикл
, что происходит в цикле? Что значит Группировка Товар? Что значит Группировка()? Что значит Группировка (2)? Что значит Группировка(1)? Объясните, пожалуйста, кратко, кто может. Потому что без понимания этого нет смысла пытаться найти причину неправильной работы запроса! Для того, чтобы найти причину некорректной работы системы, нужно четко понимать, КАК она работает.
Спасибо!

Автор: andrew76 26.09.19, 4:36

Цитата(ZUBR @ 26.09.19, 0:53) *
В Вашем варианте отчета отображается почему-то один. Правильность суммы забыл проверить. Наверное, свертка.


Если в Вашем отчете это один и тот же человек , то это свертка.
Цитата(ZUBR @ 26.09.19, 0:53) *
Что значит Группировка()? Что значит Группировка (2)? Что значит Группировка(1)?


Оператор Группировка задает способ группировки информации и порядок ее упорядочивания в запросе.
Про группировки здесь есть:
https://pro1c.org.ua/redirect.php?http://anatoly4xs.narod.ru/manual/lang/lang0342.htm
В запросе может быть несколько группировок.Поэтому обращение к группировкам происходит при помощи номера или имени группировки (Товар,Сотрудник).

Автор: ZUBR 26.09.19, 19:39

andrew76 @ Сегодня, 5:36 * , про группировки я читал. Сам давал эту ссылку. Но, не сочтите за тупого, мне не понятен сам термин Группировка. Что это значит физически? Конкретно. Как это происходит в деталях?
Вто например, Группировка Товар. Что это значит? Как группируются данные? И где?

Автор: Макс1С 26.09.19, 20:27

ZUBR @ Сегодня, 20:39 * ,
группировки можно представить в виде дерева или вот таких "группировок" таблицы которая получается в результате выполнения запроса

в 7.7 в запросе должна быть как минимум одна группировка - это будет соответствовать простой таблице без "вложенностей".
2 группировки будут означать "дерево" из 2х уровней вложенности, 3 - из 3х и т.д.
Несмотря на то, что картинка из 1С8 и там принцип чуть другой, результат в отчете примерно такой же.

Также для каждой группировки рассчитываются функции запроса. На картинке например это Количество и Сумма
Примерно такой запрос мог быть для отчета как на картинке:

    
        Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса =
    "//{{ЗАПРОС(Сформировать)
    |Период с ВыбНачПериода по ВыбКонПериода;
    |Контрагент = Документ.РасходнаяНакладная.Контрагент;
    |ТМЦ = Документ.РасходнаяНакладная.ТМЦ;
    |ТекущийДокумент = Документ.РасходнаяНакладная.ТекущийДокумент;
    |Кво = Документ.РасходнаяНакладная.Кво;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Родитель = Документ.РасходнаяНакладная.Контрагент.Родитель;
    |Функция ИтогКоличество = Сумма(Кво);
    |Функция ИтогСумма = Сумма(СуммаСНДС);
    |Группировка Родитель;
    |Группировка Контрагент;
    |Группировка ТМЦ;
    |Группировка ТекущийДокумент;
    |Условие(ТМЦ в ВыбТМЦ);
    |"//}}ЗАПРОС
;
    // Если ошибка в запросе, то выход из процедуры
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат;
    КонецЕсли;

    Пока Запрос.Группировка(1) = 1 Цикл
        // Заполнение полей Родитель
        Пока Запрос.Группировка(2) = 1 Цикл
            // Заполнение полей Контрагент
            Пока Запрос.Группировка(3) = 1 Цикл
                 // Заполнение полей ТМЦ
                Пока Запрос.Группировка(4) = 1 Цикл
                    // Заполнение полей ТекущийДокумент
                КонецЦикла;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;

если оставим обход запроса только по одной группировке - получим обычную таблицу без вложений
Пока Запрос.Группировка(1) = 1 Цикл

КонецЦикла;

в данном случае параметр функции Группировка() = 1 , это соответствует родителю, папке с клиентами.
получим таблицу такого вида (например у нас все клиенты находятся в группах: "покупатели мелкий опт" и "покупатели диллеры")

Родитель ИтогоСумма ИтогоКоличество
"покупатели мелкий опт" 23423,00 44
"покупатели диллеры" 1231545,00 444







Автор: ZUBR 26.09.19, 21:24

Макс1С @ Сегодня, 21:27 * , так, немного яснее. А как выводятся результаты? Они где-то хранятся, или при каждом прохождении цикла их надо выводить? Чтобы получилась таблица отчета.

Автор: Макс1С 27.09.19, 8:31

ZUBR @ Вчера, 22:24 * ,
Для каждой группировки итоги (функции запроса) рассчитаны и доступны при обходе циклами.
Вот такую таблицу генерирует конструктор запроса:

и обработку результата запроса:

     Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("Сформировать"); // это имя макета
    // Заполнение полей "Заголовок"
    Таб.ВывестиСекцию("Заголовок");
    Таб.Опции(0, 0, Таб.ВысотаТаблицы(), 0);
    Пока Запрос.Группировка(1) = 1 Цикл
        // Заполнение полей Родитель
        Таб.ВывестиСекцию("Родитель");
        Пока Запрос.Группировка(2) = 1 Цикл
            // Заполнение полей Контрагент
            Таб.ВывестиСекцию("Контрагент");
            Пока Запрос.Группировка(3) = 1 Цикл
                // Заполнение полей ТМЦ
                Таб.ВывестиСекцию("ТМЦ");
                Пока Запрос.Группировка(4) = 1 Цикл
                    // Заполнение полей ТекущийДокумент
                    Таб.ВывестиСекцию("ТекущийДокумент");
                КонецЦикла;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
    // Заполнение полей "Итого"
    Таб.ВывестиСекцию("Итого");
    // Вывод заполненной формы
    Таб.ТолькоПросмотр(1);
    Таб.Показать("Сформировать", "");

В каждом из вложенных циклов выводится своя область,но имя переменных в макете "Запрос.ИтогКоличество" и "Запрос.ИтогСумма" одинаково во всех строках. Показатели которые будут там выводится как раз зависят от группировки для которой они рассчитаны - фактически в цикле какого уровня была дана команда на заполнение и вывод этой области

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

Автор: ZUBR 01.10.19, 23:55

Доброй ночи! Сегодня создал нужній мне отчет. Небольшой. Состоит из 3 текстов запросов. Работает))) Очень Прошу профессуру посмотреть и дать свои замечания. Можно ли его сократить? Оптимизировать? Спасибо!

Процедура Сформировать()   

    Запрос = СоздатьОбъект("Запрос");
    
ТекстЗапросаС =
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);

    |Функция СумУс = Сумма(СуммаСНДС) когда (ВидТовара = Перечисление.ВидыТоваров.Услуга);
    |Группировка Товар Без Групп;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));";
    
ТекстЗапросаК =
     "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |ТекДок = Документ.РасходнаяНакладная.ТекущийДокумент;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |Функция КолСис = Счётчик(ТекДок);
    |Группировка  ТекДок;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));";
    
    ТекстЗапросаАкс =
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция СумАкс = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (СтатусЗаказа = Перечисление.Статусы.Акс);";
    
Запрос.Выполнить(ТекстЗапросаС);
    Пока Запрос.Группировка() = 1 Цикл
        Вал = Запрос.Сум;
        СумУс = Запрос.СумУс;
    КонецЦикла;
    
Запрос.Выполнить(ТекстЗапросаК);
   КолСис = Запрос.КолСис;
  
Запрос.Выполнить(ТекстЗапросаАкс);
    Пока Запрос.Группировка() = 1 Цикл
        СумАкс = Запрос.СумАкс;
    КонецЦикла;
    
Сообщить("Количество систем:"+КолСис);    
Сообщить("Сумма:"+Вал);
Сообщить("Сумма услуг:"+СумУс);
Сообщить("Сумма акс:"+СумАкс);


КонецПроцедуры

Автор: Макс1С 02.10.19, 8:14

ZUBR @ Сегодня, 0:55 * ,
Предлагаю для начал изложить цель этой процедуры, пользовательскую историю, так сказать. Чего хочется получить, какова конечная цель отчета? Потому что первое впечатление, что оно работает не так )))

Автор: andrew76 02.10.19, 15:03

Цитата(Макс1С @ 02.10.19, 11:14) *
Состоит из 3 текстов запросов. Работает))) Очень Прошу профессуру посмотреть и дать свои замечания. Можно ли его сократить? Оптимизировать? Спасибо!


А может лучше не трогать ничего ? Ведь есть ветхозаветная истина: "Техника не тронет техника,если техник не тронет технику".
Тем более автор говорит,что все работает.


Вот такой вариант :

СумУс=0;
КолСис=0;
СумАкс=0;

Расх = СоздатьОбъект("Документ.РасходнаяНакладная");
Расх.ВыбратьДокументы(НачДата,КонДата);
          
Пока Расх.ПолучитьДокумент()=1 Цикл
        
     Если  (Расх.СтатусЗаказа = Перечисление.Статусы.Выдан) или (Расх.СтатусЗаказа = Перечисление.Статусы.Выезд) или (Расх.СтатусЗаказа =
                Перечисление.Статусы.ВыдОтказ) тогда
              КолСис=КолСис+1;

        Если Расх.ВидТовара = Перечисление.ВидыТоваров.Услуга тогда
               СумУс=СумУс+Расх.СуммаСНДС;
        КонецЕсли;

    КонецЕсли;

    Если Расх.СтатусЗаказа = Перечисление.Статусы.Акс тогда
           СумАкс =СумАкс+Рас.СуммаСНДС;
    КонецЕсли;

КонецЦикла;


Забыл про переменную Вал.Звиняйте,паны добродии...

СумУс=0;
КолСис=0;
СумАкс=0;
Вал=0;

Расх = СоздатьОбъект("Документ.РасходнаяНакладная");
Расх.ВыбратьДокументы(НачДата,КонДата);
          
Пока Расх.ПолучитьДокумент()=1 Цикл
        
     Если  (Расх.СтатусЗаказа = Перечисление.Статусы.Выдан) или (Расх.СтатусЗаказа = Перечисление.Статусы.Выезд) или (Расх.СтатусЗаказа =
                Перечисление.Статусы.ВыдОтказ) тогда
              КолСис=КолСис+1;
              Вал=Вал+Расх.СуммаСНДС;

        Если Расх.ВидТовара = Перечисление.ВидыТоваров.Услуга тогда
               СумУс=СумУс+Расх.СуммаСНДС;
        КонецЕсли;

    КонецЕсли;

    Если Расх.СтатусЗаказа = Перечисление.Статусы.Акс тогда
           СумАкс =СумАкс+Рас.СуммаСНДС;
    КонецЕсли;

КонецЦикла;

Сообщить("Количество систем:"+КолСис);    
Сообщить("Сумма:"+Вал);
Сообщить("Сумма услуг:"+СумУс);
Сообщить("Сумма акс:"+СумАкс);

Автор: ZUBR 02.10.19, 21:47

andrew76 @ Сегодня, 16:03 * , у меня вопрос тогда. Как к профессору. Какой вариант забирает меньше ресурсов и более быстродейственен? Вариант запросов? Или предложенный Вами? Вопрос чисто академический для лучшего понимания оптимальных методов программирования. Осмелюсь предположить, что Ваш вариант проще и лучше.

Автор: andrew76 03.10.19, 3:59

ZUBR @ Сегодня, 0:47 * ,

Цитата(ZUBR @ 03.10.19, 0:47) *
Какой вариант забирает меньше ресурсов и более быстродейственен?


Это смотря по ситуации.Замеряйте производительность в каждом варианте ( запрос или перебор документов ).
Ну а код должен быть лёгким для восприятия.Мой вариант считает правильно ?

Автор: Макс1С 03.10.19, 8:22

andrew76 @ Вчера, 16:03 * ,
но как минимум вот такие конструкции надо поменять:

    Пока Запрос.Группировка() = 1 Цикл
        Вал = Запрос.Сум;
        СумУс = Запрос.СумУс;
    КонецЦикла;
.............
Пока Запрос.Группировка() = 1 Цикл
        СумАкс = Запрос.СумАкс;
    КонецЦикла;

на
  
Вал  = 0;
СумУс = 0;  
СумАкс = 0;

Пока Запрос.Группировка() = 1 Цикл
        Вал = Вал + Запрос.Сум;
        СумУс = СумУс  + Запрос.СумУс;
    КонецЦикла;
.............
Пока Запрос.Группировка() = 1 Цикл
        СумАкс = СумАкс  + Запрос.СумАкс;
    КонецЦикла;

А то получим только результат последнего элемента выборки в каждом случае. Возможно в тестовой базе 1 документ удовлетворяющий условиям поэтому создается впечатление, что всё правильно


Автор: andrew76 03.10.19, 13:34

Цитата(Макс1С @ 03.10.19, 11:22) *
Возможно в тестовой базе 1 документ удовлетворяющий условиям поэтому создается впечатление, что всё правильно


Да,вчера не досмотрел я это дело.
Цитата(Макс1С @ 03.10.19, 11:22) *
Какой вариант забирает меньше ресурсов


Если мой вариант с перебором документов работает правильно,то этот вариант забирает меньше ресурсов.За один проход цикла решаются все
поставленные задачи.А в варианте с запросами - трижды.Одна задача бъётся на 3 подзадачи.

Автор: volodya1122 03.10.19, 13:58

Цитата(ZUBR @ 02.10.19, 22:47) *
Какой вариант забирает меньше ресурсов и более быстродейственен?


Не завжди варіант який забирає манше ресурсів є більш швидкодійним. Ну і зараз на 1с7 слідкувати за ресурсами не думаю що потрібно (звичайно в розумних межах), або дуже потужній звіт і дуже велика база (тоді звіт може використати 1 чи 2 Гбайт (точно не памятаю) оперативної памяті - а це максимум що може використати 1с7, і тоді 1с просто зависне.
А на рахунок швидкодії можна ввикористовувати в "отладчику" "Замер производительности" -тут можна конкретно визначити який саме рядок виконується найдовше. Або просто на початку процедури написати
а2=_GetPerformanceCounter();

а в кінці процедури
    а2=_GetPerformanceCounter(); 
    а=а2-а1;
    сек=а/1000;
    Сообщить("Тривалысть формування= "+сек);

Автор: ZUBR 03.10.19, 16:43

Макс1С @ Сегодня, 9:22 * , я не понял, в чем проблема. Отчет формируется нормально. Можете объяснить?

Автор: Макс1С 04.10.19, 14:36

ZUBR @ Вчера, 17:43 * ,
На примере этого запроса:

    ТекстЗапросаАкс = 
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция СумАкс = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (СтатусЗаказа = Перечисление.Статусы.Акс);";
  
Запрос.Выполнить(ТекстЗапросаАкс);  //*1

    Пока Запрос.Группировка() = 1 Цикл   //*2
        СумАкс = Запрос.СумАкс;
    КонецЦикла;
Сообщить("Сумма акс:"+СумАкс); //*3


//*1 - на этой строке у нас выполняется запрос и мы получаем таблицу с колонками "Товар" и "СумАкс" в которой строк будет столько, сколько разных товаров мы продали за период
пусть будет 3 строки: Товар1 на сумму 5000,00, Товар2 - 7000,00, Товар3- 3000,00

//*2 - в цикле мы обходим строки этой талицы, т.е. код внутри цикла выполнится 3 раза. Если мы условно уберем цикл, то наш код (напишу со значениями которые записываем в переменную) будет выглядеть примерно так:
СумАкс = 5000;
СумАкс = 7000;
СумАкс = 3000;
т.е. мы в одну переменную просто три раза присваиваем разные значения

и вот когда мы доходим до //*3 - у нас будет СумАкс = 3000; - именно последнее значение которое мы туда записали.

А если сделаем так:
СумАкс = 0;
Пока Запрос.Группировка() = 1 Цикл
    СумАкс = СумАкс  + Запрос.СумАкс;
КонецЦикла;
Сообщить("Сумма акс:"+СумАкс);

после выхода из цикла у нас СумАкс = 15000,00.

Если у вас на выходе получается сумма, то это магия или я совсем ничего не понимаю в 1С 7.7)))

PS. Ваш вариант сработает в случае, если во всей выборке запроса будет всего 1 товар(точнее во всех документах из выборки будет одинаковый товар) и цикл выполнится 1 раз

Автор: ZUBR 04.10.19, 19:47

Макс1С @ Сегодня, 15:36 * ,
Я сейчас проверю и сообщу результат

Макс1С @ Сегодня, 15:36 * ,
У меня все считает правильно. Товары со статусом заказа АКС (Это аксессуары) разные и в разных количествах. Услуги тоже разные. Видов 4 или 5. В разных документах могут быть разные товары и услуги. Привожу реально работающую часть кода еще раз.

Процедура Сформировать() 

    Запрос = СоздатьОбъект("Запрос");
    
        ТЗ = СоздатьОбъект ("ТаблицаЗначений");
    
//Создание колонок
     ТЗ.НоваяКолонка("НачДата");    
     ТЗ.НоваяКолонка("КонДата");    
     ТЗ.НоваяКолонка("КолСис");   //Количество систем
     ТЗ.НоваяКолонка("Вал");     //Общая стоимость работ
     ТЗ.НоваяКолонка("СумУс");  //Стоимость услуг
     ТЗ.НоваяКолонка("ЗЧ");     //Стоимость запчастей
     ТЗ.НоваяКолонка("СумАкс");   //Стоимость аксессуаров
    
ТекстЗапросаС =
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |ВидТовара = Документ.РасходнаяНакладная.Товар.ВидТовара;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция Сум = Сумма(СуммаСНДС);
    |Функция СумУс = Сумма(СуммаСНДС) когда (ВидТовара = Перечисление.ВидыТоваров.Услуга);
    |Группировка Товар Без Групп;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));";
    
ТекстЗапросаК =
     "    
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |ТекДок = Документ.РасходнаяНакладная.ТекущийДокумент;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;
    |Функция КолСис = Счётчик(ТекДок);
    |Группировка  ТекДок;
    |Условие ((СтатусЗаказа = Перечисление.Статусы.Выдан)или(СтатусЗаказа = Перечисление.Статусы.Выезд)или(СтатусЗаказа = Перечисление.Статусы.ВыдОтказ));";
    
    ТекстЗапросаАкс =
    "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |СтатусЗаказа = Документ.РасходнаяНакладная.СтатусЗаказа;    
    |Товар = Документ.РасходнаяНакладная.Товар;
    |СуммаСНДС = Документ.РасходнаяНакладная.СуммаСНДС;
    |Функция СумАкс = Сумма(СуммаСНДС);
    |Группировка Товар Без Групп;
    |Условие (СтатусЗаказа = Перечисление.Статусы.Акс);";
    
Запрос.Выполнить(ТекстЗапросаС);
    Пока Запрос.Группировка() = 1 Цикл
        Вал = Запрос.Сум;
        СумУс = Запрос.СумУс;
    КонецЦикла;
    
Запрос.Выполнить(ТекстЗапросаК);
   КолСис = Запрос.КолСис;
  
Запрос.Выполнить(ТекстЗапросаАкс);
    Пока Запрос.Группировка() = 1 Цикл
        СумАкс = Запрос.СумАкс;
    КонецЦикла;
    
Сообщить("Количество систем:"+КолСис);    
Сообщить("Сумма:"+Вал);
Сообщить("Сумма услуг:"+СумУс);
Сообщить("Сумма акс:"+СумАкс);  
  
   ТЗ.НоваяСтрока();
   ТЗ.НачДата = НачДата;
   ТЗ.КонДата = КонДата;
   ТЗ.КолСис = КолСис;
   ТЗ.Вал = Вал;
   ТЗ.СумУс = СумУс;
   ТЗ.ЗЧ = Вал - СумУс;

// и т.д. Дальше идут колонки, данные в которые заносятся на основании предыдущих колонок

КонецПроцедуры


Сумму услуг считает правильно. Общую сумму и сумму аксесуаров за указанный период тоже считает правильно.

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

Автор: ZUBR 04.10.19, 23:27

Цитата(andrew76 @ 03.10.19, 4:59) *
Это смотря по ситуации.Замеряйте производительность в каждом варианте ( запрос или перебор документов ).
Ну а код должен быть лёгким для восприятия.Мой вариант считает правильно ?


Ваш вариант считает только количество систем. Но если его немного поправить, тогда он считает отлично! 32000000.gif


Процедура Сформировать() 
    
        ТЗ = СоздатьОбъект ("ТаблицаЗначений");
    Расх = СоздатьОбъект("Документ.РасходнаяНакладная");    
    
//Создание колонок
     ТЗ.НоваяКолонка("НачДата");    
     ТЗ.НоваяКолонка("КонДата");    
     ТЗ.НоваяКолонка("КолСис");   //Количество систем
     ТЗ.НоваяКолонка("Вал");     //Общая стоимость работ
     ТЗ.НоваяКолонка("СумУс");  //Стоимость услуг
      
//и т.д.
    
    
         СумУс=0;
             КолСис=0;
             СумАкс=0;
             Вал=0;

Расх.ВыбратьДокументы(НачДата,КонДата);
          
Пока Расх.ПолучитьДокумент()=1 Цикл
        
     Если  (Расх.СтатусЗаказа = Перечисление.Статусы.Выдан) или (Расх.СтатусЗаказа = Перечисление.Статусы.Выезд) или (Расх.СтатусЗаказа =
                Перечисление.Статусы.ВыдОтказ) тогда
              КолСис=КолСис+1;
              Вал=Вал+Расх.Итог("СуммаСНДС");
    
             Расх.ВыбратьСтроки();
             Пока Расх.ПолучитьСтроку() = 1 Цикл
                 Если Расх.Товар.ВидТовара = Перечисление.ВидыТоваров.Услуга тогда
               СумУс=СумУс+Расх.СуммаСНДС;
                КонецЕсли;
     КонецЦикла;

    КонецЕсли;

    Если Расх.СтатусЗаказа = Перечисление.Статусы.Акс тогда
           СумАкс =СумАкс+Расх.Итог("СуммаСНДС");
    КонецЕсли;

КонецЦикла;

Сообщить("Количество систем:"+КолСис);    
Сообщить("Сумма:"+Вал);
Сообщить("Сумма услуг:"+СумУс);
Сообщить("Сумма акс:"+СумАкс);
    
КонецПроцедуры


Думаю, этот вариант более быстрый, чем вариант с тремя запросами. И мне, например, он пока легче в понимании. Вам спасибо.

Автор: andrew76 05.10.19, 5:21

Доброе утро !

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

Если  (Расх.СтатусЗаказа = Перечисление.Статусы.Выдан) или (Расх.СтатусЗаказа = Перечисление.Статусы.Выезд) или (Расх.СтатусЗаказа = 
                Перечисление.Статусы.ВыдОтказ) тогда
         КолСис=КолСис+1;
         Вал=Вал+Расх.Итог("СуммаСНДС");
    
         Расх.ВыбратьСтроки();
         Пока Расх.ПолучитьСтроку() = 1 Цикл
                 Если Расх.Товар.ВидТовара = Перечисление.ВидыТоваров.Услуга тогда
                        СумУс=СумУс+Расх.СуммаСНДС;
                КонецЕсли;
         КонецЦикла;

КонецЕсли;

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua