Все для радиолюбителя

Использование временных таблиц в запросе 1с 8.3. Получаем непосредственно данные

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

Допустим в нашей системе факты покупки и продажи товара регистрируются документами Приход и Расход соответственно. Контрагент может являться как покупателем, так и поставщиком. Зачет задолженности может производится поставкой товара:

Чтобы подсчитать общую задолженность контрагента необходимо сложить сумму всех расходов по этому контрагенту и вычесть сумму всех приходов от этого же контрагента, проще всего это сделать с помощью оператора ОБЪЕДИНИТЬ ВСЕ:

Запрос.Текст =
"
//посчитаем на какую сумму мы отгрузили контрагентам
|ВЫБРАТЬ
| Расход.Контрагент,
|ИЗ
| Документ.Расход КАК Расход
|СГРУППИРОВАТЬ ПО
| Расход.Контрагент
|ОБЪЕДИНИТЬ ВСЕ
//посчитаем на какую сумму контрагенты
//поставили нам товара
|ВЫБРАТЬ
| Приход.Контрагент,
//сумму берем с отрицательным знаком,
//что при объединении она вычлась из суммы расхода
| СУММА(-Приход.Сумма)
|ИЗ
| Документ.Приход КАК Приход
|СГРУППИРОВАТЬ ПО
| Приход.Контрагент";

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

Это не совсем то, что мы хотели, но уже близко. Для достижения требуемого результата осталось сгруппировать по контрагенту. Для этого запрос необходимо поместить во временную таблицу (работа с временными таблицами рассматривается в закрытой части курса ) и уже из нее выбрать и сгруппировать поля:

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

Требования к объединению запросов

При объединении двух запросов количество полей у них должно быть одинаковым, если в каком либо из запросов не хватает полей, то их надо добавить в виде констант. Обратимся к примеру выше, пусть в документе расход также есть поле скидка, которое уменьшает сумму долга контрагента, но в документе приход нет никаких скидок. Как быть в этом случае? Так:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Расход.Контрагент,

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

Осталось вычесть скидку и сгруппировать.

Также важен порядок. Поля будут объединятся именно в том порядке в котором они указаны в секциях ВЫБРАТЬ обоих запросов. Применительно к предыдущему примеру - поменяем местами поля скидка и сумма в выборке приходов:

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

При построении запросов, в языке 1с есть возможность получения результата выполнения запроса с помощью команды: " ПОМЕСТИТЬ <ИмяВременнойТаблицы> ", где <ИмяВременнойТаблицы> - имя "временной таблицы", которая является свойством объекта "Запрос" и представляет из себя объект типа МенеджерВременныхТаблиц, который описывает пространство имен временных таблиц и отвечает за их создание и уничтожение в базе данных. Данный механизм применяется для получения промежуточных данных запросов для дальнейшего их использования в других запросах, что позволяет сделать удобней их отладку, оптимизировать код, сделать запросы более читаемыми.

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

Добавляем к себе в модуль следующую функцию (серверную, если это управляемое приложение):

Функция ДанныеВТ(Запрос, ИмяВТ) ДанныеТаблицы = Новый Запрос; ДанныеТаблицы. Текст = "Выбрать * | Из " + ИмяВТ+ " |" ; Возврат ДанныеТаблицы. Выполнить( ) . Выгрузить() ; КонецФункции

Вызовем ее после текста запроса, например:

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

Теперь в переменной Табл содержится временная таблица Итоговая, ее можно просмотреть в отладке или вывести в табличный документ.

Время жизни

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

При этом возможно уничтожить временную таблицу программным образом, выполнив в одном из пакетов запроса инструкцию "УНИЧТОЖИТЬ <ИмяВременнойТаблицы>". Тогда платформа выполняет SQL-команду "TRUNCATE" на уничтожение временной таблицы.

При использовании менеджера временных таблиц, если таблицы не были явно уничтожены разработчиком (инструкция запроса "УНИЧТОЖИТЬ", сброс менеджера временных таблиц в "Неопределено" или методом "Закрыть()"), то платформа уничтожает их самостоятельно после того, как был уничтожен контекст, в рамках которого они были сформированы. Другими словами, объект будет уничтожен при завершении процедуры или функции, в которой он был создан.

Влияние на производительность

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

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

Вывод

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

Самым главным аргументом в пользу использования временных таблиц является то, что их использование позволяет SQL-серверу строить более оптимальные планы запросов.

Механизм запросов, возникнув в 7 версии программы 1С, с выходом первых версий 8 платформы получил все более широкое распространение и постоянно растущую популярность. Появление управляемых форм и системы компоновки данных существенно увеличило область применения этого инструмента. Однако многим начинающим программистам достаточно сложно его освоить.

Использование объекта, который носит название «Менеджер временных таблиц» позволяет:

  • Значительно упростить текст запроса;
  • Разбить его на более простые блоки;
  • Увеличить его читаемость и структурированность.

Несколько слов о том, как это работает

В принципе, в работе менеджера временных таблиц можно выделить четыре этапа использования:

  1. Создание менеджера;
  2. Его заполнение;
  3. Чтение данных из таблиц;
  4. Уничтожение менеджера и очистка таблиц.

Давайте поговорим о каждом этапе поподробнее.

Создание менеджера временных таблиц

Для того, чтобы определить этот объект необходимо выполнить код, показанный на Рис.1

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

Рис.2

Заполнение менеджера

На том же рисунке 1 указана строка, которая передает выборку во временную таблицу. Начинается она с оператора «Поместить». В качестве места назначения указывается имя таблицы-приемника.

Используя «Конструктор запроса» эту строку можно создать на закладке «Дополнительно» Рис.3.

Рис.3

Для этого необходимо:

  1. Установить переключатель «Тип запроса» в положение «Создание временной таблицы»;
  2. Указать имя приемника.

Если с помощью отладчика проверить последовательность заполнения менеджера, можно обнаружить, что данные в нем появятся только после исполнения метода запроса Выполнить().

Определить заполненость менеджера можно с помощью оператора Количество(). Пример строки: МВТ.Таблицы.Количество().

Чтение таблиц менеджера

Следующий этап работы – чтение данных из существующих таблиц в другом запросе. Здесь существует одна проблема: новый создаваемый запрос не знает о существовании заполненной таблицы, поэтому в окне «База данных» консоли она не появится.

Её необходимо прописывать и создавать вручную.

Для этого на закладке «Таблицы и поля» (Рис.4) необходимо выполнить некоторую последовательность действий:

Рис.4

  1. В меню окна «Таблицы» этой закладки необходимо нажать кнопку «Создать описание временной таблицы»;
  2. В открывшемся окне необходимо указать наименование поля и его описание (тип поля), как оно задано в существующей таблице;
  3. Необходимые поля или функции с ними нужно перенести в третье окно закладки.

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

Удаление таблиц

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

Удаление таблиц из менеджера можно производить двумя основными способами:

  • Указав непосредственно в тексте запроса ключевое слово Уничтожить;
  • Использовав метод Закрыть(), примененный непосредственно к менеджеру.

Во втором случае будут принудительно уничтожены все таблицы, созданные различными запросами.

Использование первого варианта удаления данных можно прописать явно, записав в тексте запроса строку вида «Уничтожить ИмяТаблицы», либо воспользовавшись закладкой «Дополнительно» (Рис.2) окна «Конструктор запроса».

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

Передача (ТЗ) в запрос

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

Для этого текст запроса должен содержать строку вида «Выбрать * Поместить МВТ из &Тз Как Таб» . Передав в качестве параметра «ТЗ» для запроса существующую таблицу значений мы получим объект, подходящий для дальнейшей обработки в других запросах.

Единственным условием, препятствующим передаче ТЗ в качестве параметра, являются неявно объявленные типы ее колонок. То есть при создании колонок ТЗ необходимо заполнять второй параметр строкой вида «Новый ОписаниеТипов(«»)).

43
NULL – отсутствующие значения. Не путать с нулевым значением! NULL – это не число, не равно пробелу, пустой ссылке, Неопределено. NULL – типообразующее значение, т.е. есть тип NULL и единственное значение этого типа. NULL... 26
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос. Создается этот объект вызовом конструкции Новый Запрос. Запрос удобно... 18
В статье приведены полезные приемы при работе с запросами 1С v.8.2, а также сведения, которые не так хорошо известны о языке запросов. Я не стремлюсь дать полное описание языка запросов, а хочу остановиться лишь на... 13
ПОДОБНО - Оператор проверки строки на подобие шаблону. Аналог LIKE в SQL. Оператор ПОДОБНО позволяет сравнить значение выражения, указанного слева от него, со строкой шаблона, указанной справа. Значение выражения...

Рассмотрим несколько ситуаций.

Как поместить результат запроса во временную таблицу

Создадим с помощью конструктора вот такой простейший запрос:

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

Но мы хотим поместить результат запроса во временную таблицу, которую назовем ВТ_Товары , то есть привести наш запрос вот к такому виду

Для этого нам необходимо перейти на закладку Дополнительно , установить тип запроса в положение Создание временной таблицы и заполнить поле с именем таблицы

Как прочитать временную таблицу из другого запроса

Очень часто при проектировании запросов большого объема возникает необходимость передавать временные таблицы из одного запроса в другой с использованием объекта . То есть вот такая ситуация:

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

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

Как создать временную таблицу из параметра запроса

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

В этом случае нам надо сначала создать описание временной таблицы. А затем прописать ее имя на закладке Дополнительно .

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


Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности и правилами сайта, изложенными в пользовательском соглашении