7.7 Итоги по группировкам в запросе

Тема в разделе "Конфигурирование на платформе "1С:Предприятие 7.7"", создана пользователем 1Счик, 16 дек 2008.

  1. TopicStarter Overlay
    1Счик
    Offline

    1Счик

    Регистрация:
    16 дек 2008
    Сообщения:
    46
    Симпатии:
    0
    Баллы:
    1
    Добрый день.

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

    Подскажите, существует ли возможность получать итоги по группам товаров в разрезе складов в данном запросе? У меня есть идея выгрузить все в ТаблицуЗначений, но здесь я привожу весьма упрощённый вариант моего запроса, поэтому использовать ТЗ не хочется.


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

    Большое спасибо.

    Вложения:

    • Отчет.PNG
      Отчет.PNG
      Размер файла:
      9,8 КБ
      Просмотров:
      453
  2. WaRDeR
    Offline

    WaRDeR Модераторы Команда форума Модератор

    Регистрация:
    23 ноя 2006
    Сообщения:
    3.263
    Симпатии:
    14
    Баллы:
    29
    Хм... даже не знаю как написать....
    В общем, так работать не будет, нужно делать перебор только товаров (без групп), потом формировать ТЗ, которую потом нужно выводить.

    Ошибка возникает потому (точнее не ошибка, а особенность) что в 1С такие данные нигде не хранятся и их нужно самому вычислять.
  3. TopicStarter Overlay
    1Счик
    Offline

    1Счик

    Регистрация:
    16 дек 2008
    Сообщения:
    46
    Симпатии:
    0
    Баллы:
    1
    Да, про эту "особенность" я знаю... Т.к. если выводить все группировки вертикально, то глупо было бы после каждой группы товаров выводить итоги по складам в моем случае.

    Просто надеялся, что в запросах есть какие-то недокументированные возможности и т.п.

    Тема пока не закрыта.

    Ещё раз спасибо.
  4. Stado_adama
    Offline

    Stado_adama Модераторы Модератор

    Регистрация:
    27 ноя 2007
    Сообщения:
    1.086
    Симпатии:
    0
    Баллы:
    26
    а я так же хочу! только у меня вертикальные секции это дата! 1Счик, ты там еще ничего не придумал? :)
  5. TopicStarter Overlay
    1Счик
    Offline

    1Счик

    Регистрация:
    16 дек 2008
    Сообщения:
    46
    Симпатии:
    0
    Баллы:
    1
    Вариант №1.
    Вот кусок из похожего отчёта, который я когда-то написал:
    По вертикали товары, по горизонтали контрагенты.

    Код:
    	ТЗ = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("Товар");
    
    Пока Запрос.Группировка("Контрагент") = 1 Цикл
    Попытка
    ТЗ.ПолучитьПараметрыКолонки("Колонка"+СокрЛП(Запрос.Контрагент.Код));
    Исключение
    ТЗ.НоваяКолонка("Колонка"+СокрЛП(Запрос.Контрагент.Код),"Число",10,0,СокрЛП(Запрос.Контрагент));
    КонецПопытки
    КонецЦикла;
    
    Запрос.вНачалоВыборки();
    
    Пока Запрос.Группировка("Контрагент") = 1 Цикл
    Если (Запрос.Контрагент.ЭтоГруппа() = 1) Тогда
    Состояние("Обрабатываются контрагенты группы: "+СокрЛП(Запрос.Контрагент));
    КонецЕсли;
    
    Пока Запрос.Группировка("Товар") = 1 Цикл
    СтрокаТаблицы = ТЗ.НоваяСтрока();
    ТЗ.Товар = Запрос.Товар;
    ТЗ.УстановитьЗначение(СтрокаТаблицы, "Колонка"+СокрЛП(Запрос.Контрагент.Код), Запрос.ОборотСумма);
    
    КонецЦикла;
    КонецЦикла;
    
    
    

    Вариант №2. Он очень медленный. Создать ещё один запрос и вычислять суммы по группам товаров в разрезе складов.

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

    Если есть идеи получше, поделитесь
  6. ASh
    Offline

    ASh Опытный в 1С

    Регистрация:
    10 сен 2008
    Сообщения:
    568
    Симпатии:
    0
    Баллы:
    26
    Могу предложить еще один вариант решения задачи. Из минусов - время выполнения запроса сильно зависит от объема выборки и количества колонок-результатов. Из плюсов - все нужные суммы будут рассчитаны в запросе. Суть заключается в формировании дополнительных функций в запросе. Пример топика можно реализовать так:

    Код:
    //СписокСкладов - список значений, содержащий нужные нам склады
    //Кстати, удобно вывести на форму и дать пользователю выбрать интересующие склады
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "
    |Период с НачДата по КонДата;
    |ОбрабатыватьДокументы Проведенные;
    |Склад = Документ.РасходнаяНакладная.Склад;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |Сумм1 = Документ.РасходнаяНакладная.Сумма;";
    //Здесь вставляем функции с отбором по нужным складам
    Для А = 1 По СписокСкладов.РазмерСписка() Цикл
    ТекстЗапроса = ТекстЗапроса+"
    |Функция Сумма"+А+" = Сумма(Сумм1) когда (Склад = СписокСкладов.ПолучитьЗначение("+А+"));";
    КонецЦикла;
    ТекстЗапроса = ТекстЗапроса+"
    //Здесь вставляем функцию содержащую итог по всем выбранным складам
    |Функция СуммаИтого = Сумма(Сумм1) когда (Склад В СписокСкладов);
    |Группировка Товар Упорядочить по Товар.Наименование;";
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Возврат;
    КонецЕсли;
    // CUT
    Пока Запрос.Группировка(1) = 1 Цикл
    Таб.ВывестиСекцию("Строка|Товар");
    //Вторая группировка не нужна
    //В цикле будем присоединять секции с суммами по складам
    //В секции "Строка|Склад" имя выражения ТекСумма
    Для А = 1 По СписокСкладов.РазмерСписка() Цикл
    ТекСумма = Запрос.ПолучитьАтрибут("Сумма"+А);
    Таб.ПрисоединитьСекцию("Строка|Склад");
    КонецЦикла;
    ТекСумма = Запрос.ПолучитьАтрибут("СуммаИтого");
    Таб.ПрисоединитьСекцию("Строка|Склад");
    КонецЦикла;
    
    
    P.S. Если количество складов меньше 10, то в целом по скорости будет сравнимо с выгрузкой в ТЗ простого запроса (с одной функцией) и последующей обработкой данных (подсчет промежуточных итогов, проверка всяких условий при выводе и т.д.).
  7. TopicStarter Overlay
    1Счик
    Offline

    1Счик

    Регистрация:
    16 дек 2008
    Сообщения:
    46
    Симпатии:
    0
    Баллы:
    1
    Отличная идея! Работает быстро. Ошибки исключены в силу того, что всё обрабатывается в запросе.
    Спасибо!

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

    Думаю, что тему можно закрыть.

Поделиться этой страницей