Работа с массивами в запросах 1С:Предприятие — одна из самых востребованных, но при этом недостаточно документированных тем среди разработчиков. Многие привыкли оперировать одиночными значениями или временными таблицами, тогда как массивы позволяют радикально упростить код, сократить количество запросов к базе и повысить производительность. Однако их неправильное использование часто приводит к ошибкам выполнения, неоптимальным планам запросов или даже падению сервера при работе с большими объемами данных.

В этой статье мы разберём не только базовый синтаксис работы с массивами в запросах 1С 8.3, но и нюансы, которые редко упоминаются в официальной документации. Вы узнаете, как передавать массивы в параметры запроса, обрабатывать их результаты, избегать типичных ошибок при работе с МАССИВ() и В(), а также оптимизировать сложные конструкции для ускорения выполнения. Особое внимание уделим практическим примерам — от простых фильтров до динамического формирования условий на основе массивов данных.

Что такое массивы в контексте запросов 1С

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

  • 📌 Списки значений для фильтрации (аналог оператора IN в SQL)
  • 🔄 Наборы параметров для динамического формирования условий
  • 📊 Источники данных для временных таблиц (через конструктор ЗНАЧЕНИЕ())

Важно понимать, что массив в запросе — это не переменная, а синтаксическая конструкция, которая преобразуется платформой в оптимизированный SQL-код. Например, условие ГДЕ Номенклатура В (&МассивТоваров) при выполнении на сервере Microsoft SQL Server будет преобразовано в WHERE Номенклатура IN (@p1, @p2, @p3), где @p1, @p2, @p3 — параметры запроса.

Основные операторы для работы с массивами в запросах:

Оператор Описание Пример использования
В() Проверяет вхождение значения в массив (аналог IN) ГДЕ Склад В (&СписокСкладов)
МАССИВ() Создаёт массив прямо в тексте запроса ГДЕ Статус В МАССИВ("Новый", "ВРаботе")
ЗНАЧЕНИЕ() Преобразует массив в таблицу значений для JOIN ЛЕВОЕ СОЕДИНЕНИЕ ЗНАЧЕНИЕ(&МассивДанных) КАК Т...
⚠️ Внимание: В ранних версиях платформы (до 1С:Предприятие 8.3.10) оператор МАССИВ() мог работать нестабильно при передаче более 1000 элементов. В современных релизах это ограничение снято, но для больших массивов (>10 000 элементов) рекомендуется использовать временные таблицы.

Как передавать массивы в параметры запроса

Самый распространённый способ работы с массивами — передача их в качестве параметров запроса. Это позволяет динамически формировать условия отбора без изменения текста запроса. Рассмотрим базовый синтаксис:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

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

| Товары.Артикул

|ИЗ

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

|ГДЕ

| Товары.ВидыНоменклатуры В (&ВидыНоменклатуры)";

Запрос.УстановитьПараметр("ВидыНоменклатуры", МассивВидов); // МассивВидов - массив значений

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

Ключевые моменты:

  • 🔹 Параметр в тексте запроса обозначается как &ИмяПараметра
  • 🔹 Массив передаётся через метод УстановитьПараметр() до выполнения запроса
  • 🔹 Тип элементов массива должен соответствовать типу поля в базе (например, нельзя передать массив строк в параметр для поля типа Число)

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

Запрос.Текст =

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| " + (?(МассивВидов.Количество() = 0, "ИСТИНА", "Товары.ВидыНоменклатуры В (&ВидыНоменклатуры)") + "";

📊 Как часто вы используете массивы в запросах 1С?
Постоянно, в большинстве запросов
Иногда, для специфических задач
Редеко, предпочитаю другие методы
Никогда не использовал

Создание массивов прямо в тексте запроса (МАССИВ)

Оператор МАССИВ() позволяет создавать массивы непосредственно в тексте запроса без передачи параметров. Это удобно для статических условий или небольших наборов значений. Синтаксис:

Запрос.Текст =

"ВЫБРАТЬ

| Документы.Номер,

| Документы.Дата

|ИЗ

| Документ.ЗаказПокупателя КАК Документы

|ГДЕ

| Документы.Статус В МАССИВ("Новый", "НаСогласовании", "Отменен")";

Особенности использования МАССИВ():

  • 📝 Элементы массива перечисляются через запятую в круглых скобках
  • 📌 Поддерживаются все базовые типы: строки, числа, даты, булевы значения
  • 🚫 Нельзя использовать переменные или выражения внутри МАССИВ() — только литералы

Пример с разными типами данных:

Запрос.Текст =

"ВЫБРАТЬ

| Клиенты.Наименование

|ИЗ

| Справочник.Контрагенты КАК Клиенты

|ГДЕ

| Клиенты.Вид В МАССИВ("ЮридическоеЛицо", "ИП")

| И Клиенты.ДатаРегистрации > МАССИВ(ДАТАВРЕМЯ(2020,1,1))[0]";

⚠️ Внимание: При использовании МАССИВ() с датами обязательно указывайте элементы как ДАТАВРЕМЯ() или ДАТА(). Передача строковых дат (например, "01.01.2020") приведёт к ошибке преобразования типов.

Элементы массива статичны (не требуют динамического формирования)|

Количество элементов не превышает 100 (для больших массивов лучше использовать параметры)|

Типы данных всех элементов совпадают с типом поля в условии|

Нет необходимости в повторном использовании массива в других частях запроса-->

Работа с массивами в конструкции ВЫРАЗИТЬ

Оператор ВЫРАЗИТЬ позволяет преобразовывать массивы в строковые представления или наоборот — строки в массивы. Это полезно для динамического формирования условий или работы с данными в нестандартных форматах. Рассмотрим пример:

Запрос.Текст =

"ВЫБРАТЬ

| ВЫРАЗИТЬ(МАССИВ("А", "Б", "В") КАК СТРОКА) КАК СтрокаИзМассива,

| ВЫРАЗИТЬ("1,2,3" КАК МАССИВ(ЧИСЛО)) КАК МассивИзСтроки";

Результат выполнения этого запроса:

  • 📌 Первое поле вернёт строку: "А,Б,В"
  • 📌 Второе поле преобразует строку "1,2,3" в массив чисел: [1, 2, 3]

Практическое применение ВЫРАЗИТЬ с массивами:

Задача Пример кода Результат
Преобразование массива в строку для отладки ВЫРАЗИТЬ(&Массив КАК СТРОКА) "элемент1,элемент2,элемент3"
Разбор строки с разделителями в массив ВЫРАЗИТЬ("a;b;c" КАК МАССИВ(СТРОКА), ";") ["a", "b", "c"]
Фильтрация по массиву, хранящемуся в строковом поле ГДЕ ВЫРАЗИТЬ(Документ.Теги КАК МАССИВ) СОДЕРЖИТ "Срочно" Документы, в поле Теги которых есть слово "Срочно"

Важно: При преобразовании строки в массив с помощью ВЫРАЗИТЬ(... КАК МАССИВ) можно указать разделитель (по умолчанию — запятая). Например:

ВЫРАЗИТЬ("яблоко|груша|банан" КАК МАССИВ(СТРОКА), "|")
Запрос.УстановитьПараметр("СтрокаТегов", "тег1,тег2,тег3");

Запрос.Текст = "ГДЕ ВЫРАЗИТЬ(&СтрокаТегов КАК МАССИВ) СОДЕРЖИТ Тег";-->

Оптимизация запросов с массивами: типичные ошибки и решения

Неправильное использование массивов в запросах может привести к значительному падению производительности. Рассмотрим наиболее распространённые ошибки и способы их исправления:

1. Передача больших массивов в параметры

Если массив содержит тысячи элементов, его передача в параметр запроса может вызвать:

  • 🐢 Замедление выполнения из-за генерации длинного SQL-кода
  • 💥 Переполнение буфера параметров (особенно в PostgreSQL)

Решение: Для массивов размером >1000 элементов используйте временные таблицы:

// 1. Создаём временную таблицу

ВТ = Новый ТаблицаЗначений;

ВТ.Колонки.Добавить("Значение");

// 2. Заполняем данными из массива

Для Каждого Элемент Из БольшойМассив Цикл

Строка = ВТ.Добавить();

Строка.Значение = Элемент;

КонецЦикла;

// 3. Используем во временной таблице

Запрос.Текст =

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Товары.Код В (ВЫБРАТЬ ВТ.Значение ИЗ &ВТ КАК ВТ)";

2. Несоответствие типов данных

Ошибка "Тип не совпадает с ожидаемым" возникает, когда:

  • 🔢 В массив чисел передаются строки (например, ["1", "2"] вместо [1, 2])
  • 📅 В массив дат передаются строки без преобразования

Решение: Всегда проверяйте типы элементов перед передачей:

Если ТипЗнч(Массив[0]) <> Тип("Число") Тогда

Для Инд = 0 По Массив.ВГраница() Цикл

Массив[Инд] = Число(Массив[Инд]); // Преобразуем в число

КонецЦикла;

КонецЕсли;

3. Избыточные условия с массивами

Частая ошибка — использование В () там, где достаточно простого сравнения:

// Некорректно (если массив всегда содержит 1 элемент)

ГДЕ Статус В (&МассивСтатусов)

// Корректно

ГДЕ Статус = &Статус

💡

Для массивов размером 1-3 элемента оператор В() работает эффективнее, чем несколько условий с ИЛИ. Но для больших массивов (>10 элементов) временные таблицы дают лучшую производительность.

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

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

Пример 1: Фильтрация по динамическому списку значений

Задача: Выбрать документы, у которых статус входит в список, формируемый пользователем.

Процедура ПолучитьДокументыПоСтатусам(СписокСтатусов)

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

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

| Документы.Дата

|ИЗ

| Документ.ЗаказПокупателя КАК Документы

|ГДЕ

| Документы.Статус В (&Статусы)";

Запрос.УстановитьПараметр("Статусы", СписокСтатусов);

Возврат Запрос.Выполнить();

КонецПроцедуры

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

Задача: Найти контрагентов, у которых хотя бы одно из полей (телефон, email, сайт) содержит искомое значение.

Запрос.Текст =

"ВЫБРАТЬ

| Контрагенты.Наименование

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|ГДЕ

| (Контрагенты.Телефон ПОДОБНО &ПоисковыйЗапрос)

| ИЛИ (Контрагенты.Email ПОДОБНО &ПоисковыйЗапрос)

| ИЛИ (Контрагенты.Сайт ПОДОБНО &ПоисковыйЗапрос)";

Запрос.УстановитьПараметр("ПоисковыйЗапрос", "%" + Поиск + "%");

Альтернативный вариант с массивом полей:

Запрос.Текст =

"ВЫБРАТЬ

| Контрагенты.Наименование

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|ГДЕ

| ВЫРАЗИТЬ(Контрагенты.Телефон КАК СТРОКА) ПОДОБНО &ПоисковыйЗапрос

| ИЛИ ВЫРАЗИТЬ(Контрагенты.Email КАК СТРОКА) ПОДОБНО &ПоисковыйЗапрос

| ИЛИ ВЫРАЗИТЬ(Контрагенты.Сайт КАК СТРОКА) ПОДОБНО &ПоисковыйЗапрос";

Пример 3: Группировка по значениям из массива

Задача: Получить остатки товаров только по заданным складам.

Запрос.Текст =

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| ОстаткиТоваров.Склад В (&СписокСкладов)

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

| ОстаткиТоваров.Номенклатура";

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

Если список складов содержит >100 элементов, замените условие В (&СписокСкладов) на соединение с временной таблицей:

ВТ = Новый ТаблицаЗначений;

ВТ.Колонки.Добавить("Склад");

// Заполняем ВТ данными из массива

Запрос.Текст =

"ВЫБРАТЬ

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

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

|ИЗ

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

| ЛЕВОЕ СОЕДИНЕНИЕ &ВТ КАК ВТ

| ПО Остатки.Склад = ВТ.Склад

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

Это снизит нагрузку на СУБД за счёт использования индексов.

Особенности работы с массивами в разных СУБД

Платформа 1С:Предприятие поддерживает несколько типов СУБД, и поведение запросов с массивами может отличаться:

СУБД Особенности работы с массивами Рекомендации
Microsoft SQL Server Поддерживает параметры массивов размером до 2100 элементов. При превышении — ошибка. Для больших массивов используйте временные таблицы или разбивайте запрос.
PostgreSQL Ограничение на размер параметра — ~10 000 элементов. Медленнее обрабатывает большие массивы. Оптимальный размер массива — до 1000 элементов. Для больших данных используйте UNNEST().
IBM DB2 Хорошо оптимизирует запросы с массивами, но может выдавать ошибки при несоответствии типов. Всегда явно преобразуйте типы (например, ЧИСЛО() для числовых массивов).
Файловая база Массивы размером >100 элементов значительно замедляют выполнение. Избегайте больших массивов. Для фильтрации используйте циклы по элементам.

Пример оптимизации для PostgreSQL:

// Вместо:

ГДЕ Товар В (&БольшойМассивТоваров)

// Используйте:

ГДЕ Товар В (

ВЫБРАТЬ

Элемент КАК Товар

ИЗ

&БольшойМассивТоваров КАК Элемент

)

⚠️ Внимание: В файловом варианте запросы с массивами размером >500 элементов могут приводить к ошибке "Недостаточно памяти". В этом случае разбивайте массив на части и выполняйте несколько запросов с последующим объединением результатов.

FAQ: Частые вопросы по работе с массивами в запросах

Можно ли использовать массивы в подзапросах?

Да, массивы можно передавать в подзапросы через параметры. Например:

Запрос.Текст =

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Товары.Код В (

| ВЫБРАТЬ Коды.Значение ИЗ &Коды КАК Коды

| )";

Где &Коды — параметр, содержащий массив кодов номенклатуры.

Как передать массив структур в запрос?

Прямая передача массива структур в запрос невозможна. Необходимо:

  1. Преобразовать массив структур в ТаблицаЗначений
  2. Использовать её как временную таблицу в запросе
ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Поле1");

ТЗ.Колонки.Добавить("Поле2");

// Заполняем ТЗ данными из массива структур

Запрос.Текст = "ВЫБРАТЬ ... ЛЕВОЕ СОЕДИНЕНИЕ &ТЗ КАК ВТ ...";

Почему запрос с массивом работает медленно?

Основные причины:

  • 🔍 Отсутствует индекс по полю, используемому в условии В ()
  • 📦 Слишком большой массив (>1000 элементов) передаётся в параметр
  • 🔄 Неоптимальный план выполнения (проверьте в консоли запросов)

Решения:

  • Добавьте индекс по фильтруемому полю
  • Для больших массивов используйте временные таблицы
  • Проверьте план выполнения и при необходимости используйте подсказки оптимизатору
Можно ли в массиве использовать NULL-значения?

Да, но с оговорками:

  • 🔹 В МАССИВ() нельзя явно указать NULL — вместо этого используйте ЗНАЧЕНИЕ(NULL)
  • 🔹 При передаче массива в параметр NULL-значения сохранятся

Пример:

Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Поле В МАССИВ(1, ЗНАЧЕНИЕ(NULL), 3)";
Как сравнить два массива в запросе?

Прямого оператора для сравнения массивов в языке запросов нет. Альтернативные подходы:

  1. Через строковое представление:
    ГДЕ ВЫРАЗИТЬ(&Массив1 КАК СТРОКА) = ВЫРАЗИТЬ(&Массив2 КАК СТРОКА)

    Минус: Чувствителен к порядку элементов.

  2. Через проверку вхождения:
    ГДЕ НЕ СУЩЕСТВУЕТ (
    

    ВЫБРАТЬ Элемент ИЗ &Массив1 КАК Элемент

    ГДЕ НЕ Элемент В (&Массив2)

    )

    И НЕ СУЩЕСТВУЕТ (

    ВЫБРАТЬ Элемент ИЗ &Массив2 КАК Элемент

    ГДЕ НЕ Элемент В (&Массив1)

    )

    Плюс: Работает независимо от порядка элементов.