gifts2017

Календарь в запросе

Опубликовал Ildar Gabdrakhmanov (spezc) в раздел Программирование - Практика программирования

Календарь в запросе (последовательный список дат за определенный период) без использования предварительно созданных объектов метаданных (таких как производственный календарь, график).

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

 

За основу взят известный алгоритм получения чисел от 0 до 9999 в запросе, суть которого заключается в том, чтобы перемножить таблицы, содержащие цифры от 0 до 9, столько раз, сколько порядков вам требуется в итоговом максимальном числе. Например для получения последовательности цифр от 0 до 9999 - вам потребуется соединить 4 таблицы (как в примере).

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

"ТаблицаМесяцев" - таблица, содержащая наименование месяцев.
"ТаблицаДнейНедели" - таблица, содержащая наименование дней недели и признак выходного дня.
"ТаблицаЦифр", "ТаблицаЧисел" - служебные таблицы, используемые для последующего построения таблицы "Календарь".
"Календарь" - таблица, содержащая непоследственно список дат за определенный период.
Результирующая таблица - фактически тот самый производственный каледнарь, за исключением праздников.

Сам запрос:

ВЫБРАТЬ
	"Январь" КАК НазваниеМесяца,
	1 КАК НомерМесяца
ПОМЕСТИТЬ ТаблицаМесяцев

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

ВЫБРАТЬ
	"Февраль",
	2

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

ВЫБРАТЬ
	"Март",
	3

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

ВЫБРАТЬ
	"Апрель",
	4

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

ВЫБРАТЬ
	"Май",
	5

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

ВЫБРАТЬ
	"Июнь",
	6

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

ВЫБРАТЬ
	"Июль",
	7

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

ВЫБРАТЬ
	"Август",
	8

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

ВЫБРАТЬ
	"Сентябрь",
	9

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

ВЫБРАТЬ
	"Октябрь",
	10

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

ВЫБРАТЬ
	"Ноябрь",
	11

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

ВЫБРАТЬ
	"Декабрь",
	12
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	"Понедельник" КАК ДеньНедели,
	"Пн" КАК ДеньНеделиСокращено,
	1 КАК НомерДняНедели,
	ЛОЖЬ КАК СтандартныйВыходной
ПОМЕСТИТЬ ТаблицаДнейНедели

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

ВЫБРАТЬ
	"Вторник",
	"Вт",
	2,
	ЛОЖЬ

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

ВЫБРАТЬ
	"Среда",
	"Ср",
	3,
	ЛОЖЬ

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

ВЫБРАТЬ
	"Четверг",
	"Чт",
	4,
	ЛОЖЬ

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

ВЫБРАТЬ
	"Пятница",
	"Пт",
	5,
	ЛОЖЬ

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

ВЫБРАТЬ
	"Суббота",
	"Сб",
	6,
	ИСТИНА

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

ВЫБРАТЬ
	"Воскресенье",
	"Вс",
	7,
	ИСТИНА
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	0 КАК Цифра
ПОМЕСТИТЬ ТаблицаЦифр

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

ВЫБРАТЬ
	1

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

ВЫБРАТЬ
	2

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

ВЫБРАТЬ
	3

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

ВЫБРАТЬ
	4

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

ВЫБРАТЬ
	5

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

ВЫБРАТЬ
	6

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

ВЫБРАТЬ
	7

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

ВЫБРАТЬ
	8

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

ВЫБРАТЬ
	9
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ТаблицаЦифрДляТысяч.Цифра * 1000 + ТаблицаЦифрДляСотен.Цифра * 100 + ТаблицаЦифрДляДесятков.Цифра * 10 + ТаблицаЦифрДляЕдиниц.Цифра КАК Число
ПОМЕСТИТЬ ТаблицаЧисел
ИЗ
	ТаблицаЦифр КАК ТаблицаЦифрДляЕдиниц,
	ТаблицаЦифр КАК ТаблицаЦифрДляДесятков,
	ТаблицаЦифр КАК ТаблицаЦифрДляСотен,
	ТаблицаЦифр КАК ТаблицаЦифрДляТысяч
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ДОБАВИТЬКДАТЕ(&НачПериода, ДЕНЬ, ТаблицаЧисел.Число) КАК Дата
ПОМЕСТИТЬ Календарь
ИЗ
	ТаблицаЧисел КАК ТаблицаЧисел
ГДЕ
	ДОБАВИТЬКДАТЕ(&НачПериода, ДЕНЬ, ТаблицаЧисел.Число) <= &КонПериода
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ТаблицаМесяцев.НазваниеМесяца КАК Месяц,
	Календарь.Дата КАК ДатаКалендаря,
	ТаблицаДнейНедели.ДеньНедели КАК ДеньНедели,
	ТаблицаДнейНедели.ДеньНеделиСокращено КАК ДеньНеделиСокращено,
	ТаблицаДнейНедели.СтандартныйВыходной КАК СтандартныйВыходной
ИЗ
	Календарь КАК Календарь
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТаблицаМесяцев КАК ТаблицаМесяцев
		ПО (МЕСЯЦ(Календарь.Дата) = ТаблицаМесяцев.НомерМесяца)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТаблицаДнейНедели КАК ТаблицаДнейНедели
		ПО (ДЕНЬНЕДЕЛИ(Календарь.Дата) = ТаблицаДнейНедели.НомерДняНедели)

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


См. также

Подписаться Добавить вознаграждение
Комментарии
1. Константин Юрин (kostyaomsk) 24.02.15 07:35
Интересный прием. Похож на недавно попавшийся в отчете прием получения списка дат с &НачалоПериода по &КонецПериода
ВЫБРАТЬ
	ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&НачалоПериода, ДЕНЬ), ДЕНЬ, t.n) КАК Дата
ПОМЕСТИТЬ ТаблицаДата
ИЗ
	(ВЫБРАТЬ
		6 * (t1.a - 1) + t2.b - 1 КАК n
	ИЗ
		(ВЫБРАТЬ
			1 КАК a
		
		ОБЪЕДИНИТЬ
		
		ВЫБРАТЬ
			2
		
		ОБЪЕДИНИТЬ
		
		ВЫБРАТЬ
			3
		
		ОБЪЕДИНИТЬ
		
		ВЫБРАТЬ
			4
		
		ОБЪЕДИНИТЬ
		
		ВЫБРАТЬ
			5
		
		ОБЪЕДИНИТЬ
		
		ВЫБРАТЬ
			6) КАК t1
			ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
				1 КАК b
			
			ОБЪЕДИНИТЬ
			
			ВЫБРАТЬ
				2
			
			ОБЪЕДИНИТЬ
			
			ВЫБРАТЬ
				3
			
			ОБЪЕДИНИТЬ
			
			ВЫБРАТЬ
				4
			
			ОБЪЕДИНИТЬ
			
			ВЫБРАТЬ
				5
			
			ОБЪЕДИНИТЬ
			
			ВЫБРАТЬ
				6) КАК t2
			ПО (ИСТИНА)) КАК t
ГДЕ
	ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&НачалоПериода, ДЕНЬ), ДЕНЬ, t.n) <= &КонецПериода
...Показать Скрыть

Фрагмент из отчета по прайсу.

Прикрепленные файлы:
2. Константин Юрин (kostyaomsk) 24.02.15 07:48
В случае автора результат в консоле запросов аналогичен. Наверное, стоит применять, когда действительно нужны таблицы месяцев и дней недели.
"ТаблицаМесяцев" - таблица, содержащая наименование месяцев.
"ТаблицаДнейНедели" - таблица, содержащая наименование дней недели и признак выходного дня.

Естественно, задачи бывают разные и стоит собирать подобные решения чтоб не ломать голову, когда нужно что-то срочное. Да и в таблице "ТаблицаДнейНедели" можно ставить свой признак выходного дня или она также будет промежуточной при объединении с еще одной таблицей.
3. Ildar Gabdrakhmanov (spezc) 24.02.15 07:49
(1) kostyaomsk, интересный запрос. сходу и не сообразил как работает. попробую в консоли.
4. Ildar Gabdrakhmanov (spezc) 24.02.15 07:58
(1) kostyaomsk, вложенный запрос "ВЫБРАТЬ 6 * (t1.a - 1) + t2.b - 1 КАК n" возвращает числа от 0 до 35. В чем профит? Как получить больший диапазон?
kostyaomsk; +1 Ответить 1
5. Константин Юрин (kostyaomsk) 24.02.15 08:34
(4) spezc, тоже большой плюс Вам что заметили. У меня был приведенный выше фрагмент из отчета "прайс", показывающий изменения цен прайса на заданную грубину. Месяца, видимо, достаточно. Более точно 36 дней максимум в моем случае. Еще в коде стоит для этого ограничение на две цифры переменной "количество дней для проверки изменений". Можно и увеличить если нужно количество, но это сильно увеличит нагрузку на сервер.
Используется же ограничитель ГДЕ
ГДЕ
    ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&НачалоПериода, ДЕНЬ), ДЕНЬ, t.n) <= &КонецПериода

Полагаю, сначала все равно вся таблица запроса генерируется средствами SQL? Если лезть глубоко такого накопать можно.
6. Олег (OLEG4120) 24.02.15 10:04
На старых платформах (8.1) почему-то упорядочивание не срабатывает
7. Ildar Gabdrakhmanov (spezc) 24.02.15 10:18
(6) OLEG4120, "УПОРЯДОЧИТЬ ПО ДатаКалендаря"?
8. Макс Зеленский (mzelensky) 25.02.15 11:04
Единожды потребовалась такая ерундовина. Огромное спасибо!!!
9. Enot tut (enot_tut) 24.12.15 15:01
10. Ildar Gabdrakhmanov (spezc) 24.12.15 15:11
(9) enot_tut, исходник чего? если запроса - то он в самой статье.