gifts2017

Обращение к результатам пакетного запроса по именам

Опубликовал Яков Коган (Yashazz) в раздел Программирование - Практика программирования

Пакетный запрос возвращает массив результатов, обращаться к которым можно лишь по индексам. При изменениях запроса индексы сбиваются. Их много. Их трудно помнить и считать, тыкая пальцем по порядку. Упростим себе жизнь!

Используется это так: в тексте запроса, например, рядом с "итоговой" выборкой, результат которой надо будет получить из пакетного запроса, пишется некое ключевое слово и указывается осмысленное имя для этого результата. Например:

ВЫБРАТЬ ДыраВКармане.Виновник ПОМЕСТИТЬ ВТ_КтоКрайний
ИЗ РегистрыРазорения.Убытки(&ДеньПослеКорпоратива) КАК ДыраВКармане;
ВЫБРАТЬ * ИЗ Справочник.VIP КАК Оборзевшие ГДЕ Оборзевшие.Пол = "М";
ВЫБРАТЬ //ИмяРезультата:МояНужнаяВыборка
Крайние.Виновник.Фамилия,
Крайние.Виновник.Адрес,
ИЗ ВТ_КтоКрайний КАК Крайние

Обратим внимание на строку "//ИмяРезультата:МояНужнаяВыборка" - это и есть желаемая маркировка блока в пакете.

Готовый текст запроса (до или после его выполнения, неважно) передаётся этой функции:

// Возвращает соответствие, где ключ - строковое имя результата в пакетном запросе, а значение - его числовой индекс.
// Параметры:
//    тзИсходная - строка, исходный текст запроса, который следует обработать;
//    рМаркер - строка, предваряющая имя результата в исходном тексте запроса.
//
Функция ПостроитьСоответствиеИмёнИНомеровРезультатовПакетногоЗапроса(тзИсходная,рМаркер="")
	соотИмён=Новый Соответствие;
	//
	Если ПустаяСтрока(рМаркер) Тогда рМаркер="//ИмяРезультата:" КонецЕсли;
	рДлинаМаркера=СтрДлина(рМаркер);
	рРазделители="?,=\|:;&"" @#$^!~`'[]{}№+-/*%()<>"+Символы.ВК+Символы.ВТаб+Символы.НПП+Символы.ПС+Символы.ПФ+Символы.Таб;
	//
	тзПлоская=СтрЗаменить(тзИсходная,Символы.ПС,Символы.Таб);
	тзПлоская=СтрЗаменить(тзПлоская,";",Символы.ПС);
	Для й=1 По СтрЧислоСтрок(тзПлоская) Цикл
		стрБлок=СтрПолучитьСтроку(тзПлоская,й);
		пози=Найти(стрБлок,рМаркер);
		Если пози=0 Тогда Продолжить КонецЕсли;
		рДлинаБлока=СтрДлина(стрБлок);
		пози=пози+рДлинаМаркера;
		резИмя="";
		Для ы=пози По рДлинаБлока Цикл
			сим=Сред(стрБлок,ы,1);
			Если Найти(рРазделители,сим)<>0 Тогда Прервать КонецЕсли;
			резИмя=резИмя+сим;
		КонецЦикла;
		Если не ПустаяСтрока(резИмя) Тогда
			соотИмён.Вставить(резИмя,й-1);
		КонецЕсли;
	КонецЦикла;
	//
	Возврат соотИмён;
КонецФункции

После можно работать с полученным соответствием следующим образом:

НужныйРезультат=МассивРезультатов.Получить(соотИмён.Получить("МояНужнаяВыборка")); // ну и можно проверку, получено ли

Собственно, всё. Эта мелочь сильно упрощает работу, если текст запроса часто перетасовывается, меняется, или если в нём более 5-7 "финальных" фрагмента, чьи данные нужны, и компонуется он в разных местах кода. Ведь достаточно появиться одному дополнительному "Выбрать" или "Уничтожить", чтобы ВСЯ нумерация поехала известно куда. А так можно не беспокоиться, которым по счёту идёт получение нужной вам выборки.

Жаль, что разработчики платформы не предусмотрели подобные зарезервированные слова и конструкции в тексте запроса и получение по ним средствами языка. Пришлось эмулировать)

Хотел было сделать через схему запроса (новомодную объектную технику), но - упс, она игнорирует комментарии как таковые. Зато этот подход можно применять и на 8.2, где схем запроса нет в принципе.

Почти наверняка это велосипед, и многие, столкнувшиеся с проблемой раньше меня, уже сделали себе такие "костыльчики", но супруга сказала - публиковать. Вот я и публикую)  Если баян, просьба кинуть в меня тапкой ссылкой.

Кому пригодится, передайте дальше)

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Сергей Ожерельев (Поручик) 25.04.16 15:20
Действительно, стоит добавить запрос в пакет и надо перенумеровывать выборки в коде и потом заново отлаживать.
2. Яков Коган (Yashazz) 25.04.16 17:35
Ах да, естественно, имя результата должно удовлетворять нотации имён переменных в 1С.
3. Андрей Карпов (karpik666) 25.04.16 17:51
Я так понимаю, любое неосторожное использование конструктора запроса затрет эти имена таблиц, не помню только в 1С добавил поддержку комментариев в конструкторе или нет, но идея интересная.
4. Яков Коган (Yashazz) 25.04.16 18:10
(3) karpik666, затрёт, конечно. Но подобные монструозные запросы уже и не рассчитаны на конструктор. Они собираются по частям, иногда в разных блоках кода, изобилуют нечитаемыми для конструктора кусками, и потому... Терять особо нечего.
5. Сергей Старых (tormozit) 25.04.16 18:48
Конструктор запроса из подсистемы "Инструменты разработчика" не затрет такие комментарии.
6. Сергей Старых (tormozit) 25.04.16 18:59
Для тех, кто имеет доступ на партнерский форум 1С, приведу ссылку на одну из тем где это обсуждалось https://partners.v8.1c.ru/forum/topic/1182939
Думаю скоро это добавят в платформе.
7. Яков Коган (Yashazz) 25.04.16 19:49
(6) tormozit, ага, оно самое. Приятно, что не мне одному сие показалось неудобно; спасибо за ссылку.
Честно говоря, вообще впервые имел дело с большим пакетным запросом, раньше как-то везло. А тут... Не вынесла душа поэта))
8. борян петров (TODD22) 26.04.16 12:31
(6) tormozit,
Думаю скоро это добавят в платформе.

Из топика по ссылке таких выводов сделать нельзя...
9. Денис (konstruktiv) 26.04.16 15:56
(4) Yashazz, круто, а ведь наверное можно "идентификатор" результата в пакете поместить не как комментарий, а в виде фиктивного поля в выборке в самом запросе:
...
;
ВЫБРАТЬ
"МояНужнаяВыборка" КАК IDРезультат,
Крайние.Виновник.Фамилия,
Крайние.Виновник.Адрес ...

или
...
0 КАК ID_МояНужнаяВыборка,
...

Ну и доработать функцию, которая строит соответствие. Плюс в том, что эта конструкция не затрется, а минус в том, что дополнительное поле не должно повлиять на сам конечный результат вопроса, но оно вроде в большинстве случаев и не повлияет.
sevushka; Yashazz; +2 Ответить 1
10. Александр Полтава (Патриот) 26.04.16 18:13
(9) konstruktiv, ну тогда уж лучше фиктивная выборка. Никаких минусов и данных хранить в ней можно сколько душе угодно.
ВЫБРАТЬ
	"Это фиктивный пакет для записи любого количества сведений о нижеидущем пакете, которые не будут стираться конструктором запросов." КАК МаркерФиктивности,
	"МояНужнаяВыборка" КАК ИмяРезультата,
	"любой текст 1" КАК Параметр1,
	"любой текст 2" КАК Параметр2,
	"любой текст 3" КАК Параметр3
;

////////////////////////////////////////////////////////////­////////////////////
...Показать Скрыть
11. Вадим Миляев (PrinzOfMunchen) 27.04.16 06:12
(10) Патриот, не, тогда уж лучше так
//Пакет основных запросов
..........................................
..........................................
//Служебный запрос
ВЫБРАТЬ РАЗРЕШЕННЫЕ
&КоличествоЗапросовВПакете - 2 Как МойВажныйЗапрос,
&КоличествоЗапросовВПакете - 3 Как МойВлажныйЗапрос,
&КоличествоЗапросовВПакете - 4 Как МойХорошийЗапрос,
&КоличествоЗапросовВПакете - 5 Как ЗапросЛайкаБосс
...Показать Скрыть


А потом

РезультатыЗапроса = Запрос.ВыполнитьПакет();
ВыборкаПакетов = РезультатыЗапросов[РезультатыЗапросов.Количество() - 1].Выбрать();
ВыборкаПакетов.Следующий();

РезультатЗапросаЛайкаБос = ПолучитьРезультатПакетаЗапросовПоИмени(ВыборкаПакетов, "ЗапросЛайкаБосс", РезультатыЗапроса);

....................................................................

Функция ПолучитьРезультатПакетаЗапросовПоИмени(ХранилищеПакетов, ИмяПакета, ПакетРезультатов)

    Возврат ПакетРезультатов[ХранилищеПакетов.ИмяПакета];

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

...Показать Скрыть


Ну это если без проверок. )))))
12. Вадим Назаров (NazarovV) 27.04.16 06:45
Ну раз супруга сказала...) Мне пригодиться, спасибо!
13. Денис (konstruktiv) 27.04.16 06:50
(10) Патриот, тогда при редактировании запроса в конструкторе придется следить за положением запросов для идентификации результатов, быть особенно аккуратным при изменении места запроса в очереди, которая в конструкторе выглядит просто "запрос1/запрос2/.../запросN".
14. Денис (konstruktiv) 27.04.16 06:53
(11) PrinzOfMunchen, что-то я не разобрался спросонья, получается в последнем запросе опять же нужно вручную указать где какой результат, и при редактировании исходного запроса следить, чтобы эти места соответствовали реальным - от чего и хотел избавиться автор публикации?
15. Вадим Миляев (PrinzOfMunchen) 27.04.16 07:27
(14) konstruktiv, да. ) Но это так, в порядке бреда, в ответ на пост (10).
А вообще, за всю свою насыщенную 1С-кой жизнь, не натыкался на такой уж огромный запрос, который надо настолько часто редактировать, что можно забить на производительность и пойдя на поводу лени написать такую функцию, вместо того чтобы один раз указать индексы.
16. Александр (МимохожийОднако) 27.04.16 07:30
Может быть, в каждый выходной запрос добавить поле как идентификатор очередного результата?
17. Денис (konstruktiv) 27.04.16 10:12
18. Сергей Старых (tormozit) 27.04.16 11:49
В следующей версии подсистемы "Инструменты разработчика" будет широкая поддержка имен запросов и частей объединений.
19. ффф ыыы (zqzq) 27.04.16 16:49
Я обычно пишу:
последний результат запроса:
МассивРезультатов.Получить(МассивРезультатов.Количество() - 1);

Предпоследний:
МассивРезультатов.Получить(МассивРезультатов.Количество() - 2);

и т.д., так меньше вероятность словить ошибку, чем если с начала считать, т.к. новые пакеты обычно перед результирующими добавляются и нумерация с конца не сбивается. И с конца в любом случае проще считать.
fomstas; SiAl; skif47; +3 Ответить
20. Xer shi (Xershi) 27.04.16 16:54
Сегодня наткнулся на такой запрос. Его же сложно понять, в чем специфика? Скорость?
21. борян петров (TODD22) 27.04.16 16:58
(20) Xershi,
Его же сложно понять, в чем специфика? Скорость?

В том что ты читаешь данные один раз. И возвращаешь результаты нескольких запросов за один раз. А не выполняешь трижды(или сколько у тебя пакетов) чтение из базы.
22. Xer shi (Xershi) 27.04.16 17:01
(21) TODD22, т.е. только скорость и не более?
23. борян петров (TODD22) 27.04.16 17:02
(22) Xershi, Уменьшение количества обращений к базе.
24. Sergey Andreev (starik-2005) 27.04.16 17:07
(20) Xershi, в базовом функционале последних версий типовых пакетный запрос часто используется для сборки всех движений, Но там грамотно сделано, а не как у автора заметки - там используются функции, возвращающие текст запросов, которые в итоге объединяются в один пакет и за раз отправляются на сервер. Обычно первая часть запроса - это временные таблицы, в которые выбираются ТЧ документа и прочие нужные параметры.

Лично я так бы делать не стал, как в статье описано.
25. Сергей Толмачев (sss999) 27.04.16 20:53
У меня в консоли запросов есть парсинг по именам таблиц может пригодится,сделал для упр форм тоже,раньше были только обычные формы.http://infostart.ru/public/64616/
26. Сергей Афонькин (killovolt) 28.04.16 08:05
На платформе 8.3.8
Во время отладки запросов реализована возможность работы с временными таблицами: просмотр списка временных таблиц, структуры временных таблиц и содержимого временных таблиц.
Реализован метод Запрос.ВыполнитьПакетСПромежуточнымиДанными(). Реализовано свойство МенеджерВременныхТаблиц.Таблицы.
27. Сергей Старых (tormozit) 03.05.16 19:48
В версии 3.61 подсистемы "Инструменты разработчика" реализовано:

Консоль запросов
+Реализовано чтение имен запросов и частей объединений при построении дерева запроса
+Над таблицей результата пакета добавлен флажок "По именам" для вывода только именованных элементов
+Добавлен параметр мРезультатПоИменам обработчика результата для доступа к именованным элементам результата пакета
Конструктор запроса
+Реализована возможность присвоения имен запросам и частям объединений с чтением и сохранением их в комментариях

Пример текста запроса:
//{Запрос: МойЗапрос1 ////////////////////////////////////////
ВЫБРАТЬ
    1 КАК _1
;
//{Запрос: МойЗапрос2 ////////////////////////////////////////
ВЫБРАТЬ
    2 КАК _2
ОБЪЕДИНИТЬ
//{Выборка: МояВыборка1 ////////////////////////////////////////
ВЫБРАТЬ
    5 КАК _2
...Показать Скрыть


На скриншотах показан вид этого текста в дереве запроса консоли запросов и конструкторе запросов.

Пример кода:
РезультатПакета = Запрос.ВыполнитьПакет();
РезультатПоИменам = ПолучитьСтруктуруРезультатаПакетногоЗапроса(Запрос.Текст);
РезультатЗапросаМойЗапрос1 = РезультатПакета[РезультатПоИменам.МойЗапрос1];
Прикрепленные файлы: