gifts2017

Почти динамическая группировка по периоду в СКД

Опубликовал Артем Целовальников (slazzy) в раздел Программирование - Практика программирования

Простой способ позволить пользователю самому выбрать период, по которому будут сгруппированы колонки. Смысл в использовании исключительно возможностей СКД, без редактирования модуля отчета.

 

На самом деле все мы помним замечательный Универсальный отчет, который легким движением руки позволял пользователю самому выбрать период развертки. В СКД пользователь тоже может это сделать сам, но для этого ему надо изменять вариант отчета, а, к сожалению, пользователи редко хотят и умеют это делать. Да и всё равно для этого необходимо создать список необходимых полей периодов.

 

Я же хочу показать, как это сделать для пользователя максимально наглядно и максимально очевидно для программиста.

Покажу 2 варианта, но существуют, конечно же, и другие. Можно, к примеру, в процедуре

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) 	
// тут можно проанализировать какие-то параметры 
// и в структуре СКД сделать необходимые перестановки, но 
// это не true way потому что не интересно. КонецПроцедуры



Я хотел сделать всё исключительно в СКД, и такой способ тоже есть, более того, он, вероятно, даже проще. Я покажу два очень похожих варианта, смысл в двух - просто показать некоторые возможности СКД, которые кто-то, может быть, не знает.


Для начала создадим параметр, естественно, можно добавить или удалить какую-то свою периодичность.

Создание параметра

Вариант 1.


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

 

ВЫБРАТЬ

//какие-то поля,

ВЫБОР
    КОГДА &Периодичность = 1
        ТОГДА НачалоПериода(Дата, МЕСЯЦ)
    КОГДА &Периодичность = 2
        ТОГДА НачалоПериода(Дата, КВАРТАЛ)
    КОГДА &Периодичность = 3
        ТОГДА НачалоПериода(Дата, ПОЛУГОДИЕ)
    КОГДА &Периодичность = 4
        ТОГДА НачалоПериода(Дата, ГОД)
КОНЕЦ КАК Период

 


 

То есть мы получаем в одном поле любое нужное нам начало периода, но было бы неплохо выводить его не в виде даты, а удобно настроить формат. Для этого отредактируем Выражение представления, в настройках поля СКД.

 Выражение упорядочивания

 

ВЫБОР 
    КОГДА &Периодичность = 1  
        ТОГДА Формат(Дата, "ДФ='ММММ гггг ""г.""' ") 
    КОГДА &Периодичность = 2  
        ТОГДА Формат(Дата,"ДФ='к ""квартал"" гггг ""г.""'" ) 
    КОГДА &Периодичность = 3 
        ТОГДА 
        ВЫБОР 
            КОГДА Квартал(Дата) < 3 
                ТОГДА "1" ИНАЧЕ "2"
        КОНЕЦ + Формат(Дата, "ДФ=' ""полугодие"" гггг ""г."" '")
    КОГДА &Периодичность = 4 
        ТОГДА Формат(Дата,"ДФ='гггг ""г.""'")
КОНЕЦ

Естественно, можно настроить формат так, как хотите. Можно и не настраивать.

 

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

Группировка

В общем-то, всё, почти динамическая группировка готова. Почему почти? Ну мы же должны заранее задать и описать необходимые периоды!

 

Вариант 2.

Этот вариант очень похож на первый, я тут просто покажу пару возможностей СКД. Тут мы, вместо одного поля Период, сделаем несколько полей. Месяц, Квартал, Полугодие, Год и т.д.

 

В запросе опишем эти поля вот таким образом

ВЫБОР
    КОГДА &Периодичность = 1
        ТОГДА НАЧАЛОПЕРИОДА(ВТ_Данные.Месяц, МЕСЯЦ)
    ИНАЧЕ NULL
КОНЕЦ КАК Месяц,
ВЫБОР
    КОГДА &Периодичность = 2
        ТОГДА НАЧАЛОПЕРИОДА(ВТ_Данные.Месяц, Квартал)
    ИНАЧЕ NULL
КОНЕЦ КАК Квартал,
ВЫБОР
    КОГДА &Периодичность = 3
        ТОГДА НАЧАЛОПЕРИОДА(ВТ_Данные.Месяц, Полугодие)
    ИНАЧЕ NULL
КОНЕЦ КАК Полугодие,
ВЫБОР
    КОГДА &Периодичность = 4
        ТОГДА НАЧАЛОПЕРИОДА(ВТ_Данные.Месяц, Год)
    ИНАЧЕ NULL
КОНЕЦ КАК Год,

 

NULL обязателен, чтобы использовать одну из настроек СКД - "Игнорировать NULL". Если не хотите использовать NULL, то никто не мешает для каждой из 4 группировок создать свой собственный отбор на параметр Периодичность. Я это описывать не буду, думаю и так всё очевидно.

Настройка поля

 

И создаем 4 группировки с этими полями.

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

 Результат запроса

Так что в СКД избавляться от NULL нужно с умом :) иногда оно бывает полезно.

 

 

На самом деле такой подход работает далеко не только для периода. Я подобным подходом пользуюсь в разных отчетах довольно часто

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Яков Коган (Yashazz) 30.01.15 16:27
Я бы это делал вычисляемыми полями...
2. Артем Целовальников (slazzy) 30.01.15 16:42
(1) Yashazz, можно и полями, собственно какая разница? :)

3. Александр Крынецкий (echo77) 31.01.15 14:23
4. Павел Никифоров (Lyns_owner) 01.02.15 22:41
Я уже писал подобную статью, а почитав комментарии к ней, можно написать отличный отчет - http://infostart.ru/public/125216/

Самым правильным вариантом считаю составление текста запроса с учетом переданного параметра (задавать периодичность виртуальной таблицы) с последующей передачей внешнего набора данных (таблицы) в макет СКД.
Как-то так:

	
"ВЫБРАТЬ
	|	ВирутальнаяТаблица.Поле1 КАК Поле1,
	|	ВирутальнаяТаблица.Поле2 КАК Поле2,
	|	НАЧАЛОПЕРИОДА(ВирутальнаяТаблица.Период, " + Периодичность + ") КАК Период,
	|ИЗ
	|	РегистрНакопления.ВирутальнаяТаблица.Обороты(&НачалоПериода, &КонецПериода, " + Периодичность + ", ) КАК ВирутальнаяТаблицаОбороты"
...Показать Скрыть
5. Сергей Ожерельев (Поручик) 02.02.15 00:46
Очень интересно. Не забыть попробовать переделать один отчет. Пытался несколько раз, но ничего путного не выходило
6. ффф ыыы (zqzq) 02.02.15 09:00
В СКД пользователь тоже может это сделать сам, но для этого ему надо изменять вариант отчета
В настройках СКД можно включить группировки (строк, колонок, подчинённых строк) в быстрые пользовательские настройки. Тогда пользователь хоть период, хоть 2 периода, хоть любую другую группировку сможет убрать/добавить в отчет без изменения варианта. Без всякого программирования и порчи текста запроса.
7. Артем Целовальников (slazzy) 02.02.15 09:57
(4) Lyns_owner, спасибо за ссылку, Вашу статью я не нашел при поиске. По поводу
Самым правильным вариантом считаю составление текста запроса с учетом переданного параметра (задавать периодичность виртуальной таблицы) с последующей передачей внешнего набора данных (таблицы) в макет СКД.

У меня только один вопрос. На каком основании Вы считаете, что этот метод "самый правильный"? Я вот так не считаю. К тому же далеко не всегда у нас виртуальная таблица оборотов используется в отчете.

(6) zqzq, да можно, но всё равно это не так удобно, однако как вариант почему нет. Я же написал - это один из вариантов. Мне удобнее делать так, кому-то удобнее иначе :)
8. Павел Никифоров (Lyns_owner) 02.02.15 14:02
(7) slazzy, Не считаете - обоснуйте, почему. Правильный - значит быстродейственный. При его использовании нет необходимости вычисления периода для каждой строчки отчета.
К тому же далеко не всегда у нас виртуальная таблица оборотов используется в отчете.

Я стесняюсь спросить, ЧТО вы еще собираетесь в отчете с вертикальной группировкой по периоду? Регистр сведений? Может вообще дату документов? Опять же возвращаемся к разговору про быстродействие.
9. Артем Целовальников (slazzy) 02.02.15 15:54
(8) Lyns_owner,
Правильный - значит быстродейственный. При его использовании нет необходимости вычисления периода для каждой строчки отчета.

зато есть необходимость менять текст запроса, создавать ТЗ, загружать его в СКД и прочее. А посчитать case для строчки дело не сложное, к тому же в моем примере идет сравнение чисел, что в общем-то вряд ли сильно затруднит обработку.

Но я так же могу поспорить и с фразой "правильный - значит быстродейственный." Мы пишем не на С++ и 1С сама по себе довольно медлительна и много где теряет производительность. Вообще код в 1С должен соблюдать баланс между скоростью работы и скоростью восприятия этого кода другим программистом. По моему сугубо личному мнению все эти обработки при компановке, передача ТЗ как внешний источник и прочие извращения это от криворукости, когда человек не может в СКД сделать нормальный запрос. И анализировать это разбирая процедуры, которые наваял автор бывает довольно проблемно. И если вы ради вычисления одного поля будете всё переносить в модуль, то...ну даже не знаю. Бывают ситуации, когда без этого не обойтись, но они бывают редко.

однако вариант с переносом расчета периода из запроса в вычисляемые поля он и правда с этой точки зрения лучше, тк всё воспринимается ещё легче.

Не считаете - обоснуйте, почему.

Зачем? Это Вы должны обосновывать на каких таких основаниях вы считаете свой метод лучше и быстрее :) я ничего не брался доказывать, просто рассказал более удобный способ.
Более того, я в начале сказал, что мы можем что-то сделать с СКД при компановке, но это совершенно не интересно.


Я только что специально протестировал этот механизм с использованием планировщика(только сам запрос), чтобы я ни делал выше 0% общая стоимость выполнения comptute scalar не превышала, там что-то в районе 0.000000014 общая стоимость. Поэтому истории про то, что тяжело рассчитать case для каждой строчки несколько надуманы.
Кстати что интересно в SQL запрос попадает не весь case а только верный вариант, не знаю с чем это связано пока.


Я стесняюсь спросить, ЧТО вы еще собираетесь в отчете с вертикальной группировкой по периоду? Регистр сведений? Может вообще дату документов? Опять же возвращаемся к разговору про быстродействие.

Стесняться не надо, в этом нет необходимости. Дело в том, что мой метод универсален и конкретно я его придумал когда делал разворот по датам, которые брались из документа(но не дата документа) довольно сложная аналитическая самописная конфа для финансового планирования и ради одного отчета делать регистр начальство не посчитало нужным. Но в целом да, это своего рода обороты. Но дело ведь не в этом, правда? :) моя маленькая заметка находится в разделе "практика программирования" и она довольно универсальна, плюс раскрывает некоторые довольно интересные методы работы с СКД.
Я вообще не понимаю откуда этот спор. Я просто предложил ещё один метод(о чем и написал) как это сделать. На мой личный взгляд это самый красивый способ, хотя способов конечно много. Плюс, я уверен, он работает с не худшей производительностью, чем предложенный Вами способ.
10. Павел Никифоров (Lyns_owner) 03.02.15 00:38
(9) slazzy,
Мы пишем не на С++ и 1С сама по себе довольно медлительна и много где теряет производительность

А вам сказать, благодаря кому она такая медленная? или Сами догадаетесь? А тестировали вы на каких данных? Сколько строк в результирующем запросе? 10?
Программист пишет не так, чтобы это было легко сделать (очень близко к определению понятия "говнокод"), а так, чтобы это работа правильно и максимально быстро.
Да извольте анализировать процедуры, написанные автором. Все правильное реализуется непросто, а что реализуется просто - то поделка школьника. Возьмите к примеру запросы вычисления страховых взносов в ЗУПе - их тупо листать устанешь, не то что разбирать. А на первый взгляд, там сложного ничего нет - есть база и есть процент))

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

Но дело ведь не в этом, правда? :)

Да, дело не в этом. Дело в том, что ваша статья в том или ином виде уже больше года присутствует на Инфостарте. А еще ваши ответы характеризуют вас как некомпетентного специалиста.
11. Артем Целовальников (slazzy) 03.02.15 12:19
(10),
А еще ваши ответы характеризуют вас как некомпетентного специалиста.

Пойду поплачу.

А теперь по делу. Сделал регистр сведений, добавил туда пару полей и одно из полей Дата, добавил в него 510к строк. Судя по плану запроса вычисление периода тратит 1% от общего времени(ориентировочно)

Такие дела.

Да и, к слову, в 1С есть стандарты разработки, которые ставят качество восприятия кода на одну ступень с его быстродействием, за редчайшим исключением вроде процедур проведения, где каждая секунда важна.
И если по Вашему стоит из-за любого чиха обработку переносить в модуль, вместо СКД и считаете это правильным, то мне надо Вас огорчить. Сказать почему? Ну например СКД динамически формирует запрос и отборы в СКД автоматически переносятся в запрос тоже... Может случиться такая ситуация, что пользователю будет нужна одна строка, а вы создадите свою таблицу из миллиона записей в модуле и СКД всё равно отберет одну строку....поспорим о производительности? Или будете все допустимые отборы выносить на форму и обрабатывать в своем запросе? СКД автоматически работает с характеристиками. Но главная причина спора и производительность это тема тоже сложная. Я например абсолютно убежден, что сделать запрос на миллион строк и выгрузить его в ТЗ, а потом передать как внешний источник данных в СКД - нереально медленная операция, тут потери производительности на создание ТЗ просто громадны и они даже близко не сопоставимы с мизерными потерями на расчет периода в строке.
Да и просто анализировать единый запрос в СКД куда правильнее чем раскидывать код по модулям без причин.


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

(10), я надеюсь на этом мы закончим нашу беседу, мне она не очень интересна, извините уж :)
12. Алексей (alest) 04.02.15 16:58
Ну например СКД динамически формирует запрос и отборы в СКД автоматически переносятся в запрос тоже...
Ну а зачем трюк с нуллом? Выбрал в запросе сразу поля, а скд откинет лишнее. Она даже соединения таблиц убирает, если поля не выбраны в настройках.
Прошу прощения, не так понял, вы не хотели заморачиваться с выбором вариантов...

(10) Lyns_owner, я тоже считаю, что ваш вариант с программным составлением явно не для СКД. Может вы вообще все за СКД сделаете и отдадите ей только те поля в запросе, которые в конкретном варианте настроек будут, да еще и отборы сразу наложите?
13. Артем Целовальников (slazzy) 04.02.15 17:20
(12) alest,
Ну а зачем трюк с нуллом? Выбрал в запросе сразу поля, а скд откинет лишнее. Она даже соединения таблиц убирает, если поля не выбраны в настройках.

Хороший вопрос :) нет тут дело немного в другом, в моем примере я именно "выбираю все поля", но те, где NULL, автоматически отсекаются. То есть если бы там не было NULL, они бы вывелись.
Вы же говорите про другое, то есть я гипотетически могу создать 4 поля(для 4-х периодов) и выводить только одно из них, а остальные сами отсекутся. Да, это так, но для этого надо вручную менять структуру отчета, чтобы включить только нужные поля. Я же хотел именно чтобы к структуре отчета пользователь даже не подходил. Но, справедливости ради, это и правда довольно нетипичный метод и в данном случае он излишне сложный :) я его показал просто как пример работы с NULL.

Очень похожий способ используется в типовых конфигурациях, когда идет работа с таблицей ОстаткиИОбороты и надо вывести регистратор.
14. Пикалев Николай (dabu-dabu) 03.03.15 13:28
Если используется виртуальная таблица Обороты или ОстаткиИОбороты, то можно просто поставить параметр компоновки, например так:
ВЫБРАТЬ
	ПродажиОбороты.Период,
	ПродажиОбороты.Контрагент,
	ПродажиОбороты.СтоимостьОборот
ИЗ
	РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, ДЕНЬ{(&Периодичность)}, ) КАК ПродажиОбороты
...Показать Скрыть
15. Артем Целовальников (slazzy) 03.03.15 14:10
(14) dabu-dabu, а Вы не могли бы поподробнее показать? Дело в том, что я попробовал так сделать. Передаю параметр, например, "Месяц", а всё равно период берется как день, что и логично в общем-то...у меня не получилось сделать корректный разворот по динамическому периоду
16. Пикалев Николай (dabu-dabu) 03.03.15 18:09
(15) slazzy, Тип формируемого параметра не надо менять, либо установить тип число. Если я не ошибаюсь, значения следующие: 0 - период, 1 - запись, 2 - регистратор, 3 - секунда, 4 - минута и т.д.
Список доступных значений, при этом, устанавливать не обязательно. СКД как-то сам понимает, что это периодичность.
17. Иван Титов (Ibrogim) 12.03.15 13:38
Интересен второй метод, автору +
Однако к каждому измерению(квартал,месяц, ... ) выводится Итог, а если в "других настройках" для измерений установить Расположение итогов = нет, то почему то не выводится ресурс...
Возможно Я где то напутал конечно...
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа