Как использовать временные таблицы в запросах 1С: применение и примеры?

База знаний Одина — Одинэсника › Форумы › ODIN — Форум по 1С Предприятию › Как использовать временные таблицы в запросах 1С: применение и примеры?

Просмотр 1 ветки ответов
  • Автор
    Записи
    • #38782
      Фото аватараOdineski
      Участник

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

      • #38783
        bot_avaOdin — Одинэсник
        Участник

          # Временные таблицы в запросах 1С

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

          Обычно временные таблицы применяют для:

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

          В 1С временная таблица создается с помощью ключевого слова ПОМЕСТИТЬ.

          —

          # 1. Простейший пример

          Допустим, сначала нужно получить товары с НДС 20%, а затем выбрать из временной таблицы только нужные поля.

          |ВЫБРАТЬ
          | Номенклатура.Ссылка,
          | Номенклатура.Наименование
          |ПОМЕСТИТЬ ВТ_Товары
          |ИЗ
          | Справочник.Номенклатура КАК Номенклатура
          |ГДЕ
          | Номенклатура.СтавкаНДС = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20)
          |;
          |
          |ВЫБРАТЬ
          | ВТ_Товары.Ссылка,
          | ВТ_Товары.Наименование
          |ИЗ
          | ВТ_Товары КАК ВТ_Товары

          Здесь выполняются два этапа:

          1. Из справочника номенклатуры выбираются товары со ставкой НДС 20%.
          2. Результат помещается во временную таблицу ВТ_Товары.
          3. Второй запрос читает данные из ВТ_Товары.

          Символ ; разделяет части пакетного запроса.

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

          —

          # 2. Временная таблица создается в рамках менеджера

          Для работы с временными таблицами обычно создают объект МенеджерВременныхТаблиц.

          Пример:

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

          Полный пример:

          Важный момент: в строке текста запроса каждая строка начинается с символа |. Это специальный синтаксис многострочной строки 1С.

          —

          # 3. Пакетный запрос и временная таблица

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

          Общая структура выглядит так:

          |ВЫБРАТЬ
          | …
          |ПОМЕСТИТЬ ВТ_ИмяТаблицы
          |ИЗ
          | …
          |;
          |
          |ВЫБРАТЬ
          | …
          |ИЗ
          | ВТ_ИмяТаблицы КАК ВТ_ИмяТаблицы

          После ПОМЕСТИТЬ указывается имя временной таблицы:

          |ПОМЕСТИТЬ ВТ_Товары

          Имя временной таблицы не является объектом конфигурации. В конфигураторе такую таблицу создавать не нужно.

          —

          # 4. Временная таблица из табличной части документа

          Один из самых полезных вариантов, это передать табличную часть документа в запрос.

          Допустим, у документа есть табличная часть Товары, в которой находятся поля:

          — Номенклатура;
          — Количество;
          — Цена;
          — Сумма.

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

          Здесь Товары справа в параметре:

          это табличная часть документа или таблица значений.

          После выполнения временная таблица ВТ_Товары будет содержать переданные строки.

          Теперь можно выполнить другой запрос с тем же менеджером:

          Главное условие: второй запрос должен использовать тот же объект МенеджерВременныхТаблиц.

          Если создать новый менеджер, временная таблица ВТ_Товары в нем видна не будет.

          —

          # 5. Временная таблица из таблицы значений

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

          Например, в коде сформирована таблица значений ТаблицаОтбора с колонкой Номенклатура.

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

          После этого список номенклатуры можно использовать при работе с регистром.

          —

          # 6. Отбор регистра по списку из временной таблицы

          Допустим, есть регистр накопления ОстаткиТоваров с измерением Номенклатура и ресурсом Количество.

          Нужно получить остатки только по номенклатуре из таблицы ВТ_ОтборНоменклатуры.

          |ВЫБРАТЬ
          | Остатки.Номенклатура,
          | Остатки.КоличествоОстаток
          |ИЗ
          | РегистрНакопления.ОстаткиТоваров.Остатки(
          | ,
          | Номенклатура В
          | (ВЫБРАТЬ
          | ВТ_ОтборНоменклатуры.Номенклатура
          | ИЗ
          | ВТ_ОтборНоменклатуры КАК ВТ_ОтборНоменклатуры)
          | ) КАК Остатки

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

          Это важнее, чем сначала получить все остатки регистра, а потом отфильтровать их обычным ГДЕ.

          Правильно:

          |ИЗ
          | РегистрНакопления.ОстаткиТоваров.Остатки(
          | ,
          | Номенклатура В
          | (ВЫБРАТЬ
          | Номенклатура
          | ИЗ
          | ВТ_ОтборНоменклатуры)
          | ) КАК Остатки

          Менее эффективно:

          |ИЗ
          | РегистрНакопления.ОстаткиТоваров.Остатки() КАК Остатки
          |ГДЕ
          | Остатки.Номенклатура В
          | (ВЫБРАТЬ
          | Номенклатура
          | ИЗ
          | ВТ_ОтборНоменклатуры)

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

          —

          # 7. Практический пример для проведения документа

          Допустим, при проведении документа нужно:

          1. взять товары из табличной части;
          2. сгруппировать их по номенклатуре;
          3. получить остатки только по этим товарам;
          4. сравнить количество в документе с остатком.

          Сначала помещаем сгруппированную табличную часть во временную таблицу:

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

          Параметр Ссылка устанавливается в коде:

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

          —

          # 8. Зачем сначала группировать данные во временной таблице

          Табличная часть документа может содержать одну и ту же номенклатуру несколько раз:

          Для проверки остатков обычно нужна одна строка на товар:

          Именно поэтому сначала используется:

          |СУММА(Товары.Количество) КАК КоличествоДокумента

          с группировкой:

          |СГРУППИРОВАТЬ ПО
          | Товары.Номенклатура

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

          —

          # 9. Временная таблица и несколько запросов

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

          Пример:

          Нельзя сделать так:

          Создать таблицу через МенеджерВТ1, а прочитать ее через МенеджерВТ2. Это разные пространства временных таблиц.

          —

          # 10. Уничтожение временной таблицы

          Временную таблицу можно удалить явно с помощью УНИЧТОЖИТЬ.

          |УНИЧТОЖИТЬ ВТ_Товары

          Например:

          |ВЫБРАТЬ
          | …
          |ПОМЕСТИТЬ ВТ_Товары
          |ИЗ
          | …
          |;
          |
          |ВЫБРАТЬ
          | …
          |ИЗ
          | ВТ_Товары КАК ВТ_Товары
          |;
          |
          |УНИЧТОЖИТЬ ВТ_Товары

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

          Явное УНИЧТОЖИТЬ используют, когда:

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

          В коде:

          Если объект больше не нужен, также можно присвоить ему Неопределено:

          —

          # 11. Индексы временных таблиц

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

          Синтаксис:

          |ВЫБРАТЬ
          | Товары.Номенклатура,
          | Товары.Количество
          |ПОМЕСТИТЬ ВТ_Товары
          |ИЗ
          | &Товары КАК Товары
          |ИНДЕКСИРОВАТЬ ПО
          | Номенклатура

          После этого по полю Номенклатура будет создан индекс временной таблицы.

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

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

          Или если отбор происходит по полю:

          |ГДЕ
          | ВТ_Товары.Номенклатура В
          | (ВЫБРАТЬ
          | Номенклатура
          | ИЗ
          | ВТ_СписокНоменклатуры)

          Индексировать все поля подряд не нужно. Индекс имеет смысл создавать для полей, которые:

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

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

          —

          # 12. Соединение временной таблицы с регистром

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

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

          Используется ЛЕВОЕ СОЕДИНЕНИЕ, потому что товар должен попасть в результат даже в том случае, если остаток равен нулю или записи в регистре нет.

          Если использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ, товары без остатков могут исчезнуть из результата.

          —

          # 13. Временные таблицы для составных ключей

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

          — организация;
          — склад;
          — номенклатура;
          — серия;
          — характеристика;
          — партия.

          Например, нужно найти данные только по конкретным сочетаниям:

          Обычный вариант с большим количеством ИЛИ получается неудобным:

          |ГДЕ
          | (Организация = &Организация1
          | И Склад = &Склад1
          | И Номенклатура = &Номенклатура1
          | И Серия = &Серия1)
          | ИЛИ
          | (Организация = &Организация2
          | И Склад = &Склад2
          | И Номенклатура = &Номенклатура2
          | И Серия = &Серия2)

          Вместо этого список ключей можно передать во временную таблицу:

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

          Такой вариант удобнее и безопаснее, особенно когда ключей десятки, сотни или тысячи.

          —

          # 14. Временная таблица для повторного использования данных

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

          Например, сначала формируется список действующих договоров:

          |ВЫБРАТЬ
          | Договоры.Ссылка,
          | Договоры.Контрагент,
          | Договоры.Организация
          |ПОМЕСТИТЬ ВТ_Договоры
          |ИЗ
          | Справочник.ДоговорыКонтрагентов КАК Договоры
          |ГДЕ
          | НЕ Договоры.ПометкаУдаления
          | И Договоры.Действует

          Затем этот список используется несколько раз:

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

          И отдельным запросом:

          |ВЫБРАТЬ
          | ВТ_Договоры.Организация,
          | КОЛИЧЕСТВО(*) КАК КоличествоДоговоров
          |ИЗ
          | ВТ_Договоры КАК ВТ_Договоры
          |СГРУППИРОВАТЬ ПО
          | ВТ_Договоры.Организация

          Без временной таблицы отбор договоров пришлось бы повторять в каждом запросе.

          —

          # 15. Временная таблица и виртуальные таблицы регистров

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

          Например, во временной таблице находятся товары:

          |ВЫБРАТЬ
          | Товары.Номенклатура
          |ПОМЕСТИТЬ ВТ_Номенклатура
          |ИЗ
          | &Товары КАК Товары
          |ИНДЕКСИРОВАТЬ ПО
          | Номенклатура

          Далее выполняется обращение к виртуальной таблице:

          |ВЫБРАТЬ
          | Обороты.Номенклатура,
          | Обороты.КоличествоОборот,
          | Обороты.СуммаОборот
          |ИЗ
          | РегистрНакопления.Продажи.Обороты(
          | &ДатаНачала,
          | &ДатаОкончания,
          | ,
          | Номенклатура В
          | (ВЫБРАТЬ
          | ВТ_Номенклатура.Номенклатура
          | ИЗ
          | ВТ_Номенклатура КАК ВТ_Номенклатура)
          | ) КАК Обороты

          В коде:

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

          —

          # 16. Когда временная таблица действительно нужна

          Временная таблица оправдана в следующих случаях.

          ## Сложный запрос нужно разделить на этапы

          Например:

          1. получить документы;
          2. сгруппировать товары;
          3. получить остатки;
          4. сравнить данные;
          5. получить итог.

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

          ## Один результат используется несколько раз

          Если один набор данных нужен в трех местах, его удобно сначала сохранить во временную таблицу.

          ## Нужно передать список значений в запрос

          Например:

          — список номенклатуры;
          — список документов;
          — список складов;
          — список характеристик;
          — список составных ключей.

          ## Нужно отфильтровать виртуальную таблицу регистра

          Особенно это актуально для регистров накопления с большим объемом данных.

          ## Нужно предварительно агрегировать данные

          Например, сгруппировать табличную часть документа до соединения с регистром.

          ## Нужно избежать повторного чтения одной и той же таблицы

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

          —

          # 17. Когда временная таблица не нужна

          Не следует создавать временную таблицу только ради самого факта ее использования.

          Например, такой запрос можно оставить обычным:

          |ВЫБРАТЬ
          | Номенклатура.Наименование
          |ИЗ
          | Справочник.Номенклатура КАК Номенклатура
          |ГДЕ
          | Номенклатура.Наименование ПОДОБНО &Шаблон

          Временная таблица здесь ничего не улучшит.

          Также не всегда нужно делать два пакета вместо одного:

          |ВЫБРАТЬ
          | Номенклатура.Ссылка,
          | Номенклатура.Наименование
          |ПОМЕСТИТЬ ВТ_Номенклатура
          |ИЗ
          | Справочник.Номенклатура КАК Номенклатура
          |;
          |
          |ВЫБРАТЬ
          | ВТ_Номенклатура.Ссылка,
          | ВТ_Номенклатура.Наименование
          |ИЗ
          | ВТ_Номенклатура КАК ВТ_Номенклатура

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

          —

          # 18. Производительность временных таблиц

          Временные таблицы не гарантируют автоматическое ускорение запроса.

          Их влияние зависит от:

          — размера исходных таблиц;
          — количества строк во временной таблице;
          — количества повторных обращений к ней;
          — наличия индексов;
          — типа соединений;
          — используемой СУБД;
          — настроек и версии платформы;
          — правильности отборов виртуальных таблиц.

          Временная таблица может ускорить запрос, если:

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

          Но она может замедлить работу, если:

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

          Поэтому производительность нужно проверять замером, а не предполагать только по наличию ПОМЕСТИТЬ.

          —

          # 19. Частая ошибка: разные менеджеры временных таблиц

          Неправильно:

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

          Правильно:

          —

          # 20. Частая ошибка: временная таблица не создана

          Если написать:

          |ВЫБРАТЬ
          | ВТ_Товары.Номенклатура
          |ИЗ
          | ВТ_Товары КАК ВТ_Товары

          но до этого не выполнить пакет с:

          |ПОМЕСТИТЬ ВТ_Товары

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

          Также ошибка появится, если:

          — имя таблицы написано с опечаткой;
          — таблица была уничтожена через УНИЧТОЖИТЬ;
          — используется другой менеджер временных таблиц;
          — первый запрос, создающий таблицу, завершился ошибкой.

          —

          # 21. Частая ошибка: неправильная структура таблицы значений

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

          Например, в коде колонка называется Товар, а в запросе написано Номенклатура:

          |ВЫБРАТЬ
          | Отбор.Номенклатура
          |ПОМЕСТИТЬ ВТ_Отбор
          |ИЗ
          | &ТаблицаОтбора КАК Отбор

          Если в таблице значений нет колонки Номенклатура, запрос завершится ошибкой.

          Нужно либо изменить имя колонки в таблице значений, либо использовать фактическое имя:

          |ВЫБРАТЬ
          | Отбор.Товар
          |ПОМЕСТИТЬ ВТ_Отбор
          |ИЗ
          | &ТаблицаОтбора КАК Отбор

          —

          # 22. Частая ошибка: дубли во временной таблице

          Если список используется только как фильтр, часто не нужно хранить одинаковые значения несколько раз.

          Можно использовать РАЗЛИЧНЫЕ:

          |ВЫБРАТЬ РАЗЛИЧНЫЕ
          | Товары.Номенклатура
          |ПОМЕСТИТЬ ВТ_Номенклатура
          |ИЗ
          | &Товары КАК Товары

          Это особенно полезно, если в таблице значений одна номенклатура встречается много раз.

          Но если количество строк важно, например при расчете общей суммы, РАЗЛИЧНЫЕ применять нельзя без понимания последствий.

          —

          # 23. Просмотр временной таблицы в отладчике

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

          В простых случаях в окне вычисления можно выполнить:

          Но если запрос уже содержит финальную выборку, это покажет только результат последнего пакета.

          Для просмотра конкретной временной таблицы можно временно заменить текст запроса на:

          |ВЫБРАТЬ
          | ВТ_Товары.*
          |ИЗ
          | ВТ_Товары КАК ВТ_Товары

          Затем выполнить:

          При этом у объекта Запрос должен быть установлен тот же МенеджерВременныхТаблиц, в котором таблица создавалась.

          —

          # 24. Пример полноценной схемы с таблицей значений

          Ниже пример, где:

          1. в программу передается таблица товаров;
          2. она помещается во временную таблицу;
          3. данные группируются;
          4. по списку товаров читаются остатки;
          5. результат выгружается в таблицу значений.

          Здесь временная таблица дает несколько преимуществ:

          — исходные данные группируются один раз;
          — одинаковая номенклатура не дублируется;
          — список товаров передается внутрь виртуальной таблицы остатков;
          — в основном запросе используется уже подготовленный набор данных;
          — по полю Номенклатура создан индекс.

          —

          # 25. Главное правило выбора подхода

          Можно ориентироваться на такую практическую схему:

          Обычный запрос используйте, если задача простая и данные читаются один раз.

          Временную таблицу используйте, если необходимо:

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

          Рекомендую посмотреть здесь:

          — https://infostart.ru/1c/articles/17064/
          — https://infostart.ru/1c/articles/69743/
          — https://infostart.ru/1c/articles/1217577/
          — https://helpf.pro/faq/view/925.html

      Просмотр 1 ветки ответов
      • Для ответа в этой теме необходимо авторизоваться.
      База знаний 1С