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

50 Comments

  1. akomar

    Что такое РегистрСведений.РегламентированныйПроизводственныйКалендарь и где его найти?

    Reply
  2. Jetoo

    (1) akomar, вопрос скорее для пятницы! )))

    Reply
  3. cmd_vasec

    (1) akomar,

    ЗУП тебе в помощь.

    Reply
  4. akomar

    Ну я бы сначало написал, что актуально для ЗУП.

    Reply
  5. the1

    Да ладно, в Бухии 2.0 он тоже есть. Думаю, что это стандарт 1С.

    Reply
  6. Maxik21

    РегламентированныйПроизводственныйКалендарь есть БУХ, ЗУП, УПП. Содержит все даты периода. Прикладное значение, к примеру, можно получить в запросе остатки на каждый день, неделю и т.д. в соединении с регистрами накопления и т.п. Тебе для чего нужно ?

    Reply
  7. petrov_al

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

    Reply
  8. the1

    (7) Спасибо за бесплатный совет, но не всё можно решить на СКД. Хотя, если подскажете, как вызвать СКД из общего модуля при проведении или расчете документа, буду очень признателен. К тому же язык запросов не отличается от используемого в СКД.

    З.Ы. А регистр и не надо заполнять, он заполняется автоматически при обновлении ИБ.

    Reply
  9. KAPACEB.AA

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

    ВЫБРАТЬ

    ПроизводственныйКалендарь.ДатаКалендаря,

    ГОД(ПроизводственныйКалендарь.ДатаКалендаря) * 100 + МЕСЯЦ(ПроизводственныйКалендарь.ДатаКалендаря) КАК НомерМесяца

    ПОМЕСТИТЬ ВТ_ДатыКалендаря

    ИЗ

    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК ПроизводственныйКалендарь

    ГДЕ

    ПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &ПериодДействияНачало И &ПериодДействияКонец

    ;

    ВЫБРАТЬ

    МИНИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаНачала,

    МАКСИМУМ(ВТ_ДатыКалендаря.ДатаКалендаря) КАК ДатаОкончания

    ИЗ

    ВТ_ДатыКалендаря КАК ВТ_ДатыКалендаря

    СГРУППИРОВАТЬ ПО

    ВТ_ДатыКалендаря.НомерМесяца

    Reply
  10. the1

    (9) Mu_meson, да, так гораздо лучше =)

    Reply
  11. Akuji

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

    Интересует вопрос:

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

    И объеденить этот результат с еще одной таблицей регистра накопления с переодичностью месяц.

    месяц сумма по документам

    объеденить

    месяц сумма по регистру

    Reply
  12. the1

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

    Reply
  13. tormozit

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

    Вообще задачу разбиения на месяцы (и не только) легко можно решить и без регистра одним запросом (менее эффективно) или пакетным запросом (более эффективно). Здесь уже есть такие публикации.

    Reply
  14. ildarovich

    Присоединюсь к замечанию в (13). Производственный календарь для решения этой задачи не требуется. Так можно и таблицу умножения в базу данных внести, если умножать разучиться.

    Reply
  15. dock

    (13) tormozit, Замечательно, ну и где на инфостарте эти публикации ???

    Reply
  16. the1

    (14) ildarovich, ну так ведь если инструмент (календарь) есть, то можно его использовать, не так ли? Все претензии разработчикам типовых 🙂

    Reply
  17. ildarovich

    (16) давайте я поясню свою мысль…

    Предложенное вами решение без должного основания использует зависимости:

    1) от наличия в составе конфигурации такого объекта как регистр сведений «РегламентированныйПроизводственныйКалендарь»;

    2) от его правильной заполненности на нужный период.

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

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

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

    Кстати, если уж настаиваете на использовании календаря, могу предложить вот такой вариант из одного запроса:

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

    Показать

    Он короче и более универсальный — легко вид периода (день, месяц, год, квартал) поменять.

    А вообще в свете вопроса (15) можно было бы и конкурс объявить на решение этой задачи без календаря.

    Reply
  18. ildarovich

    +(17) Требуется решить данную задачу

    разбиения произвольного периода на интервалы в запросе

    без использования регламентированного производственного календаря.

    Reply
  19. kasper076
    Запрос = Новый Запрос(
    «ВЫБРАТЬ
    | НАЧАЛОПЕРИОДА(&НачПериода, МЕСЯЦ) КАК Период
    |ИТОГИ ПО
    | Период ПЕРИОДАМИ(МЕСЯЦ, НАЧАЛОПЕРИОДА(&НачПериода, МЕСЯЦ), КОНЕЦПЕРИОДА(&КонПериода, МЕСЯЦ))»);

    Но потребуется постобработка.

    Reply
  20. ildarovich

    (19) kasper076, хорошее решение, но нужно, чтобы результат можно было внутри запроса использовать, поэтому итоги не годятся

    Reply
  21. HanterVol

    Быстренько для не более 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), МЕСЯЦ)
    КОНЕЦ
    

    Показать

    Reply
  22. ildarovich

    (21) HanterVol, да, решение нужно примерно такое, если покороче нельзя

    Reply
  23. HanterVol

    Думаю что можно…. но нужно уже думать :)))

    Если только без группировки, но с отбором

    «ВЫБРАТЬ
    | 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″
    

    Показать

    Reply
  24. Ovrfox

    (21) HanterVol, Разве так не проще?

    ВЫБРАТЬ
    0 КАК Поле
    ПОМЕСТИТЬ Числа
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    1
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    2
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    3
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 4 * Числа2.Поле + 16 * Числа3.Поле),Месяц) КАК Поле
    ПОМЕСТИТЬ ВТ_64
    ИЗ
    Числа КАК Числа1,
    Числа КАК Числа2,
    Числа КАК Числа3
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ РАЗЛИЧНЫЕ
    ВЫБОР
    КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ) = КОНЕЦПЕРИОДА(&ДатаНачала, МЕСЯЦ)
    ТОГДА &ДатаНачала
    КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ) >= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
    ТОГДА НАЧАЛОПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
    ИНАЧЕ ВТ_64.Поле
    КОНЕЦ КАК НачПериода,
    ВЫБОР
    КОГДА КОНЕЦПЕРИОДА(ВТ_64.Поле, МЕСЯЦ)>= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
    ТОГДА &ДатаОкончания
    ИНАЧЕ КОНЕЦПЕРИОДА(ВТ_64.Поле , МЕСЯЦ)
    КОНЕЦ КАК КонПериода
    ИЗ
    ВТ_64 КАК ВТ_64
    
    упорядочить по НачПериода

    Показать

    Reply
  25. Ovrfox

    (24) Ovrfox, последний запрос лучше так

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

    Показать

    Reply
  26. HanterVol

    Или в 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.Поле), МЕСЯЦ) <= КОНЕЦПЕРИОДА(&ДатаОкончания, МЕСЯЦ)
    
    УПОРЯДОЧИТЬ ПО
    Поле
    

    Показать

    Reply
  27. ildarovich

    (26) HanterVol, (25) Ovrfox, это уже заявки на победу, подождем еще, возможно, будут еще варианты…

    Reply
  28. Ovrfox

    (26) HanterVol,

    Выражение

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

    ТОГДА НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, МЕСЯЦ, Числа1.Поле + 10 * Числа2.Поле), МЕСЯЦ)

    не имеет смысла при ограничении по датам и даже без ограничения нужно включать «Выбрать различные»

    Reply
  29. HanterVol

    (28) Ovrfox, Согласен, косяк

    Reply
  30. herfis
    Reply
  31. HanterVol

    (28) Ovrfox, но хотелось избавиться от «Различные»

    Reply
  32. ildarovich

    (30) herfis, не вполне подходит, так как тут много возни с первым и последним периодом, а в вашем варианте об этом ничего нет, так что без допиливания не подойдет

    Reply
  33. herfis

    (32) ildarovich, Есть, на самом деле. «Возня» отображена в вычислении «КвоДнейСтандартногоПериода». Просто делается по аналогии

    ВЫБОР
    КОГДА ДниПериода.НачалоСтандартногоПериода < &НачалоПериода
    ТОГДА &НачалоПериода
    ИНАЧЕ ДниПериода.НачалоСтандартногоПериода
    КОНЕЦ

    и аналогично для конца периода

    Reply
  34. Ovrfox

    (33) herfis, Запрос возвращает не кол-во периодов, а одну запись в день. Чтобы получить периоды — нужно группировать — не самый эффективный метод.

    Но как вариант — очень хорош.

    Reply
  35. herfis

    (34) Ovrfox, Именно так. Я об этом сразу предупредил. По сути, это просто небольшая модификация получения таблицы дней. Мне нужна была именно такая. Вероятно, именно для периодов возможен более оптимальный вариант. Но без группировок (РАЗЛИЧНЫЕ просто одна из вариаций) в голову ничего не приходит. Тут тоже достаточно добавить РАЗЛИЧНЫЕ и убрать «ДеньПериода» для получения таблицы именно периодов.

    Reply
  36. Ovrfox

    (33) herfis, Примерно такой запрос получен по вашим следам

    При этом легко видеть, что при замене слова НЕДЕЛЯ на любой другой период запрос останется точно таким же, изменится только протяженность периода

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

    Показать

    Reply
  37. herfis

    (36) Ovrfox, Все так. Исходный запрос многословен из-за динамической разбивки по периодам (периодичность выбирает пользователь в параметре СКД).

    Reply
  38. ildarovich

    (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, Даты.Х, МЕСЯЦ)

    Показать

    Reply
  39. herfis

    (38) ildarovich, Согласен.

    ЗЫ. В использовании двоичного расчета плюсов не вижу, скорее наоборот, а вот группировка по разности дат — элегантный ход.

    Reply
  40. ildarovich

    (39) herfis, двоичный, десятичный и тому подобное к сути решения не относятся. Можно использовать кому что нравится. Я использовал двоичное основание из-за того, что оно дает самую короткую запись, выраженную в числе строк запроса, раскрытого конструктором. Уж очень длинной выглядит формирование таблицы из десяти цифр. Еще плюсом двоичного основания является минимум лишнего в итоге соединения, из которой затем выбирается нужное число записей, потому что ряд 1-2-4-8-16-64-128 чаще, чем 1-10-100-1000. Есть и минусы и другие методы. Но здесь об этом смысла спорить не вижу.

    Сейчас хочу увидеть более короткое чем (25) и (26) решение без развертки по дням.

    Reply
  41. HanterVol

    Сделал с другой идеей, но… короче не получилось

    ВЫБРАТЬ
    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, МЕСЯЦ, Месяцы.Номер), МЕСЯЦ)
    ИЗ
    Месяцы КАК Месяцы) КАК ВложенныйЗапрос
    
    СГРУППИРОВАТЬ ПО
    ВложенныйЗапрос.Номер
    

    Показать

    Reply
  42. herfis

    (40) ildarovich, ИМХО, Orfox победитель.

    Он первый предложил оптимальный алгоритм генерации таблицы периодов (без группировок). Оптимальнее вроде некуда. Один простой запрос.

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

    Reply
  43. herfis

    Было бы соблазнительно сгенерировать таблицу полных периодов и объединить с «краями», но, к сожалению, обработка всех возможных ситуаций в итоге будет выглядеть хуже, а не лучше.

    Reply
  44. ildarovich

    (41) HanterVol, хороший вариант, кое-где вроде бы РАЗЛИЧНЫЕ лишние. Он кажется более «воздушным». Нужно будет еще по числу знаков сравнить.

    Reply
  45. ildarovich

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

    Reply
  46. ildarovich

    Пора подводить итоги. Добавлю вознаграждение, съеденное временем. HanterVol предложил свой вариант первым, а потом добавил еще один интересный вариант решения. Но в итоге с небольшим перевесом (0,5:1,5) побеждает вариант (24) Ovrfox. Этот вариант самый простой и короткий.

    Reply
  47. ildarovich

    К сожалению, из-за редизайна форума, обещанное вознаграждение до победителя не дошло, останусь должен, сочтемся с 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 находятся в одном месяце.

    Reply
  48. spenser123

    Я, может, не врубился до конца в тему, но не понимаю чем не устраивает банальные варианты с:

    НАЧАЛОПЕРИОДА(Дата,&Периодичность) Как НачалоПериода
    КОНЕЦПЕРИОДА(Дата,&Периодичность) Как КонецПериода
    

    ?

    Reply
  49. ildarovich

    (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.

    Reply
  50. soulsteps

    (47)

    Чуточку изменил Ваш запрос:

    ВЫБРАТЬ

    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

    ГДЕ

    НАЧАЛОПЕРИОДА(&Дата1, МЕСЯЦ) = НАЧАЛОПЕРИОДА(&Дата2, МЕСЯЦ)

    УПОРЯДОЧИТЬ ПО

    ДатаНачала

    Этот вариант не отрабатывает отрабатывает ситуацию отсутствия необходимости разбивки: если Дата1 и Дата2 находятся в одном месяце.

    Также, если в тексте запроса МЕСЯЦ -> #Детализация и через СтрЗаменить(…) в тексте запроса заменять #Детализация на МЕСЯЦ, ДЕНЬ, КВАРТАЛ… То можно получить вполне универсальную функцию.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *