Работа с данными в платформе 1С:Предприятие строится на основе мощного языка запросов, который позволяет извлекать, агрегировать и преобразовывать информацию из базы данных. Понимание того, как писать запросы в 1С, является фундаментальным навыком для любого разработчика, начиная от стажера и заканчивая архитектором системы. В отличие от стандартного SQL, язык запросов 1С имеет свои уникальные конструкции, такие как виртуальные таблицы и специфический синтаксис работы с регистрами.
Неправильно составленный запрос может привести к серьезному падению производительности всей информационной системы, особенно в многопользовательском режиме. Поэтому важно не просто знать синтаксис, но и понимать, как платформа транслирует ваш код в команды для СУБД. В этой статье мы разберем основные принципы построения запросов, типичные ошибки и способы их оптимизации для обеспечения высокой скорости отклика.
Современные версии платформы предоставляют разработчику удобные инструменты для отладки и анализа планов выполнения. Однако автоматические подсказки не всегда гарантируют идеальный результат, и часто требуется ручная доработка логики выборки. Мы рассмотрим практические примеры, которые помогут вам писать чистый, понятный и быстрый код.
Основы синтаксиса и структура запроса
Любой запрос в 1С начинается с ключевого слова ВЫБРАТЬ, за которым следует перечень полей, которые необходимо получить из источника данных. Структура запроса во многом напоминает классический SQL, однако имеет ряд отличий, продиктованных объектной моделью платформы. Основными блоками являются выборка полей, указание источника данных и условия фильтрации.
Источником данных могут выступать справочники, документы, регистры сведений или даже результаты других запросов. При обращении к таблицам базы данных через объект метаданных используется конструкция ИЗ. Важно правильно указывать псевдонимы таблиц, чтобы избежать конфликтов имен полей при соединении нескольких источников.
Рассмотрим базовый пример простого запроса, который выбирает номенклатуру из справочника:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование КАК Наименование,
Номенклатура.Артикул КАК Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ
В данном примере мы видим использование псевдонима Номенклатура для таблицы справочника. Ключевое слово КАК позволяет переименовывать поля в результирующей выборке, что делает код более читаемым. Обратите внимание на условие в блоке ГДЕ: оно отсеивает элементы, являющиеся группами, оставляя только конкретные товары.
Всегда явно перечисляйте необходимые поля вместо использования звездочки (*). Это снижает нагрузку на сеть и ускоряет выполнение запроса, так как СУБД не будет выбирать лишние данные.
Синтаксический анализатор встроенной конфигураторы 1С автоматически проверяет правильность написания ключевых слов и наличия указанных полей в метаданных. Если вы допустите ошибку в названии поля или таблицы, система сразу подсветит проблемное место красным цветом при попытке выполнить запрос.
Работа с соединениями таблиц (JOIN)
Одной из самых частых задач при разработке является необходимость объединить данные из разных таблиц. В языке запросов 1С для этого используются соединения, которые позволяют связывать записи по определенным ключам. Существует несколько типов соединений, каждый из которых имеет свое назначение и влияет на итоговый набор данных.
Наиболее распространенным является ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN), которое возвращает только те строки, для которых есть соответствие в обеих таблицах. Если в одной из таблиц нет записи, такая строка будет исключена из результата. Это идеальный вариант, когда вам нужны только полные данные.
- 🔗 ВНУТРЕННЕЕ СОЕДИНЕНИЕ: выбирает только пересекающиеся данные из обеих таблиц.
- 📥 ЛЕВОЕ СОЕДИНЕНИЕ: выбирает все данные из левой таблицы и подходящие из правой (если нет совпадения, поля правой будут пустыми).
- 📤 ПРАВОЕ СОЕДИНЕНИЕ: выбирает все данные из правой таблицы и подходящие из левой.
- 🔄 ПОЛНОЕ СОЕДИНЕНИЕ: возвращает все записи из обеих таблиц, заполняя пустоты нулями там, где совпадений нет.
Рассмотрим пример левого соединения, которое часто используется для получения остатков товаров. Нам нужно вывести весь список номенклатуры, даже если по каким-то товарам остатков еще нет:
ВЫБРАТЬ
Номенклатура.Наименование,
Остатки.КоличествоОстаток
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
В этом коде ключевое слово ПО задает условие связывания таблиц. Если для какого-то товара не найдется записи в регистре остатков, поле КоличествоОстаток будет равно NULL. Это позволяет не потерять товары, которые еще никогда не проводились по складу.
При использовании соединений важно следить за тем, чтобы поля, по которым происходит связывание, были проиндексированы в базе данных. В противном случае СУБД будет вынуждена выполнять полный перебор таблиц, что критически замедлит работу системы при больших объемах данных.
Группировка и агрегатные функции
Когда требуется получить сводные данные, например, общую сумму продаж по менеджерам или среднюю цену товара, используются агрегатные функции и группировка. Механизм СГРУППИРОВАТЬ ПО объединяет строки с одинаковыми значениями указанных полей в одну запись результата.
В 1С доступны стандартные математические функции для обработки выборок: СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ и СРЕДНЕЕ. Эти функции применяются только к числовым полям или полям, которые можно привести к числовому типу. Все поля, не участвующие в агрегации, должны быть обязательно указаны в секции группировки.
| Функция | Описание | Пример использования |
|---|---|---|
| СУММА(Поле) | Вычисляет сумму значений | СУММА(Продажи.Сумма) |
| КОЛИЧЕСТВО(*) | Подсчитывает количество строк | КОЛИЧЕСТВО(Документы.Ссылка) |
| МИНИМУМ(Поле) | Находит наименьшее значение | МИНИМУМ(Товары.Цена) |
| МАКСИМУМ(Поле) | Находит наибольшее значение | МАКСИМУМ(Сотрудники.ДатаПриема) |
Пример запроса с группировкой по контрагентам для получения оборотов:
ВЫБРАТЬ
Продажи.Контрагент,
СУММА(Продажи.Сумма) КАК ОбщаяСумма,
КОЛИЧЕСТВО(Продажи.Ссылка) КАК КоличествоДокументов
ИЗ
Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
Продажи.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
Обратите внимание, что поле Контрагент вынесено в секцию СГРУППИРОВАТЬ ПО, так как оно не является агрегатным. Если вы попытаетесь выбрать это поле без группировки, конструктор запросов выдаст ошибку. Это строгое правило языка запросов 1С, которое нельзя нарушать.
Порядок полей в секции"СГРУППИРОВАТЬ ПО" влияет на сортировку результата. Если вам нужна дополнительная сортировка, используйте явное указание"УПОРЯДОЧИТЬ ПО".
Частой ошибкой новичков является попытка использовать агрегатные функции в условии ГДЕ. Это невозможно, так как фильтрация по ГДЕ происходит до группировки. Для фильтрации результатов агрегации необходимо использовать секцию ИМЕЮЩИЕ.
Использование временных таблиц и объединений
В сложных сценариях, когда данные нужно подготовить в несколько этапов, или когда один запрос становится слишком громоздким, целесообразно использовать временные таблицы. В языке запросов 1С они создаются автоматически при использовании символа # в имени таблицы.
Временные таблицы существуют только в рамках сеанса пользователя и удаляются сразу после завершения работы с ними или закрытия соединения. Это отличный способ разбить сложную логику на понятные этапы и упростить отладку. Кроме того, использование временных таблиц может ускорить выполнение запроса, если одни и те же данные используются многократно.
Пример создания и использования временной таблицы:
// Создаем временную таблицу с отобранными данными
ВЫБРАТЬ
Номенклатура.Ссылка,
Номенклатура.Наименование
ПОМЕСТИТЬ ВТ_АктуальныеТовары
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ
// Используем временную таблицу в основном запросе
ВЫБРАТЬ
ВТ_АктуальныеТовары.Наименование,
Остатки.КоличествоОстаток
ИЗ
ВТ_АктуальныеТовары КАК ВТ_АктуальныеТовары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО ВТ_АктуальныеТовары.Ссылка = Остатки.Номенклатура
Оператор ПОМЕСТИТЬ завершает первый запрос и сохраняет результат во временную структуру. Обратите внимание на точку с запятой ; в конце первого блока — она обязательна для разделения команд. Далее мы можем обращаться к таблице ВТ_АктуальныеТовары как к обычной таблице базы данных.
Особенности работы с временными таблицами
Временные таблицы не индексируются автоматически так же эффективно, как физические таблицы. При очень больших объемах данных (миллионы строк) использование временных таблиц может иногда замедлить работу по сравнению с одним сложным запросом с подзапросами. Всегда тестируйте производительность на реальных данных.
Помимо временных таблиц, для объединения результатов разных выборок используется конструкция ОБЪЕДИНИТЬ. Она позволяет склеить два запроса с одинаковой структурой полей в один результат. Это полезно, когда нужно вывести данные из разных источников в едином списке, например, историю движений из разных регистров.
⚠️ Внимание: При использовании оператора
ОБЪЕДИНИТЬтипы и порядок полей в объединяемых запросах должны строго совпадать. Если типы не совпадают (например, Число и Строка), система попытается привести их к общему типу, что может привести к непредсказуемым результатам или ошибкам выполнения.
Виртуальные таблицы регистров
Одной из самых мощных особенностей платформы 1С являются виртуальные таблицы регистров. Они позволяют получать срезы данных (остатки, обороты) на конкретную дату или период без необходимости писать сложные запросы с группировками и условиями по времени. Платформа сама оптимизирует такие запросы, используя специальные таблицы итогов.
Для работы с регистрами накопления и сведений используются специальные конструкции: Остатки, Обороты, СрезПоследних, СрезПервых. Обращение к ним происходит через точку после имени регистра. Например, РегистрНакопления.Продажи.Обороты.
Рассмотрим пример получения оборотов продаж за месяц с использованием виртуальной таблицы:
ВЫБРАТЬ
Обороты.Номенклатура,
Обороты.КоличествоОборот,
Обороты.СуммаОборот
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода,, ) КАК Обороты
ГДЕ
Обороты.СуммаОборот > 0
Здесь параметры в скобках (&НачалоПериода, &КонецПериода,, ) задают временной интервал для расчета оборотов. Пустые параметры означают, что группировка по измерениям не задана явно, и будут выведены все комбинации. Использование виртуальных таблиц значительно упрощает код и повышает его производительность.
☑️ Проверка эффективности запроса к регистрам
Если итоги не ведутся, платформа будет рассчитывать данные"на лету" путем полного сканирования таблицы движений, что может быть очень медленно на больших объемах.
⚠️ Внимание: Параметры виртуальных таблиц чувствительны к типу данных. Передавайте в них значения дат или строки в формате даты. Передача неверного типа может привести к тому, что запрос вернет пустой результат или выполнится некорректно.
Оптимизация и типичные ошибки
Написание работающего запроса — это только половина дела. Запрос должен работать быстро даже при заполненной базе данных. Оптимизация запросов в 1С требует понимания того, как СУБД обрабатывает условия фильтрации и соединения. Главный враг производительности — полный перебор таблиц (Table Scan).
Чтобы избежать полного перебора, необходимо, чтобы условия в секции ГДЕ использовали индексируемые поля. В 1С автоматически индексируются поля типов Ссылка, Перечисление, а также поля, помеченные как Лидер в конфигурации. Условия должны быть записаны в виде сравнения поля со значением или параметром.
Типичные ошибки, снижающие производительность:
- 🚫 Использование функций в условии ГДЕ: Например,
ГДЕ ЛЕВЫЙ(Поле, 3) ="АБВ". Это запрещает использование индекса, так как СУБД должна применить функцию к каждой строке таблицы. - 🚫 Некорректный порядок таблиц в соединении: Хотя оптимизатор 1С старается сам выбрать лучший план, явное указание маленькой таблицы слева в левом соединении часто помогает.
- 🚫 Выборка лишних полей: Выборка полей типа
БинарныеДанныеилиХранилищеЗначениябез необходимости сильно нагружает сеть и память.
Для анализа проблемных запросов используйте встроенную консоль запросов и инструмент"Технологический журнал". Они позволяют увидеть план выполнения запроса и понять, какие таблицы сканируются полностью. Использование оператора"ТОЛЬКО РАЗЛИЧНЫЕ" (DISTINCT) без необходимости также может замедлить запрос, так как требует дополнительной сортировки для удаления дублей.
⚠️ Внимание: Интерфейс и возможности Консольных команд могут отличаться в зависимости от версии платформы 1С:Предприятие и типа используемой СУБД (MS SQL, PostgreSQL, Oracle). Всегда проверяйте актуальность синтаксических функций в официальной документации для вашей конкретной версии платформы.
Если запрос выполняется долго, попробуйте разбить его на части с использованием временных таблиц. Иногда это позволяет оптимизатору СУБД построить более эффективный план выполнения, чем для одного монолитного запроса.
Регулярный аудит запросов в конфигурации помогает выявлять"узкие места" до того, как они станут критическими для пользователей. Следите за ростом базы данных и тестируйте отчеты на объемах, приближенных к боевым.
Часто задаваемые вопросы (FAQ)
Как получить список всех таблиц базы данных через запрос?
Прямого запроса ко всем физическим таблицам базы данных в языке 1С нет из соображений безопасности и абстракции. Однако вы можете получить список всех объектов метаданных, используя системные таблицы или объекты метаданных в коде. Для этого обычно используется объект Метаданные в встроенном языке, а не запрос.
В чем разница между ПОМЕСТИТЬ и ОБЪЕДИНИТЬ?
ПОМЕСТИТЬ создает временную таблицу в памяти или во временном хранилище СУБД, которую можно использовать в следующих запросах. ОБЪЕДИНИТЬ просто склеивает результаты двух выборок в один поток данных"на лету", не создавая промежуточного хранилища. ПОМЕСТИТЬ полезно для многократного использования данных, ОБЪЕДИНИТЬ — для простого слияния списков.
Почему запрос возвращает пустой результат, хотя данные есть?
Чаще всего проблема кроется в условиях соединения или фильтрации. Проверьте, не отфильтровываются ли данные условием ГДЕ. Убедитесь, что типы данных в условиях сравнения совпадают. Также проверьте права доступа пользователя: возможно, у него нет прав на чтение конкретных записей или полей.
Можно ли выполнять запросы напрямую к SQL базе из 1С?
Нет, платформа 1С:Предприятие не поддерживает выполнение нативных SQL-запросов напрямую через стандартный объект Запрос. Все запросы должны быть написаны на языке запросов 1С. Это сделано для обеспечения независимости конфигурации от типа СУБД. Для специфических задач можно использовать внешние обработки или расширенные возможности администрирования, но это выходит за рамки стандартной разработки.
Как передать параметр в запрос из кода?
В тексте запроса параметр обозначается символом & followed by имя параметра (например, &Период). В коде перед выполнением запроса необходимо получить объект параметра через метод Запрос.Параметры и установить его значение: Запрос.Параметры.Период = ТекущаяДата.