gifts2017

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

Опубликовал Александр Остапченко (ostapchenko.alexandr) в раздел Программирование - Инструментарий

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

Для отладки запросов 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;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

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

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

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

См. также

Подписаться Добавить вознаграждение

Комментарии

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

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

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

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

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

Эх-х-х если бы Вы его довели до ума, цены бы не было.
11. Александр Остапченко (ostapchenko.alexandr) 01.09.16 20:30
Если данный алгоритм не работает на каких-либо примерах, присылайте, буду править.
12. Александр Остапченко (ostapchenko.alexandr) 01.09.16 20:34
(9) kiruha, на управляемых формах должно работать, все функции выполняются на сервере
13. Сергей Старых (tormozit) 02.09.16 07:56
Бездумно выносить все вложенные запросы в отдельные запросы пакета вредно. Временные таблицы имеют свои накладные расходы. Поэтому выносить оправдано те подзапросы, для которых эти расходы будут меньше "сложности" для построения плана запроса, вносимой подзапросом. Поэтому то и была сделана команда для выборочного вынесения (10)
14. Сергей Старых (tormozit) 02.09.16 09:49
(9)
на современных конфигурациях(управляемые) не открываются даже если выбрать толстый клиент управляемое приложение
надо выбирать Толстый клиент обычное приложение, а не управляемое.
15. Олег Родионов (Ovrfox) 02.09.16 10:59
А еще добавлять обработки на УФ в конфигурацию. чтобы они открывались.
Этот вариант не для того, чтобы к конфе на УФ добавить обычную обработку, а как раз наоборот
К обычной конфе добавить обработку на УФ.

Т.е не реально использовать эту обработку на УФ конфе, чтобы при этом конфа еще и работала.
16. Александр (МимохожийОднако) 03.09.16 09:02
ОФФ наверное. Маленькое замечание. В режиме отладки, если не применять специальные инструменты можно использовать метод Запрос.ВыполнитьПакетСПромежуточнымиРезультатами()
После отладки можно вернуть метод ВыполнитьПакет() на место
17. Denis Bazin (Bazin) 05.09.16 05:25
(13) tormozit, Публикация начинается со слов "Запросы неудобно отлаживать...", а не использовать
18. Сергей Старых (tormozit) 05.09.16 07:27
(17) Согласен, чисто для отладки такое может быть полезно быть полезно с учетом того, что нет возможности использовать дерево запроса. Однако связь частей полученного пакетного запроса с частями оригинального запроса может быть довольно ненаглядной после переноса всех подзапросов во временные таблицы.
19. Андрей Акулов (DrAku1a) 08.09.16 02:46
(10) uri1978, Как обычно, руки не доходят сделать. Да и смысл? Есть же хорошая консоль от ИР (в т.ч. мобильных ИР).
Сам - пользуюсь отладчиком, мне удобно - то, что разделил всё по вкладкам. В итоге - большое окно для редактирования текста запроса, большое окно для просмотра результата, и ничего лишнего.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа