Работа с таблицами значений — одна из самых частых задач разработчика 1С. Часто возникает ситуация, когда данные (например, остатки товаров) приходят из разных источников или разных складов в виде отдельных таблиц, и их необходимо «склеить» в одну общую таблицу для отчета или выгрузки. В этой статье мы подробно разберем, как эффективно объединить данные из нескольких таблиц значений, избегая типичных ошибок новичков.
Самый правильный и производительный способ объединения таблиц значений — это использование механизма запросов. Вместо того чтобы писать сложные циклы, мы можем поместить наши таблицы во временные таблицы запроса и соединить их по ключевому полю (например, по артикулу или коду товара).
Важное условие: Для того чтобы передать таблицу значений в запрос, у всех ее колонок должны быть явно заданы типы данных. Если колонка создана динамически без указания типа, запрос не сможет с ней работать.
Рассмотрим по шагам, как это реализовать:
ЛЕВОЕ СОЕДИНЕНИЕ.Пример кода для объединения основной таблицы с таблицей остатков склада:
// 1. Создаем запрос и менеджер временных таблиц
Запрос = Новый Запрос;
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// 2. Передаем таблицы как параметры.
// Предположим, у нас есть ИтоговаяТаблица и ТЗОстаткиСтаврополь
Запрос.УстановитьПараметр("ВнешняяТЗ_Основная", ИтоговаяТаблица);
Запрос.УстановитьПараметр("ВнешняяТЗ_Ставрополь", ТЗОстаткиERP_1024);
// 3. Текст запроса: помещаем таблицы во временные и соединяем их
Запрос.Текст =
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Основная ИЗ &ВнешняяТЗ_Основная КАК ВнешняяТЗ_Основная;
|
|ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Ставрополь ИЗ &ВнешняяТЗ_Ставрополь КАК ВнешняяТЗ_Ставрополь;
|
|ВЫБРАТЬ
| Осн.Название,
| Осн.Артикул,
| ЕСТЬNULL(Стр.Остаток, 0) КАК СвободныйОстатокСтаврополь
|ИЗ
| ВТ_Основная КАК Осн
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Ставрополь КАК Стр
| ПО Осн.Артикул = Стр.Артикул";
ИтоговаяТаблица = Запрос.Выполнить().Выгрузить();
Этот подход позволяет избежать «геометрической прогрессии» сложности при добавлении новых складов. Мы просто добавляем еще одно ЛЕВОЕ СОЕДИНЕНИЕ в текст запроса, и платформа сама оптимизирует процесс сопоставления строк.
Если по каким-то причинам использование запроса невозможно (например, таблицы слишком маленькие или структура данных крайне динамична), можно использовать перебор строк. Однако здесь кроется главная ловушка производительности: обычный поиск методом Найти() в большой таблице будет работать очень медленно.
Проанализируем ситуацию: если в таблице 10 000 товаров и мы ищем остатки для 5 складов, программе придется выполнить до 50 000 полных сканирований таблицы. Чтобы этого избежать, обязательно нужно использовать индексацию.
Разберем алгоритм правильного программного добавления колонки:
Колонки.Добавить().
// Добавляем колонку для нового склада
ИтоговаяТаблица.Колонки.Добавить("СвободныйОстатокРостов", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
// Индексируем таблицу-источник для мгновенного поиска
ТЗОстаткиРостов.Индексы.Добавить("Артикул");
Для Каждого СтрокаИтог Из ИтоговаяТаблица Цикл
// Используем метод Найти(), который теперь работает мгновенно благодаря индексу
СтрокаИсточник = ТЗОстаткиРостов.Найти(СтрокаИтог.Артикул, "Артикул");
Если СтрокаИсточник <> Неопределено Тогда
СтрокаИтог.СвободныйОстатокРостов = СтрокаИсточник.Остаток;
Иначе
СтрокаИтог.СвободныйОстатокРостов = 0;
КонецЕсли;
КонецЦикла;
Когда имена колонок в таблице-источнике и таблице-приемнике совпадают, удобно использовать метод ЗаполнитьЗначенияСвойств. Рассмотрим ситуацию, когда мы хотим быстро перенести данные из одной строки в другую.
Если в исходной таблице колонка называется Остаток, а нам нужно записать ее в колонку СвободныйОстатокТверь, мы можем временно переименовать колонку в исходной таблице или просто присвоить значение напрямую, как в примере выше. Однако если колонок много, ЗаполнитьЗначенияСвойств значительно сокращает объем кода.
Никогда не используйте ВыгрузитьКолонку() и ЗагрузитьКолонку() для сопоставления данных. Эти методы работают с массивами и просто вставляют данные по порядку индексов строк (0, 1, 2...). Если в одной таблице товар «А» идет первой строкой, а во второй таблице первой строкой идет товар «Б», данные перемешаются, и вы получите неверные остатки. Эти методы допустимы только если вы абсолютно уверены, что состав и порядок строк в обеих таблицах идентичен (например, одна получена из другой методом Скопировать()).
Форматирование вывода. При выгрузке в файл (как в коде автора темы) часто используют конструкцию ?(Строка.СвободныйОстаток <> Неопределено, ...). В 1С хорошим тоном считается использование функции ЕСТЬNULL в запросах или предварительное заполнение пустых значений нулями, чтобы код выгрузки оставался чистым и читаемым.
Вместо ручного формирования текстовых строк с разделителями ;, что может привести к ошибкам, если в названии товара встретится точка с запятой, мы рекомендуем использовать ТабличныйДокумент.
Разберем кратко этот процесс:
ТабличныйДокумент.
ТабДок = Новый ТабличныйДокумент;
// ... код заполнения ТабДок из ИтоговаяТаблица ...
// Записываем результат напрямую в файл XLSX
ТабДок.Записать("C:\Остатки\Отчет.xlsx", ТипФайлаТабличногоДокумента.XLSX);
Подведем итог: Для эффективного добавления колонок с данными в таблицу значений в 1С лучше всего использовать запросы с левым соединением. Это гарантирует высокую скорость работы, корректность сопоставления данных по ключам и легкость поддержки кода в будущем. Если же вы работаете с циклами, никогда не забывайте про индексацию таблиц, в которых осуществляется поиск.