Расчет рабочих дней в запросе

25.12.14

Разработка - Запросы

Популярная тема - расчет просрочки в рабочих днях. Если это нужно сделать по одному объекту, то тут всё достаточно просто. Что же делать, если нужно сразу по множеству объектов, при этом быстро и не особо загружая сервер?

Исходные данные

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

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

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

 

ВЫБРАТЬ РАЗРЕШЕННЫЕ
	РегламентированныйПроизводственныйКалендарь.ДатаКалендаря КАК ДатаКалендаря
ПОМЕСТИТЬ ВТ_ДанныеКалендаря
ИЗ
	РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ
	(РегламентированныйПроизводственныйКалендарь.Рабочий = ИСТИНА)
	И ГОД(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) >= ГОД(&ТекущаяДата) - 1
	И ГОД(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) <= ГОД(&ТекущаяДата) + 1

ИНДЕКСИРОВАТЬ ПО
	ДатаКалендаря
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
	ВТ_ДанныеКалендаря.ДатаКалендаря КАК ДатаКалендаря,
	СУММА(1) КАК НомерРабочегоДня
ПОМЕСТИТЬ ВТ_НомераРабочихДней
ИЗ
	ВТ_ДанныеКалендаря КАК ВТ_ДанныеКалендаря
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДанныеКалендаря КАК ВТ_ДанныеКалендаряДляСуммы
		ПО ВТ_ДанныеКалендаря.ДатаКалендаря >= ВТ_ДанныеКалендаряДляСуммы.ДатаКалендаря

СГРУППИРОВАТЬ ПО
	ВТ_ДанныеКалендаря.ДатаКалендаря

ИНДЕКСИРОВАТЬ ПО
	ДатаКалендаря



рабочие дни расчет просрочки матрицы

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

15500 руб.

02.09.2020    184667    1029    403    

967

Обновление 1С Запросы Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Абонемент ($m)

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

2 стартмани

06.02.2025    2198    17    XilDen    26    

36

Запросы Программист Платформа 1С v8.3 Запросы 1C:Бухгалтерия Бесплатно (free)

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

03.12.2024    5731    artemusII    11    

23

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    13135    sergey279    18    

66

Запросы Программист Платформа 1С v8.3 Запросы 1C:Бухгалтерия Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    8215    XilDen    36    

90

СКД Механизмы типовых конфигураций Запросы Программист Платформа 1С v8.3 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Россия Бесплатно (free)

Работая с типовыми отчетами в конфигурациях «Зарплата и управление персоналом, редакция 3», «Зарплата и кадры государственного учреждения, редакция 3» и подобных, в схемах компоновки данных можно встретить конструкции запросов, которые обращаются к некоторым виртуальным таблицам.

20.08.2024    3191    PROSTO-1C    0    

23

Запросы Программист Запросы Бесплатно (free)

Отлаживая взаимодействие с базой данных, мы регулярно сталкиваемся с зависающими или подозрительно долго выполняющимися обращениями, негативно влияющими на производительность. О том, как в PostgreSQL выявить подозрительные запросы, основываясь на доступной о них информации, расскажем в статье.

16.08.2024    10797    user1840182    5    

29
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ZLENKO 398 25.12.14 15:58 Сейчас в теме
Вот в этом отчете по просроченной дебиторке используется расчет по рабочим дням http://infostart.ru/public/117647/

2. chmv 25.12.14 16:52 Сейчас в теме
Любопытно. А как на счет соединения в запросе даты+наименование
Например ФизЛицо.Наименование+ФизЛицо.Дата
3. ildarovich 7958 26.12.14 00:34 Сейчас в теме
А в чем проблема просто соединить таблицу долгов с "РегистрСведений.РегламентированныйПроизводственныйКалендарь" по условию ДатаКалендаря МЕЖДУ ДатаВозникновенияДолга И &ТекущаяДата ГДЕ Рабочий = ИСТИНА и получить число рабочих дней как КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДатаКалендаря) ? По идее, при соединении должен использоваться индекс и никаких проблем с производительностью у этого запроса быть не должно.
А вот в предлагаемом решении проблемы есть - время предварительного расчета таблицы "интеграл рабочих дней" квадратично зависит от интервала. Не зря тут ограничение на плюс-минус год стоит. И что будет, если долг имеет двухгодичную давность?
В общем, для убедительности нужно привести проблемный запрос, который вы пытаетесь таким образом оптимизировать и сравнительные замеры времени выполнения запросов. Иначе может оказаться, что предлагается никому не нужное усложнение простого запроса.
user779781; Muhin555; xzorkiix; Badakismati; Valerich; +5 Ответить
4. ksuman 24 31.12.14 14:01 Сейчас в теме
(3) ildarovich, Вы правильно заметили: ГОД(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) в условиях - и сервер БД не будет использовать Кластерный индекс по полю даты календаря, что в случае использования системы после десятка лет неоправданно увеличит время выполнения запроса.

Можно использовать Пакетный запрос, только условие надо писать корректно: не так как нам читабельно, а так чтобы быстро выполнялся.
xzorkiix; +1 Ответить
5. Sergey.Noskov 1414 13.01.15 13:14 Сейчас в теме
Мы таким же запросом определяли, потом таки переделали регистр - добавили несколько ресурсов, соответствующих самым часто востребованным рабочим дням (след рабочий день, третий, 10й)
6. Diego_Iv 34 15.01.15 10:19 Сейчас в теме
Мы тоже поначалу использовали аналогичный запрос в отчетах по просроченной задолженности.
На тысяче контрагентов (у контрагента может быть до 10 договоров с разными условиями по срокам оплаты, сроки считаются как по календарным, так и рабочим дням) отчет мог строиться до 30 минут, из-за того что срок погашения долга рассчитывался в момент формирования отчета для каждого документа, сформировавшего этот долг).
В результате сделали так: добавили регистр сведений "сроки погашения". Измерения - Договор контрагента, документ расчетов. Ресурс - Дата погашения.
В момент проведения документа поступления (реализации) подпиской на событие в регистр добавляется запись с уже рассчитанной датой погашения долга по этому документу.

В результате все отчеты по долгам строятся за секунды.
dgolovanov; +1 Ответить
7. chmv 16.01.15 12:09 Сейчас в теме
8. vis_tmp 32 26.05.19 16:29 Сейчас в теме
Спасибо, очень хороший метод для расчета числа рабочих дней между двумя датами.
9. vis_tmp 32 26.05.19 19:50 Сейчас в теме
А как быть если дата приходится на выходной день, отсутствующий в выборке?
10. kozusenok 54 20.04.22 08:20 Сейчас в теме
Недавно тоже столкнулся с проблемой поиска ближайшего рабочего дня к дате. Запрос похож на запрос из публикации, но оставлю здесь на всякий случай.

ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1000000
	Календарь.ДатаКалендаря КАК ДатаКалендаря
ПОМЕСТИТЬ БанковскиеДниКалендаря
ИЗ
	РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
	(Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
			ИЛИ Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))

УПОРЯДОЧИТЬ ПО
	Календарь.ДатаКалендаря

ИНДЕКСИРОВАТЬ ПО
	Календарь.ДатаКалендаря
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ДАТАВРЕМЯ(2022, 4, 1) КАК ДатаДокумента,
	5 КАК ДнейОтсрочки
ПОМЕСТИТЬ ТаблицаОплат

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

ВЫБРАТЬ
	ДАТАВРЕМЯ(2022, 4, 9),
	7
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Оплаты.ДатаДокумента КАК ДатаДокумента,
	Оплаты.ДнейОтсрочки КАК ДнейОтсрочки,
	Календарь.ДатаКалендаря КАК ДатаОплаты
ИЗ
	ТаблицаОплат КАК Оплаты
		ЛЕВОЕ СОЕДИНЕНИЕ БанковскиеДниКалендаря КАК Календарь
		ПО ((Календарь.ДатаКалендаря, Оплаты.ДнейОтсрочки) В
				(ВЫБРАТЬ
					Выборка.ДатаКалендаря КАК МаксДатаКалендаря,
					СУММА(1) КАК НомерРабочегоДня
				ИЗ
					БанковскиеДниКалендаря КАК Выборка ЛЕВОЕ СОЕДИНЕНИЕ БанковскиеДниКалендаря КАК ПодВыборка
						ПО
							ПодВыборка.ДатаКалендаря >= Оплаты.ДатаДокумента
								И ПодВыборка.ДатаКалендаря <= Выборка.ДатаКалендаря
				ГДЕ
					Выборка.ДатаКалендаря >= Оплаты.ДатаДокумента
				СГРУППИРОВАТЬ ПО
							Выборка.ДатаКалендаря))
Показать
11. kozusenok 54 20.04.22 20:47 Сейчас в теме
Если не нужно считать день даты документа то ставим "> Оплаты.ДатаДокумента"

ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1000000
    Календарь.ДатаКалендаря КАК ДатаКалендаря
ПОМЕСТИТЬ БанковскиеДниКалендаря
ИЗ
    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
    (Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
            ИЛИ Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))

УПОРЯДОЧИТЬ ПО
    Календарь.ДатаКалендаря

ИНДЕКСИРОВАТЬ ПО
    Календарь.ДатаКалендаря
;

////////////////////////////////////////////////////////////­­////////////////////
ВЫБРАТЬ
    ДАТАВРЕМЯ(2022, 4, 1) КАК ДатаДокумента,
    5 КАК ДнейОтсрочки
ПОМЕСТИТЬ ТаблицаОплат

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

ВЫБРАТЬ
    ДАТАВРЕМЯ(2022, 4, 9),
    7
;

////////////////////////////////////////////////////////////­­////////////////////
ВЫБРАТЬ
    Оплаты.ДатаДокумента КАК ДатаДокумента,
    Оплаты.ДнейОтсрочки КАК ДнейОтсрочки,
    Календарь.ДатаКалендаря КАК ДатаОплаты
ИЗ
    ТаблицаОплат КАК Оплаты
        ЛЕВОЕ СОЕДИНЕНИЕ БанковскиеДниКалендаря КАК Календарь
        ПО ((Календарь.ДатаКалендаря, Оплаты.ДнейОтсрочки) В
                (ВЫБРАТЬ
                    Выборка.ДатаКалендаря КАК МаксДатаКалендаря,
                    СУММА(1) КАК НомерРабочегоДня
                ИЗ
                    БанковскиеДниКалендаря КАК Выборка ЛЕВОЕ СОЕДИНЕНИЕ БанковскиеДниКалендаря КАК ПодВыборка
                        ПО
                            ПодВыборка.ДатаКалендаря > Оплаты.ДатаДокумента
                                И ПодВыборка.ДатаКалендаря <= Выборка.ДатаКалендаря
                ГДЕ
                    Выборка.ДатаКалендаря > Оплаты.ДатаДокумента
                СГРУППИРОВАТЬ ПО
                            Выборка.ДатаКалендаря))
Показать
12. daa147 6 24.03.25 14:53 Сейчас в теме
Спасибо. На мысль натолкнул, дальше разобрался.
Оставьте свое сообщение