В процессе разработки часто возникает необходимость преобразовать агрегированные данные вида «Номенклатура — Количество (например, 8)» в набор поштучных записей вида «Номенклатура — 1» (8 отдельных строк). Проанализируем, в каких ситуациях требуется такое решение, как реализовать его непосредственно в языке запросов 1С и какие существуют альтернативные подходы.
Рассмотренный механизм размножения строк широко применяется в следующих практических сценариях:
Так как в языке запросов 1С отсутствуют встроенные функции генерации последовательностей (генераторы рядов чисел) и рекурсивные запросы, размножение строк выполняется путем внутреннего соединения исходных данных с таблицей чисел по условию ПорядковыйНомер <= Количество.
Разберем по шагам, как сформировать временную таблицу чисел и объединить ее с исходными данными:
ВЫБРАТЬ 1 КАК Номер
ПОМЕСТИТЬ ВТ_Числа
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 3
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 5
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 6
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 7
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 8
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИсходныеДанные.Номенклатура КАК Номенклатура,
1 КАК Количество,
ВТ_Числа.Номер КАК НомерЗаписи
ИЗ
ВТ_ИсходныеДанные КАК ИсходныеДанные
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Числа КАК ВТ_Числа
ПО ВТ_Числа.Номер <= ИсходныеДанные.Количество
В результате этого запроса строка с количеством 8 соединится с числами от 1 до 8 и даст в итоговой выборке ровно 8 отдельных строк.
Если максимальное количество может быть достаточно большим (например, сотни или тысячи единиц), прописывать конструкцию ОБЪЕДИНИТЬ ВСЕ в запросе неэффективно. В таком случае разберем вариант с генерацией ТаблицаЗначений в коде 1С и передачей ее в запрос в качестве параметра.
Посмотрим на пример программной реализации:
// 1. Создаем и заполняем таблицу чисел в коде 1С
ТЗЧисел = Новый ТаблицаЗначений;
ТЗЧисел.Колонки.Добавить("Число", Новый ОписаниеТипов("Число"));
МаксимальноеКоличество = 500; // Устанавливаем требуемый предел
Для Индекс = 1 По МаксимальноеКоличество Цикл
НоваяСтрока = ТЗЧисел.Добавить();
НоваяСтрока.Число = Индекс;
КонецЦикла;
// 2. Передаем таблицу в запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗЧисел.Число КАК Число
|ПОМЕСТИТЬ ВТ_Числа
|ИЗ
| &ТЗЧисел КАК ТЗЧисел
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| 1 КАК Количество,
| ВТ_Числа.Число КАК НомерПоПорядку
|ИЗ
| ДокументРеализацияТоваровУслугТовары КАК Товары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Числа КАК ВТ_Числа
| ПО ВТ_Числа.Число <= Товары.Количество";
Запрос.УстановитьПараметр("ТЗЧисел", ТЗЧисел);
Результат = Запрос.Выполнить();
Проанализируем ситуацию с точки зрения производительности СУБД. Генерация большого количества строк внутри запроса может создавать значительную нагрузку на сервер БД. Зачастую гораздо выгоднее выполнить простой агрегированный запрос, а разворачивание строк выполнить на стороне сервера 1С в цикле.
Рассмотрим пример алгоритма обработки выборки:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Внутренний цикл по количеству из результата запроса
Для Счетчик = 1 По Выборка.Количество Цикл
// Выполняем действия для каждой штучной единицы
// Например, формируем область печатной формы
КонецЦикла;
КонецЦикла;
При выборе подходящего способа выясним ключевые ограничения платформы 1С:
ОБЪЕДИНИТЬ ВСЕ существенно раздувает текст запроса и увеличивает время его компиляции на стороне СУБД.