Синтаксис и применение Работа с временными таблицами в платформе 1С:Предприятие. Описание и примеры кода.
Полное описание, параметры и ограничения
Работа с временными таблицами
Менеджер временных таблиц
Создание временных таблиц
Использование временных таблиц
Удаление временных таблиц
Язык запросов 1С:Предприятия 8 позволяет использовать временные таблицы в запросах. Использование временных таблиц помогает повысить производительность запросов и сделать текст сложных запросов более легким для восприятия.
Работа с временными таблицами обеспечивается двумя составляющими:
объектом встроенного языка МенеджерВременныхТаблиц, который хранит в себе данные временных таблиц;
синтаксисом языка запросов, позволяющим создавать новые временные таблицы и использовать существующие временные таблицы.
Менеджер временных таблиц
Менеджер временных таблиц предназначен для управления временем жизни временных таблиц, создаваемых в процессе работы прикладного решения.
В одном прикладном решении может быть создано произвольное количество экземпляров менеджера временных таблиц, каждый из которых хранит свой набор временных таблиц. Каждая временная таблица однозначно идентифицируется своим именем, и в пределах одного менеджера временных таблиц все временные таблицы должны иметь уникальные имена.
Экземпляр менеджера временных таблиц может быть создан с помощью конструктора Новый. Например:
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Все временные таблицы, созданные в данном экземпляре менеджера, существуют до тех пор, пока существует сам экземпляр менеджера временных таблиц. При уничтожении экземпляра менеджера все временные таблицы, содержащиеся в нем, также удаляются.
Менеджер временных таблиц можно закрыть принудительно при помощи метода Закрыть(). При этом будут удалены все созданные в нем таблицы. Дальнейшая работа с данным экземпляром менеджера будет невозможна.
Создание временных таблиц
Создание временных таблиц осуществляется с помощью объекта Запрос встроенного языка 1С:Предприятия 8.
Связь запроса с менеджером временных таблиц осуществляется с помощью свойства МенеджерВременныхТаблиц запроса, в котором указывается тот экземпляр менеджера, в котором должны создаваться временные таблицы. Например:
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
Временная таблица может быть создана на основе данных базы данных или на основе внешнего источника данных (например, таблицы значений).
Для того чтобы создать временную таблицу на основе данных базы данных, следует установить объекту Запрос менеджер временных таблиц, а затем выполнить запрос к базе данных, используя ключевое слово ПОМЕСТИТЬ, после которого указать имя создаваемой временной таблицы. Ключевое слово ПОМЕСТИТЬ располагается после списка выборки запроса. Например:
ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ Справочник.Номенклатура
Результат исполнения такого запроса будет содержать одну строку с одной колонкой с именем "Количество", в которой будет находится количество записей, помещенных в созданную таблицу.
В случае если менеджер временных таблиц не установлен, или менеджер был закрыт, будет выдана ошибка.
В случае если в установленном менеджере временных таблиц уже существует таблица с указанным именем, будет выдана ошибка.
При необходимости создания индекса для временной таблицы, следует в запросе указать ключевое слово ИНДЕКСИРОВАТЬ ПО, после которого перечислить поля, по которым нужно построить индекс.
Например:
ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ Справочник.Номенклатура
ИНДЕКСИРОВАТЬ ПО Код
Поля, по которым происходит индексирование должны находиться в списке выборки.
Чтобы в создаваемой временной таблице создать колонку, значение которой будет уникальным в рамках создаваемой таблицы, следует использовать функцию языка запросов АВТОНОМЕРЗАПИСИ().
Для того, чтобы создать временную таблицу и заблокировать данные таблиц, на основании которых создается временная, следует использовать конструкцию ДЛЯ ИЗМЕНЕНИЯ.
Например:
ВЫБРАТЬ
РасходнаяНакладная.Ссылка,
РасходнаяНакладная.Номер,
РасходнаяНакладная.Дата
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ
Документ.РасходнаяНакладная КАК РасходнаяНакладная
ГДЕ
РасходнаяНакладная.Ссылка В(&Документы)
ДЛЯ ИЗМЕНЕНИЯ
Для того чтобы создать временную таблицу на основании внешнего источника, следует в тексте запроса в списке источников указать имя параметра, в который будет помещен внешний источник. Остальной синтаксис идентичен обычному созданию временной таблицы. В качестве внешнего источника могут выступать:
таблица значений;
табличная часть;
результат запроса.
Ниже приведен пример создания временной таблицы на основе внешнего источника:
ВЫБРАТЬ
Код,
Наименование
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ &ВнешнийИсточник КАК ВнешнийИсточник
В данном примере во временную таблицу "ВременнаяТаблица" будет помещено содержимое колонок "Код" и "Наименование" из внешнего источника, например, таблицы значений, переданной в качестве параметра "ВнешнийИсточник".
В случае если временная таблица создается на основании внешнего источника, в запросе нельзя использовать объединения и соединения. Также нельзя использовать поля, являющиеся реквизитами элементов таблиц, на основании которых создается временная таблица.
Использование временных таблиц
Для использования существующих временных таблиц в запросе следует установить объекту Запрос менеджер временных таблиц, после чего к временным таблицам, содержащимся в данном менеджере временных таблиц, можно обращаться по имени, как к обычным таблицам запроса.
Удаление временных таблиц
Для удаления временной таблицы из менеджера временных таблиц следует воспользоваться ключевым словом языка запроса УНИЧТОЖИТЬ, после которого указывается имя уничтожаемой таблицы. Например:
УНИЧТОЖИТЬ ВременнаяТаблица
В случае если уничтожаемой таблицы не существует, будет выдана ошибка.
См. также:
Ключевые слова для работы с временными таблицами
Функция АВТОНОМЕРЗАПИСИ
Практические примеры
Дополнить свою временную таблицу, проверить индексы и технические ключи, затем удалить
Три позиции и дополнение из двух строк дают пять собственных записей. Один индекс и два набора индексов не задают порядок строк и не заменяют проверку бизнес-дублей; автонумерация создаёт отдельный ключ только новой временной таблицы.
Где и как запускать
Полный серверный модуль своего учебного стенда 8.5.1.1343, совместимость Не использовать. Только пять собственных позиций, приватный менеджер и значения памяти; рабочие источники, файлы и сеть не используются. Здесь не запускался.
Подготовка
В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.
Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.
В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.
Все товары, количества и строки придуманы в этом модуле. Запись документов, подключение к чужой базе, файлы, сеть и печать не используются. В рабочие общие модули текст не вставляйте.
HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.
Корневой режим совместимости своей учебной конфигурации — Не использовать. Совместимость проверяет код; на старой совместимости новые конструкции не обещаются.
Метаданные товаров, документов и регистров не нужны: все числа/строки создаются модулем. Вставьте также три вспомогательные процедуры/функции из полного текста.
Не передавайте существующий менеджер временных таблиц. Новый приватный Менеджер создаётся самим уроком и содержит только его три таблицы.
Контрольные позиции: номера 1..5, регионы 1,1,2,2,1, коды 10,10,20,10,30, количества 2,3,1,4,5. Не запускайте фрагменты вразнобой: создание предшествует ДОБАВИТЬ и УНИЧТОЖИТЬ.
Процедура ВыполнитьПример() Экспорт
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда
ВызватьИсключение "Нужен собственный учебный стенд без старого режима совместимости";
КонецЕсли;
Первый = СоздатьСвойИсточник();
Дополнение = СоздатьСвойИсточник();
ДобавитьСвоюПозицию(Первый, 3, 2, 20, 1);
ДобавитьСвоюПозицию(Первый, 1, 1, 10, 2);
ДобавитьСвоюПозицию(Первый, 2, 1, 10, 3);
ДобавитьСвоюПозицию(Дополнение, 4, 2, 10, 4);
ДобавитьСвоюПозицию(Дополнение, 5, 1, 30, 5);
Если Первый.Количество() <> 3 Или Дополнение.Количество() <> 2 Тогда
ВызватьИсключение "Изменился состав собственных источников";
КонецЕсли;
Ожидаемые = Первый.Скопировать();
Для Каждого Позиция Из Дополнение Цикл
ДобавитьСвоюПозицию(Ожидаемые, Позиция.СвойНомер, Позиция.Регион, Позиция.Код, Позиция.Количество);
КонецЦикла;
Менеджер = Новый МенеджерВременныхТаблиц;
Попытка
Если Менеджер.Таблицы.Количество() <> 0 Тогда
ВызватьИсключение "Новый собственный менеджер должен быть пустым";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Менеджер;
Запрос.Текст = "ВЫБРАТЬ Начальные.СвойНомер КАК СвойНомер,
|Начальные.Регион КАК Регион, Начальные.Код КАК Код, Начальные.Количество КАК Количество
|ПОМЕСТИТЬ ВТСвойОдинИндекс
|ИЗ &Первый КАК Начальные
|ИНДЕКСИРОВАТЬ ПО Код;
|
|ВЫБРАТЬ Начальные.СвойНомер КАК СвойНомер,
|Начальные.Регион КАК Регион, Начальные.Код КАК Код, Начальные.Количество КАК Количество
|ПОМЕСТИТЬ ВТСвоиНаборыИндексов
|ИЗ &Первый КАК Начальные
|ИНДЕКСИРОВАТЬ ПО НАБОРАМ ((СвойНомер) УНИКАЛЬНО, (Регион, Код))";
Запрос.УстановитьПараметр("Первый", Первый);
Запрос.ВыполнитьПакет();
Если Менеджер.Таблицы.Количество() <> 2 Тогда
ВызватьИсключение "Не созданы две свои временные таблицы";
КонецЕсли;
Запрос.Текст = "ВЫБРАТЬ Дополнительные.СвойНомер КАК СвойНомер,
|Дополнительные.Регион КАК Регион, Дополнительные.Код КАК Код,
|Дополнительные.Количество КАК Количество
|ДОБАВИТЬ ВТСвоиНаборыИндексов
|ИЗ &Дополнение КАК Дополнительные";
Запрос.УстановитьПараметр("Дополнение", Дополнение);
Запрос.Выполнить();
Запрос.Текст = "ВЫБРАТЬ СвойНомер, Регион, Код, Количество
|ИЗ ВТСвойОдинИндекс УПОРЯДОЧИТЬ ПО СвойНомер";
ИсходнаяКопия = Запрос.Выполнить().Выгрузить();
ПроверитьСвоиСтроки(ИсходнаяКопия, Первый);
Запрос.Текст = "ВЫБРАТЬ СвойНомер, Регион, Код, Количество
|ИЗ ВТСвоиНаборыИндексов УПОРЯДОЧИТЬ ПО СвойНомер";
ВсеПозиции = Запрос.Выполнить().Выгрузить();
ПроверитьСвоиСтроки(ВсеПозиции, Ожидаемые);
Если ВсеПозиции.Количество() <> 5 Или ВсеПозиции.Итог("Количество") <> 15 Тогда
ВызватьИсключение "Не подтверждены пять своих позиций и сумма 15";
КонецЕсли;
Для Индекс = 0 По ВсеПозиции.Количество() - 1 Цикл
Если ВсеПозиции[Индекс].СвойНомер <> Индекс + 1 Тогда
ВызватьИсключение "Явный порядок по собственному номеру не подтверждён";
КонецЕсли;
КонецЦикла;
Запрос.Текст = "ВЫБРАТЬ СвойНомер, Регион, Код, Количество
|ИЗ ВТСвоиНаборыИндексов
|ГДЕ Регион = &Регион И Код = &Код
|УПОРЯДОЧИТЬ ПО СвойНомер";
Запрос.УстановитьПараметр("Регион", 1);
Запрос.УстановитьПараметр("Код", 10);
Срез = Запрос.Выполнить().Выгрузить();
ПроверитьСвоиСтроки(Срез, Первый.НайтиСтроки(Новый Структура("Регион,Код", 1, 10)));
Если Срез.Количество() <> 2 Или Срез.Итог("Количество") <> 5 Тогда
ВызватьИсключение "Не подтверждён свой срез 1/10";
КонецЕсли;
Запрос.Текст = "ВЫБРАТЬ Код КАК Код, КОЛИЧЕСТВО(*) КАК Строк, СУММА(Количество) КАК Количество
|ИЗ ВТСвоиНаборыИндексов
|СГРУППИРОВАТЬ ПО Код УПОРЯДОЧИТЬ ПО Код";
ПоКодам = Запрос.Выполнить().Выгрузить();
Если ПоКодам.Количество() <> 3 Тогда
ВызватьИсключение "Ожидались три собственных кода";
КонецЕсли;
Если ПоКодам[0].Код <> 10 Или ПоКодам[0].Строк <> 3 Или ПоКодам[0].Количество <> 9
Или ПоКодам[1].Код <> 20 Или ПоКодам[1].Строк <> 1 Или ПоКодам[1].Количество <> 1
Или ПоКодам[2].Код <> 30 Или ПоКодам[2].Строк <> 1 Или ПоКодам[2].Количество <> 5 Тогда
ВызватьИсключение "Не подтверждён полный состав собственных групп";
КонецЕсли;
Сообщить("Код 10 повторяется в трёх строках: уникальный индекс собственного номера не убирает эти позиции");
Запрос.Текст = "ВЫБРАТЬ Позиции.СвойНомер КАК СвойНомер,
|Позиции.Регион КАК Регион, Позиции.Код КАК Код, Позиции.Количество КАК Количество,
|АВТОНОМЕРЗАПИСИ() КАК ТехническийКлюч
|ПОМЕСТИТЬ ВТСвоиТехническиеКлючи
|ИЗ ВТСвоиНаборыИндексов КАК Позиции";
Запрос.Выполнить();
Запрос.Текст = "ВЫБРАТЬ СвойНомер, Регион, Код, Количество, ТехническийКлюч
|ИЗ ВТСвоиТехническиеКлючи УПОРЯДОЧИТЬ ПО СвойНомер";
Технические = Запрос.Выполнить().Выгрузить();
ПроверитьСвоиСтроки(Технические, Ожидаемые);
Для Каждого СтрокаРезультата Из Технические Цикл
Если ТипЗнч(СтрокаРезультата.ТехническийКлюч) <> Тип("Число") Тогда
ВызватьИсключение "Автонумерация не вернула числовой технический ключ";
КонецЕсли;
КонецЦикла;
Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Строк,
|КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТехническийКлюч) КАК Ключей
|ИЗ ВТСвоиТехническиеКлючи";
Ключи = Запрос.Выполнить().Выгрузить();
Если Ключи.Количество() <> 1 Тогда
ВызватьИсключение "Не получена своя контрольная строка ключей";
КонецЕсли;
Если Ключи[0].Строк <> 5 Или Ключи[0].Ключей <> 5 Тогда
ВызватьИсключение "Не подтверждена уникальность пяти собственных технических ключей";
КонецЕсли;
Если Менеджер.Таблицы.Количество() <> 3
Или Менеджер.Таблицы.Найти("ВТСвойОдинИндекс") = Неопределено
Или Менеджер.Таблицы.Найти("ВТСвоиНаборыИндексов") = Неопределено
Или Менеджер.Таблицы.Найти("ВТСвоиТехническиеКлючи") = Неопределено Тогда
ВызватьИсключение "Нельзя удалять неподтверждённые собственные таблицы";
КонецЕсли;
Запрос.Текст = "УНИЧТОЖИТЬ ВТСвойОдинИндекс;
|УНИЧТОЖИТЬ ВТСвоиНаборыИндексов;
|УНИЧТОЖИТЬ ВТСвоиТехническиеКлючи";
Запрос.ВыполнитьПакет();
Если Менеджер.Таблицы.Количество() <> 0
Или Менеджер.Таблицы.Найти("ВТСвоиНаборыИндексов") <> Неопределено Тогда
ВызватьИсключение "Удаление собственных временных таблиц не подтверждено";
КонецЕсли;
Если Первый.Количество() <> 3 Или Дополнение.Количество() <> 2 Тогда
ВызватьИсключение "Собственные исходные коллекции неожиданно изменились";
КонецЕсли;
Исключение
Менеджер.Закрыть();
ВызватьИсключение;
КонецПопытки;
Менеджер.Закрыть();Сообщить(Технические.Количество() = 5);
Сообщить("Выгруженные значения сохранились; свой менеджер закрыт и больше не используется");
КонецПроцедуры
Функция СоздатьСвойИсточник()
Источник = Новый ТаблицаЗначений;
ЧисловойТип = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(5, 0, ДопустимыйЗнак.Неотрицательный));
Источник.Колонки.Добавить("СвойНомер", ЧисловойТип);
Источник.Колонки.Добавить("Регион", ЧисловойТип);
Источник.Колонки.Добавить("Код", ЧисловойТип);
Источник.Колонки.Добавить("Количество", ЧисловойТип);
Возврат Источник;
КонецФункции
Процедура ДобавитьСвоюПозицию(Источник, СвойНомер, Регион, Код, Количество)
Позиция = Источник.Добавить();
Позиция.СвойНомер = СвойНомер;
Позиция.Регион = Регион;
Позиция.Код = Код;
Позиция.Количество = Количество;
КонецПроцедуры
Процедура ПроверитьСвоиСтроки(Таблица, Ожидаемые)
Если Таблица.Количество() <> Ожидаемые.Количество() Тогда
ВызватьИсключение "Не совпало число своих строк";
КонецЕсли;
Для Каждого Позиция Из Ожидаемые Цикл
Поля = Новый Структура("СвойНомер,Регион,Код,Количество",
Позиция.СвойНомер, Позиция.Регион, Позиция.Код, Позиция.Количество);
Совпадения = Таблица.НайтиСтроки(Поля);
Если Совпадения.Количество() <> 1 Тогда
ВызватьИсключение "Не совпал полный состав своей позиции";
КонецЕсли;
КонецЦикла;
Сообщить("Проверены все поля своих строк, всего " + Строка(Таблица.Количество()));
КонецПроцедурыРазбор по шагам
Создать свои типизированные таблицы: первая содержит позиции 3,1,2, дополнение 4,5. Все четыре поля — Число 5,0. Порядок ввода специально отличается от СвойНомер.
Скопировать ожидаемый полный состав в памяти и создать НОВЫЙ приватный менеджер. Никакой существующий менеджер формы или отчёта сюда не передаётся.
Пакетом создать две независимые таблицы. Первая имеет один индекс по Коду; вторая — уникальный индекс по СвойНомер и составной по Регион,Код. Все индексируемые поля входят в выборку.
ДОБАВИТЬ направляет две дополнительные строки только во вторую таблицу. Структура и типы совпадают; поле перед ДОБАВИТЬ имеет явный псевдоним Количество.
Выгрузить обе таблицы: первая остаётся с тремя строками, вторая имеет пять и сумму 15. Полный состав четырёх полей каждой позиции проверяется, не только количество.
УПОРЯДОЧИТЬ ПО СвойНомер задаёт порядок явно. Наличие индекса и порядок исходной таблицы не принимаются за гарантию порядка результата.
Отбор Регион=1 и Код=10 даёт позиции 1,2 и количество 5. По всем регионам Код=10 встречается трижды и даёт 9: техническая уникальность номера не устраняет бизнес-повторения.
Создать третью временную таблицу из пяти позиций. АВТОНОМЕРЗАПИСИ используется только отдельным полем списка выборки при ПОМЕСТИТЬ, не при ДОБАВИТЬ и не внутри выражения.
Выгрузить полный состав и проверить число строк/различных числовых технических ключей: 5/5. Не предполагать начальный ключ или соответствие ключа товару, собственному номеру, UUID либо номеру документа.
Проверить три имени в коллекции своего менеджера до удаления. УНИЧТОЖИТЬ пакетом удаляет только эти три собственные таблицы; отсутствие подтверждается количеством ноль и Найти=Неопределено.
Закрыть свой менеджер при успехе и ошибке. После закрытия не обращаться к нему; ранее выгруженная ТаблицаЗначений из пяти строк остаётся значением памяти.
Как проверить результат
Исходная копия содержит три позиции, дополненная пять; количества по позициям 1..5 равны 2,3,1,4,5, сумма 15.
Срез 1/10 содержит две конкретные позиции и сумму 5. Группы кодов 10,20,30 имеют числа строк 3,1,1 и количества 9,1,5.
Техническая таблица сохраняет все пять исходных позиций и имеет пять разных числовых ключей; никакого заданного соответствия ключ→товар нет.
До удаления три своих имени найдены; после удаления таблиц ноль. Исходные коллекции остаются 3 и 2, выгруженная техническая таблица после закрытия содержит 5.
Проверки в коде вызывают исключение при несовпадении содержимого; индексы не объявляются измеренным ускорением.
Ожидаемый результат
Новичок получает законченный жизненный цикл собственных временных таблиц, проверяет добавление, состав, выборки и технические ключи, затем видит границу между удалением временной таблицы и сохранённой выгрузкой.
На что обратить внимание
ДОБАВИТЬ не пересоздаёт таблицу и не заменяет её данные. Повторение запроса ещё раз добавит ещё две строки; этот модуль создаёт новый менеджер при каждом запуске.
Индекс, в том числе УНИКАЛЬНО, не используйте для проверки уникальности бизнес-данных: справка предупреждает о различиях СУБД. Здесь уникальные СвойНомер известны заранее, а повторяющийся Код проверяется отдельно.
Несколько индексов расходуют ресурсы и не доказывают ускорение на пяти строках. Для реальной оптимизации нужны измерения на своём объёме и составе запросов.
АВТОНОМЕРЗАПИСИ нельзя использовать вне списка выборки, внутри выражения, при запросе без формирования временной таблицы или с ОБЪЕДИНИТЬ на верхнем уровне.
УНИЧТОЖИТЬ отсутствующей таблицы вызывает ошибку. Не повторяйте удаление после успешного пакета и не заменяйте свой менеджер существующим менеджером рабочего отчёта.
Закрыть удаляет оставшиеся таблицы, но не позволяет дальнейшую работу с этим менеджером. Выгруженные значения и исходные коллекции в памяти — другие объекты.
Пример сверяется с точной 8.5.1.1343 без старого режима совместимости. Python-тесты проверяют текст/фикстуры и контракты, не выполнение запросов в 1С.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.