HelpF.pro

История развития запросов: Простые запросы, Временные таблицы, Пакетные запросы

Простые запросы

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

Структура конфигурации представлена на рисунке справа: 

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

Код 1C v 8.х
 Процедура ОбработкаПроведения(Отказ, РежимПроведения)

   Запрос = Новый Запрос;
   Запрос.Текст = "
   |ВЫБРАТЬ
   |   Док.Номенклатура,
   |   СУММА(Док.Количество) КАК Док_Количество,
   |   МИНИМУМ(ЕСТЬNULL(Рег.КоличествоОстаток,0)) КАК Рег_Количество
   |
   |ИЗ
   |   Документ.Расходная.Товары КАК Док
   |   ЛЕВОЕ СОЕДИНЕНИЕ
   |     РегистрНакопления.ОстаткиТоваров.Остатки() КАК Рег
   |   ПО
   |     Док.Номенклатура = Рег.Номенклатура
   |
   |ГДЕ
   |   Ссылка =Ссылка
   |СГРУППИРОВАТЬ ПО Док.Номенклатура";

   Запрос.УстановитьПараметр("Ссылка", Ссылка);
   РезультатЗапроса = Запрос.Выполнить();
   Выборка = РезультатЗапроса.Выбрать();

   Пока Выборка.Следующий() Цикл

   //Проверка отрицательных остатков 
   //Проведение по регистру
   КонецЦикла;

КонецПроцедуры

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

Код 1C v 8.х
 |ВЫБРАТЬ
| Док.Номенклатура,
| Док.Количество КАК Док_Количество, 
| ЕСТЬNULL(Рег.КоличествоОстаток,0) КАК Рег_Количество
|
|ИЗ
| (ВЫБРАТЬ
|   Номенклатура, СУММА(Количество) КАК Количество
|  ИЗ 
|   Документ.Расходная.Товары
|  ГДЕ 
|   Ссылка =Ссылка
|  СГРУППИРОВАТЬ ПО Номенклатура) КАК Док
|
|  ЛЕВОЕ СОЕДИНЕНИЕ
|   РегистрНакопления.ОстаткиТоваров.Остатки( , Номенклатура В
|                                              (ВЫБРАТЬ РАЗЛИЧНЫЕ 
|                                                Номенклатура
|                                               ИЗ
|                                                Документ.Расходная.Товары
|                                               ГДЕ 
|                                                Ссылка =Ссылка)) КАК Рег
|  ПО
|   Док.Номенклатура = Рег.Номенклатура";

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

Временные таблицы

Не помню уже с какого релиза в запросах стало можно использовать временные таблицы. Для этого используется объект «Менеджер временных таблиц». Фактически менеджер временных таблиц описывает пространство имен временных таблиц и отвечает за их создание и уничтожение в базе данных.

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

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

Код 1C v 8.х
 Процедура ОбработкаПроведения(Отказ, РежимПроведения)


 МВТ = Новый МенеджерВременныхТаблиц;


 Запрос = Новый Запрос;
 Запрос.МенеджерВременныхТаблиц = МВТ;
 Запрос.Текст = "
 |ВЫБРАТЬ
 | Номенклатура, СУММА(Количество) КАК Количество
 |ПОМЕСТИТЬ ДокТЧ
 |ИЗ 
 | Документ.Расходная.Товары
 |ГДЕ 
 | Ссылка =Ссылка
 |СГРУППИРОВАТЬ ПО Номенклатура";


 Запрос.УстановитьПараметр("Ссылка", Ссылка);
 РезультатЗапроса = Запрос.Выполнить(); //Прим. 1


 Запрос = Новый Запрос;
 Запрос.МенеджерВременныхТаблиц = МВТ;
 Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
 | Номенклатура
 |ПОМЕСТИТЬ СписокТоваров
 |ИЗ 
 | Документ.Расходная.Товары
 |ГДЕ 
 | Ссылка =Ссылка";


 Запрос.УстановитьПараметр("Ссылка", Ссылка);
 РезультатЗапроса = Запрос.Выполнить(); //Прим. 2


 Запрос = Новый Запрос;
 Запрос.МенеджерВременныхТаблиц = МВТ;
 Запрос.Текст = "
 |ВЫБРАТЬ
 | Док.Номенклатура,
 | Док.Количество КАК Док_Количество,
 | ЕСТЬNULL(Рег.КоличествоОстаток,0) КАК Рег_Количество
 |ИЗ
 | ДокТЧ КАК Док
 | ЛЕВОЕ СОЕДИНЕНИЕ
 |  РегистрНакопления.ОстаткиТоваров.Остатки(,
 |  Номенклатура В(ВЫБРАТЬ РАЗЛИЧНЫЕ
 |                           Номенклатура
 |                          ИЗ
 |                           СписокТоваров КАК СписокТоваров)) КАК Рег
 | ПО
 |  Док.Номенклатура = Рег.Номенклатура";

 РезультатЗапроса = Запрос.Выполнить();
 Выборка = РезультатЗапроса.Выбрать();

 Пока Выборка.Следующий() Цикл

  //Проверка отрицательных остатков

  //Проведение по регистру

 КонецЦикла;

КонецПроцедуры

При использовании временных таблиц в тексте запроса применяют инструкцию Поместить для создания новой временной таблицы, в этом случае в результат запроса система передает не содержимое этой таблицы (см прим 1 и прим 2 в тексте выше), а количество записей помещенных во временную таблицу, по желанию можно не принимать это значение.

Также допускается использование инструкции Уничтожить в этом случае временная таблица уничтожается, в противном случае временные таблицы уничтожаются вместе с объектом менеджер временных таблиц.

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

Пакетные запросы

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

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

В тексте запроса, запросы пакета разделяются символом «;» (точка с запятой). Область имен виртуальных таблиц у одного пакетного запроса одна. Использование менеджера временных таблиц не требуется, но возможно если вы хотите передать временные таблицы из одного пакетного запроса в другой.

Перепишем процедуру для использования пакетных запросов:

Код 1C v 8.х
 Процедура ОбработкаПроведения(Отказ, РежимПроведения)

Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| Номенклатура, СУММА(Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары
|ГДЕ 
| Ссылка =Ссылка
|СГРУППИРОВАТЬ ПО Номенклатура
|;
|
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
|ПОМЕСТИТЬ СписокТоваров
|ИЗ 
| Документ.Расходная.Товары
|ГДЕ 
| Ссылка =Ссылка
|;
|
|ВЫБРАТЬ
| Док.Номенклатура,
| Док.Количество КАК Док_Количество,
| ЕСТЬNULL(Рег.КоличествоОстаток,0) КАК Рег_Количество
|ИЗ
| ДокТЧ КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ
|  РегистрНакопления.ОстаткиТоваров.Остатки(,
|  Номенклатура В(ВЫБРАТЬ РАЗЛИЧНЫЕ
|                           Номенклатура
|                          ИЗ
|                           СписокТоваров КАК СписокТоваров)) КАК Рег
| ПО
|  Док.Номенклатура = Рег.Номенклатура";


Запрос.УстановитьПараметр("Ссылка", Ссылка);
МассивРезультаттов = Запрос.ВыполнитьПакет(); //Прим. 1
РезультатЗапроса = Запрос.Выполнить(); //Прим. 2
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл

 //Проверка отрицательных остатков
 //Проведение по регистру

КонецЦикла;

КонецПроцедуры

Фактически я убрал определение объекта запрос и использование менеджера временных таблиц, объединил тексты запросов (обратите внимание на разделитель «;» между текстами). В результате текст запроса стал читабельнее (а при использовании конструктора запросов намного увеличивается удобство чтения запроса).

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

В переменную РезультатЗапроса попадет только выборка.

Ну вот и все что касается пакетных запросов. Очень удобный механизм и с точки зрения написания запросов и с точки зрения чтения сложных запросов.

Автор: Павел Чистов


Опубликовано на сайте: https://HelpF.pro
Прямая ссылка: https://HelpF.pro/faq82/view/1717.html