Профессия — 1С

Рукопашный бой Карташ

Категории

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

рубрики: Запросы | Дата: 17 Январь, 2016

Абсолютно все программисты 1С сталкивались с динамическими запросами. То есть когда в зависимости от тех или иных условий текст запроса может меняться. Допустим в зависимости от какой-то переменной может меняться условие в запросе или список полей и т.д. Или текст запроса может формироваться в цикле.




Те кто работал с ЗУП наверняка сталкивались с тем, что во многих отчетах когда указывается начало и конец периода и требуется разбивка по месяцам изначально используется динамический запрос в результате выполнения, которого формируется примерно такая таблица (допустим, что мы формируем отчет за первый квартал 2016 г.):

НачалоПериода
01.01.2016
01.02.2016
01.03.2016

Соответственно текст запроса для формирования такой таблицы выглядит следующим образом:



"ВЫБРАТЬ
|	ДАТАВРЕМЯ(2016, 1, 1) КАК НачалоПериода
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|	ДАТАВРЕМЯ(2016, 2, 1)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
|	ДАТАВРЕМЯ(2016, 3, 1)";

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



ТекущаяДата		= НачалоМесяца(Объект.ДатаНачала);

ТекстЗапроса = "
|ВЫБРАТЬ
|	ДАТАВРЕМЯ(" + Формат(Год(ТекущаяДата), "ЧГ=") + ", " + Месяц(ТекущаяДата) + ", 1) КАК НачалоПериода";

ТекущаяДата = ДобавитьМесяц(ТекущаяДата, 1);

Пока ТекущаяДата <= Объект.ДатаОкончания Цикл

	ТекстЗапроса = ТекстЗапроса + "
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ДАТАВРЕМЯ(" + Формат(Год(ТекущаяДата), "ЧГ=") + ", " + Месяц(ТекущаяДата) + ", 1)";
	
	ТекущаяДата = ДобавитьМесяц(ТекущаяДата, 1);
	
КонецЦикла;

В свое время, когда я только начинал программировать на 1С и впервые столкнулся с необходимостью сформировать динамический запрос, то некоторое время не мог понять как же правильно, и в каких местах расставлять все эти плюсики и кавычки. И только потом до меня дошло, что текст запроса это всего лишь длинная строка текста, а знак «|» означает лишь перенос на следующую строку. И таким образом правила внедрения переменных в текст запроса те же самые, что и при работе с обычной строкой.




Теперь немного о том как писать динамические запросы быстро. Поначалу их написание приводило у меня к большим временным затратам и взрыву мозга. Ведь если взять даже пример приведенный выше, то чтобы сразу написать формирование запроса в цикле придется немножко подумать. А если итоговый запрос содержит порядка 200 строк с кучей вставок переменных(а в конфигурации ЗУП есть и по 2000 строк)? Поэтому не особо задумываясь, открываем конструктор запросов и пишем один вариант (или несколько вариантов) конечного запроса. Проверяем работоспособность в консоли запросов. Потом копируем текст запроса в процедуру, где он будет формироваться динамически и в необходимых местах заменяем текст на переменные. Ну и конечно не забываем тестировать.

А теперь рассмотрим еще один пример формирования динамического запроса.
Допустим, что в зависимости от какой то переменной нам надо выбирать данные (пусть это будут период регистрации, сотрудник и сумма) либо из регистра расчетов «ОсновныеНачисленияРаботниковОрганизаций» либо из регистра «ДополнительныеНачисленияРаботниковОрганизаций». Вот код с формированием текста:



Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
|	ДанныеРегистра.ПериодРегистрации,
|	ДанныеРегистра.Сотрудник,
|	ДанныеРегистра.Результат
|ИЗ
|	РегистрРасчета." + ?(ЭтоОсновныеНачисления, "ОсновныеНачисленияРаботниковОрганизаций", "ДополнительныеНачисленияРаботниковОрганизаций") + " КАК ДанныеРегистра";

Но можно сделать и по другому:



Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
|	ДанныеРегистра.ПериодРегистрации,
|	ДанныеРегистра.Сотрудник,
|	ДанныеРегистра.Результат
|ИЗ
|	//ТАБЛИЦА_РЕГИСТРА";

Если ЭтоОсновныеНачисления Тогда
	ТекстТаблица = "	РегистрРасчета.ОсновныеНачисленияРаботниковОрганизаций КАК ДанныеРегистра";
Иначе
	ТекстТаблица = "	РегистрРасчета.ДополнительныеНачисленияРаботниковОрганизаций КАК ДанныеРегистра";
КонецЕсли;

Запрос.Текст = СтрЗаменить(Запрос.Текст, "//ТАБЛИЦА_РЕГИСТРА", ТекстТаблица);

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



	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 10
	|	//ДОПОЛНИТЕЛЬНЫЕ_ПОЛЯ
	|	ДанныеРегистра.ПериодРегистрации,
	|	ДанныеРегистра.Сотрудник,
	|	ДанныеРегистра.Результат
	|ИЗ
	|	РегистрРасчета.ОсновныеНачисленияРаботниковОрганизаций КАК ДанныеРегистра
	|//УСЛОВИЯ_ЗАПРОСА
	|";

Для небольшого по объему запроса существенной разницы нет, но когда он большой, то в конструкторе его анализировать гораздо удобней. Только помните, что если вы открыли такой запрос в конструкторе, ни в коем случае не нажимайте потом на кнопу «ОК», иначе все закоментированные строчки внутри запроса пропадут.

Добавить комментарий

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

   

2018г. Профессия — 1С. Обмен опытом по программированию в 1С