Опубликовано: 09.07.2022

Работа с запросами

Для формирования и выполнения запросов к документам, справочникам, регистрам, журналам расчётов, планам счетов, бухгалтерским операциям и проводкам в системе используется специальный агрегатный тип данных — "Запрос". Возможности работы со справочниками, документами и журналами расчётов предоставляют достаточно мощные средства получения различной информации об этих объектах. Однако, существует также необходимость в получении информации, сгруппированной определённым образом, которую невозможно или очень сложно получить, непосредственно работая с документами, справочниками, регистрами или журналами расчётов. Для получения такой информации и существует механизм запросов.

Рассмотрим основные моменты работы с данным механизмом:

Контекст работы с запросами

Во всех программных модулях доступ к атрибутам и методам запросов может выполняться только через переменную со ссылкой на объект типа "Запрос", созданный с помощью функции СоздатьОбъект(). Чтобы вызвать атрибут или метод объекта, имя этого атрибута или метода пишется через точку после имени такой переменной.

При создании объекта типа "Запрос" в качестве параметра функции СоздатьОбъект() используется ключевое слово «Запрос» (англоязычный синоним — «Query»).

Запрос = СоздатьОбъект("Запрос");

Структура запросов и методика их использования

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

Запросы можно использовать не только для построения отчётов, но и для реализации других процедур конфигурации, требующих получения из базы данных некой сводной информации. Например, реализация алгоритма списания стоимости товара по методам FIFO или LIFO.

Работа с запросами предполагает следующий порядок:

  • при помощи функции СоздатьОбъект() создаётся объект типа "Запрос" и ссылка на него присваивается какой-либо переменной. Далее обращение к запросу производится посредством этой ссылки;
  • после создания переменной типа "Запрос" следует обращение к методу Выполнить(), которому в качестве параметра передаётся текст запроса, написанный на специальном языке запросов. Метод Выполнить() анализирует текст запроса, выполняет в соответствии с ним выборку данных и формирует временный выходной набор данных (выборку);
  • после этого организуется циклическая обработка сформированного временного набора данных (выборки) с целью получения требуемого отчёта.

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

НашЗапрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|СКЛАД = Регистр.ТоварныйЗапас.Склад;
|ТОВАР = Регистр.ТоварныйЗапас.Товар;
|КОЛИЧЕСТВО = Регистр.ТоварныйЗапас.Количество;
|Группировка ТОВАР Упорядочить По ТОВАР.Код;
|Группировка СКЛАД Упорядочить По СКЛАД.Код;
|Функция КОЛ = КонОст(КОЛИЧЕСТВО);
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если НашЗапрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Структура временного набора данных, созданная запросом НашЗапрос после его выполнения, представлена на следующем рисунке.

Структура временного набора данных

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

Далее, допустим, в цикле мы проходим только по самой внешней группировке запроса: Товар. В теле этого цикла объект НашЗапрос позиционируется во временном наборе данных на записи, содержащие итоги по каждому конкретному товару, поэтому в теле этого цикла мы можем использовать итоги по товарам.

После завершения цикла по самой внешней группировке, объект НашЗапрос снова позиционируется на первой записи временного набора данных, где содержится общий итог по запросу. Поэтому, общие итоги по запросу можно использовать в двух местах: до и после цикла по самой внешней группировке запроса.

Продолжение примера:

// Доступен итог общий
 . . .
Пока НашЗапрос.Группировка("Товар") = 1 Цикл
   // Доступен итог по товару
    . . .
КонецЦикла;
// Доступен итог общий
 . . .

Поскольку после первого просмотра временного набора данных (как мы это сделали выше) объект НашЗапрос снова спозиционирован на первой записи, то можно запустить просмотр ещё раз.

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

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

После завершения цикла по вложенной группировке (Склад), объект НашЗапрос снова позиционируется на записи временного набора данных, где содержится общий итог по конкретному товару. Поэтому, общие итоги по конкретному товару можно использовать в двух местах: до и после цикла по вложенной группировке (Склад).

После завершения цикла по самой внешней группировке, объект НашЗапрос снова позиционируется на первой записи временного набора данных, где содержится общий итог по запросу. Поэтому, общие итоги по запросу можно использовать в двух местах: до и после цикла по самой внешней группировке запроса.

Продолжение примера:

// Доступен итог общий
 . . .
Пока НашЗапрос.Группировка("Товар") = 1 Цикл
   // Доступен итог по товару
    . . .
   Пока НашЗапрос.Группировка("Склад") = 1 Цикл
      // Строка по товару — складу
       . . .
   КонецЦикла;
   // Доступен итог по товару
    . . .
КонецЦикла;
// Доступен итог общий
 . . .

После выхода из процедуры, где была определена переменная, содержащая объект типа "Запрос" (в нашем примере НашЗапрос) или после уничтожения объекта типа "Запрос" (Наш3апрос = 0;), временный набор данных на локальной машине пользователя уничтожается.

Из приведенного выше примера можно сделать несколько важных заключений:

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

Примера обработки запроса:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Если (Запрос.Товар = НужныйТовар) Тогда
      Пока Запрос.Группировка("Отдел") = 1 Цикл
         Если (Запрос.Отдел = НужныйОтдел) Тогда
            Пока Запрос.Группировка("Сотрудник") = 1 Цикл
               Если (Запрос.Сотрудник = НужныйСотрудник) Тогда
                  Пока Запрос.Группировка("Док") = 1 Цикл
                     Док = Запрос.Док;
                     Если Запрос.ПрихКол <> 0 Тогда
                        Таб.ВывестиСекцию("Приход");
                     ИначеЕсли Запрос.РасхКол <> 0 Тогда
                        Приращение = Запрос.РасхКол;
                        Таб.ВывестиСекцию("Расход");
                     КонецЕсли;
                  КонецЦикла;
               КонецЕсли;
            КонецЦикла;
         КонецЕсли;
      КонецЦикла;
   КонецЕсли;
КонецЦикла;

Атрибуты запросов

Атрибутами запроса являются объявленные в описании запроса внутренние переменные (см. далее описание языка запросов), имена группировок и функций запроса. Все атрибуты запросов — только для чтения. Чтобы обратиться к атрибуту запроса, имя этого атрибута пишется через точку после имени ссылки на запрос. Значения атрибутов запроса определяются текущим положением в полученной выборке.

Методы запросов

Выполнить запрос позволяет метод Выполнить() (англоязычный синоним — Execute()). Он анализирует описание, содержащееся в тексте запроса, выполняет выборку данных, формирует временный выходной набор данных (выборку) и вычисляет значения функций запроса. Возвращаемым значением метода является число 1, если запрос выполнен успешно, или 0, если зафиксирована ошибка при выполнении запроса (синтаксическая или времени выполнения).

Синтаксис метода:

Выполнить(<ТекстЗапроса>)

где <ТекстЗапроса> — строковое выражение, содержащее текст запроса на языке запросов.

Пример использования:

Процедура Сформировать()
   // сформируем данные на начало месяца
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   _Дата = ЖР.НачалоТекущегоПериода();
   // Создание объектов типа "Запрос"
   Запрос = СоздатьОбъект("Запрос");
   ЗапросКат = СоздатьОбъект("Запрос");
   флаг1 = Запрос.Выполнить(
   "//({ЗАПРОС(Двойной)
   |Период с _Дата по _Дата;
   |Оклад = Справочник.Сотрудники.Оклад;
   |Пдр = Справочник.Сотрудники.МестоРаботы.Владелец;
   |Ктг = Справочник.Сотрудники.Категория;
   |Условие((Ктг.Выбран() = 1) И (Пдр.Выбран() = 1));
   |Группировка Пдр без групп;
   |Группировка Ктг без групп;
   |Функция Всего = Сумма(Оклад);
   |"//}} ЗАПРОС
   );
   Флаг2 = ЗапросКат.Выполнить(
   "//{{ЗАПРОС(Одинарный)
   |Период с _Дата по _Дата;
   |Оклад = Справочник.Сотрудники.Оклад;
   |Ктг = Справочник.Сотрудники.Категория;
   |Условие(Ктг.Выбран() = 1);
   |Группировка Ктг без групп;
   |Функция Всего = Сумма(Оклад);
   |"//}}ЗАПРОС
   );
   // Если ошибка в запросе, то выход из процедуры
   Если ((Флаг1 = 0) ИЛИ (Флаг2 = 0)) Тогда
      Сообщить("Ошибка в запросе!");
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   // Выводим заглавие таблицы
   Таб.ВывестиСекцию("Документ<|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("Документ<|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("Документ<|ДокументВерт>");
   // Выводим колонтитул таблицы
   Таб.ВывестиСекцию("КолонТитул|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("КолонТитул|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("КолонТитул|ДокументВерт>");
   Продолжать = 1;
   Пока Запрос.Группировка("Пдр") = 1 Цикл
      // Заполнение полей Пдр
      Таб.ВывестиСекцию("Осн1|ДокументВерт<");
      Далее = 1;
      Пока Продолжать = 1 Цикл
         // Заполнение полей Ктг
         СлКат = ЗапросКат.Группировка("Ктг");
         Если Далее = 1 Тогда
            ОК = Запрос.Группировка("Ктг");
         КонецЕсли;
         Если СлКат = 0 Тогда
            Прервать;
         КонецЕсли;
         Если ЗапросКат.Ктг = Запрос.Ктг Тогда
            Таб.ПрисоединитьСекцию("Осн1|Осн2");
            Далее = 1;
         Иначе
            Таб.ПрисоединитьСекцию("Осн1|Пусто");
            Далее = 0;
         КонецЕсли;
      КонецЦикла;
      Таб.ПрисоединитьСекцию("Осн1|ДокументВерт>");
   КонецЦикла;
   // Заполнение полей "Итого"
   Таб.ВывестиСекцию("Документ>|ДокументВерт<");
   Пока ЗапросКат.Группировка("Ктг") = 1 Цикл
      Таб.ПрисоединитьСекцию("Документ>|Осн2");
   КонецЦикла;
   Таб.ПрисоединитьСекцию("Документ>|ДокументВерт>");
   // Вывод заполненной формы
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Установить режим использования графы отбора в запросе позволяет метод ИспользоватьГрафуОтбора() (англоязычный синоним — UseSelectionColumn()). Если метод не используется — по умолчанию устанавливается автоматический выбор графы отбора. Возвращаемым значением метода является строковое значение — идентификатор использованной реально графы отбора, если метод вызывается после выполнения запроса.

Синтаксис метода:

ИспользоватьГрафуОтбора(<ГрафаОтбора>)

где <ГрафаОтбора> — строковое выражение — идентификатор графы отбора, как он задан в Конфигураторе. Данный параметр устанавливает режим использования определённой графы отбора. Возможными значениями параметра также являются:

  • "*" — автоматический выбор графы отбора;
  • "" (пустая строка) — не использовать графу отбора.

Пример использования:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Документ.РасхНакл.Товар;
|Клиент = Документ.РасхНакл.Клиент;
|Группировка Клиент;
|Группировка Тов;
|Группировка Документ;
|"//)}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Запрос.ИспользоватьГрафуОтбора("Клиент");
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Организовать цикла получения данных из выборки, сформированной в результате работы метода Выполнить(), позволяет метод Группировка() (англоязычный синоним — Group()). Метод позиционирует в выборке очередную строку в порядке, определённом параметром <Группировка>. Нельзя использовать метод Группировка(), задавая в качестве параметра младшие группировки, не использовав предварительно этот метод для позиционирования по старшим группировкам. Старшинство группировок определяется порядком их следования в тексте запроса.

Синтаксис метода:

Группировка(<Группировка>, <Направление>)

где

  • <Группировка> — выражение, содержащее порядковый номер или имя группировки;
  • <Направление> — необязательный параметр — числовое выражение, определяющее направление выборки. Возможные значения:
    • 1 — выборка значений группировки по возрастанию (значение по умолчанию);
    • -1 (минус единица) — выборка значений группировки по убыванию.

Возвращаемым значением метода является число 1, если получено следующее значение выборки запроса, или 0, если нет.

Пример использования:

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса;
   Если (Число(ДатаНач) = 0) ИЛИ (Число(ДатаКон) = 0) Тогда
      Предупреждение("Не задан период!");
      Возврат;
   КонецЕсли;
   // Создание объекта типа "Запрос"
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Сформировать)
   |с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка ПериодЖурнала;
   |Функция Сум = Сумма(Рез);
   |"//}}ЗАПРОС
   ;
   Если Сотрудник.Выбран() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Сотр = Сотрудник);";
   КонецЕсли;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   // Сначала используем группировку по сотрудникам
   // а потом группировку по периоду журнала!!!
   Пока Запрос.Группировка("Сотр") = 1 Цикл
      // Заполнение полей Сотр
      Таб.ВывестиСекцию("Сотр<");
      Пока Запрос.Группировка("ПериодЖурнала") = 1 Цикл
         // Заполнение полей ПериодЖурнала
         Таб.ВывестиСекцию("Мес");
      КонецЦикла;
      Таб.ВывестиСекцию("Сотр>");
   КонецЦикла;
   // Вывод заполненной формы
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Выделить строки временного набора данных, которые являются группой справочника, позволяет метод ЭтоГруппа() (англоязычный синоним — IsItAGroup()). Возвращаемым значением метода является число 1, если текущая строка выборки (временного набора данных, сформированного в результате выполнения запроса) является группой справочника, или 0, если это обычный элемент справочника.

Синтаксис метода:

ЭтоГруппа(<ИмяГруппировки>)

где <ИмяГруппировки> — выражение, содержащее порядковый номер или имя группировки.

Пример использования:

Пока (Запр.Группировка("Товар") = 1) И (Запр.ЭтоГруппа("Товар") = 0) Цикл
    . . .
КонецЦикла;

Получить дату начала периода запроса позволяет метод НачалоПериода() (англоязычный синоним — BeginOfPeriod()). Если в тексте запроса указана одна из предопределённых группировок типа период ("Год", "Месяц", "День" и т.д.), то при обработке этой и вложенных в неё группировок метод НачалоПериода() будет возвращать начало периодов текущих значений этих группировок. Параметры у метода отсутствуют.

Пример использования:

ДатаНачала = Запрос.НачалоПериода();

Получить дату конца периода запроса позволяет метод КонецПериода() (англоязычный синоним — EndOfPeriod()). Если в тексте запроса указана одна из предопределённых группировок типа период ("Год", "Месяц", "День" и т.д.), то при обработке этой и вложенных в неё группировок метод КонецПериода() будет возвращать конец периодов текущих значений этих группировок. Параметры у метода отсутствуют.

Пример использования:

ДатаКонца = Запрос.КонецПериода();

Осуществить прямое позиционирование на запись в выборке по конкретным значениям группировок позволяет метод Получить() (англоязычный синоним — Get()). Количество параметров метода зависит от количества группировок в запросе. Можно пропускать значения одной или нескольких последних группировок, в этом случае метод позиционируется на запись, которая будет содержать итоговые значения для указанных группировок. Пропускаемые при вызове метода последние значения группировок должны заменяться запятыми. Если при вызове метода опущены все параметры, то выборка позиционируется на самое начало временного набора данных, на строку итогов. Возвращаемым значением метода является число 1, если запись найдена, или 0 – если нет.

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

Синтаксис метода:

Получить(<ЗначениеГруппировки1>, ..., <ЗначениеГруппировкиN>)

где <ЗначениеГруппировки1>,, <ЗначениеГруппировкиN> — выражения, содержащие значения группировок запроса.

Пример использования:

// Текст запроса
Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";
// Текст процедуры обработки запроса
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
Если Запрос.Получить(ВыбДолжн, ВыбКатег) = 0 Тогда
   Если Запрос.Получить(ВыбДолжн, ) = 0 Тогда
       . . .
   КонецЕсли;
КонецЕсли;

Осуществить прямое позиционирование на начало выборки позволяет метод ВНачалоВыборки() (англоязычный синоним — ToSelectionBegin()). Например, если необходимо перейти на верхний уровень группировок, чтобы затем организовать проход группировки первого уровня (в любом направлении), следует использовать метод ВНачалоВыборки(). Возвращаемым значением метода является число 1, если операция выполнена успешно, или 0 – если нет. Параметры у метода отсутствуют.

Пример использования:

// Текст запроса
Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";
// Текст процедуры обработки запроса
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
Если Запрос.Получить(ВыбДолжн, ВыбКатег) = 0 Тогда
   Если Запрос.Получить(ВыбДолжн, ) = 0 Тогда
       . . .
   КонецЕсли;
КонецЕсли;
Запрос.ВНачалоВыборки();
Пока Запрос.Группировка(1, -1) Цикл
    . . .
КонецЦикла;

Получить значение поля упорядочивания из временной выборки запроса, не обращаясь к базе данных, позволяет метод ЗначениеУпорядочивания() (англоязычный синоним — OrderValue()).

Примечание: Если в тексте запроса для данной группировки не используется конструкция "Упорядочить по", то в этом случае действует упорядочивание по умолчанию:

  • для справочников — зависит от основного представления при описании справочника в Конфигураторе (код или наименование);
  • для документов — дата и время создания документа.

Синтаксис метода:

ЗначениеУпорядочивания(<Группировка>, <Упорядочив>)

где

  • <Группировка> — выражение, содержащее значение номера или имени группировки (номер работает быстрее);
  • <Упорядочив> — необязательный параметр. Порядковый номер параметра упорядочивания указанной группировки. Значение по умолчанию — 1.

Пример использования:

// Текст запроса
Текст3апроса = "
|ВидРаб = Документ.Наряд.ВидРаботы;
|Сотр = Документ.Наряд.Сотрудник;
|Группировка ВидРаб
|Упорядочить По ВидРаб.Код, ВидРаб.Стоимость;
|Группировка Сотр;
|";
 . . .
// Фрагмент заполнения таблицы
// Выбираем значение ВидРаб.Стоимость
Запрос.ЗначениеУпорядочивания("ВидРаб", 2);
// Выбираем имя сотрудника
Запрос.ЗначениеУпорядочивания(2, 1);

Получить значение атрибута запроса по его имени позволяет метод ПолучитьАтрибут() (англоязычный синоним — SetAttrib()).

Синтаксис метода:

ПолучитьАтрибут(<ИмяАтрибута>)

где <ИмяАтрибута> — строковое выражение, содержащее имя любого атрибута запроса.

Пример использования:

// Текст запроса
Текст3апроса = "
|ВидРаб = Документ.Наряд.ВидРаботы;
|Сотр = Документ.Наряд.Сотрудник;
|Группировка ВидРаб
|Упорядочить По ВидРаб.Код, ВидРаб.Стоимость;
|Группировка Сотр;
|";
 . . .
// Фрагмент заполнения таблицы
// Выбираем значение ВидРаб
Запрос.ПолучитьАтрибут("ВидРаб");
// Выбираем сотрудника
Запрос.ПолучитьАтрибут("Сотр");

Выгрузить результаты запроса в указанную таблицу значений позволяет метод Выгрузить() (англоязычный синоним — Unload()). Возвращаемым значением метода является число 1, если выгрузка произошла успешно, иначе – 0.

Синтаксис метода:

Выгрузить(<ТаблЗнач>, <Флаг>, <Итоги>)

где

  • <ТаблЗнач> — таблица значений, куда выгружаются результаты запроса;
  • <Флаг> — необязательный параметр. Число:
    • 0 — значения групп и функций (значение по умолчанию);
    • 1 — значения групп и функций, дополнительных переменных;
    • 2 — значения упорядочиваний групп и функций;
    • 3 — значения упорядочиваний групп и функций, дополнительных переменных;
    или строка типа "Товар(1), Товар(2), Товар, Склад, Приход, Расход", где Товар(1) — значение первого упорядочивания группировки "Товар" и т.д.
  • <Итоги> — необязательный параметр. Число:
    • 0 — итоги по группировкам не выводить;
    • 1 — итоги по группировкам выводить сверху (значение по умолчанию);
    • 2 — итоги по группировкам выводить снизу;
    • 3 — итоги по группировкам выводить сверху и снизу.

Пример использования:

// Текст запроса
Текст3апроса = "
| ...
|Группировка Должность;
|Группировка Категория;
| ...
|";
// Текст процедуры обработки запроса
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
ТаблЗнач = Создать("ТаблицаЗначений");
Запрос.Выгрузить(ТаблЗнач, 0, 0);

Введение в язык запросов

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

Формат текста описания запроса

Текст описания запроса на языке запросов состоит из последовательности операторов. Концом оператора является символ «;» (точка с запятой). Операторы могут записываться в любом порядке, однако, следует помнить, что интерпретатор языка запросов однопроходный, следовательно, сначала следует описать переменную, и только потом её использовать в операторах Группировка, Функция или Условие.

Пример:

// Текст запроса
Текст3апроса =
"//({ЗАПРОС(РасчЛистки)
|  // Задаем интервал запроса
|Период с ДатаНач по ДатаКон;
|  // Определяем внутренние переменные
|Рез = ЖурналРасчетов.Зарплата.Результат;
|Расч = ЖурналРасчетов.Зарплата.ВидРасч;
|Дни = ЖурналРасчетов.Зарплата.Дни;
|Сотр = ЖурналРасчетов.Зарплата.Объект;
|  // Назначаем группировки
|Группировка Сотр без групп;
|Группировка Расч;
|  // Назначаем функции
|Функция Сум = Сумма(Рез);
|Функция Дней = Сумма(Дни);
|  // Назначаем условие
|Условие(Рез <> 0);
|"//}}ЗАПРОС
;
 . . .

Как видно из вышеприведённого примера, в тексте запроса, также как и в остальном программном коде, допускается использование комментариев. Комментарий в тексте описания запроса начинается парой символов слэша (//) и заканчивается концом строки.

Соглашения и обозначения, используемые при описании языка

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

  • [] — в квадратные скобки заключаются необязательные синтаксические элементы;
  • []+ — в квадратные скобки со знаком «+» заключаются обязательные синтаксические элементы, которые могут использоваться один или более раз;
  • []* — в квадратные скобки со знаком «*» заключаются необязательные синтаксические элементы, которые могут использоваться один или более раз;
  • () — круглые скобки заключают в себе список параметров;
  • | — вертикальной линией разделяются синтаксические элементы, среди которых нужно выбирать один и только один.

Зарезервированные слова языка запросов

Ключевые слова — это слова, которые используются в языке запросов для обозначения встроенных операторов. Приведённые далее ключевые слова являются зарезервированными и не могут использоваться в качестве имён внутренних переменных описания запросов. Каждое ключевое слово имеет два представления — русское и английское. Английское представление является традиционным для языков программирования. Ключевые слова в русском и английском представлении могут свободно смешиваться в одном исходном тексте. Регистр букв ключевых слов не имеет значения, то есть они могут быть набраны в любом регистре, например: Функция, ФУНКЦИЯ, фУНКЦИЯ.

Ниже приведен полный список зарезервированных слов языка запросов в обоих представлениях:

  • Без (Without)
  • Год (Year)
  • Групп (Groups)
  • Группировка (Group)
  • День (Day)
  • Документ (Document)
  • И (And)
  • ИЛИ (Or)
  • Квартал (Quarter)
  • Когда (When)
  • Месяц (Month)
  • Неделя (Week)
  • НомерСтроки (LineNum)
  • Обрабатывать (Process)
  • ОбрабатыватьДокументы (ProcessDocuments)
  • ОбрабатыватьОперации (PrосessOperations)
  • Период (Period)
  • ПериодЖурнала (JournalPeriod)
  • По (By)
  • По (Till)
  • С (From)
  • СтрокаДокумента (DocumentLine)
  • Упорядочить (Order)
  • Условие (Condition)
  • Функция (Function)

Использование констант

В тексте запроса, также как и в остальном программном коде, допускается использование числовых и строковых констант (литералов), а также констант типа "Дата".

Числовая константа описывается следующей синтаксической диаграммой:

[+|-][0-9]+ | [0-9]*.[0-9]+

Пример числовых констант:

-17
43.712
.43842

Строковая константа — это строка, заключенная в двойные кавычки. Она не может быть многострочной.

Пример строковой константы:

"Это текстовая константа"

Константа типа "Дата" задаётся в виде строки, заключённой в одинарные кавычки, в формате 'ДД.ММ.ГГ' или 'ДД.ММ.ГГГГ'.

Примеры констант типа "Дата":

'21.05.96'
'25.09.1964'

Внутренние переменные

Внутренние переменные — это переменные, объявленные в тексте описания запроса. Именем переменной может быть любая последовательность букв, цифр и символов подчёркивания (_), начинающаяся с буквы или знака подчёркивания. Имена внутренних переменных не должны совпадать с зарезервированными словами языка запросов. Распознавание имён переменных, названий операторов, процедур и функций ведётся без учёта регистра букв.

Примеры имён переменных:

_43842
НачПериода

Примеры использования переменных:

Сотр = НовЗапрос.Сотр;
Кат = НовЗапрос.Кат;
ИТОГ = НовЗапрос.Итого;

Конкретизация переменной

Конкретизация переменной — это уточнение описания внутренней переменной, если это возможно в текущем контексте. Конкретизации переменной могут использоваться в языке запросов в операторах Группировка ... Упорядочить По и в качестве аргумента оператора Функция.

Синтаксис:

<ВнутренняяПеременная>[.<Путь>]+

где

  • <ВнутренняяПеременная> — идентификатор объявленной ранее внутренней переменной;
  • <Путь> — доступный атрибут внутренней переменной или конкретизации переменной (см. ниже «Атрибуты, доступные при описании внутренних переменных»).

Пример использования:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
" //{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Справочник.Товары.ТекущийЭлемент, Документ.РасхНакл.Товар;
|  // используем конкретизацию внутренней переменной Тов
|Группировка Тов Упорядочить По Тов.Наименование;
|Группировка Документ;
|Группировка СтрокаДокумента;
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Внимание! Запрос не манипулирует величинами типа "Строка неограниченной длины".

Внешние переменные

Внешние переменные — это переменные из области видимости процедуры или функции программного модуля, в теле которого используется данный запрос. Внешние переменные в тексте описания запроса могут использоваться в операторах Период с и Условие.

Пример использования:

Перем ДатаНач, ДатаКон;

Процедура Сформировать()
   Если (Число(ДатаНач) = 0) ИЛИ (Число(ДатаКон) = 0) Тогда
      Предупреждение("Не задан период!");
      Возврат;
   КонецЕсли;
   // Создание объекта типа "Запрос"
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Сформировать)
   |  // используем внешние переменные ДатаНач и ДатаКон
   |с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка ПериодЖурнала;
   |Функция Сум = Сумма(Рез);
   |"//}}ЗАПРОС
   ;
   // используем внешнюю переменную ВыбСотр (это реквизит диалога)
   Если ВыбСотр.Выбран() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Сотр = ВыбСотр);";
   КонецЕсли;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапр) = 0 Тогда
      Возврат;
   КонецЕсли;
    . . .
КонецПроцедуры

Атрибуты, доступные при описании внутренних переменных

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

  • Документ (Document) — данные документов;
  • Справочник (Reference) — данные справочников;
  • Регистр (Register) — данные регистров;
  • ЖурналРасчетов (CalcJournal) — данные журналов расчёта;
  • Счет (Account) — данные счетов;
  • Операция (Operation) — данные бухгалтерских операций и проводок.

Эти названия являются первыми в пути описания переменных. В качестве атрибутов допускается использовать любые реквизиты, которые заданы для них в Конфигураторе в дереве метаданных (реквизиты для справочников, документов и журналов расчётов; измерения и ресурсы для регистров). Кроме этих атрибутов, разрешён так же доступ к следующим предопределённым атрибутам:

  • Доступные атрибуты объектов типа "Документ":
    • ВремяДок (DocTime) — время документа;
    • ДатаДок (DocDate) — дата документа;
    • НомерДок (DocNum) — номер документа;
    • НомерСтроки (LineNum) — номер строки документа;
    • ТекущийДокумент (CurDocument) — значение текущего документа.
  • Доступные атрибуты объектов типа "Справочник":
    • Родитель (Parent) — родитель элемента многоуровневого справочника;
    • Владелец (Owner) — владелец подчиненного справочника;
    • Код (Code) — код элемента справочника;
    • Наименование (Description) — наименование элемента справочника;
    • ТекущийЭлемент (CurItem) — значение текущего элемента справочника.
  • Доступные атрибуты объектов типа "Регистр":
    • НомерСтроки (LineNum) — номер строки документа, выполнившего движение регистра (в случае, когда в Модулях документов в конфигурации перед движением регистра использовали метод ПривязыватьСтроку);
    • ТекущийДокумент (CurDocument) — значение документа, выполнившего движение регистра.
  • Доступные атрибуты объектов типа "ПланСчетов":
    • БезКорреспонденций (IsSingle) — флаг того, что элемент плана счетов — забалансовый;
    • Валютный (IsCurrency) — флаг валютного учёта элемента плана счетов;
    • Код (Code) — код элемента плана счетов;
    • Количественный (IsAmount) — флаг количественного учёта элемента плана счетов;
    • Наименование (Description) — наименование элемента плана счетов;
    • ТекущийСчет (CurAccount) — значение текущего счета плана счетов.
  • Доступные атрибуты объектов типа "Операция":
    • ВремяОперации (OperTime) — время операции;
    • ДатаОперации (OperDate) — дата операции;
    • Содержание (Description) — содержание операции;
    • СуммаОперации (OperSum) — сумма операции;
    • ТекущийДокумент (CurDocument — значение документа создавшего операцию.
  • Доступные атрибуты объектов типа "Проводка":
    • ВалСумма (CurSum) — валютная сумма проводки (для счетов с валютным учётом);
    • Валюта (Currency) — валюта проводки;
    • Количество (Amount) — количество проводки (для счетов с количественным учётом);
    • КорСчет (CorAccount) — корреспондирующий счёт. Корреспондирующим счетом, для которого является Счет;
    • Сумма (Sum) — сумма проводки;
    • Счет (Account) — счет, для обработки корреспонденции. Корреспондирующим счётом, для которого является КорСчет.

Примеры использования атрибутов:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
" //{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ДОКУМ = Документ.РасходнаяБН.ТекущийДокумент,
|   Документ.РасходнаяКредит.ТекущийДокумент,
|   Документ.РасходнаяНал.ТекущийДокумент,
|   Документ.РасходнаяРеализ.ТекущийДокумент,
|   Документ.Счет.ТекущийДокумент;
|Группировка ДОКУМ; //по документам
|"//}}ЗАПРОС
;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Печать)
|Товар = Справочник.Товары.ТекущийЭлемент;
|Группировка Товар Упорядочить по Товар.МинЗапас;
|"//}}ЗАПРОС
;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
|Вес = Регистр.ПокупателиКолво.Кг;
|Покуп = Регистр.ПокупателиКолво.Покупатели;
|Док = Регистр.ПокупателиКолво.ТекущийДокумент;
|Ном = Регистр.ПокупателиКолво.НомерСтроки;
|Группировка ВидТоплива; //по измерению Регистра
|Группировка Док; // по документам, двигавшим Регистр
|Группировка Ном; // по номерам строк документов
|Функция ВсегоКолво = КонОст(Вес);
|Функция ПриходКолво = Приход(Вес);
|Условие(Покуп = ВыбПокупатель);
|"//}}ЗАПРОС
;

Правила объявления внутренних переменных

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

Синтаксис объявления внутренней переменной:

<ИмяПеременной> = <ОписаниеПеременной> [, <ОписаниеПеременной>]+;

где

  • <ИмяПеременной> — имя объявляемой внутренней переменной описания запроса;
  • <ОписаниеПеременной> — ссылка, указывающая на доступный в языке запросов атрибут документа, справочника, регистра или журнала расчётов (см. выше «Атрибуты, доступные при описании внутренних переменных»).

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

Например, можно определить внутреннюю переменную:

Товар = Документ.Перемещение.Товар, Документ.Расходная.Товар;

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

Еще пример. Допустим, у нас есть регистр Взаиморасчеты и регистр Кредиты, и в том и в другом есть измерение Клиент. Определяем внутреннюю переменную:

Должник = Регистр.Взаиморасчеты.Клиент, Регистр.Кредиты.Клиент;

Если использовать такую внутреннюю переменную для образования группировки, то она будет означать следующее: пройти по регистру Взаиморасчеты и по регистру Кредиты, вычислить заданные в запросе функции и выбрать значения клиентов, для которых значения хотя бы одной функции будет ненулевой. Здесь мы видим, что формирование запроса по регистрам имеет некоторые особенности (обязательно наличие функций, причём их вычисленные значения должны быть отличны от нуля, только в этом случае найденные объекты включаются во временный набор данных формируемый запросом).

Внимание! Если при описании внутренней переменной указать на разные типы данных, например, на "Справочник" и на "Документ", то это просто вызовет сообщение об ошибке. Например, следующее определение внутренней переменной будет ошибочным:

ААА = Справочник.Товары.ТекущийЭлемент, Документ.Счет.ТекущийДокумент;   // ЭТО ОШИБКА !!!

Однако допускается в описании внутренней переменной указание на разные справочники либо на разные документы. Переменной, указывающей на разные справочники или документы, присваивается тип данных "Справочник неопределённого вида" или "Документ неопределённого вида" соответственно. Например, правомерно задать такую внутреннюю переменную:

Парам = Документ.Счет.Клиент, Документ.Счет.Фирма;

(Здесь предполагается, что в контексте конфигурации, реквизиты Клиент и Фирма — это элементы справочников). Если использовать такую внутреннюю переменную для построения группировки, то она будет означать следующее: пройти по документам Счет и выбрать значения клиентов и фирм, встречающихся в них (и, например, упорядочить эти элементы по наименованию). Как интерпретировать результаты полученной выборки при таком запросе — будет зависеть от контекста поставленной задачи.

Особенности описания внутренних переменных для типов "Операция" и "Проводка"

В языке запросов описание внутренних переменных для агрегатных типов данных типа "Операция" и "Проводка" начинается со слова «Операция» вне зависимости от того, будет ли обращение к бухгалтерским операциям или к проводкам. Описание переменной определяется следующим образом:

Операция.(
   <Реквизиты0перации>
   |  <ПредРеквОпераций>
   |  <РеквизитыПроводок>
   |  <ПредРеквПроводок>
   |  Дебет. ( Счет | <Субконто> )
   |  Кредит. ( Счет | <Су6конто> )
   |  Субконто.<ВидСубконто>
   |  КорСубконто.<ВидСубконто>
)

где

  • <Реквизиты0перации> — реквизиты операции, объявленные в метаданных;
  • <ПредРеквОпераций> — предопределённые реквизиты операций;
  • <РеквизитыПроводок> — реквизиты проводок, объявленные в метаданных;
  • <ПредРеквПроводок> — предопределённые реквизиты проводок;
  • <ВидСубконто> — идентификатор вида субконто.

Применение слов «Дебет», «Кредит» в описании переменных позволяют оперировать дебетовой и кредитовой частями проводки, такими как счёт и вид субконто. Применение слов «Субконто» и «КорСубконто» в описании переменных позволяют оперировать как субконто, так и корреспондирующим субконто.

Пример:

Сум = Операция.Сумма;
Сч = Операция.Дебет.Счет, Операция.Кредит.Счет;

О дополнительных именах доступа

Несколько слов о дополнительных именах доступа к стандартной информации, которые определены в языке запросов. Речь идёт о конструкции ТекущийЭлемент для справочников и ТекущийДокумент для документов и регистров (не надо путать эти конструкции языка запросов с одноимёнными методами встроенного языка, хотя их смысл во многом совпадает).

Для справочников использование конструкции ТекущийЭлемент в описании внутренней переменной означает выборку элемента справочника как такового (целиком всей записи справочника).

Аналогично при работе с документами, использование конструкции ТекущийДокумент в описании внутренней переменной, означает выборку документа как такового (целиком всего документа как объекта конфигурации). Сравните два примера, приведённых ниже.

Пример 1. Здесь нас интересуют товары, встречающиеся в документах:

ТОВАР = Документ.РасходнаяБН.Товар, 
   Документ.РасходнаяКредит.Товар,
   Документ.РасходнаяНал.Товар,
   Документ.РасходнаяРеализ.Товар,
   Документ.Счет.Товар;

Пример 2. Здесь нас интересуют сами документы указанных видов как таковые:

ДОКУМ = Документ.РасходнаяБН.ТекущийДокумент, 
   Документ.РасходнаяКредит.ТекущийДокумент,
   Документ.РасходнаяНал.ТекущийДокумент,
   Документ.РасходнаяРеализ.ТекущийДокумент,
   Документ.Счет.ТекущийДокумект;

Использование для документов конструкции НомерСтроки в описании внутренней переменной, означает выборку номеров строк документов (не самих строк, а чисел, обозначающих номера строк в документе):

СТРОКА = Документ.РасходнаяБН.НомерСтроки;

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

Использование для регистра конструкции НомерСтроки в описании внутренней переменной, означает выборку связанных номеров строк тех документов, которые произвели движение по регистру (в случае, когда в Модулях документов в конфигурации перед движением регистра использовали метод ПривязыватьСтроку()).

Пример:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
|Покуп = Регистр.ПокупателиКопво.Покупатели;
|Док = Регистр.ПокупателиКолво.ТекущийДокумент;
|Ном = Регистр.ПокупателиКолво.НомерСтроки;
|Вес = Регистр.ПокупателиКолво.Кг;
|Группировка ВидТоплива; // по измерению Регистра
|Группировка Док; //по документам, двигавшим Регистр
|Группировка Ном; // по номерам строк документов
|Функция ВсегоКолво = КонОст(Вес);
|Функция ПриходКолво = Приход(Вес);
|Условие(Покуп = Покупат);
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

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

Операторы языка запросов

Установить интервал дат формирования запроса позволяет оператор Период С ... По (англоязычный синоним — Period From ... Till). Если в описании запроса оператор Период С ... По опущен, то интервал дат формирования запроса устанавливается в точку актуальности итогов (ТА) (или на рабочую дату, если не установлена компонента «Оперативный учет»), запрос формируется только на этот момент времени.

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

Синтаксис оператора:

[[Период] С <Дата>|<ВнешПеременная> [По <Дата>|<ВнешПеременная>];]

где

  • <Дата> — константа типа "Дата", "Документ" или позиция документа;
  • <ВнешПеременная> — внешняя переменная типа "Дата", "Документ" или позиция документа. Если указан документ, то за момент времени принимается дата и время документа;
  • По — добавочное ключевое слово для связки первой части команды со второй, необязательной частью.

Параметрами оператора Период С являются значения момента времени ("Дата", "Документ" или позиция документа) начала и конца временного интервала. Следует особо обратить внимание, что если интервал задаётся с точностью до даты, то интервал времени считается от начала даты нижней границы интервала до конца даты верхней границы интервала. Если вторая часть оператора после ключевого слова По пропущена или значение второго параметра команды равно нулю, то интервал времени применяется от начального момента времени до ТА (или по рабочую дату, если не установлена компонента «Оперативный учет»). Это особенно важно при формировании запросов по регистрам, так как запрос по регистрам может строиться от любой даты в прошлом до ТА. Поэтому, если вы укажете в запросе верхнюю границу интервала большей или равной дате ТА, то программа, скорее всего, сообщит «Не могу рассчитать регистры за ТА» (поскольку время ТА лежит где то в пределах даты, а запрос пытается учесть всю дату в целом). Поэтому при формировании текста запроса следует вставлять дополнительную проверку типа той, что приведена в следующем примере:

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
 . . .
|Счет = Регистр.Cash.Счет;
|Статья = Регистр.Cash.Статья;
|СуммаЭквивалента2 = Регистр.Cash.СуммаЭквивалента2;
|СуммаЭквивалента1 = Регистр.Cash.СуммаЭквивалента1;
 . . .

Если ДатаКонца >= ПолучитьДатуТА() Тогда
   ТекстЗапроса = ТекстЗапроса + "Период с ДатаНачала;";
Иначе
   ТекстЗапроса = ТекстЗапроса + "Период с ДатаНачала по ДатаКонца;";
КонецЕсли;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

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

Применение конструкции С ... По ... приводит к тому, что выборка записей из журнала расчётов проводится по времени действия записей журнала расчётов, определяемых реквизитами журнала расчётов ДатаНачала и ДатаОкончания, а не временем их ввода в журнал.

Примечание: Работа запроса с журналами расчётов, с использованием конструкции Период С ... По ..., аналогична выборке записей в журнале расчётов, организуемой при помощи метода журнала расчётов ВыбратьПериод(). С другой стороны, запрос, использующий конструкцию С ... По ..., аналогичен выборке, организуемой при помощи метода журнала расчётов ВыбратьЗаписи().

Пример 1:

Процедура РасчЛистки()
   Перем Запрос, Флаг;
   Перем ДатаНач, ДатаКон;
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   ДатаНач = ЖР.НачалоТекущегоПериода();
   ДатаКон = ЖР.КонецТекущегоПериода();
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   Флаг = Запрос.Выполнить(
   "//{{ЗАПРОС(РасчЛистки)
   |Период С ДатаНач По ДатаКон; // выборка по расчетным периодам!
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Расч = ЖурналРасчетов.Зарплата.ВидРасч;
   |Дни = ЖурналРасчетов.Зарплата.Дни;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка Расч;
   |функция Сум = Сумма(Рез);
   |функция Дней = Сумма(Дни);
   |Условие(Рез о 0);
   |"//}}ЗАПРОС
   );
    . . .
КонецПроцедуры;

Пример 2:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
// Ниже формируется текст запроса с выборкой по времени
// действия записей журнала расчетов, а не по расчетным периодам!
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|С ДатаНач По ДатаКон;
|Рез = ЖурналРасчетов.Зарплата.Результат;
|Сотр = ЖурналРасчетов.Зарплата.Объект;
|ПЖ = ЖурналРасчетов.Зарплата.ПериодРегистрации;
|Группировка Сотр без групп;
|Группировка ПЖ;
|Функция Сум = Сумма(Рез);
|"//}}ЗАПРОС
;
Флаг = Запрос.Выполнить(ТекстЗапроса);
 . . .

Назначить режим обработки документов в запросе позволяет оператор ОбрабатыватьДокументы (англоязычный синоним — ProcessDocuments). В операторе указывается, какими документами должен оперировать запрос: непроведёнными (NonTransacted), проведёнными (Transacted) или теми и другими (All). По умолчанию в запросе обрабатываются только проведённые документы.

Синтаксис оператора:

ОбрабатыватьДокументы [Непроведенные|Проведенные|Все];

где Непроведенные, Проведенные, Все — указание, какие документы следует обрабатывать.

Пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаДок)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьДокументы Все;
|Тов = Справочник.Товары.ТекущийЭлемент, Документ.РасхНакл.Товар;
|Группировка Тов упорядочить по Тов.Наименование;
|Группировка Документ;
|Группировка СтрокаДокумента;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Назначить режим обработки бухгалтерских операций в запросе позволяет оператор ОбрабатыватьОперации (англоязычный синоним — ProcessOperations). В операторе указывается, какими операциями должен оперировать запрос: с включенными проводками (On), с выключенными проводками (Off) или теми и другими (All). По умолчанию в запросе обрабатываются только операции с включенными проводками.

Синтаксис оператора:

ОбрабатыватьОперации [Включенные|Выключенные|Все];

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

Пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ОбработкаОпер)
|Период с '01.10.96' по '05.10.96';
|ОбрабатыватьОперации Все;
|Опер = Операция.ТекущийДокумент;
|Группировка Опер;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Назначить режим обработки помеченных на удаление объектов в запросе позволяет оператор Обрабатывать (англоязычный синоним — Process). В операторе указывается, какими объектами должен оперировать запрос: не помеченными на удаление (NonMarkedOnRemoving), помеченными на удаление (MarkedOnRemoving) или теми и другими (All). По умолчанию в запросе обрабатываются все объекты.

Синтаксис оператора:

Обрабатывать [ПомеченныеНаУдаление|НеПомеченныеНаУдаление|Все];

где ПомеченныеНаУдаление, НеПомеченныеНаУдаление, Все — указание, какие объекты следует обрабатывать.

Пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Обработка)
|Период с '01.10.96' по '05.10.96';
|Обрабатывать НеПомеченныеНаУдаление;
|Товар = Справочник.Товар.ТекущийЭлемент;
|Группировка Товар упорядочить по Товар.Наименование;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Вычислить указанный тип функции и присваивает её значение внутренней переменной позволяет оператор Функция (англоязычный синоним — Function).

Синтаксис оператора:

Функция <ИмяФункции> = <ТипФункции> (<Параметр>|<УточненныйПараметр>) [Когда (<Условие>)];

где

  • <ИмяФункции> — имя, которое присваивается функции. По этому имени можно в дальнейшем обращаться к значению вычисленной функции из вызывающего программного модуля как к атрибуту запроса. Данную внутреннюю переменную заранее объявлять не нужно. Она фактически неявно объявляется в операторе Функция;
  • <ТипФункции> — ключевое слово одной из встроенных функций языка (см. список типов ниже);
  • <Параметр> — имя объявленной ранее внутренней переменной, значение которой используется как параметр встроенной функции. В функциях Сумма, Среднее, Максимум, Минимум в качестве данного параметра возможно использование арифметического выражения в терминах встроенного языка «1С:Предприятие»;
  • <УточненныйПараметр> — конкретизация объявленной ранее внутренней переменной, значение которой используется как аргумент встроенной функции;
  • Когда (англ. When) — необязательное добавочное ключевое слово, использование которого в команде означает, что вычисление функции следует производить только при условии, когда заданное логическое выражение <Условие> истинно;
  • <Условие> — логическое выражение встроенного языка «1С:Предприятие». В логическом выражении могут участвовать как внутренние, так и внешние переменные запроса. Используется только после ключевого слова Когда.

Типы применяемых функций предопределены и могут быть следующими:

  • Сумма (Sum) — вычисляет сумму выбранных по запросу значений параметра*;
  • Среднее (Avg) — вычисляет среднее из выбранных по запросу значений параметра;
  • Минимум (Min) — вычисляет минимум из выбранных по запросу значений параметра;
  • Максимум (Мах) — вычисляет максимум из выбранных по запросу значений параметра;
  • Счётчик (Count) — подсчитывает количество записей, вошедших в выборку;
  • НачОст (BegRest) — вычисляет начальный остаток для выбранных по запросу значений параметра**;
  • КонОст (EndRest) — вычисляет конечный остаток для выбранных по запросу значений параметра**;
  • Приход (Debit) — вычисляет приход для выбранных но запросу значений параметра**;
  • Расход (Credit) — вычисляет расход для выбранных по запросу значений параметра**;
  • СНД (IDB) — вычисляет сальдо начальное дебетовое для выбранных по запросу значений параметра***;
  • СКД (FDB) — вычисляет сальдо конечное дебетовое для выбранных по запросу значений параметра***;
  • СНК (ICD) — вычисляет сальдо начальное кредитовое для выбранных по запросу значений параметра***;
  • СКК (FCD) — вычисляет сальдо конечное кредитовое для выбранных по запросу значений параметра***;
  • ДО (TD) — вычисляет дебетовые обороты для выбранных по запросу значений параметра***;
  • КО (TC) — вычисляет кредитовые обороты для выбран ных по запросу значений параметра***;
  • КорДО (CorTD) — вычисляет дебетовые обороты между корреспондирующим счетам или субконто для выбранных по запросу значений параметра****;
  • КорКО (CorTC) — вычисляет кредитовые обороты между корреспондирующим счетам или субконто для выбранных по запросу значений параметра****;

Примечания:

* Для ресурсов оборотных регистров допускается вызывать только тип функции "Сумма".

** Типы функций "НачОст", "КонОст", "Приход", "Расход" можно использовать только с параметрами, указывающими на ресурсы регистров остатков. Для ресурсов регистров остатков другие типы функций вызывать нельзя.

*** Функции "СНД", "СНК", "СКД", "СКК", "ДО", "КО" можно использовать только с реквизитами проводки: Сумма, Количество или ВалСумма.

**** Функции "КорДО" и "КорКО" можно использовать только с реквизитами проводки: Сумма, Количество или ВалСумма. Функции накапливают значения только тогда, когда в запросе есть обращение к реквизитам проводок Счет, КорСчет, Субконто или КорСубконто.

Примечание 5: В программном модуле, где используется запрос, <ИмяФункции> будет являться атрибутом запроса. При помощи данного атрибута можно обращаться к значению вычисленной в запросе функции.

Примечание 6: В функциях "Сумма", "Среднее", "Максимум", "Минимум" в качестве аргумента возможно использование арифметического выражения в терминах встроенного языка.

Пример:

 . . .
|КолВо = Документ.ВидДокумента.Количество;
|Цена = Документ.ВидДокумента.Цена;
|Функция Сум = Сумма(КолВо * Цена);
|Функция Макс = Максимум(Окр(КолВо) * Окр(Цена));
|Функция Средн = Среднее(ФункцияОпределеннаяВМодуле(КолВо, Цена));
 . . .

Другой пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//ЗАПРОС(Функции)
|Период с ДатаНач по ДатаКон;
|Оклад = Справочник.Сотрудники.Оклад;
|Подр = Справочник.Сотрудники.Подразделение;
|Ктг = Справочник.Сотрудники.Категория;
|Группировка Подр без групп;
|Группировка Ктг без групп;
|Функция Всего = Сумма(Оклад);
|Условие((Ктг.Выбран() = 1) И (Подр.Выбран() = 1));
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;
 . . .
Итог = Запрос.Всего;
 . . .

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

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

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

В тексте запроса, при описании оператора Функция можно использовать необязательное ключевое слово Когда, использование которого в операторе означает, что вычисление функции следует производить только при условии, что значение логического выражения, заданного в параметре ключевого слова является "Истина". Синтаксис применяемого логического выражения полностью аналогичен синтаксису разрешённому к применению в операторах Условие.

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

|Функция ПрихКол = Приход(Количество);
|Функция РасхКол = Расход(Количество);

имеют четкий смысл — приращения, сделанные документом при движении регистра. С другой стороны, в той же группировке следующие функции

|Функция НачКол = НачОст(Количество);
|Функция КонКол = КонОст(Количество);

явно не имеют смысла (в запросах по регистрам, обычно задают период запроса при помощи оператора Период C. Функция "НачКол" в данном примере должна по смыслу показывать остаток ресурса Количество на начальную дату запроса. Внутри группировки по документу вопрос: «Какой начальный остаток ресурса на дату 10.01.97?» по документу, проведённому, например, 13.01.97, не имеет смысла). Поэтому в таких ситуациях функция будет иметь нулевое значение.

Пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//ЗАПРОС(Функции)
|Период с ДатаОтчета;
|Товар = Регистр.КвотыТоваров.Товар;
|Отдел = Регистр.КвотыТоваров.Отдел;
|Сотрудник = Регистр.КвотыТоваров.Сотрудник;
|Партнер = Регистр.КвотыТоваров.Партнер;
|Док = Регистр.КвотыТоваров.ТекущийДокумент;
|Количество = Регистр.КвотыТоваров.КвотаТовара;
|Группировка Товар;
|Группировка Отдел;
|Группировка Сотрудник;
|Группировка Партнер;
|Группировка Док;
|Функция НачКол = НачОст(Количество);
|Функция ПрихКол = Приход(Количество);
|Функция РасхКол = Расход(Количество);
|Функция КонКол = КонОст(Количество);
|// Следующие Функции вычисляем только при определенных
|// условиях, чтобы получить отфильтрованные итоги
|Функция ПрихКолТов = Приход(Количество) Когда (Док.ФлагТовара = 1);
|Функция РасхКолТов = Расход(Количество) Когда (Док.ФлагТовара = 1);
|Функция ПрихКолОтд = Приход(Количество) Когда (Док.ФлагОтдела = 1);
|Функция РасхКолОтд = Расход(Количество) Когда (Док.ФлагОтдела = 1);
|Функция ПрихКолСотр = Приход(Количество) Когда (Док.ФлагСотрудника = 1);
|Функция РасхКолСотр = Расход(Количество) Когда (Док.ФлагСотрудника = 1);
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

Задать способ группировки информации и порядок её упорядочивания в запросе позволяет оператор Группировка (англоязычный синоним — Group). От способа группировки информации и порядка её упорядочивания в запросе зависит последующий порядок её выборки.

Синтаксис оператора:

Группировка <ИмяГруппировки>|<ПредопредГруппировка> [Упорядочить по <Порядок>[, <Порядок&#gt;]*]
            [Без Упорядочивания][Без Групп][Все [ВошедшиеВЗапрос]];

где

  • <ИмяГруппировки> — имя объявленной ранее внутренней переменной, по значению которой устанавливается порядок выборки. По этому имени можно в дальнейшем обращаться к значению группировки из вызывающего программного модуля как к атрибуту запроса;
  • <ПредопредГруппировка> — ключевое слово одной из встроенных предопределенных группировок языка запросов (см. список ниже). По этому имени можно будет обращаться к значению группировки из вызывающего программного модуля;
  • Упорядочить по (англ. Order By) — необязательное добавочное ключевое слово. Параметры, следующие за данным ключевым словом, определяют упорядочивание строк в группировке. По умолчанию документы упорядочиваются по дате и времени документов, справочники — по коду или наименованию, в зависимости от основного представления, заданного при описании справочника в Конфигураторе;
  • <Порядок> — используется только после ключевого слова Упорядочить по. Конкретизация внутренней переменной <ИмяГруппировки>, значение которой является параметром упорядочивания строк в группировке. Кроме того, в данном параметре можно использовать имя функции, объявленной в этом же запросе в операторе Функция;
  • Без Упорядочивания (англ. Without Order) — необязательное добавочное ключевое слово, которое преследует цель уменьшения времени формирования запроса, при условии, что ни упорядочивание, ни значения упорядочивания при использовании данного запроса не нужны;
  • Без Групп (англ. Without Groups) — необязательное добавочное ключевое слово, использование которого назначает вывод в запрос только простых элементов справочников (исключая группы). Используется только для группировок, построенных на основе внутренней переменной типа "Справочник";
  • Все (англ. All) — необязательное добавочное ключевое слово, действие которого зависит от типа внутренней переменной, на основе которой построена группировка. Используется только для группировок, построенных на основе внутренней переменной типа "Справочник", или для предопределённых группировок, задающих временной интервал (Год, Месяц, Квартал, Неделя, День). Для предопределённых временных группировок подразумевается, что в запрос будут включены любые значения данных (в том числе нулевые) в каждый заданный момент времени с даты начала запроса по дату конца запроса (интервал задаётся оператором Период С...). Для группировок по справочникам подразумевается, что в запрос будут включены любые значения данных (в том числе нулевые) для каждого допустимого элемента справочника;
  • ВошедшиеВЗапрос (англ. IncludedInQuery) — необязательное добавочное ключевое слово действие которого уточняет предыдущее ключевое слово Все. Использование данного слова подразумевает, что в каждую строку запроса будут включены значения данных (в том числе нулевые), для которых есть ненулевое значение хотя бы в одной строке запроса.

Предопределённые группировки могут быть следующими:

  • Документ (Document) — позволяет детализацию до каждого документа;
  • СтрокаДокумента (DocumentLine) — позволяет детализацию до каждой строки табличной части каждого документа;
  • День (Day), Неделя (Week), Месяц (Month), Квартал (Quarter), Год (Year) — группировки по дате, дают возможность накапливать значения по документам за конкретный период (на каждый день, неделю, месяц и т.д.). В запросе может присутствовать несколько группировок такого типа.

Замечание: В программном модуле, где используется запрос, имя <ИмяГруппировки> (или <ПредопредГруппировка>) будет являться атрибутом запроса. Кроме того, это имя используется в качестве параметра метода запросов Группировка().

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

Несколько операторов Группировка, следующих друг за другом в описании запроса, создают вложенные группировки запроса. Первая группировка — самая старшая, в неё будет вложена следующая группировка, далее будет вложена следующая и т.д. По смыслу, вложенная группировка осуществляет более детальный просмотр объекта внешней группировки. Например, если во внешней группировке мы просматриваем регистр, то во вложенной группировке можно просмотреть документы движений этого регистра, а далее можно сформировать группировку по номерам строк этих документов.

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

По умолчанию, документы упорядочиваются в группировке по дате и времени документов, элементы справочников — в зависимости от основного представления, заданного при описании справочника в Конфигураторе (код или наименование). Однако критерий упорядочивания в группировке можно установить при помощи необязательного ключевого слова Упорядочить по. Параметры, следующие за данным ключевым словом, определяют упорядочивание строк в группировке.

С параметром упорядочивания связан специальный метод для доступа к значениям объекта "Запрос". Речь идет об использовании метода ЗначениеУпорядочивания(). В программном модуле, после того как запрос уже сформирован, мы можем при помощи этого метода получить значение поля упорядочивания из временного набора данных, не обращаясь к базе данных. Например, если у нас в запросе была группировка "Товар", а нам для формирования некоторого отчёта нужны значения наименований товаров, то эти наименования товаров можно получить двумя способами:

Наим = Запрос.Товар.Наименование;

// или

Наим = Запрос.ЗначениеУпорядочивания("Товар", 1);

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

Пример:

Процедура Группировки()
   Перем Запрос, ТекстЗапроса;
   Перем ДатаНач, ДатаКон;
   ЖР = СоздатьОбъект("ЖурналРасчетов.Зарплата");
   ДатаНач = ЖР.НачалоТекущегоПериода();
   ДатаКон = ЖР.КонецТекущегоПериода();
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(Группировки)
   |Период с ДатаНач по ДатаКон;
   |Рез = ЖурналРасчетов.Зарплата.Результат;
   |Расч = ЖурналРасчетов.Зарплата.ВидРасч;
   |Дни = ЖурналРасчетов.Зарплата.Дни;
   |Сотр = ЖурналРасчетов.Зарплата.Объект;
   |Группировка Сотр без групп;
   |Группировка Расч;
   |Функция Сум = Сумма(Рез);
   |Функция Дней = Сумма(Дни);
   |Условие(Рез о 0);
   |"//})ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Пока Запрос.Группировка("Сотр") = 1 Цикл
      // Заполнение полей Сотр
      Таб.ВывестиСекцию("Сотр");
      Пока Запрос.Группировка("Расч") = 1 Цикл
         // Заполнение полей Расч
         Таб.ВывестиСекцию("Расч");
      КонецЦикла;
   КонецЦикла;
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Результат", );
КонецПроцедуры

Увеличить скорости выполнения запроса, если итоговые записи при использовании запроса не нужны, позволяет оператор Без итогов (англоязычный синоним — Without Totals). Данный оператор языка запросов, даёт возможность не накапливать итоги по группировкам. Использовать данный оператор в тексте запроса имеет смысл, когда запрос строится не для формирования сложного отчёта, а например, для простой выборки значений из информационной базы для последующей их обработки.

В случае применения данного оператора в тексте запроса, при обходе результатов запроса применяется только один цикл обхода, используя метод объекта "Запрос" Группировка() без параметра.

Пример:

// Создание объекта типа Запрос
Запрос = СоздатьОбъект("Запрос");
Текст3апроса = "
 . . .
|Группировка Товар;
|Группировка Склад;
|Без Итогов;
|"//})ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
   Возврат;
КонецЕсли;

Пока Запрос.Группировка() = 1 Цикл
    . . .
КонецЦикла;

Примечание: Если в тексте запроса используется группировка по многоуровневому справочнику и не указано "Без Групп", то итоги по группам справочника будут накапливаться. Другими словами, если в запросе не нужны итоги по группам справочника, то в тексте запроса кроме использования оператора Без Итогов дополнительно следует в операторах Группировка ... использовать ключевое слово Без Групп.

Задать условие включения информации в запрос позволяет оператор Условие (англоязычный синоним — Condition). Если указанное в качестве параметра логическое выражение истинно, то информация включается в запрос, иначе нет.

Синтаксис оператора:

Условие(<ЛогическоеВыражение>);

где <ЛогическоеВыражение> — логическое выражение встроенного языка «1С:Предприятие». В логическом выражении могут участвовать как внутренние, так и внешние переменные запроса, то есть переменные программного модуля, доступные в процедуре, использующей запрос.

Пример:

ТекстЗапроса =
"//{{ЗАПРОС(Одинарный)
|Период с ДатаНачала по ДатаКонец;
|Оклад = Справочник.Сотрудники.Оклад;
|Ктг = Справочник.Сотрудники.Категория;
|Группировка Ктг без групп;
|Функция Всего = Сумма(Оклад);
|Условие(Ктг.Выбран() = 1);   // только для тех сотрудников
| // у кого заполнен реквизит Категория
|"//}}ЗАПРОС
;

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

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Квоты)
|Товар = Регистр.КвотыТоваров.Товар;
|Отдел = Регистр.КвотыТоваров.Отдел;
|Сотрудник = Регистр.КвотыТоваров.Сотрудник;
|Партнер = Регистр.КвотыТоваров.Партнер;
|Количество = Регистр.КвотыТоваров.КвотаТовара;
|Группировка Товар;
|Группировка Отдел;
|Группировка Сотрудник;
|Группировка Партнер;
|Функция Кол_во = КонОст(Количество);
|Условие(Товар.ПринадлежитГруппе(ВыбТовар) = 1);
|Условие(Отдел = ВыбОтдел);
|Условие(Сотрудник = ВыбСотрудник.Сотрудник);
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
   Возврат;
КонецЕсли;

В параметре оператора Условие(), в принципе, можно записывать логические выражения любой сложности (по правилам встроенного языка «1С:Предприятие»), используя любые логические операторы (>, <, =, >=, <>, И, ИЛИ, НЕ и др.), при этом в качестве операндов могут участвовать как внутренние, так и внешние переменные запроса (если существуют внутренняя и внешняя переменные с одинаковым именем, то использоваться по данному имени будет внутренняя переменная).

Пример:

Условие(Цена > 23.5);
Условие((Товар.ПринадлежитГруппе(ВыбТовар) = 1) И (Товар.Розн_Цена = 100));

Использование двух операторов

Условие(Товар.Наименование <> "Стол");
Условие(Товар.Наименование <> "Шкаф");

аналогично одному оператору

Условие((Товар.Наименование <> "Стол") И (Товар.Наименование <> "Шкаф"));

Кроме обычных логических операторов в операторе Условие() языка запросов можно использовать дополнительный оператор — логический оператор принадлежности В (англоязычный синоним — In). Тогда, например, оператор языка запросов Условие (А в Б); будет говорить о том, что условие истинно, когда значение А является подмножеством значения Б. Причём, следует особо отметить, что если значение Б будет пустое (объект не выбран), то условие будет является истинным, в отличии от оператора = (равно).

Если на принадлежность проверяется значение типа "элемент справочника", то проверка выполняется с учётом его возможного вхождения в группу справочника. Аналогично, проверка на принадлежность субсчёта осуществляется с учётом его возможного вхождения в группу счетов.

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

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

Текст3апроса = "
 . . .
|Товар = Документ.ВидДокумента.Товар;";
 . . .
|"//}}ЗАПРОС
;

Если ВыбТовар.Выбран() = 1 Тогда
   Если ВыбТовар.ЭтоГруппа() = 1 Тогда
      ТекстЗапроса = ТекстЗапроса + "Условие(Товар.ПринадлежитГруппе(ВыбТовар) = 1);";
   Иначе
      ТекстЗапроса = ТекстЗапроса + "Условие(Товар = ВыбТовар);";
   КонецЕсли
КонецЕсли;

А теперь тот же пример, но с использованием логического оператора принадлежности:

Текст3апроса = "
 . . .
|Товар = Документ.ВидДокумента.Товар;";
 . . .
|Условие(Товар В ВыбТовар);
 . . .
|"//}}ЗАПРОС
;

Примеры использования запросов

Печать каталога товаров

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

Процедура ПечатьСправочника()
   // Процедура печати полного справочника товаров
   Перем Запрос, ТекстЗапроса, Таб;
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   Текст3апроса = "//{{ЗАПРОС(Печать)
   |Товар = Справочник.Товары.ТекущийЭлемент;
   |Группировка Товар Упорядочить по Товар.МинЗапас;
   |"//}}ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Заполнение выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Товар") = 1 Цикл
      // Заполнение полей Товар
      Если Запрос.Товар.ЭтоГруппа() = 1 Тогда
         Таб.ВывестиСекцию("Группа");
      Иначе
         Таб.ВывестиСекцию("Товар");
      КонецЕсли;
   КонецЦикла;
   // Отображение выходного отчета
   Таб.Опции(0, 0, 4, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("Список товаров по каталогу", "");
КонецПроцедуры

Отчёт по неходовым товарам

Ниже приведён пример нетривиального использования запроса для просмотра одновременно многих видов документов. Цель данной процедуры — вывести в отчёт перечень неходовых товаров, которые совсем не продавались за заданный период и показать в каждой строке текущий остаток и стоимость этих товаров. В данном примере запрос формируется с целью определить, что в него не вошло.

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса, Таб;
   Рег = СоздатьОбъект("Регистр.ОстаткиТовара");
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период С ДатаНачала По ДатаКонца;
   |ТОВАР = Документ.РасходнаяБН.Товар, 
   |   Документ.РасходнаяКредит.Товар, Документ.РасходнаяНал.Товар,
   |   Документ.РасходнаяРеализ.Товар, Документ.Счет.Товар;
   |Группировка ТОВАР упорядочить по ТОВАР.Наименование без групп;
   |"//}}ЗАПРОС
   ;
   Если ДатаКонца >= ПолучитьДатуТА() Тогда
      ТекстЗапроса = ТекстЗапроса + "Период С ДатаНачала;";
   Иначе
      ТекстЗапроса = ТекстЗапроса + "Период С ДатаНачала По ДатаКонца;";
      Peг.ВременныйРасчет();
      РассчитатьРегистрыНа(ДатаКонца);
   КонецЕсли;
   // Выполнение Запроса
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   Тов = СоздатьОбъект("Справочник.Товары");
   // обход включая группировки
   Тов.ВключатьПодчиненные(1);
   // упорядочить по наименованиям
   Тов.ПорядокНаименований();
   ИтогоОстаток = 0;
   ИтогоСумма = 0;
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   // Запускаем полный цикл по товарам Справочника
   Тов.ВыбратьЭлементы();
   Пока Тов.ПолучитьЭлемент() > 0 Цикл
      Флаг = 0;
      Товар = Тов.ТекущийЭлемент();
      Если Товар.ЭтоГруппа() = 1 Тогда
         Продолжить;
      КонецЕсли;
      // Здесь пытаемся получить из Запроса информацию о товаре, 
      // но используем просто сам факт того, что товар попал во
      // временный набор данных Запроса.
      // Если товар есть в Запросе, то значит он упоминался в
      // каких то документах, 
      // иначе — товар не пользуется спросом — неходовой.
      Если Запрос.Получить(Товар) = 1 Тогда
         Продолжить;
      КонецЕсли;
      // находим остатки неходового товара на складе
      Рег.СводныеОстатки(Товар, );
      ТекОстаток = Рег.ОстатокТовара;
      ТекСумма = Рег.БазоваяСтоимость;
      Если ТекОстаток = 0 Тогда
         Продолжить;
      КонецЕсли;
      Таб.ВывестиСекцию("Товар");
      ИтогоОстаток = ИтогоОстаток + ТекОстаток;
      ИтогоСумма = ИтогоСумма + ТекСумма;
   КонецЦикла;
   Таб.ВывестиСекцию("Итоги");
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 0, 3, 0);
   Таб.Показать("Отчет о неходовых товарах", "");
КонецПроцедуры

// ----------------------------------------------

ДатаКонца = РабочаяДата();
ДатаНачала = ДатаКонца — Константа.ПериодАнализа;

Отчёт по регистру с точностью до строки документа

Ниже приведён пример использования запроса для просмотра регистра с выборкой документов, производивших движение данного регистра, с доступом к каждой строке этих документов. Цель данной процедуры — сформировать отчёт, чтобы по каждому из видов топлива, отпущенных за заданный период покупателям, показать перечень номеров автомашин, которым производилась отгрузка. Особенностью данного отчёта является то, что номера автомашин не являются измерениями регистра, а зафиксированы в каждой строке отпускного документа.

Использование в описании внутренней переменной для регистра атрибута НомерСтроки, означает выборку связанных номеров строк тех документов, которые произвели движение по регистру (предполагается, что в конфигурации в Модулях документов перед движением данного регистра использовали метод ПривязыватьСтроку()).

Процедура Сформировать()
   Перем Запрос, ТекстЗапроса, Таб;
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период с НачДата по КонДата;
   |ВидТоплива = Регистр.ПокупателиКолво.ВидыТоплива;
   |Вес = Регистр.ПокупателиКолво.Кг;
   |Покуп = Регистр.ПокупателиКолво.Покупатели;
   |Док = Регистр.ПокупателиКолво.ТекущийДокумент;
   |Ном = Регистр.ПокупателиКолво.НомерСтроки;
   |Группировка ВидТоплива;      // по измерению Регистра
   |Группировка Док;             // по документам, двигавшим Регистр
   |Группировка Ном;             // по номерам строк документов
   |Функция ВсегоКолво = КонОст(Вес);
   |Функция ПриходКолво = Приход(Вес);
   |Условие(Покуп = ВыбПокупатель);
   |"//}}ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Заполнение выходных форм данными Запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("Таблица1");
   Таб.ВывестиСекцию("Шапка");
   Пока Запрос.Группировка(1) = 1 Цикл
      // Отображаем значение измерения — ВидТоплива
      Таб.ВывестиСекцию("ВидТоплива");
      // запускаем вложенную группировку по документам,
      // которые производили движения Регистра
      Пока Запрос.Группировка(2) = 1 Цикл
         Док1 = Запрос.Док;
         // отфильтруем нужные нам документы
         Если НЕ(Док1.Вид() = "Продажа") Тогда
            Продолжить;
         КонецЕсли;
         // запускаем вложенную группировку по строкам
         // документа, связанным с движениями регистра
         Пока Запрос.Группировка(3) = 1 Цикл
            // Получаем в документе строку по найденному номеру
            Док1.ПолучитьСтрокуПоНомеру(Запрос.Ном);
            Таб.ВывестиСекцию("Строка");
         КонецЦикла;
      КонецЦикла;
   КонецЦикла;
   // Вывод заполненной формы
   Таб.Опции(0, 0, 0, 0);
   Таб.ТолькоПросмотр(1);
   Таб.Показать("", "");
КонецПроцедуры

Анализ счёта

Ниже приведён пример использования запроса для работы с бухгалтерскими операциями и проводками. Запрос обрабатывает корреспонденции счёта Сч со счетами КорСч за расчётный период. Значение счёта для анализа задаётся в диалоге установкой ВыбСч.

Процедура АнализСчета()
   Перем Запрос, ТекстЗапроса, Таб;
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
   |Период с ДатаС по ДатаПо;
   |Сч = Операция.Счет;
   |КорСч = Операция.КорСчет;
   |Сумма = Операция.Сумма;
   |Группировка Сч упорядочить по Сч.Код;
   |Группировка КорСч упорядочить по КорСч.Код;
   |Функция КорДо = КорДО(Сумма);
   |Функция КорКо = КорКО(Сумма);
   |Условие(Сч = ВыбСч);
   |"//}}ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("Сформировать");
   // Заполнение полей "Заголовок"
   Таб.ВывестиСекцию("Заголовок");
   Состояние("Заполнение выходной таблицы...");
   Пока Запрос.Группировка("Сч") = 1 Цикл
      // Заполнение полей Сч
      Таб.ВывестиСекцию("Сч");
      Пока Запрос.Группировка("КорСч") = 1 Цикл
         // Заполнение полей КорСч
         Таб.ВывестиСекцию("КорСч");
      КонецЦикла;
   КонецЦикла;
   // Заполнение полей "Итого"
   Таб.ВывестиСекцию("Итого");
   // Вывод заполненной формы
   Таб.Опции(1, 0, 1, 0);
   Таб.Показать("Сформировать", "");
КонецПроцедуры

Разработка вложенных отчётов

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

Поскольку каждая ячейка таблицы может содержать значение, записанное в неё, то в программном модуле формы отчёта возможно обрабатывать это значение. Обработка значения ячейки таблицы вызывается системой по клавише Enter или по двойному щелчку мышью на какой-либо ячейке (если режим «только просмотр»). Стандартными действиями системы на обработку такого события являются: для документа — открытие документа, для элемента справочника — открытие формы редактирования элемента справочника. Другими словами, стандартные действия системы зависят от типа данных содержащегося в ячейке значения. Однако, это событие возможно перехватить и обработать нестандартным способом. Для этого предназначена предопределённая процедура встроенного языка ОбработкаЯчейкиТаблицы().

Примером нестандартной обработки значения ячейки таблицы может быть, например, вызов на формирование другого отчёта. Таким образом, мы можем создавать как бы вложенные отчёты, которые вызываются один из другого, выдавая с каждым разом более детальную информацию. Допустим отчёт «Взаиморасчеты» при формировании всегда выводится в кратком виде, когда виден только сводный баланс по контрагенту. Для того, чтобы получить детальный отчёт по данному контрагенту, достаточно встать курсором в готовой форме отчёта на этого контрагента и нажать клавишу Enter. Тогда сработает процедура ОбработкаЯчейкиТаблицы(), в которой можно записать вызов формирования детального отчёта. А если, кроме того, завести флаг режима отображения, то можно вместо этого показывать карточку этого контрагента из справочника.

Рассмотрим построение вложенных отчётов на примере. Допустим, у вас есть отчёт «ПродажиТоваров», в котором отображается перечень товаров, количество и сумма проданных за некоторый период товаров. Программный модуль формирования такого отчёта приведён ниже.

Процедура ПродВсего()
   Перем Запрос, ТекстЗапроса, Таб;
   ДатаКон = ДатаКонца;
   Если ДатаКон >= ПолучитьДатуТА() Тогда
      ДатаКон = Дата(0);
   КонецЕсли;
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(ПродВсего)
   |Период с ДатаНачала по ДатаКон;
   |ТОВАР = Документ.РасхНакл.Товар;
   |Сумма_Прод = Документ.РасхНакл.СуммаРуб;
   |КОЛВО_Прод = Документ.РасхНакл.Количество;
   |Группировка ТОВАР;
   |Функция Продано = Сумма(КОЛВО_Прод);
   |Функция СуммаПродано = Сумма(Сумма_Прод);
   |"//}}ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("ТабВсего");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Товар") = 1 Цикл
      ПродСумма = Запрос.СуммаПродано;
      Если Запрос.Товар.ЭтоГруппа() = 1 Тогда
         Таб.ВывестиСекцию("Группа");
      Иначе
         Таб.ВывестиСекцию("Товар");
      КонецЕсли;
   КонецЦикла;
   // Вывод заполненной формы
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 0, 4, 0);
   Таб.Показать("Продажа товаров", "");
КонецПроцедуры

В режиме исполнения у нас получится такой отчёт:

Отчёт

Далее, допустим, мы хотим получить более подробный отчёт по конкретному товару, так, чтобы указав на товар в отчёте, и дважды нажав кнопку мыши, мы получали отчёт по продажам именно этого товара с точностью до каждого клиента. Для этого откроем в Конфигураторе редактор таблицы нашего отчёта и в свойствах ячейки (Свойства ячейки -> Текст -> поле «Значение»), отображающей наименование товара, проставим значение ячейки — «Запрос.Товар».

Далее, в программном модуле напишем процедуру формирования дополнительного отчёта:

// *********************************
// Процедура дополнительного отчета

Процедура ПродТовар(ВТовар)
   Перем Запрос, ТекстЗапроса, Таб;
   ДатаКон = ДатаКонца;
   Если ДатаКон >= ПолучитьДатуТА() Тогда
      ДатаКон = Дата(0);
   КонецЕсли;
   // Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса = "//{{ЗАПРОС(ПродТовар)
   |Период с ДатаНачала по ДатаКон;
   |КЛИЕНТ = Документ.РасхНакл.Клиент;
   |ТОВАР = Документ.РасхНакл.Товар;
   |СУММ = Документ.РасхНакл.СуммаВал;
   |КОЛВО = Документ.РасхНакл.Количество;
   |Группировка КЛИЕНТ Упорядочить По КЛИЕНТ.Наименование;
   |Группировка ТОВАР Упорядочить По ТОВАР.Наименование;
   |Функция Продано = Сумма(КОЛВО);
   |Функция ПродСум = Сумма(СУММ);
   |"//}}ЗАПРОС
   ;
   Если ВТовар.Выбран() = 1 Тогда
      Если ВТовар.ЭтоГруппа() = 1 Тогда
         ТекстЗапроса = ТекстЗапроса + "Условие(Товар.ПринадлежитГруппе(ВТовар) = 1);";
      Иначе
         ТекстЗапроса = ТекстЗапроса + "Условие (Товар = ВТовар);";
         ФОдинТовар = 1;
      КонецЕсли;
   КонецЕсли;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
      Возврат;
   КонецЕсли;
   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ВывестиСекцию("Отчет");
   Пока Запрос.Группировка("Клиент") = 1 Цикл
      Таб.ВывестиСекцию("Клиент");
      Пока Запрос.Группировка("Товар") = 1 Цикл
         Если ФОдинТовар = 0 Тогда
            Таб.ВывестиСекцию("Товар");
         КонецЕсли;
      КонецЦикла;
   КонецЦикла;
   // Вывод заполненной формы
   Таб.ТолькоПросмотр(1);
   Таб.Опции(0, 4, 0, 0);
   Таб.Показать("Продажа товара", "");
КонецПроцедуры

Теперь нам осталось написать предопределённую процедуру, которая возьмёт на себя обработку события «двойной щелчок мышью на выбранной ячейке таблицы». Главная задача этой процедуры — определить, что выбрана ячейка, где указано значение товара и вызвать на исполнение процедуру формирования дополнительного отчёта, написанную ранее.

// *********************************

Процедура ОбработкаЯчейкиТаблицы(ЗначЯч, ФлагСтандартнойОбработки)   // предопределенная процедура
   Если ТипЗначения(ЗначЯч) = 2 Тогда
      ФлагСтандартнойОбработки = 1;
      Возврат;
   КонецЕсли;
   ПродТовар(ЗначЯч);
КонецПроцедуры

Теперь, в режиме исполнения, если в отчёте «Продажи товаров» мы укажем курсором на товар, например, «Сапоги женские» и дважды щёлкнем на нём мышью, то сформируется дополнительный подробный отчёт «Продажа товара».

Способы оптимизации формирования отчётов

Процесс получения отчётов с использованием запросов можно условно разделить на две фазы: сначала формируется запрос, затем полученные данные выводятся в таблицу. В данном разделе речь пойдёт о второй фазе получения отчёта — выводе данных в таблицу.

Рассмотрим следующий пример. Допустим, требуется вывести в отчёт полный перечень товаров со всеми их реквизитами. Для этого сначала формируется запрос с одной группировкой — "Товар", затем полученные данные выводятся в таблицу. Ниже приведены три варианта вывода данных в таблицу.

Вариант 1:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Таб.ВывестиСекцию("Товар");
КонецЦикла;

Секция "Товар" в таблице имеет следующий формат:

Секция 'Товар'

В этом варианте отображаемые реквизиты товара полностью вычисляются в ячейках таблицы, причём доступ к каждому реквизиту товара происходит по полному пути: Запрос-Товар-Реквизит. Поэтому данный вариант вывода данных в таблицу самый медленный.

Вариант 2:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   ПечНаим = Запрос.Товар.Наименование;
   ПечАртикул = Запрос.Товар.Артикул;
   ПечЦена = Запрос.Товар.Цена;
   ПечВалюта = Запрос.Товар.Валюта;
   Таб.ВывестиСекцию("Товар1");
КонецЦикла;

Секция "Товар1" в таблице имеет следующий формат:

Секция 'Товар1'

Во этом варианте отображаемые реквизиты товара вычисляются в программном модуле, а в ячейках таблицы размещены простые выражения — ссылки на идентификаторы программного модуля. Доступ к каждому реквизиту товара, как и в первом варианте, происходит по полному пути: Запрос-Товар-Реквизит. Но в данном варианте фаза вывода данных в таблицу работает быстрее первого варианта (выигрыш примерно 20%), так как в программном модуле выражения вычисляются существенно быстрее, чем выражения, помещённые в ячейках таблицы (программный модуль при загрузке компилируется, а выражения в ячейках таблицы интерпретируются каждый раз при выводе секций).

Вариант 3:

В программном модуле текст вывода данных в таблицу следующий:

Пока Запрос.Группировка("Товар") = 1 Цикл
   Тов = Запрос.Товар;
   ПечНаим = Тов.Наименование;
   ПечАртикул = Тов.Артикул;
   ПечЦена = Тов.Цена;
   ПечВалюта = Тов.Валюта;
   Таб.ВывестиСекцию("Товар1");
КонецЦикла;

Секция «Товар1» в таблице имеет следующий формат:

Секция 'Товар1'

В этом варианте отображаемые реквизиты товара также вычисляются в программном модуле, а в ячейках таблицы размещены простые выражения — ссылки на идентификаторы программного модуля. Однако доступ к каждому реквизиту товара происходит по сокращённому пути — через промежуточную переменную: Товар—Реквизит. Поэтому в данном варианте фаза вывода данных в таблицу работает быстрее, чем во втором варианте (выигрыш примерно 20%) и существенно быстрее, чем в первом варианте (выигрыш примерно 40%), так как вычисление значений реквизитов объектов через «одну точку» выполняется быстрее, чем через «две (и более) точки».

Отсюда вывод: при реализации больших отчётов, которые рассчитаны на отображение более сотни строк:

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

Другие статьи по схожей тематике