При изучении языка запросов 1С начинающие разработчики часто сталкиваются с необходимостью обработать данные, которые еще не записаны в базу данных, но уже имеются в оперативной памяти (например, в массиве или таблице значений) или же вовсе должны быть сформированы «на лету» прямо в тексте самого запроса. В классическом SQL для этого существуют свои механизмы, однако в 1С есть свои специфические особенности и ограничения, которые мы подробно разберем в этой статье.
Рассмотрим ситуацию, когда у нас есть массив данных или готовая таблица в памяти, и нам нужно использовать ее в сложном запросе совместно с данными из информационной базы. Напрямую передать объект Массив в секцию ИЗ нельзя. Чтобы сделать данные доступными для запроса, их необходимо сначала поместить в объект ТаблицаЗначений, а затем передать как параметр.
Разберем по шагам, как это реализовать:
УстановитьПараметр.Посмотрим на пример кода, реализующий этот подход:
// 1. Подготовка данных в коде 1С:Предприятие
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"));
ТаблицаДанных.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
// Заполнение (например, из массива или других данных)
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Склад = СкладСсылка;
НоваяСтрока.Количество = 10;
// 2. Выполнение запроса
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ВнешнийИсточник", ТаблицаДанных);
Запрос.Текст =
"ВЫБРАТЬ
| ВнешнийИсточник.Склад КАК Склад,
| ВнешнийИсточник.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_ДанныеИзПамяти
|ИЗ
| &ВнешнийИсточник КАК ВнешнийИсточник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ДанныеИзПамяти.Склад,
| СУММА(ВТ_ДанныеИзПамяти.Количество) КАК ИтоговоеКоличество
|ИЗ
| ВТ_ДанныеИзПамяти КАК ВТ_ДанныеИзПамяти
|СГРУППИРОВАТЬ ПО
| ВТ_ДанныеИзПамяти.Склад";
РезультатЗапроса = Запрос.Выполнить();
Проанализируем этот пример: использование конструкции ПОМЕСТИТЬ является обязательным условием при работе с внешними таблицами значений. Без этого платформа не сможет связать локальные данные с таблицами СУБД.
Иногда требуется создать небольшую статичную таблицу прямо «в коде» запроса, не передавая ничего извне. В SQL это можно сделать простым перечислением в VALUES, а в 1С мы используем механизм объединения выборок из пустых источников (или параметров-констант).
Рассмотрим подробнее, как собрать таблицу из произвольных строк:
ВЫБРАТЬ
ДАТАВРЕМЯ(2023, 1, 1) КАК Период,
&Номенклатура1 КАК Номенклатура,
10 КАК Количество
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2023, 1, 15),
&Номенклатура2,
5
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2023, 2, 01),
&Номенклатура3,
20
Выясним причину, почему это работает: первая секция ВЫБРАТЬ задает имена колонок и их типы. Все последующие секции ОБЪЕДИНИТЬ ВСЕ просто добавляют строки в этот виртуальный набор данных. Важный нюанс: в языке запросов 1С обязательна секция ИЗ, если вы выбираете поля из реальных таблиц. Однако, если вы выбираете только литералы (числа, строки, даты) или параметры, секция ИЗ может отсутствовать, что и позволяет нам «генерировать» данные из ничего.
Для выбора специфических системных данных или предопределенных элементов конфигурации без передачи их через параметры, мы используем функцию ЗНАЧЕНИЕ(). Это позволяет сделать запрос более автономным.
Примеры использования этой конструкции:
ЗНАЧЕНИЕ(Справочник.Валюты.Доллар)ЗНАЧЕНИЕ(Перечисление.Статусы.Активен)ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)ЗНАЧЕНИЕ(Тип(Число))Разберем ситуацию: вам нужно составить таблицу, где одна колонка будет содержать тип документа, а другая — его описание. Это можно сделать, комбинируя ЗНАЧЕНИЕ() и ОБЪЕДИНИТЬ ВСЕ.
Проанализируем технические лимиты, которые могут повлиять на стабильность вашей системы:
1. Ограничение на количество объединений: При использовании метода с ОБЪЕДИНИТЬ ВСЕ для создания больших таблиц (например, более 100-200 строк), вы можете столкнуться с ошибкой СУБД или крайне медленной работой. В таких случаях всегда лучше использовать ТаблицаЗначений как параметр (Метод 1).
2. Типизация данных: Платформа 1С определяет типы колонок по первому запросу в объединении. Если в первой секции вы укажете НЕОПРЕДЕЛЕНО в качестве значения, а во второй — ссылку, запрос может отработать некорректно. Старайтесь всегда явно указывать типы в первой выборке (например, через ВЫРАЗИТЬ или используя конкретные литералы).
3. Работа с Массивами: Как мы уже выяснили, массив нельзя использовать как таблицу. Однако его очень удобно использовать в условии фильтрации. Рассмотрим пример:
// Массив ссылок
МассивНоменклатуры = Новый Массив;
МассивНоменклатуры.Добавить(Ссылка1);
МассивНоменклатуры.Добавить(Ссылка2);
Запрос.УстановитьПараметр("СписокТоваров", МассивНоменклатуры);
Запрос.Текст = "ВЫБРАТЬ * ИЗ Справочник.Номенклатура ГДЕ Ссылка В (&СписокТоваров)";
4. Менеджер временных таблиц: Если вы планируете использовать созданную таблицу в нескольких разных запросах подряд, не забудьте инициализировать МенеджерВременныхТаблиц и передать его в объект Запрос. Это позволит хранить временные данные в течение всего сеанса работы программного кода.
Таким образом, мы рассмотрели основные способы «создания данных» внутри запроса. Выбор метода зависит от объема данных: для 1–5 строк подойдет ОБЪЕДИНИТЬ ВСЕ, для динамических списков — передача Таблицы Значений, а для системных констант — функция ЗНАЧЕНИЕ().