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

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

В этой статье мы детально разберем процесс создания запроса, рассмотрим структуру оператора ВЫБРАТЬ, научимся работать с временными таблицами и соединениями. Вы узнаете, как оптимизировать код для работы с большими объемами данных и какие инструменты отладки предоставляет система.

Базовая структура оператора выбора данных

Любой запрос в 1С начинается с ключевого слова ВЫБРАТЬ. Это команда сообщает интерпретатору, какие именно поля необходимо извлечь из источника данных. Сразу за этим словом следует перечень полей, которые вы хотите видеть в результирующей выборке. Если полей много, их можно перечислять через запятую, соблюдая правила именования.

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

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

⚠️ Внимание: При использовании оператора ГДЕ старайтесь избегать функций в условиях отбора по индексным полям. Это может привести к полному сканированию таблицы вместо быстрого поиска по индексу, что резко снизит скорость выполнения запроса.

Рассмотрим простой пример выборки номенклатуры из справочника:

ВЫБРАТЬ

Номенклатура.Ссылка КАК Ссылка,

Номенклатура.Наименование КАК Наименование,

Номенклатура.Артикул КАК Артикул

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.ЭтоГруппа = ЛОЖЬ

В данном примере мы выбираем три поля из справочника Номенклатура. Ключевое слово КАК позволяет задать псевдонимы полям, что упрощает дальнейшую работу с результатом в коде 1С. Условие в блоке ГДЕ отсеивает папки (группы), оставляя только конкретные товары.

💡

Используйте псевдонимы таблиц (например, "КАК Номенклатура") сразу после указания источника в блоке ИЗ. Это делает код более читаемым и позволяет сокращать обращения к полям в условиях отбора и соединениях.

Работа с соединениями таблиц и объединениями

Часто данные для отчета разбросаны по разным таблицам. Например, нужно вывести список товаров и остатки по ним на складах. Для этого в 1С используются соединения (JOIN). Платформа поддерживает несколько типов соединений: ВНУТРЕННЕЕ СОЕДИНЕНИЕ, ЛЕВОЕ СОЕДИНЕНИЕ и ПРАВОЕ СОЕДИНЕНИЕ.

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

  • 🔗 ВНУТРЕННЕЕ СОЕДИНЕНИЕ — идеально подходит, когда нужны только записи с наличием данных в обоих источниках (например, реализованные товары).
  • 📉 ЛЕВОЕ СОЕДИНЕНИЕ — необходимо, когда нужно показать весь список объектов слева, даже если справа данных нет (например, все товары, даже с нулевым остатком).
  • 📈 ПРАВОЕ СОЕДИНЕНИЕ — используется реже, по сути является зеркальным отражением левого соединения, где приоритет отдается правой таблице.

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

ВЫБРАТЬ

Товары.Наименование,

Остатки.КоличествоОстаток

ИЗ

Справочник.Номенклатура КАК Товары

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

ПО Товары.Ссылка = Остатки.Номенклатура

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

Что такое декартово произведение?

Это ситуация, когда каждая строка первой таблицы соединяется с каждой строкой второй таблицы. Если в первой таблице 1000 строк, а во второй 1000, результат будет содержать 1 000 000 строк. Это критическая ошибка производительности.

Группировка данных и агрегатные функции

Для построения итоговых отчетов часто требуется не просто вывести список документов, а посчитать суммы, количества или средние значения. В языке запросов 1С за это отвечает блок СГРУППИРОВАТЬ ПО. Он позволяет объединять строки с одинаковыми значениями в указанных полях и применять к остальным полям агрегатные функции.

Основные агрегатные функции включают СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ и СРЕДНЕЕ. При использовании группировки все поля, не попавшие в агрегатные функции, обязательно должны быть перечислены в блоке СГРУППИРОВАТЬ ПО. Нарушение этого правила приведет к ошибке синтаксиса.

Пример запроса для получения оборотов по контрагентам:

ВЫБРАТЬ

Продажи.Контрагент,

СУММА(Продажи.Сумма) КАК ОбщаяСумма,

КОЛИЧЕСТВО(Продажи.Ссылка) КАК КоличествоДокументов

ИЗ

Документ.РеализацияТоваровУслуг КАК Продажи

ГДЕ

Продажи.Проведен = ИСТИНА

СГРУППИРОВАТЬ ПО

Продажи.Контрагент

В этом запросе мы группируем все реализации по контрагенту. Для каждого уникального контрагента система посчитает общую сумму продаж и количество документов. Поле Продажи.Ссылка в функции КОЛИЧЕСТВО используется просто как счетчик строк, так как нам не важно содержание ссылки, важно лишь их число.

⚠️ Внимание: Агрегатные функции игнорируют значения NULL (Неопределено). Функция СУММА просуммирует только числа, а КОЛИЧЕСТВО посчитает только непустые значения. Если нужно учесть пустые значения, используйте функцию ЕСТЬNULL.

💡

Порядок полей в блоке СГРУППИРОВАТЬ ПО не влияет на результат, но для читаемости кода рекомендуется располагать их в том же порядке, в котором они выбираются в блоке ВЫБРАТЬ.

Использование временных таблиц и объединений

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

Синтаксис создания временной таблицы начинается со слова ПОМЕСТИТЬ, за которым следует имя таблицы с префиксом #. После выполнения первой части запроса данные сохраняются во временную таблицу, которую затем можно использовать как обычный источник данных в последующих запросах.

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

  • 📂 ПОМЕСТИТЬ — создает временную таблицу для промежуточного хранения данных.
  • 🔄 ОБЪЕДИНИТЬ — склеивает результаты двух запросов, удаляя полные дубликаты строк.
  • ОБЪЕДИНИТЬ ВСЕ — склеивает результаты без проверки на дубликаты, что значительно ускоряет работу.

Пример работы с временной таблицей:

ПОМЕСТИТЬ ВременныеОстатки

ВЫБРАТЬ

Остатки.Номенклатура,

СУММА(Остатки.Количество) КАК Остаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

ГДЕ

Остатки.Период МЕЖДУ &НачалоПериода И &КонецПериода

СГРУППИРОВАТЬ ПО

Остатки.Номенклатура

;

ВЫБРАТЬ

Номенклатура.Наименование,

ВременныеОстатки.Остаток

ИЗ

Справочник.Номенклатура КАК Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ ВременныеОстатки КАК ВременныеОстатки

ПО Номенклатура.Ссылка = ВременныеОстатки.Номенклатура

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

📊 Какой метод объединения вы используете чаще?
ОБЪЕДИНИТЬ (с удалением дублей)
ОБЪЕДИНИТЬ ВСЕ (без проверки)
Временные таблицы
Не использую, пишу один большой запрос

Параметризация запросов и защита от инъекций

Жестко прописанные значения в тексте запроса — плохая практика. Это делает код негибким и уязвимым. Вместо подстановки значений напрямую следует использовать параметры. В языке запросов 1С параметры обозначаются знаком амперсанда &, например, &ДатаНачала или &Контрагент.

Передача параметров осуществляется через объект Запрос в коде 1С. Вы создаете объект запроса, устанавливаете его текст, а затем с помощью метода УстановитьПараметр передаете значения. Это не только удобно, но и безопасно, так как платформа автоматически экранирует специальные символы, предотвращая SQL-инъекции.

Пример установки параметров в коде:

ТекстЗапроса = "ВЫБРАТЬ ... ГДЕ Дата > &НачПериода";

Запрос = Новый Запрос(ТекстЗапроса);

Запрос.УстановитьПараметр("НачПериода", ДатаНачалаОтчета);

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

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

⚠️ Внимание: Никогда не формируйте текст запроса через конкатенацию строк для подстановки значений, полученных от пользователя. Это грубейшая ошибка безопасности. Используйте только механизм параметров &ИмяПараметра.

☑️ Проверка параметров запроса

Выполнено: 0 / 1

Оптимизация и анализ производительности

Написание работающего запроса — это только половина дела. Запрос должен работать быстро, особенно если он используется в отчетах, формируемых большим количеством пользователей. Для анализа скорости выполнения в 1С встроен мощный инструмент — Консоль запросов и режим отладки с замером производительности.

Одним из главных индикаторов проблем является чтение данных с диска. Хороший запрос должен максимально использовать индексы базы данных. Если вы видите в плане выполнения запроса операцию "Полное сканирование таблицы" (Table Scan) на больших регистрах, это сигнал к оптимизации. Часто решение заключается в добавлении условий в блок ГДЕ по полям, входящим в ключи таблиц.

Также стоит обращать внимание на тип соединения. Замена ЛЕВОЕ СОЕДИНЕНИЕ на ВНУТРЕННЕЕ СОЕДИНЕНИЕ там, где это логически допустимо, часто дает прирост скорости, так как оптимизатор базы данных получает больше свободы для перестановки таблиц местами при построении плана.

Проблема Симптом Решение
Отсутствие индексов Медленный отбор по полю Добавить условие по индексному полю в ГДЕ
Декартово произведение Огромное число строк результата Проверить условие соединения ПО
Функции в отборе Игнорирование индекса Убрать функцию из левой части условия ГДЕ
Неверный тип соединения Лишние проверки на пустоту Заменить ЛЕВОЕ на ВНУТРЕННЕЕ где возможно

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

💡

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

Часто задаваемые вопросы (FAQ)

Как выбрать все поля из таблицы, не перечисляя их?

В 1С можно использовать символ звездочки в блоке ВЫБРАТЬ. Например: ВЫБРАТЬ ИЗ Справочник.Номенклатура. Однако в промышленных решениях это не рекомендуется, так как изменение структуры справочника может сломать код, а выборка лишних полей снижает производительность.

В чем разница между ПОМЕСТИТЬ и временной таблицей в коде?

Оператор ПОМЕСТИТЬ создает временную таблицу непосредственно на стороне СУБД (или в памяти сервера 1С), что позволяет использовать её в следующих запросах внутри одного текста. В коде 1С можно также создать объект ТаблицаЗначений, но это уже клиентская или серверная структура данных, а не часть языка запросов.

Можно ли делать вложенные запросы (подзапросы)?

Да, язык запросов 1С поддерживает подзапросы. Вы можете использовать запрос внутри скобок в блоке ВЫБРАТЬ, ИЗ или ГДЕ. Например, для проверки существования записи: ГДЕ ЕСТЬ(ВЫБРАТЬ 1 ИЗ ...).

Как обработать результат запроса в коде?

Результат выполнения запроса возвращается в виде объекта ВыборкаИзРезультатаЗапроса. Для обхода записей используется цикл Пока Выборка.Следующий() Цикл ... КонецЦикла. Поля доступны через точку, например Выборка.Наименование.

Почему запрос выполняется долго только у некоторых пользователей?

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