Алгоритм по переносу вложенных запросов в пакеты

01.12.17

Разработка - Инструментарий разработчика

Запросы неудобно отлаживать, если в них есть вложенные запросы. Данный алгоритм помогает отредактировать текст запроса таким образом, чтобы все вложенные запросы перенеслись в пакеты.

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

Наименование Файл Версия Размер
Набор функций
.txt 20,40Kb
6
.txt 20,40Kb 6 Скачать
КонсольОтчетов (Вынесение вложенных запросов)
.epf 91,52Kb
15
.epf 91,52Kb 15 Скачать

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

Пример использования:

ТекстЗапросаНовый = ВынестиВложенныеТаблицы(ТекстЗапроса);

Пример того, что было:

ВЫБРАТЬ
	ВложенныйЗапрос.Ссылка
ИЗ
	(ВЫБРАТЬ
		Банки.Ссылка КАК Ссылка
	ИЗ
		Справочник.Банки КАК Банки) КАК ВложенныйЗапрос

Стало:

ВЫБРАТЬ
	Банки.Ссылка КАК Ссылка
ПОМЕСТИТЬ Банки
ИЗ
	Справочник.Банки КАК Банки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВложенныйЗапрос.Ссылка
ИЗ
	Банки КАК ВложенныйЗапрос

Для примера использования встроил функции в типовую обработку КонсольОтчетов из 1С УПП 1.3, см. приложенный файл:

Также набор функций приложил в отдельном файле txt.

Или можно скачать здесь:

// --
// Функции редактирования запроса

// Функция выноса вложенных таблиц
Функция ВынестиВложенныеТаблицы(Знач ГлобальныйТекстЗапроса)
		
	МассивПакетовЗапросов = Новый Массив;	
	
	// Получаем все подзапросы, разделенные ";"
	МассивИсключенийСимоволов = Новый Массив;
	МассивИсключенийСимоволов.Добавить("""");
	ПакетыЗапросов = ПолучитьМассивСловРазделенныхСимволом(ГлобальныйТекстЗапроса, ";", , , МассивИсключенийСимоволов);	
	
	// --
	// Из ПакетыЗапросов сформируем МассивПакетовЗапросов
	
	// При формировании пакетов имена должны быть уникальны. Вложенные запросы могут иметь неуникальные наименования. 
	// Для этого ведём массив созданных пакетов, в случае неуникального наименования добавляем порядковый номер	
	МассивИменПакетов = Новый Массив;
	
	// Заполним массив пакетов имена существующих пакетов
	ГлобальныйТекстЗапросаПоискПакетов = ГлобальныйТекстЗапроса;
	МассивСпециальныхСимволов = ПолучитьМассивСпециальныхСимволов();
	Пока Истина Цикл
		ПозицияПоместить = Найти(ГлобальныйТекстЗапросаПоискПакетов, "ПОМЕСТИТЬ ");
		Если ПозицияПоместить = 0 Тогда
			Прервать;
		КонецЕсли;
		НачальнаяПозиция = ПозицияПоместить + 10;
		ИмяПакета = ПолучитьСлово(ГлобальныйТекстЗапросаПоискПакетов, НачальнаяПозиция, Ложь, Истина, МассивСпециальныхСимволов);
		МассивИменПакетов.Добавить(ИмяПакета);
		ГлобальныйТекстЗапросаПоискПакетов = Сред(ГлобальныйТекстЗапросаПоискПакетов, НачальнаяПозиция, СтрДлина(ГлобальныйТекстЗапросаПоискПакетов));
	КонецЦикла;	
	
	ПозицияНачала = 1;
	ПозицияОкончания = 0;
	Для Каждого ПакетЗапроса Из ПакетыЗапросов Цикл
		ПозицияОкончания = ПозицияНачала + СтрДлина(ПакетЗапроса);		
		СтруктураПодзапросовПакета = ПолучитьСтруктуруПодзапросов(ПакетЗапроса, ПозицияНачала, ГлобальныйТекстЗапроса, МассивИменПакетов);	
		МассивПакетовЗапросов.Добавить(Новый Структура("ТекстЗапроса, Подзапросы, ПозицияНачала, ПозицияОкончания", ПакетЗапроса, СтруктураПодзапросовПакета, ПозицияНачала, ПозицияОкончания));
		
		ПозицияНачала = ПозицияОкончания + 1;		
	КонецЦикла;
	// Из ПакетыЗапросов сформируем МассивПакетовЗапросов
	// --
	
	// Сформируем запрос из МассивПакетовЗапросов
	ГлобальныйТекстЗапросаНовый = "";
	Для Каждого ПакетЗапроса Из МассивПакетовЗапросов Цикл		
		
		МассивВырезок = Новый Массив;
		ТекстПодзапросов = ПолучитьТекстПодзапросов(ГлобальныйТекстЗапроса, ПакетЗапроса.Подзапросы, МассивВырезок);
		ГлобальныйТекстЗапросаНовый = ГлобальныйТекстЗапросаНовый + ?(ГлобальныйТекстЗапросаНовый = "" Или ТекстПодзапросов = "", "", ";") + ТекстПодзапросов;
		
		ТекстПакета = ПолучитьВырезкуТекста(ГлобальныйТекстЗапроса, ПакетЗапроса.ПозицияНачала, ПакетЗапроса.ПозицияОкончания, МассивВырезок);
		
		ГлобальныйТекстЗапросаНовый = ГлобальныйТекстЗапросаНовый + ?(ГлобальныйТекстЗапросаНовый = "" Или ТекстПакета = "", "", ";") + ТекстПакета;	
	КонецЦикла;
	
	Возврат ГлобальныйТекстЗапросаНовый;

КонецФункции

// ПозицияВГлобальномТексте - позиция переданного текста в тексте глобального запроса
Функция ПолучитьСтруктуруПодзапросов(Знач ТекстПакетаЗапроса, Знач ПозицияВГлобальномТексте = 0, Знач ГлобальныйТекстЗапроса, МассивИменПакетов)
	
	ТекстДлина = СтрДлина(ТекстПакетаЗапроса);
	
	Структура = Новый Структура;
	
	МассивСпециальныхСимволов = ПолучитьМассивСпециальныхСимволов();
	МассивСпециальныхСимволовКромеСкобок = ПолучитьМассивСпециальныхСимволов("()");
	
	// --
	// Перебираем текст по символьно
	Для НомерБуквы = 1 По ТекстДлина Цикл
		
		// --
		// Определяем, что это начало нового запроса
		
		// В целях оптимизации не используем ПолучитьСлово, но могут быть ошибки, поэтому перепроверим через ПолучитьСлово ещё раз внизу
		Если Сред(ТекстПакетаЗапроса, НомерБуквы, 8) = "(ВЫБРАТЬ" Тогда
			
			ПрошлоеСлово = ПолучитьСлово(ТекстПакетаЗапроса, НомерБуквы, Истина, Ложь, МассивСпециальныхСимволов);
			Если 
				ПолучитьСлово(ТекстПакетаЗапроса, НомерБуквы, Ложь, Истина, МассивСпециальныхСимволовКромеСкобок) = "(ВЫБРАТЬ"
				И
				ПрошлоеСлово <> "ВСЕ" И ПрошлоеСлово <> "ОБЪЕДИНИТЬ" И ПрошлоеСлово <> "В" И ПрошлоеСлово <> "ИЕРАРХИИ" Тогда			
				
				ПозицияИз = Неопределено;
				
				Для НомерПодбуквы = НомерБуквы + 1 По ТекстДлина Цикл
					
					ТекстПодзапроса = Сред(ТекстПакетаЗапроса, НомерБуквы, НомерПодбуквы - НомерБуквы);
					
					// Определяем позицию ИЗ в запросе
					Если ПозицияИз = Неопределено Тогда
						Если Сред(ТекстПакетаЗапроса, НомерПодбуквы, 2) = "ИЗ" И СтрЧислоВхождений(ТекстПодзапроса, "(") - СтрЧислоВхождений(ТекстПодзапроса, ")") = 1 Тогда
							ПозицияИз = ПозицияВГлобальномТексте + НомерПодбуквы - 1;	
						ИначеЕсли Сред(ТекстПакетаЗапроса, НомерПодбуквы + 1, 10) = "ОБЪЕДИНИТЬ" Тогда
							ПозицияИз = ПозицияВГлобальномТексте + НомерПодбуквы - 1;
						КонецЕсли;
					КонецЕсли;
					
					// --				
					// Проверим, что скобки закрылись, значит подзапрос закрывается
					Если СтрЧислоВхождений(ТекстПодзапроса, "(") = СтрЧислоВхождений(ТекстПодзапроса, ")") Тогда
						
						// Если ПозицияИз не определена, значит ставим её в конце
						Если ПозицияИз = Неопределено Тогда
							ПозицияИз = НомерПодбуквы;
						КонецЕсли;
						
						// Урезаем скобки по краяем
						ТекстПодзапросаБезСкобок = Сред(ТекстПодзапроса, 2, СтрДлина(ТекстПодзапроса) - 2);
						
						Ключ = "Запрос" + Строка(Структура.Количество());
						
						// Получаем имя пакета как слово после КАК во вложенном запросе
						НачальнаяПозиция = ПозицияВГлобальномТексте + НомерПодбуквы;
						СловоКАК = ПолучитьСлово(ГлобальныйТекстЗапроса, НачальнаяПозиция, , Истина, МассивСпециальныхСимволов, НачальнаяПозиция);
						Если СловоКАК = "КАК" Тогда
							ИмяПакета = ПолучитьСлово(ГлобальныйТекстЗапроса, НачальнаяПозиция + 4, , Истина, МассивСпециальныхСимволов);		
							Если ИмяПакета = "" Тогда
								ВызватьИсключение("СП. Не смогли определить имя пакета!");	
							КонецЕсли;
						Иначе
							ВызватьИсключение("СП. Не смогли определить имя пакета!");
						КонецЕсли;						
						
						// Проверка на уникальность будущего пакета
						Если МассивИменПакетов.Найти(ИмяПакета) = Неопределено Тогда
							МассивИменПакетов.Добавить(ИмяПакета);	
						Иначе
							Индекс = 0;
							Пока Истина Цикл
								Индекс = Индекс + 1;
								ИмяНовое = ИмяПакета + "_ИзВложенногоЗапроса" + Строка(Индекс);
								Если МассивИменПакетов.Найти(ИмяНовое) = Неопределено Тогда
									ИмяПакета = ИмяНовое;
		                        	МассивИменПакетов.Добавить(ИмяПакета);
									Прервать;
								КонецЕсли;
							КонецЦикла;
						КонецЕсли;
						
						Структура.Вставить(Ключ, Новый Структура("ТекстЗапроса, ИмяПакета, ПозицияНачалаСоСкобкой, ПозицияОкончанияСоСкобкой, ПозицияИз, Подзапросы", ТекстПодзапросаБезСкобок, ИмяПакета, ПозицияВГлобальномТексте - 1 + НомерБуквы, ПозицияВГлобальномТексте - 1 + НомерПодбуквы, ПозицияИз));
						Структура[Ключ].Подзапросы = ПолучитьСтруктуруПодзапросов(ТекстПодзапросаБезСкобок, ПозицияВГлобальномТексте + НомерБуквы, ГлобальныйТекстЗапроса, МассивИменПакетов);		
						НомерБуквы = НомерПодбуквы + 1;
						Прервать;
					КонецЕсли;
					// Проверим, что скобки закрылись, значит подзапрос закрывается
					// --
					
				КонецЦикла;			
			КонецЕсли;
		КонецЕсли;
		// Определяем, что это начало нового запроса
		// --
		
	КонецЦикла; 
	// Перебираем текст по символьно
	// --
	
	Возврат Структура;
	
КонецФункции

// Функция получает тексты подзапросов из структуры подзапросов
// МассивВырезок - нужен для накопления информации о подзапросах
Функция ПолучитьТекстПодзапросов(Знач ГлобальныйТекстЗапроса, Подзапросы, МассивВырезок)
	ТекстЗапроса = "";
	
	Для Каждого Подзапрос Из Подзапросы Цикл
		
		// Добавляем вырезку текушего подзапроса
		МассивВырезок.Добавить(Новый Структура("ПозицияНачала, ПозицияОкончания, ТекстЗапроса", Подзапрос.Значение.ПозицияНачалаСоСкобкой, Подзапрос.Значение.ПозицияОкончанияСоСкобкой, Подзапрос.Значение.ИмяПакета));	
		
		// Получаем подзапросы подзапроса, потом получаем текст подзапроса
		МассивПодвырезок = Новый Массив;
		ТекстПодзапросов = ПолучитьТекстПодзапросов(ГлобальныйТекстЗапроса, Подзапрос.Значение.Подзапросы, МассивПодвырезок);
		ТекстЗапроса = ТекстЗапроса + ?(ТекстЗапроса = "" Или ТекстПодзапросов = "", "", ";") + ТекстПодзапросов;
		
		ТекстПодзапроса = 
		Сред(ГлобальныйТекстЗапроса, Подзапрос.Значение.ПозицияНачалаСоСкобкой + 1, Подзапрос.Значение.ПозицияИз - Подзапрос.Значение.ПозицияНачалаСоСкобкой - 1)
		+ 
		" ПОМЕСТИТЬ " + Подзапрос.Значение.ИмяПакета + " "
		+ 
		ПолучитьВырезкуТекста(ГлобальныйТекстЗапроса, Подзапрос.Значение.ПозицияИз, Подзапрос.Значение.ПозицияОкончанияСоСкобкой - 1, МассивПодвырезок);
	
		ТекстЗапроса = ТекстЗапроса + ?(ТекстЗапроса = "" Или ТекстПодзапроса = "", "", ";") + ТекстПодзапроса;
		
		//// Объединим массив подвырезок с массивом вырезок
		//Для Каждого Элемент Из МассивПодвырезок Цикл
		//	МассивВырезок.Добавить(Элемент);	
		//КонецЦикла;                                    

	КонецЦикла;
	
	Возврат ТекстЗапроса;
КонецФункции

// Функция получает вырезку из текста с учётом всех фрагментов, которые должны быть вырезаны внутри неё
// МассивВырезок - сожержит элементы - структуры (ПозицияНачала, ПозицияОкончания, ТекстЗапроса = ""), где ТекстЗапроса - будет вставлено вместо вырезаемого текста
Функция ПолучитьВырезкуТекста(ГлобальныйТекстЗапроса, ПозицияНачала, ПозицияОкончания, Знач МассивВырезок)
	
	// --
	// Строим МассивТочекТекста
	
	// Массив, элементами которого будет структура(Позиция, ТекстЗапроса = "")
	// Если ТекстЗапроса заполнено, то вместо текста между позициями, берём этот текст
	МассивТочекТекста = Новый Массив;
	
	МассивТочекТекста.Добавить(Новый Структура("Позиция, ТекстЗапроса", ПозицияНачала, ""));
	
	Для Каждого Вырезка Из МассивВырезок Цикл
		Если ПозицияНачала <> Вырезка.ПозицияНачала Тогда
			МассивТочекТекста.Добавить(Новый Структура("Позиция, ТекстЗапроса", Вырезка.ПозицияНачала, Вырезка.ТекстЗапроса));
		КонецЕсли;
		Если ПозицияОкончания <> Вырезка.ПозицияОкончания Тогда
			МассивТочекТекста.Добавить(Новый Структура("Позиция, ТекстЗапроса", Вырезка.ПозицияОкончания, ""));
		КонецЕсли;
	КонецЦикла;
	
	МассивТочекТекста.Добавить(Новый Структура("Позиция, ТекстЗапроса", ПозицияОкончания, ""));
	
	// Строим МассивТочекТекста
	// --
	
	// --
	// Формируем текст
	ТекстЗапроса = "";
	
	ПозицияПрошлая = Неопределено;
	ТекстПрошлый = "";
	Для Каждого ТочкаТекста Из МассивТочекТекста Цикл
		Если ПозицияПрошлая <> Неопределено Тогда
			Если ТекстПрошлый <> "" Тогда
				ТекстЗапроса = ТекстЗапроса + ТекстПрошлый;
			Иначе
				ТекстЗапроса = ТекстЗапроса + Сред(ГлобальныйТекстЗапроса, ПозицияПрошлая, ТочкаТекста.Позиция - ПозицияПрошлая);
			КонецЕсли;
		КонецЕсли;
		
		ПозицияПрошлая = ТочкаТекста.Позиция;
		ТекстПрошлый = ТочкаТекста.ТекстЗапроса;
	КонецЦикла;	
	// Формируем текст
	// --
	
	Возврат ТекстЗапроса;
	
КонецФункции

// СловоИсключение - содержит символы, которые не являются специальными символами
Функция ПолучитьМассивСпециальныхСимволов(СловоИсключение = "")
	МассивДляВозврата = Новый Массив;
	
	Массив = Новый Массив;
	
	Массив.Добавить(Символы.ВК);
	Массив.Добавить(Символы.ВТаб);
	Массив.Добавить(Символы.НПП);
	Массив.Добавить(Символы.ПС);
	Массив.Добавить(Символы.ПФ);
	Массив.Добавить(Символы.Таб); 
	Массив.Добавить(")");
	Массив.Добавить("(");
	Массив.Добавить("{");
	Массив.Добавить(".");
	Массив.Добавить(",");
	Массив.Добавить(";");
	Массив.Добавить(" ");
	
	Для Каждого Символ Из Массив Цикл
		Если Найти(СловоИсключение, Символ) = 0 Тогда
			МассивДляВозврата.Добавить(Символ);	
		КонецЕсли;
	КонецЦикла;
	
	Возврат МассивДляВозврата;
КонецФункции

// Функции редактирования запроса
// --

// --
// Дополнительные строковые функции

// Функция разбивает текст на слова и возвращает массив.
// Если нужно получить конкретное количество слов, то
// надо задать параметр НужноСлов.
// В случае если найденных слов меньше показателя НужноСлов, то
// оставшиеся элементы массива будут заданы значением ТекстЗаменыНенайденных.
//
// Параметры
//	- ТекстЗапроса:Строка - текст, в котором ищем слова, разделенные символом
//	- Символ:Строка - символ разделения
//	- НужноСлов:Число - нужно элементов в возвращаемом массиве
//	- ТекстЗаменыНенайденных:Строка - текст, в котором ищем слова, разделенные символом
//  - СимволыКоторыеДолжныЗакрываться:Массив - массив символов, которые в нутри слова должны иметь четное количество или 0. Например в слове не может быть одной открывающей кавычки
//
// Возвращаемое значение:
//	МассивСлов:Массив – массив, элементами которого являются части переданного в функцию текст
//
Функция ПолучитьМассивСловРазделенныхСимволом(Знач ТекстЗапроса, Символ, НужноСлов = 0, ТекстЗаменыНенайденных = "", СимволыКоторыеДолжныЗакрываться = Неопределено) Экспорт
		
	// --
	// Массив слов для возврата
	МассивСлов = Новый Массив();
	// --
	
	// --
	// Предварительно удалаем повтор заданного символа в слове
	ТекстЗапроса = УдалитьДублирующиеСимволы(ТекстЗапроса, Символ);
	// --
	
	// --
	// Находим позицию первого Символа
	ПозицияСимвола = Найти(ТекстЗапроса, Символ);
	// --
	
	// --
	// Перебираем все позиции Символа
	Пока ПозицияСимвола <> 0 Цикл
		
		// Получаем слово и заносим его в массив
		Слово = Лев(ТекстЗапроса, ПозицияСимвола - 1);		
		
		// --
		// Проверка на СимволыДолжныЗакрываться
		Если СимволыКоторыеДолжныЗакрываться <> Неопределено Тогда
			ВыйтиИзВерхнегоЦикла = Ложь;
			
			// --
			// Перебираем символы, которые должны закрываться
			Для Каждого СимволКоторыйДолженЗакрываться Из СимволыКоторыеДолжныЗакрываться Цикл
				ЧислоВхождений = СтрЧислоВхождений(Слово, СимволКоторыйДолженЗакрываться);
				Если ЧислоВхождений <> 0 Тогда
					РезультатДеления = ЧислоВхождений / 2;
					Если РезультатДеления <> Окр(РезультатДеления, 0) Тогда
						ТекстПослеВхожденияСимвола = Сред(ТекстЗапроса, ПозицияСимвола + 1, СтрДлина(ТекстЗапроса));
						НоваяПозиция = Найти(ТекстПослеВхожденияСимвола, Символ);
						Если НоваяПозиция = 0 Тогда
							ПозицияСимвола = 0;
						Иначе							
							ПозицияСимвола = ПозицияСимвола + НоваяПозиция;	
						КонецЕсли;
						// Если находим случай незакрытого символа, то входим в цикл по новому
						ВыйтиИзВерхнегоЦикла = Истина;
						Прервать;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
			// Перебираем символы, которые должны закрываться
			// --
			
			Если ВыйтиИзВерхнегоЦикла = Истина Тогда
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		// Проверка на СимволыДолжныЗакрываться
		// --
		
		МассивСлов.Добавить(Слово);
		
		// Уменьшаем количество НужноСлов
		НужноСлов = НужноСлов - 1;
		
		// Обрезаем текст
		ТекстЗапроса = Прав(ТекстЗапроса, СтрДлина(ТекстЗапроса) - ПозицияСимвола);
		
		// Находим позицию следующего Символа
		ПозицияСимвола = Найти(ТекстЗапроса, Символ);
		
	КонецЦикла;
	// --
	
	// --
	// Добавляем последнее слово
	МассивСлов.Добавить(ТекстЗапроса);
	// --
	
	// --
	// Дополняем при необходимости массив пустыми значениями
	Для Нумератор = 1 По НужноСлов Цикл 
		МассивСлов.Добавить(ТекстЗаменыНенайденных); 
	КонецЦикла;
	// --
	
	// --
	// Возвращаем массив
	Возврат МассивСлов;
	// --
	
КонецФункции

// Функция удаления дублирующих символов в строке
//
// Параметры
//	- ТекстЗапроса:Строка - строка, из которой удаляем дублирующие символы
//	- ТекстЗапроса:Символ - строка, которая является разделительным символом в строку замены
//	- НужноСлов:Число - нужно слов, разделенных в данной строке заданным символом
//	- ТекстЗаменыНенайденных:Строка - строки, которые добавляются для достижения нужного количества слов
//
// Возвращаемое значение:
//	ТекстЗапроса:Строка – отредактированная строка ТекстЗапроса 
//
//&НаСервере
Функция УдалитьДублирующиеСимволы(Знач ТекстЗапроса, ТекстУдаления) Экспорт
	
	// --
	// Определяем длину текста удаления
	ДлинаТекстаУдаленияТекст = СтрДлина(ТекстУдаления);
	// --
	
	// --
	// Удаляем дублирующие символы
	Пока Найти(ТекстЗапроса, ТекстУдаления + ТекстУдаления) <> 0 Цикл 
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ТекстУдаления + ТекстУдаления, ТекстУдаления); 
	КонецЦикла;
	// --
	
	// --
	// Обрезаем пробелы
	ТекстЗапроса = СокрЛП(ТекстЗапроса); 
	// --
	
	// --
	// Удалям заданный символ из начала и конца строки: слева и справа
	// Слева
	Если Лев(ТекстЗапроса, ДлинаТекстаУдаленияТекст) = ТекстУдаления Тогда
		ТекстЗапроса = Прав(ТекстЗапроса, СтрДлина(ТекстЗапроса) - ДлинаТекстаУдаленияТекст);	
	КонецЕсли;
	
	// Справа
	Если Прав(ТекстЗапроса, ДлинаТекстаУдаленияТекст) = ТекстУдаления Тогда
		ТекстЗапроса = Лев(ТекстЗапроса, СтрДлина(ТекстЗапроса) - ДлинаТекстаУдаленияТекст);	
	КонецЕсли;
	// --
	
	// --
	// Возвращаем отредактированный текст
	Возврат ТекстЗапроса;
	// --
	
КонецФункции

// Разбивает строку вида ключ=значение;ключ2=значение;
// где СимволМеждуКлючомИЗначением - =, СимволМеждуЗначениемИКлючом - ; 
Функция ПолучитьСтрктуруЗначенийИзСтроки(Знач ТекстЗапроса, СимволМеждуКлючомИЗначением, СимволМеждуЗначениемИКлючом, СимволыКоторыеДолжныЗакрываться)
	
	Структура = Новый Структура;
	
	МассивКлючЗначение = ПолучитьМассивСловРазделенныхСимволом(ТекстЗапроса, СимволМеждуЗначениемИКлючом, , , СимволыКоторыеДолжныЗакрываться);
	Для Каждого КлючЗначение Из МассивКлючЗначение Цикл
		Массив = ПолучитьМассивСловРазделенныхСимволом(КлючЗначение, СимволМеждуКлючомИЗначением, , , СимволыКоторыеДолжныЗакрываться);
		Если Массив.Количество() = 2 Тогда
			Структура.Вставить(Массив[0], Массив[1]);			
		Иначе
			// Что-то распарсили не так, возможно надо вызвать ошибку
		КонецЕсли;
	КонецЦикла;
	
	Возврат Структура;
	
КонецФункции

// Получает следующее слово в тексте
// ОбходВперед - Слово должно быть за начальной позицией или до начальной позиции
// НачальнаяПозицияСкорректированная - служит для возврата скорректированной начальной позиции
Функция ПолучитьСлово(ТекстЗапроса, Знач НачальнаяПозиция, КорриктороватьНачальнуюПозицию = Ложь, ОбходВперед = Истина, МассивСпециальныхСимволов, НачальнаяПозицияСкорректированная = Неопределено)
		
	ДлинаТекста = СтрДлина(ТекстЗапроса);
	
	// --
	// Подредактировать начальную позицию.
	// Например, если начальная позиия не верна, равна пробелу, то нужно увеличить вправо начальную позицию, чтобы добравться до первой буквы
	// и потом получить начиная с неё слово
	Если КорриктороватьНачальнуюПозицию = Истина Тогда
		
		Если ОбходВперед = Истина Тогда
			Для НомерБуквы = НачальнаяПозиция По ДлинаТекста Цикл				
				Если МассивСпециальныхСимволов.Найти(Сред(ТекстЗапроса, НомерБуквы, 1)) = Неопределено Тогда				
					НачальнаяПозиция = НачальнаяПозиция + 1;				
				Иначе				
					Прервать;				
				КонецЕсли;				
			КонецЦикла;
		Иначе
			Пока НачальнаяПозиция <> 0 Цикл
				Если МассивСпециальныхСимволов.Найти(Сред(ТекстЗапроса, НачальнаяПозиция, 1)) <> Неопределено Тогда
					НачальнаяПозиция = НачальнаяПозиция - 1;	
				Иначе
					Прервать;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
	КонецЕсли;
	
	НачальнаяПозицияСкорректированная = НачальнаяПозиция;
	// Подредактировать начальную позицию.
	// Например, если начальная позиия не верна, равна пробелу, то нужно увеличить вправо начальную позицию, чтобы добравться до первой буквы
	// и потом получить начиная с неё слово
	// --
	
	// --
	// Ищем конец слова
	Если ОбходВперед = Истина Тогда
		Для НомерБуквы = НачальнаяПозиция По ДлинаТекста Цикл
			Если МассивСпециальныхСимволов.Найти(Сред(ТекстЗапроса, НомерБуквы, 1)) <> Неопределено 
				Или
				НомерБуквы = ДлинаТекста
				Тогда
				
				// --
				// Возвращаем найденное слово
				// Если слово последнее в тексте (НомерБуквы = ДлинаТекста), то возвращаем с последним символом
				НайденноеСлово = Сред(
				ТекстЗапроса,
				НачальнаяПозиция,
				НомерБуквы - НачальнаяПозиция + ?(НомерБуквы = ДлинаТекста, 1, 0)
				); 
				Возврат НайденноеСлово;
				// --
				
			КонецЕсли;
		КонецЦикла;
	Иначе
		НомерБуквы = НачальнаяПозиция;
		Пока НомерБуквы <> 0 Цикл
			Если МассивСпециальныхСимволов.Найти(Сред(ТекстЗапроса, НомерБуквы, 1)) <> Неопределено
				Или
				НомерБуквы = 0
				Тогда
				
				// --
				// Возвращаем найденное слово
				// Если слово последнее в тексте (НомерБуквы = ДлинаТекста), то возвращаем с последним символом
				НайденноеСлово = Сред(
				ТекстЗапроса,
				НомерБуквы + ?(НомерБуквы = 0, 0, 1),
				НачальнаяПозиция - НомерБуквы
				); 
				Возврат НайденноеСлово;
				// --
				
			КонецЕсли;
			НомерБуквы = НомерБуквы - 1;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Дополнительные строковые функции
// --

 

Запросы 1С вложенные запросы 1С пакетные запросы в 1С оптимизация запросов 1С

См. также

SALE! 20%

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

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

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

13000 10400 руб.

02.09.2020    122137    670    389    

714

SALE! 25%

Infostart PrintWizard

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

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

18000 15300 руб.

06.10.2023    7288    21    6    

39

SALE! 20%

Infostart УДиФ: Управление данными и формами

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

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

10000 8000 руб.

10.11.2023    3531    11    1    

34

SALE! 30%

PowerTools

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

Универсальный инструмент программиста для администрирования конфигураций. Сборник наиболее часто используемых обработок под единым интерфейсом.

3600 2520 руб.

14.01.2013    177744    1073    0    

849

Многопоточность. Универсальный «Менеджер потоков» 2.1

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Восстановление партий или взаиморасчетов, расчет зарплаты, пакетное формирование документов или отчетов - теперь все это стало доступнее. * Есть желание повысить скорость работы медленных алгоритмов! Но... * Нет времени думать о реализации многопоточности? * о запуске и остановке потоков? * о поддержании потоков в рабочем состоянии? * о передаче данных в потоки и как получить ответ из потока? * об организации последовательности? Тогда ЭТО - то что надо!!!

5000 руб.

07.02.2018    99345    239    97    

296

[ЕХТ] Фреймворк для Расширений 1С

Инструментарий разработчика Платформа 1С v8.3 Управляемые формы Платные (руб)

"Фреймворк для Расширений 1С" это универсальное и многофункциональное решение, упрощающее разработку и поддержку создаваемых Расширений. Поставляется в виде комплекта из нескольких Расширений с открытым исходным кодом. Работает в любых Конфигурациях в режиме Управляемого приложения с режимом совместимости 8.3.12 и выше без необходимости внесения изменений в Конфигурацию.

3000 руб.

27.08.2019    18109    6    8    

39

1С HTML Шаблоны / HTML Templates

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Быстрая и удобная обработка для работы с шаблонами HTML. Позволяет легко и быстро формировать код HTML.

2040 руб.

27.12.2017    28108    3    10    

15

Выполнение произвольного кода или запроса с параметрами через Web-сервис (замена COM-подключений)

Инструментарий разработчика Обмен между базами 1C Платформа 1С v8.3 Платные (руб)

В процессе работы в 1С часто возникает потребность получить данные из другой базы.  Обычно это делается через COM-соединение, и время выполнения запроса при этом оставляет желать лучшего. В данной публикации представлено универсальное решение, позволяющее практически моментально выполнить произвольный код или запрос с параметрами в другой информационной базе через Web-сервис.

2400 руб.

24.09.2019    23601    15    15    

32
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Bazin 5 30.08.16 12:19 Сейчас в теме
Интересно, нашел маленький баг, нужно добавить проверку СтрДлина(ИмяПакета) > 0:
// Проверка на уникальность будущего пакета
	Если МассивИменПакетов.Найти(ИмяПакета) = Неопределено И СтрДлина(ИмяПакета) > 0 Тогда
		МассивИменПакетов.Добавить(ИмяПакета);	

2. ostapchenko.alexandr 21 30.08.16 12:31 Сейчас в теме
(1) Bazin, Здравствуйте, а как может ИмяПакета быть пустой строкой? Имя пакета берётся из вложенного запроса после слова КАК. Т.е. в запросе
ВЫБРАТЬ
	ВложенныйЗапрос.Ссылка
ИЗ
	(ВЫБРАТЬ
		Банки.Ссылка КАК Ссылка
	ИЗ
		Справочник.Банки КАК Банки) КАК ВложенныйЗапрос
Показать

ВложенныйЗапрос - это ИмяПакета. Разве есть вложенные запросы без КАК ... ?
3. Bazin 5 30.08.16 12:59 Сейчас в теме
Вот пример:
ВЫБРАТЬ
	ВложенныйЗапрос.Поле1
ИЗ
	(ВЫБРАТЬ
		ПОДСТРОКА(Банки.Код, 1, 9) КАК Поле1
	ИЗ
		Справочник.Банки КАК Банки
	
	СГРУППИРОВАТЬ ПО
		ПОДСТРОКА(Банки.Код, 1, 9)) КАК ВложенныйЗапрос
Показать
4. Bazin 5 30.08.16 13:06 Сейчас в теме
А вот вообще без "КАК"
ВЫБРАТЬ
	ВложенныйЗапрос.Поле1
ИЗ
	(ВЫБРАТЬ
		1 КАК Поле1
	
	ОБЪЕДИНИТЬ ВСЕ
	
	ВЫБРАТЬ
		2) КАК ВложенныйЗапрос
Показать
5. Bazin 5 30.08.16 13:19 Сейчас в теме
И вот такой, "Временная таблица уже существует":
ВЫБРАТЬ
	Банки.Ссылка
ПОМЕСТИТЬ Банки
ИЗ
	Справочник.Банки КАК Банки
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ВложенныйЗапрос.Ссылка
ИЗ
	(ВЫБРАТЬ
		Банки.Ссылка КАК Ссылка
	ИЗ
		Банки КАК Банки) КАК ВложенныйЗапрос
Показать
6. ostapchenko.alexandr 21 30.08.16 14:19 Сейчас в теме
(5) Bazin, Спасибо! Все замечания исправил.
7. DrAku1a 1679 31.08.16 10:52 Сейчас в теме
У меня в отладчике запросов - это реализовано, года так три назад...
http://infostart.ru/public/190493/#UnwrapQueryToBatch
8. Bazin 5 01.09.16 06:21 Сейчас в теме
9. kiruha 388 01.09.16 12:33 Сейчас в теме
(7)Мощная вещь, но к сожалению там обычные формы, на современных конфигурациях(управляемые) не открываются даже если выбрать толстый клиент управляемое приложение. Так что автору плюс за алгоритм, но просьба для в запросник для управляемых добавить
12. ostapchenko.alexandr 21 01.09.16 20:34 Сейчас в теме
(9) kiruha, на управляемых формах должно работать, все функции выполняются на сервере
14. tormozit 7136 02.09.16 09:49 Сейчас в теме
(9)
на современных конфигурациях(управляемые) не открываются даже если выбрать толстый клиент управляемое приложение
надо выбирать Толстый клиент обычное приложение, а не управляемое.
10. uri1978 137 01.09.16 17:54 Сейчас в теме
(7) DrAku1a, Но при этом сам обработчик толком не работает. Уж извините за пост в защиту автора.
А если добавить что есть комментарий к Вашему обработчику:
13.06.2013 12:37
Функция "Разложить вложенный запрос в пакетный" (ноухау)
...
Это довольно интересная функция - нигде такого не встречал.

Кто не хочет видеть, тот не видит =) В консоли запросов из подсистемы "Инструменты разработчика" это уже давно есть. В описании есть такая функция "Вынести в новый запрос" и даже на картинке видно http://devtool1c.ucoz.ru/index/konsol_zaprosov/0-18
Ссылка на сообщение
То совсем весело.

Эх-х-х если бы Вы его довели до ума, цены бы не было.
13. tormozit 7136 02.09.16 07:56 Сейчас в теме
Бездумно выносить все вложенные запросы в отдельные запросы пакета вредно. Временные таблицы имеют свои накладные расходы. Поэтому выносить оправдано те подзапросы, для которых эти расходы будут меньше "сложности" для построения плана запроса, вносимой подзапросом. Поэтому то и была сделана команда для выборочного вынесения (10)
17. Bazin 5 05.09.16 05:25 Сейчас в теме
(13) tormozit, Публикация начинается со слов "Запросы неудобно отлаживать...", а не использовать
18. tormozit 7136 05.09.16 07:27 Сейчас в теме
(17) Согласен, чисто для отладки такое может быть полезно быть полезно с учетом того, что нет возможности использовать дерево запроса. Однако связь частей полученного пакетного запроса с частями оригинального запроса может быть довольно ненаглядной после переноса всех подзапросов во временные таблицы.
19. DrAku1a 1679 08.09.16 02:46 Сейчас в теме
(10) uri1978, Как обычно, руки не доходят сделать. Да и смысл? Есть же хорошая консоль от ИР (в т.ч. мобильных ИР).
Сам - пользуюсь отладчиком, мне удобно - то, что разделил всё по вкладкам. В итоге - большое окно для редактирования текста запроса, большое окно для просмотра результата, и ничего лишнего.
11. ostapchenko.alexandr 21 01.09.16 20:30 Сейчас в теме
Если данный алгоритм не работает на каких-либо примерах, присылайте, буду править.
15. Ovrfox 14 02.09.16 10:59 Сейчас в теме
А еще добавлять обработки на УФ в конфигурацию. чтобы они открывались.
Этот вариант не для того, чтобы к конфе на УФ добавить обычную обработку, а как раз наоборот
К обычной конфе добавить обработку на УФ.

Т.е не реально использовать эту обработку на УФ конфе, чтобы при этом конфа еще и работала.
16. МимохожийОднако 141 03.09.16 09:02 Сейчас в теме
ОФФ наверное. Маленькое замечание. В режиме отладки, если не применять специальные инструменты можно использовать метод Запрос.ВыполнитьПакетСПромежуточнымиРезультатами()
После отладки можно вернуть метод ВыполнитьПакет() на место
20. ostapchenko.alexandr 21 01.12.17 12:54 Сейчас в теме
Исправил
ПрошлоеСлово <> "ВСЕ" И ПрошлоеСлово <> "ОБЪЕДИНИТЬ" И ПрошлоеСлово <> "В" Тогда
на
ПрошлоеСлово <> "ВСЕ" И ПрошлоеСлово <> "ОБЪЕДИНИТЬ" И ПрошлоеСлово <> "В" И ПрошлоеСлово <> "ИЕРАРХИИ" Тогда
Оставьте свое сообщение