gifts2017

[v8] Разбиение произвольного периода на интервалы (в запросе)

Опубликовал Maxim Kolkin (the1) в раздел Программирование - Практика программирования

Аналог типовой  функции РазложитьНаПериоды, только релизовано на языке запросов.

Аналог типовой  функции РазложитьНаПериоды(ДатаНачала = '00010101', ДатаОкончания = '00010101'), только релизовано на языке запросов. Не удалось найти готового решения, поэтому выкладываю запрос по разбиению периода на помесячные интервалы тут.


Обновление от 22/08/2012 - сокращен текст запроса, спасибо Mu_meson http://infostart.ru/profile/48163/

 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ 
ПроизводственныйКалендарь.ДатаКалендаря, 
ГОД(ПроизводственныйКалендарь.ДатаКалендаря) * 100 + МЕСЯЦ(ПроизводственныйКалендарь.ДатаКалендаря) КАК НомерМесяца 
ПОМЕСТИТЬ ВТ_ДатыКалендаря 
ИЗ 
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК ПроизводственныйКалендарь 
ГДЕ 
ПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &ПериодДействияНачало И &ПериодДействияКонец 
; 

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ 
МИНИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаНачала, 
МАКСИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаОкончания 
ИЗ 
ВТ_ДатыКалендаря КАК ВТ_ДатыКалендаря 
СГРУППИРОВАТЬ ПО 
ВТ_ДатыКалендаря.НомерМесяца

Скачать файлы

Наименование Файл Версия Размер
архив с текстом запроса и сохраненная версия для "Универсальной консоли отчетов" 34
.zip 2,66Kb
22.08.12
34
.zip 2,66Kb Скачать

См. также

Вознаграждение за ответ
Сумма: 2 $m
Добавили:
Сергей (ildarovich) (8.00 $m)
Подписаться Добавить вознаграждение

Комментарии

1. Андрей Комар (akomar) 16.08.12 18:39
Что такое РегистрСведений.РегламентированныйПроизводственныйКалендарь и где его найти?
2. Марат Нафиков (Jetoo) 17.08.12 06:38
(1) akomar, вопрос скорее для пятницы! )))
3. cmd_vasec (cmd_vasec) 17.08.12 08:51
(1) akomar,
ЗУП тебе в помощь.
4. Андрей Комар (akomar) 17.08.12 12:23
Ну я бы сначало написал, что актуально для ЗУП.
5. Maxim Kolkin (the1) 17.08.12 12:35
Да ладно, в Бухии 2.0 он тоже есть. Думаю, что это стандарт 1С.
6. Maxim (Maxik21) 17.08.12 12:45
РегламентированныйПроизводственныйКалендарь есть БУХ, ЗУП, УПП. Содержит все даты периода. Прикладное значение, к примеру, можно получить в запросе остатки на каждый день, неделю и т.д. в соединении с регистрами накопления и т.п. Тебе для чего нужно ?
7. al petrov (petrov_al) 17.08.12 18:57
Автор, совет, изучай СКД и не понадобится тебе зуповский регистр который к тому же в бухе редко кто заполняет
8. Maxim Kolkin (the1) 20.08.12 08:52
(7) Спасибо за бесплатный совет, но не всё можно решить на СКД. Хотя, если подскажете, как вызвать СКД из общего модуля при проведении или расчете документа, буду очень признателен. К тому же язык запросов не отличается от используемого в СКД.

З.Ы. А регистр и не надо заполнять, он заполняется автоматически при обновлении ИБ.
9. Mu_meson (KAPACEB.AA) 20.08.12 11:40
Спасибо. Правда, не совсем понял, зачем вторая временная таблица и левое соединение к ней в итоговом запросе. Может быть, так:

ВЫБРАТЬ
ПроизводственныйКалендарь.ДатаКалендаря,
ГОД(ПроизводственныйКалендарь.ДатаКалендаря) * 100 + МЕСЯЦ(ПроизводственныйКалендарь.ДатаКалендаря) КАК НомерМесяца
ПОМЕСТИТЬ ВТ_ДатыКалендаря
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК ПроизводственныйКалендарь
ГДЕ
ПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &ПериодДействияНачало И &ПериодДействияКонец
;

ВЫБРАТЬ
МИНИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаНачала,
МАКСИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаОкончания
ИЗ
ВТ_ДатыКалендаря КАК ВТ_ДатыКалендаря
СГРУППИРОВАТЬ ПО
ВТ_ДатыКалендаря.НомерМесяца
корум; the1; +2 Ответить 1
10. Maxim Kolkin (the1) 20.08.12 12:23
(9) Mu_meson, да, так гораздо лучше =)
11. Ak Uji (Akuji) 22.08.12 16:21
ПроизводственныйКалендарь для примера или он необходим по любому т.к. там все даты?
Интересует вопрос:
необходимо сгрупирровать по периодам (месяцам) данные по выборке документов, что бы в результате по куждому месяцу увидеть суммы.
И объеденить этот результат с еще одной таблицей регистра накопления с переодичностью месяц.

месяц сумма по документам
объеденить
месяц сумма по регистру
12. Maxim Kolkin (the1) 23.08.12 10:41
(11) Думаю, что ПроизводственныйКалендарь безболезненно можно заменить на выборку документов и группировать уже по дате документа, а не по дате календаря.
13. Сергей Старых (tormozit) 13.11.12 09:20
Обман во многом. Не указана область применимости (типовые конфигурации). Не указана необходимость сначала заполнить регистр за тот период, для которого нужны интервалы. И т.д. В общем очень небрежно.

Вообще задачу разбиения на месяцы (и не только) легко можно решить и без регистра одним запросом (менее эффективно) или пакетным запросом (более эффективно). Здесь уже есть такие публикации.
herfis; ildarovich; +2 1 Ответить 2
14. Сергей (ildarovich) 07.10.16 20:13
Присоединюсь к замечанию в (13). Производственный календарь для решения этой задачи не требуется. Так можно и таблицу умножения в базу данных внести, если умножать разучиться.
15. Артем Артеменко (dock) 17.10.16 10:49
(13) tormozit, Замечательно, ну и где на инфостарте эти публикации ???
16. Maxim Kolkin (the1) 18.10.16 08:22
(14) ildarovich, ну так ведь если инструмент (календарь) есть, то можно его использовать, не так ли? Все претензии разработчикам типовых :-)
17. Сергей (ildarovich) 18.10.16 12:46
(16) the1, давайте я поясню свою мысль...

Предложенное вами решение без должного основания использует зависимости:
1) от наличия в составе конфигурации такого объекта как регистр сведений "РегламентированныйПроизводственныйКалендарь";
2) от его правильной заполненности на нужный период.
Если первая зависимость легко проверяется (при попытке использовать этот метод в конфигурации без календаря, вы просто получите ошибку), то вторая зависимость неприятнее. При частичной заполненности календаря вы получите ошибку в отчете, которую еще потребуется поискать.

Кроме того, используемый принцип совершенно зря перебирает все даты периода, когда из месяца требуется только одна запись. То есть работает в 30 раз медленнее возможного.

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

Кстати, если уж настаиваете на использовании календаря, могу предложить вот такой вариант из одного запроса:
ВЫБРАТЬ
	МИНИМУМ(Календарь.ДатаКалендаря) КАК ДатаНачала,
	МАКСИМУМ(Календарь.ДатаКалендаря) КАК ДатаОкончания
ИЗ
	РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
	Календарь.ДатаКалендаря МЕЖДУ &ПериодДействияНачало И &ПериодДействияКонец

СГРУППИРОВАТЬ ПО
	РАЗНОСТЬДАТ(&ПериодДействияНачало, Календарь.ДатаКалендаря, МЕСЯЦ)
...Показать Скрыть
Он короче и более универсальный - легко вид периода (день, месяц, год, квартал) поменять.

А вообще в свете вопроса (15) можно было бы и конкурс объявить на решение этой задачи без календаря.
yurii_host; the1; +2 Ответить 2
18. Сергей (ildarovich) 18.10.16 12:51
+(17) Требуется решить данную задачу
разбиения произвольного периода на интервалы в запросе
без использования регламентированного производственного календаря.
19. Максим Зудин (kasper076) 18.10.16 14:44
Запрос = Новый Запрос(	 
"ВЫБРАТЬ
|	НАЧАЛОПЕРИОДА(&НачПериода, МЕСЯЦ) КАК Период
|ИТОГИ ПО
|	Период ПЕРИОДАМИ(МЕСЯЦ, НАЧАЛОПЕРИОДА(&НачПериода, МЕСЯЦ), КОНЕЦПЕРИОДА(&КонПериода, МЕСЯЦ))");
...Показать Скрыть

Но потребуется постобработка.
20. Сергей (ildarovich) 18.10.16 14:50
(19) kasper076, хорошее решение, но нужно, чтобы результат можно было внутри запроса использовать, поэтому итоги не годятся
21. Александр Глебов (HanterVol) 18.10.16 15:15
Быстренько для не более 64 месяцев
ВЫБРАТЬ
	0 КАК Поле
ПОМЕСТИТЬ Числа

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	2

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	3
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Числа1.Поле + 4 * Числа2.Поле + 16 * Числа3.Поле + 1 КАК Поле
ПОМЕСТИТЬ ВТ_64
ИЗ
	Числа КАК Числа1,
	Числа КАК Числа2,
	Числа КАК Числа3
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ВЫБОР
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) = КОНЕЦПЕРИОДА(&ДатаНачала, МЕСЯЦ)
			ТОГДА &ДатаНачала
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
		ИНАЧЕ НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
	КОНЕЦ КАК НачПериода,
	ВЫБОР
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА &ДатаОкончания
		ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
	КОНЕЦ КАК КонПериода
ИЗ
	ВТ_64 КАК ВТ_64

СГРУППИРОВАТЬ ПО
	ВЫБОР
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА &ДатаОкончания
		ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
	КОНЕЦ,
	ВЫБОР
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) = КОНЕЦПЕРИОДА(&ДатаНачала, МЕСЯЦ)
			ТОГДА &ДатаНачала
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
		ИНАЧЕ НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
	КОНЕЦ
...Показать Скрыть
22. Сергей (ildarovich) 18.10.16 15:20
(21) HanterVol, да, решение нужно примерно такое, если покороче нельзя
23. Александр Глебов (HanterVol) 18.10.16 15:21
Думаю что можно.... но нужно уже думать :)))
Если только без группировки, но с отбором
"ВЫБРАТЬ
|	0 КАК Поле
|ПОМЕСТИТЬ Числа
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|	1
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|	2
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|	3
|;
|
|////////////////////////////////////////////////////////////­////////////////////
|ВЫБРАТЬ
|	Числа1.Поле + 4 * Числа2.Поле + 16 * Числа3.Поле + 1 КАК Поле
|ПОМЕСТИТЬ ВТ_64
|ИЗ
|	Числа КАК Числа1,
|	Числа КАК Числа2,
|	Числа КАК Числа3
|;
|
|////////////////////////////////////////////////////////////­////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
|	ВЫБОР
|		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) = КОНЕЦПЕРИОДА(&ДатаНачала, МЕСЯЦ)
|			ТОГДА &ДатаНачала
|		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
|			ТОГДА НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
|		ИНАЧЕ НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
|	КОНЕЦ КАК НачПериода,
|	ВЫБОР
|		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
|			ТОГДА &ДатаОкончания
|		ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, ВТ_64.Поле - 1), МЕСЯЦ)
|	КОНЕЦ КАК КонПериода
|ИЗ
|	ВТ_64 КАК ВТ_64
|ГДЕ
|	ВТ_64.Поле < РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, МЕСЯЦ) + 2"
...Показать Скрыть
24. Олег Родионов (Ovrfox) 18.10.16 15:37
(21) HanterVol, Разве так не проще?
ВЫБРАТЬ
    0 КАК Поле
ПОМЕСТИТЬ Числа

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    2

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    3
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 4 * Числа2.Поле + 16 * Числа3.Поле),Месяц) КАК Поле
ПОМЕСТИТЬ ВТ_64
ИЗ
    Числа КАК Числа1,
    Числа КАК Числа2,
    Числа КАК Числа3
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ВЫБОР
        КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ) = КОНЕЦПЕРИОДА(&ДатаНачала, МЕСЯЦ)
            ТОГДА &ДатаНачала
        КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
            ТОГДА НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
        ИНАЧЕ ВТ_64.Поле
    КОНЕЦ КАК НачПериода,
    ВЫБОР
        КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле, МЕСЯЦ)>= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
            ТОГДА &ДатаОкончания
        ИНАЧЕ КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ)
    КОНЕЦ КАК КонПериода
ИЗ
    ВТ_64 КАК ВТ_64

упорядочить по НачПериода
...Показать Скрыть
25. Олег Родионов (Ovrfox) 18.10.16 15:49
(24) Ovrfox, последний запрос лучше так
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ВЫБОР
        КОГДА ВТ_64.Поле < &ДатаНачала
            ТОГДА &ДатаНачала
        ИНАЧЕ ВТ_64.Поле
    КОНЕЦ КАК НачПериода,
    ВЫБОР
        КОГДА ВТ_64.КонПериода > &ДатаОкончания
            ТОГДА &ДатаОкончания
        ИНАЧЕ ВТ_64.КонПериода
    КОНЕЦ КАК КонПериода
ИЗ
    (Выбрать ВТ_64.Поле, КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ) как КонПериода ИЗ ВТ_64 где ВТ_64.Поле<&ДатаОкончания)КАК ВТ_64

упорядочить по НачПериода
...Показать Скрыть
26. Александр Глебов (HanterVol) 18.10.16 16:19
Или в 2 Запроса
и с другим алгоритмом заполнения таблицы чисел (кому как нравится, я если честно предыдущий хреново понимаю)
ВЫБРАТЬ
	0 КАК Поле
ПОМЕСТИТЬ Цифры

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	2

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	3

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	4

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	5

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	6

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	7

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	8

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	9
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ВЫБОР
		КОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ) = НАЧАЛОПЕРИОДА(&ДатаНачала, МЕСЯЦ)
			ТОГДА &ДатаНачала
		КОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ) < НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ)
		ИНАЧЕ НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
	КОНЕЦ КАК Поле,
	ВЫБОР
		КОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
			ТОГДА &ДатаОкончания
		ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ)
	КОНЕЦ КАК Поле1
ИЗ
	Цифры КАК Числа1,
	Цифры КАК Числа2
ГДЕ
	КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ) <= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)

УПОРЯДОЧИТЬ ПО
	Поле
...Показать Скрыть
27. Сергей (ildarovich) 18.10.16 16:25
(26) HanterVol, (25) Ovrfox, это уже заявки на победу, подождем еще, возможно, будут еще варианты...
28. Олег Родионов (Ovrfox) 18.10.16 16:25
(26) HanterVol,
Выражение
КОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ) < НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ)
не имеет смысла при ограничении по датам и даже без ограничения нужно включать "Выбрать различные"
29. Александр Глебов (HanterVol) 18.10.16 16:28
30. Сан Саныч (herfis) 18.10.16 16:28
Ну, мне как-то понадобилась разбивка и по дням и по периодам одновременно. Вот так делал:
ВЫБРАТЬ
	0 КАК Цифра
ПОМЕСТИТЬ Цифры

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	1

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	2

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	3

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	4

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	5

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	6

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	7

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	8

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	9
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ДниПериода.ДеньПериода КАК ДеньПериода,
	ДниПериода.НачалоСтандартногоПериода,
	ДниПериода.КонецСтандартногоПериода,
	РАЗНОСТЬДАТ(ВЫБОР
			КОГДА ДниПериода.НачалоСтандартногоПериода < &НачалоПериода
				ТОГДА &НачалоПериода
			ИНАЧЕ ДниПериода.НачалоСтандартногоПериода
		КОНЕЦ, КОНЕЦПЕРИОДА(ВЫБОР
				КОГДА ДниПериода.КонецСтандартногоПериода > &КонецПериода
					ТОГДА &КонецПериода
				ИНАЧЕ ДниПериода.КонецСтандартногоПериода
			КОНЕЦ, ДЕНЬ), ДЕНЬ) + 1 КАК КвоДнейСтандартногоПериода
ИЗ
	(ВЫБРАТЬ
		ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня) КАК ДеньПериода,
		ВЫБОР
			КОГДА &Периодичность = "БезПериодов"
				ТОГДА &НачалоПериода
			КОГДА &Периодичность = "День"
				ТОГДА ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня)
			КОГДА &Периодичность = "Неделя"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), НЕДЕЛЯ)
			КОГДА &Периодичность = "Декада"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ДЕКАДА)
			КОГДА &Периодичность = "Месяц"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), МЕСЯЦ)
			КОГДА &Периодичность = "Квартал"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), КВАРТАЛ)
			КОГДА &Периодичность = "Полугодие"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ПОЛУГОДИЕ)
			КОГДА &Периодичность = "Год"
				ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ГОД)
		КОНЕЦ КАК НачалоСтандартногоПериода,
		ВЫБОР
			КОГДА &Периодичность = "БезПериодов"
				ТОГДА &КонецПериода
			КОГДА &Периодичность = "День"
				ТОГДА ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня)
			КОГДА &Периодичность = "Неделя"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), НЕДЕЛЯ)
			КОГДА &Периодичность = "Декада"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ДЕКАДА)
			КОГДА &Периодичность = "Месяц"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), МЕСЯЦ)
			КОГДА &Периодичность = "Квартал"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), КВАРТАЛ)
			КОГДА &Периодичность = "Полугодие"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ПОЛУГОДИЕ)
			КОГДА &Периодичность = "Год"
				ТОГДА КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, НомераДнейПериода.НомерДня), ГОД)
		КОНЕЦ КАК КонецСтандартногоПериода
	ИЗ
		(ВЫБРАТЬ
			Тысячи.Цифра * 1000 + Сотни.Цифра * 100 + Десятки.Цифра * 10 + Единицы.Цифра КАК НомерДня
		ИЗ
			Цифры КАК Тысячи,
			Цифры КАК Сотни,
			Цифры КАК Десятки,
			Цифры КАК Единицы
		ГДЕ
			Тысячи.Цифра * 1000 + Сотни.Цифра * 100 + Десятки.Цифра * 10 + Единицы.Цифра <= РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ДЕНЬ)) КАК НомераДнейПериода) КАК ДниПериода
...Показать Скрыть

Думаю, при необходимости несложно допилить до нужного варианта.
31. Александр Глебов (HanterVol) 18.10.16 16:32
(28) Ovrfox, но хотелось избавиться от "Различные"
32. Сергей (ildarovich) 18.10.16 16:39
(30) herfis, не вполне подходит, так как тут много возни с первым и последним периодом, а в вашем варианте об этом ничего нет, так что без допиливания не подойдет
33. Сан Саныч (herfis) 18.10.16 16:45
(32) ildarovich, Есть, на самом деле. "Возня" отображена в вычислении "КвоДнейСтандартногоПериода". Просто делается по аналогии
ВЫБОР
     КОГДА ДниПериода.НачалоСтандартногоПериода < &НачалоПериода
     ТОГДА &НачалоПериода
     ИНАЧЕ ДниПериода.НачалоСтандартногоПериода
КОНЕЦ
...Показать Скрыть

и аналогично для конца периода
34. Олег Родионов (Ovrfox) 18.10.16 16:59
(33) herfis, Запрос возвращает не кол-во периодов, а одну запись в день. Чтобы получить периоды - нужно группировать - не самый эффективный метод.
Но как вариант - очень хорош.
35. Сан Саныч (herfis) 18.10.16 17:14
(34) Ovrfox, Именно так. Я об этом сразу предупредил. По сути, это просто небольшая модификация получения таблицы дней. Мне нужна была именно такая. Вероятно, именно для периодов возможен более оптимальный вариант. Но без группировок (РАЗЛИЧНЫЕ просто одна из вариаций) в голову ничего не приходит. Тут тоже достаточно добавить РАЗЛИЧНЫЕ и убрать "ДеньПериода" для получения таблицы именно периодов.
36. Олег Родионов (Ovrfox) 18.10.16 17:15
(33) herfis, Примерно такой запрос получен по вашим следам
При этом легко видеть, что при замене слова НЕДЕЛЯ на любой другой период запрос останется точно таким же, изменится только протяженность периода
ВЫБРАТЬ 
    Выбор когда ДниПериода.НачалоСтандартногоПериода < &НачалоПериода
    Тогда &НачалоПериода
    Иначе ДниПериода.НачалоСтандартногоПериода Конец  КАК НачалоСтандартногоПериода,
    Выбор когда ДниПериода.КонецСтандартногоПериода > &КонецПериода
    Тогда &КонецПериода
    Иначе ДниПериода.КонецСтандартногоПериода Конец  КАК КонецСтандартногоПериода
ИЗ
    (ВЫБРАТЬ Различные
         НАЧАЛОПЕРИОДА(НомераДнейПериода.НашДень, НЕДЕЛЯ) КАК НачалоСтандартногоПериода,
         КОНЕЦПЕРИОДА(НомераДнейПериода.НашДень, НЕДЕЛЯ) КАК КонецСтандартногоПериода
    ИЗ
        (ВЫБРАТЬ
            ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ,Тысячи.Цифра * 1000 + Сотни.Цифра * 100 + Десятки.Цифра * 10 + Единицы.Цифра) КАК НашДень
        ИЗ
            Цифры КАК Тысячи,
            Цифры КАК Сотни,
            Цифры КАК Десятки,
            Цифры КАК Единицы
        ГДЕ
            Тысячи.Цифра * 1000 + Сотни.Цифра * 100 + Десятки.Цифра * 10 + Единицы.Цифра <= РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, ДЕНЬ)
        ) КАК НомераДнейПериода
 ) как ДниПериода
  упорядочить по   НачалоСтандартногоПериода
...Показать Скрыть
37. Сан Саныч (herfis) 18.10.16 17:19
(36) Ovrfox, Все так. Исходный запрос многословен из-за динамической разбивки по периодам (периодичность выбирает пользователь в параметре СКД).
38. Сергей (ildarovich) 18.10.16 20:36
(33) herfis, извиняюсь, невнимательно посмотрел, но ... теперь увидел, что интервал разворачивается по дням. Это слишком легкий путь. И хотя время выполнения тут не особенно критично, все же зачем делать лишние вычисления? Их будет в 30 раз меньше, чем при перечислении не дней, как в (30) и (36), а периодов, как в (25) и (26). Кроме того, при перечислении дней самым простым способом будет использовании уже записанного в (17) запроса. Без лишних условий:
ВЫБРАТЬ
	0 КАК Х
ПОМЕСТИТЬ Бит

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	1
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ДОБАВИТЬКДАТЕ(&Дата1, ДЕНЬ, Б0.Х + 2 * (Б1.Х + 2 * (Б2.Х + 2 * (Б3.Х + 2 * (Б4.Х + 2 * (Б5.Х + 2 * (Б6.Х + 2 * (Б7.Х + 2 * (Б8.Х + 2 * Б9.Х))))))))) КАК Х
ПОМЕСТИТЬ Даты
ИЗ
	Бит КАК Б0,
	Бит КАК Б1,
	Бит КАК Б2,
	Бит КАК Б3,
	Бит КАК Б4,
	Бит КАК Б5,
	Бит КАК Б6,
	Бит КАК Б7,
	Бит КАК Б8,
	Бит КАК Б9
ГДЕ
	Б0.Х + 2 * (Б1.Х + 2 * (Б2.Х + 2 * (Б3.Х + 2 * (Б4.Х + 2 * (Б5.Х + 2 * (Б6.Х + 2 * (Б7.Х + 2 * (Б8.Х + 2 * Б9.Х)))))))) <= РАЗНОСТЬДАТ(&Дата1, &Дата2, ДЕНЬ)
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	МИНИМУМ(Даты.Х) КАК ДатаНачала,
	МАКСИМУМ(Даты.Х) КАК ДатаОкончания
ИЗ
	Даты КАК Даты

СГРУППИРОВАТЬ ПО
	РАЗНОСТЬДАТ(&Дата1, Даты.Х, МЕСЯЦ)
...Показать Скрыть
39. Сан Саныч (herfis) 19.10.16 09:24
(38) ildarovich, Согласен.
ЗЫ. В использовании двоичного расчета плюсов не вижу, скорее наоборот, а вот группировка по разности дат - элегантный ход.
40. Сергей (ildarovich) 19.10.16 11:33
(39) herfis, двоичный, десятичный и тому подобное к сути решения не относятся. Можно использовать кому что нравится. Я использовал двоичное основание из-за того, что оно дает самую короткую запись, выраженную в числе строк запроса, раскрытого конструктором. Уж очень длинной выглядит формирование таблицы из десяти цифр. Еще плюсом двоичного основания является минимум лишнего в итоге соединения, из которой затем выбирается нужное число записей, потому что ряд 1-2-4-8-16-64-128 чаще, чем 1-10-100-1000. Есть и минусы и другие методы. Но здесь об этом смысла спорить не вижу.
Сейчас хочу увидеть более короткое чем (25) и (26) решение без развертки по дням.
41. Александр Глебов (HanterVol) 19.10.16 12:27
Сделал с другой идеей, но... короче не получилось
ВЫБРАТЬ
	1 КАК Число
ПОМЕСТИТЬ Числа

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	2

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	3

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	4

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	5

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	6

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	7

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	8

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	9

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	0
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Ед.Число + Дес.Число * 10 + Сот.Число * 100 КАК Номер
ПОМЕСТИТЬ Месяцы
ИЗ
	Числа КАК Ед,
	Числа КАК Дес,
	Числа КАК Сот
ГДЕ
	Ед.Число + Дес.Число * 10 + Сот.Число * 100 <= РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ)
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ВложенныйЗапрос.Номер,
	МАКСИМУМ(ВложенныйЗапрос.Дата1) КАК Дата1,
	МИНИМУМ(ВложенныйЗапрос.Дата2) КАК Дата2
ИЗ
	(ВЫБРАТЬ РАЗЛИЧНЫЕ
		Месяцы.Номер КАК Номер,
		&Дата1 КАК Дата1,
		&Дата2 КАК Дата2
	ИЗ
		Месяцы КАК Месяцы
	
	ОБЪЕДИНИТЬ ВСЕ
	
	ВЫБРАТЬ РАЗЛИЧНЫЕ
		Месяцы.Номер,
		НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата1, МЕСЯЦ, Месяцы.Номер), МЕСЯЦ),
		КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата1, МЕСЯЦ, Месяцы.Номер), МЕСЯЦ)
	ИЗ
		Месяцы КАК Месяцы) КАК ВложенныйЗапрос

СГРУППИРОВАТЬ ПО
	ВложенныйЗапрос.Номер
...Показать Скрыть
42. Сан Саныч (herfis) 19.10.16 12:40
(40) ildarovich, ИМХО, Orfox победитель.
Он первый предложил оптимальный алгоритм генерации таблицы периодов (без группировок). Оптимальнее вроде некуда. Один простой запрос.
Остальное, включая уточнение границ периодов - вторично.
43. Сан Саныч (herfis) 19.10.16 12:42
Было бы соблазнительно сгенерировать таблицу полных периодов и объединить с "краями", но, к сожалению, обработка всех возможных ситуаций в итоге будет выглядеть хуже, а не лучше.
44. Сергей (ildarovich) 19.10.16 12:44
(41) HanterVol, хороший вариант, кое-где вроде бы РАЗЛИЧНЫЕ лишние. Он кажется более "воздушным". Нужно будет еще по числу знаков сравнить.
45. Сергей (ildarovich) 19.10.16 12:52
(42) herfis, хотел еще подождать свежих вариантов, прежде чем победителя определять, не хотелось бы пока точку ставить. Если что, я вознаграждение увеличу.
46. Сергей (ildarovich) 21.10.16 16:31
Пора подводить итоги. Добавлю вознаграждение, съеденное временем. HanterVol предложил свой вариант первым, а потом добавил еще один интересный вариант решения. Но в итоге с небольшим перевесом (0,5:1,5) побеждает вариант (24) Ovrfox. Этот вариант самый простой и короткий.
47. Сергей (ildarovich) 24.10.16 17:07
К сожалению, из-за редизайна форума, обещанное вознаграждение до победителя не дошло, останусь должен, сочтемся с Ovrfox при случае.

Для коллекции добавлю свой вариант. Он самый короткий, но не самый простой:
ВЫБРАТЬ
	0 КАК Х
ПОМЕСТИТЬ Бит
ОБЪЕДИНИТЬ
ВЫБРАТЬ
	1
;
ВЫБРАТЬ
	Б0.Х + 2 * (Б1.Х + 2 * (Б2.Х + 2 * (Б3.Х + 2 * (Б4.Х + 2 * Б5.Х)))) КАК Х
ПОМЕСТИТЬ Периоды
ИЗ
	Бит КАК Б0,
	Бит КАК Б1,
	Бит КАК Б2,
	Бит КАК Б3,
	Бит КАК Б4,
	Бит КАК Б5
ГДЕ
	Б0.Х + 2 * (Б1.Х + 2 * (Б2.Х + 2 * (Б3.Х + 2 * (Б4.Х + 2 * Б5.Х)))) < РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ)
;
ВЫБРАТЬ
	ЕСТЬNULL(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата1, МЕСЯЦ, Начала.Х + 1), МЕСЯЦ), &Дата1) КАК ДатаНачала,
	ЕСТЬNULL(КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата1, МЕСЯЦ, Окончания.Х), МЕСЯЦ), &Дата2) КАК ДатаОкончания
ИЗ
	Периоды КАК Начала
		ПОЛНОЕ СОЕДИНЕНИЕ Периоды КАК Окончания
		ПО (Начала.Х + 1 = Окончания.Х)
...Показать Скрыть



К сожалению, этот вариант не отрабатывает ситуацию отсутствия необходимости разбивки: если Дата1 и Дата2 находятся в одном месяце.
48. Spenser (spenser123) 31.10.16 13:01
Я, может, не врубился до конца в тему, но не понимаю чем не устраивает банальные варианты с:
НАЧАЛОПЕРИОДА(Дата,&Периодичность) Как НачалоПериода
КОНЕЦПЕРИОДА(Дата,&Периодичность) Как КонецПериода

?
49. Сергей (ildarovich) 31.10.16 13:50
(48) задача совсем другая: дан интервал, его нужно РАЗБИТЬ на подпериоды. То есть ответом должно быть множество записей - по одной для каждого входящего в интервал подпериода.
Например, 15.08.16 - 30.10.16 разбивается на месяцы так: 15.08.16 - 31.08.16; 1.09.16 - 30.09.16; 1.10.16 - 30.10.16.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа