Работа с таблицами в 1С:Предприятие 8.3 — одна из самых частых задач, с которыми сталкиваются разработчики и аналитики. Нередко требуется объединить данные из двух или более источников: справочников, документов, регистров. Но как сделать это правильно, чтобы не потерять данные, не замедлить систему и получить актуальный результат?
В этой статье разберём 5 рабочих способов объединения таблиц — от простых запросов до сложных алгоритмов на встроенном языке. Вы узнаете, когда лучше использовать ОБЪЕДИНИТЬ, а когда — ВЫБРАТЬ РАЗЛИЧНЫЕ, как избежать дубликатов и почему иногда проще написать обработку, чем мучиться с SQL-подобным синтаксисом. Особое внимание уделим типичным ошибкам при работе с большими таблицами (100 000+ строк), которые могут заблокировать базу или вызвать таймаут.
Материал будет полезен как начинающим программистам 1С, так и опытным специалистам, которые хотят оптимизировать свои решения. Все примеры приведены для актуальных версий платформы (8.3.20+), но majority методов работают и в более ранних релизах.
1. Объединение через запрос (ОБЪЕДИНИТЬ)
Самый очевидный и часто используемый способ — оператор ОБЪЕДИНИТЬ в языке запросов 1С. Он позволяет "склеить" результаты двух или более выборок, если их структуры совпадают по количеству и типам полей.
Основные правила работы с ОБЪЕДИНИТЬ:
- 🔹 Оба запроса должны возвращать одинаковое количество колонок
- 🔹 Типы данных в соответствующих колонках должны совпадать (например, нельзя объединять строку с числом)
- 🔹 По умолчанию дубликаты не удаляются (используйте
ОБЪЕДИНИТЬ РАЗЛИЧНЫЕдля их исключения) - 🔹 Порядок колонок важен — первая колонка первого запроса должна соответствовать первой колонке второго
Пример объединения данных о клиентах из справочника Контрагенты и документа ЗаказыПокупателей:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Клиент,
Контрагенты.Наименование КАК ИмяКлиента
ИЗ
Справочник.Контрагенты КАК Контрагенты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ЗаказыПокупателей.Контрагент КАК Клиент,
ЗаказыПокупателей.Контрагент.Наименование КАК ИмяКлиента
ИЗ
Документ.ЗаказыПокупателей КАК ЗаказыПокупателей
⚠️ Внимание: При объединении больших таблиц (более 50 000 строк) запрос может выполняться долго или вызывать ошибку переполнения памяти. В таких случаях лучше использовать постраничную выборку или программное объединение.
2. Объединение с удалением дубликатов (РАЗЛИЧНЫЕ)
Если в результирующей таблице не должно быть повторяющихся строк, используйте конструкцию ОБЪЕДИНИТЬ РАЗЛИЧНЫЕ. Это аналог UNION в стандартном SQL.
Рассмотрим пример объединения данных о номенклатуре из справочника и документа ПоступлениеТоваров, исключая дубли:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Номенклатура.Ссылка КАК Товар,
Номенклатура.Артикул КАК Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ОБЪЕДИНИТЬ РАЗЛИЧНЫЕ
ВЫБРАТЬ
ПоступлениеТоваров.Номенклатура КАК Товар,
ПоступлениеТоваров.Номенклатура.Артикул КАК Артикул
ИЗ
Документ.ПоступлениеТоваров КАК ПоступлениеТоваров
Важные нюансы:
- 📌
РАЗЛИЧНЫЕприменяется ко всему результирующему набору, а не к отдельным запросам - 📌 Если дубликаты нужно удалять только в рамках одного запроса, используйте
ВЫБРАТЬ РАЗЛИЧНЫЕдля каждого блока отдельно - 📌 При работе с большими объёмами данных этот метод может существенно замедлить выполнение запроса
Для ускорения работы с РАЗЛИЧНЫМИ добавьте в запрос условие отбора по дате или другому индексированному полю, чтобы сократить исходный набор данных.
3. Программное объединение таблиц значений
Когда запрос не подходит (например, нужно объединить данные из разных источников с разной структурой), на помощь приходит программное объединение через ТаблицуЗначений.
Алгоритм действий:
- Создать две таблицы значений с нужной структурой
- Заполнить их данными из разных источников
- Объединить с помощью метода
Объединить()или в цикле
Пример кода для объединения данных о продажах из двух разных документов:
// Создаем первую таблицу с продажами из реализаций
Таблица1 = Новый ТаблицаЗначений;
Таблица1.Колонки.Добавить("Документ");
Таблица1.Колонки.Добавить("Сумма");
Таблица1.Колонки.Добавить("Дата");
Запрос1 = Новый Запрос;
Запрос1.Текст = "ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Документ,
| РеализацияТоваровУслуг.СуммаДокумента КАК Сумма,
| РеализацияТоваровУслуг.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг";
Результат1 = Запрос1.Выполнить();
Таблица1.Загрузить(Результат1);
// Создаем вторую таблицу с продажами из заказов
Таблица2 = Новый ТаблицаЗначений;
Таблица2.Колонки.Добавить("Документ");
Таблица2.Колонки.Добавить("Сумма");
Таблица2.Колонки.Добавить("Дата");
Запрос2 = Новый Запрос;
Запрос2.Текст = "ВЫБРАТЬ
| ЗаказыПокупателей.Ссылка КАК Документ,
| ЗаказыПокупателей.СуммаДокумента КАК Сумма,
| ЗаказыПокупателей.Дата КАК Дата
|ИЗ
| Документ.ЗаказыПокупателей КАК ЗаказыПокупателей";
Результат2 = Запрос2.Выполнить();
Таблица2.Загрузить(Результат2);
// Объединяем таблицы
РезультирующаяТаблица = Новый ТаблицаЗначений;
РезультирующаяТаблица.Колонки.Добавить("Документ");
РезультирующаяТаблица.Колонки.Добавить("Сумма");
РезультирующаяТаблица.Колонки.Добавить("Дата");
РезультирующаяТаблица.Объединить(Таблица1);
РезультирующаяТаблица.Объединить(Таблица2);
⚠️ Внимание: МетодОбъединить()добавляет строки из второй таблицы в конец первой. Если нужно избежать дубликатов, предварительно проверяйте наличие строк с помощьюНайтиСтроки()или используйтеСтруктураТаблицыдля сравнения.
4. Использование временных таблиц
Для сложных объединений с многоступенчатой обработкой удобно использовать временные таблицы. Они позволяют:
- 🔧 Разбить большой запрос на логические части
- 🔧 Сохранить промежуточные результаты
- 🔧 Оптимизировать производительность за счёт индексирования
Пример создания временной таблицы и её использования для объединения:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Товар,
| Товары.Артикул КАК Артикул
|ПОМЕСТИТЬ ВТТовары
|ИЗ
| Справочник.Номенклатура КАК Товары
|
|/////////////////////////////////////////////////
|ВЫБРАТЬ
| Остатки.Номенклатура КАК Товар,
| Остатки.КоличествоОстаток КАК Количество
|ПОМЕСТИТЬ ВТОстатки
|ИЗ
| РегистрНакопления.ОстаткиТоваров КАК Остатки
|
|/////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВТТовары.Товар КАК Товар,
| ВТТовары.Артикул КАК Артикул,
| ЕСТЬNULL(ВТОстатки.Количество, 0) КАК Количество
|ИЗ
| ВТТовары КАК ВТТовары
| ЛЕВОЕ СОЕДИНЕНИЕ ВТОстатки КАК ВТОстатки
| ПО ВТТовары.Товар = ВТОстатки.Товар";
Преимущества временных таблиц:
- 🚀 Уменьшают нагрузку на сервер за счёт промежуточного хранения данных
- 🚀 Позволяют создавать индексы для ускорения выборки
- 🚀 Упрощают отладку сложных запросов
Имена временных таблиц начинаются с ВТ
Поля для соединения имеют одинаковые типы
Добавлены индексы для полей соединения
Учтена возможность пустых значений (NULL)
Очистка временных таблиц после использования-->
5. Объединение через систему компоновки данных (СКД)
Если нужно не только объединить данные, но и представить их в виде отчёта с группировками, Система Компоновки Данных (СКД) станет мощным инструментом. Она позволяет:
- 📊 Объединять данные из разных источников в одном отчёте
- 📊 Настраивать сложные группировки и итоги
- 📊 Использовать разные виды диаграмм и таблиц
Пример настройки схемы компоновки данных для объединения данных о продажах и возвратах:
СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
ИсточникДанных1 = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
ИсточникДанных1.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Дата КАК Дата,
| РеализацияТоваровУслуг.Контрагент КАК Клиент,
| РеализацияТоваровУслуг.СуммаДокумента КАК СуммаПродаж,
| 0 КАК СуммаВозвратов
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг";
ИсточникДанных2 = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
ИсточникДанных2.Текст =
"ВЫБРАТЬ
| ВозвратТоваровОтПокупателя.Дата КАК Дата,
| ВозвратТоваровОтПокупателя.Контрагент КАК Клиент,
| 0 КАК СуммаПродаж,
| ВозвратТоваровОтПокупателя.СуммаДокумента КАК СуммаВозвратов
|ИЗ
| Документ.ВозвратТоваровОтПокупателя КАК ВозвратТоваровОтПокупателя";
Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
Настройки.Структура.Очистить();
ЭлементСтруктуры = Настройки.Структура.Элементы.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
ЭлементСтруктуры.Поле = Новый ПолеКомпоновкиДанных("Дата");
ЭлементСтруктуры.Тип = Тип("ГруппировкаКомпоновкиДанныхПоИерархии");
Особенности работы с СКД:
- 🎯 Позволяет объединять данные с разной структурой (дополняя отсутствующие поля нулями или пустыми значениями)
- 🎯 Поддерживает сложные вычисления прямо в отчёте
- 🎯 Можно сохранять настройки отчётов для повторного использования
6. Объединение через внешние обработки
Когда стандартные средства 1С не справляются (например, нужно объединить данные из разных баз или файлов), на помощь приходят внешние обработки. Они позволяют:
- 🔗 Загружать данные из Excel, XML, JSON
- 🔗 Объединять информацию из нескольких баз 1С
- 🔗 Использовать сложную логику объединения, недоступную в запросах
Пример кода для загрузки данных из Excel и объединения с данными 1С:
// Подключаем библиотеку для работы с Excel
Попытка
ПодключитьВнешнююКомпоненту("C:\Program Files\1Cv8\bin\V8Excel.dll");
Исключение
Сообщить("Не удалось подключить библиотеку для работы с Excel!");
Возврат;
КонецПопытки;
Excel = Новый COMОбъект("Excel.Application");
РабочаяКнига = Excel.Workbooks.Open("C:\Отчеты\Продажи.xlsx");
Лист = РабочаяКнига.Sheets(1);
// Чтение данных из Excel
ТаблицаExcel = Новый ТаблицаЗначений;
ТаблицаExcel.Колонки.Добавить("Дата");
ТаблицаExcel.Колонки.Добавить("Клиент");
ТаблицаExcel.Колонки.Добавить("Сумма");
СтрокаExcel = 2; // Начинаем со второй строки
Пока Лист.Cells(СтрокаExcel, 1).Value <> Неопределено Цикл
НоваяСтрока = ТаблицаExcel.Добавить();
НоваяСтрока.Дата = Лист.Cells(СтрокаExcel, 1).Value;
НоваяСтрока.Клиент = Лист.Cells(СтрокаExcel, 2).Value;
НоваяСтрока.Сумма = Лист.Cells(СтрокаExcel, 3).Value;
СтрокаExcel = СтрокаExcel + 1;
КонецЦикла;
// Получаем данные из 1С
Таблица1С = ПолучитьДанныеИз1С();
// Объединяем таблицы
РезультирующаяТаблица = Новый ТаблицаЗначений;
РезультирующаяТаблица.Колонки.Добавить("Дата");
РезультирующаяТаблица.Колонки.Добавить("Клиент");
РезультирующаяТаблица.Колонки.Добавить("Сумма");
РезультирующаяТаблица.Колонки.Добавить("Источник");
Для Каждого Строка Из ТаблицаExcel Цикл
НоваяСтрока = РезультирующаяТаблица.Добавить();
НоваяСтрока.Дата = Строка.Дата;
НоваяСтрока.Клиент = Строка.Клиент;
НоваяСтрока.Сумма = Строка.Сумма;
НоваяСтрока.Источник = "Excel";
КонецЦикла;
Для Каждого Строка Из Таблица1С Цикл
НоваяСтрока = РезультирующаяТаблица.Добавить();
НоваяСтрока.Дата = Строка.Дата;
НоваяСтрока.Клиент = Строка.Клиент;
НоваяСтрока.Сумма = Строка.Сумма;
НоваяСтрока.Источник = "1С";
КонецЦикла;
Как ускорить работу с большими Excel-файлами?
1. Отключите обновление экрана: Excel.ScreenUpdating = Ложь;
2. Используйте массивы для чтения данных пачками, а не построчно
3. После работы освободите память: Excel.Quit();
4. Для файлов >100МБ рассмотрите вариант импорта через ADO или специализированные библиотеки
Сравнение методов объединения таблиц
| Метод | Скорость | Сложность реализации | Гибкость | Когда использовать |
|---|---|---|---|---|
Запрос с ОБЪЕДИНИТЬ |
⚡⚡⚡⚡ | ⭐ | Средняя | Простые объединения с одинаковой структурой |
| Программное объединение | ⚡⚡ | ⭐⭐⭐ | Высокая | Сложная логика, разные структуры данных |
| Временные таблицы | ⚡⚡⚡ | ⭐⭐ | Высокая | Многоступенчатая обработка больших объёмов |
| Система компоновки данных | ⚡⚡ | ⭐⭐⭐⭐ | Очень высокая | Сложные отчёты с группировками |
| Внешние обработки | ⚡ | ⭐⭐⭐⭐⭐ | Максимальная | Интеграция с внешними источниками |
⚠️ Внимание: Производительность методов может существенно отличаться в зависимости от версии платформы, конфигурации и объёма данных. Для критичных операций всегда тестируйте скорость выполнения на реальных данных.
Типичные ошибки и как их избежать
При объединении таблиц в 1С разработчики часто сталкиваются с одними и теми же проблемами. Вот самые распространённые:
1. Несовпадение типов данных
Если в первом запросе поле имеет тип Строка, а во втором — Число, запрос завершится ошибкой. Всегда проверяйте типы полей через ОписаниеТипов().
2. Дублирование данных
При использовании ОБЪЕДИНИТЬ ВСЕ (аналог UNION ALL) дубликаты сохраняются. Если это не нужно, используйте ОБЪЕДИНИТЬ РАЗЛИЧНЫЕ.
3. Переполнение памяти
При работе с большими таблицами (>100 000 строк) запрос может "подвесить" базу. Решения:
- 🛠 Разбивайте запрос на части с помощью
ПЕРВЫЕили постраничной выборки - 🛠 Используйте временные таблицы с индексами
- 🛠 Выгружайте данные в файл и обрабатывайте порциями
4. Неправильная сортировка
Если нужно отсортировать итоговую таблицу, используйте УПОРЯДОЧИТЬ ПО в самом конце запроса, а не в каждом блоке ОБЪЕДИНИТЬ.
5. Потеря данных при неявных преобразованиях
При объединении полей с разными типами 1С может автоматически преобразовать данные, что приведёт к потере точности. Например, ДатаВремя может превратиться в Дата.
Всегда проверяйте результат объединения на тестовых данных перед применением в рабочей базе. Особенно важно тестировать крайние случаи: пустые таблицы, NULL-значения, максимальные объёмы данных.
FAQ: Частые вопросы по объединению таблиц
Можно ли объединить таблицы с разным количеством колонок?
Нет, для оператора ОБЪЕДИНИТЬ требуется одинаковое количество колонок в обоих запросах. Решения:
- Добавьте недостающие колонки с пустыми значениями или NULL
- Используйте программное объединение через
ТаблицаЗначений - Примените Систему Компоновки Данных, где можно задавать разные наборы полей
Как объединить данные из двух разных баз 1С?
Для этого нужно:
- Подключиться к второй базе через
COMСоединениеилиHTTPСервисы - Выгрузить данные из второй базы во временную таблицу или файл
- Объединить данные программно или через запрос к временной таблице
Пример кода для подключения к другой базе:
Соединение = Новый COMОбъект("V83.COMConnector");
База = Соединение.Connect("File=""C:\Bases\Base2"";Usr=""Администратор"";");
Запрос = База.NewObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1000...";
Почему запрос с ОБЪЕДИНИТЬ работает медленно?
Основные причины:
- Отсутствие индексов на полях, используемых в условии
ГДЕилиСОЕДИНЕНИЕ - Слишком широкие выборки (используйте
ПЕРВЫЕ Nдля тестирования) - Сложные вычисляемые поля в запросе (перенесите вычисления в программный код)
- Блокировки таблиц другими пользователями (проверьте через
АктивныеПользователи)
Для диагностики используйте ПланЗапроса():
Объяснение = Запрос.Выполнить().ПланВременногоВыполнения();
Объяснение.Записать("C:\temp\plan.txt");
Как объединить таблицы с сохранением порядка строк?
По умолчанию порядок строк в результате ОБЪЕДИНИТЬ не гарантируется. Чтобы сохранить порядок:
- Добавьте в каждый запрос колонку с порядковым номером
- В итоговом запросе отсортируйтесь по этой колонке
Пример:
ВЫБРАТЬ
1 КАК Порядок,
Товары.Наименование
ИЗ
Справочник.Номенклатура КАК Товары
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
2 КАК Порядок,
Поступления.Номенклатура.Наименование
ИЗ
Документ.ПоступлениеТоваров КАК Поступления
УПОРЯДОЧИТЬ ПО
Порядок, Наименование
Можно ли объединить таблицу значений с результатом запроса?
Да, для этого:
- Выполните запрос и загрузите результат в таблицу значений
- Используйте метод
Объединить()для соединения таблиц
Пример:
РезультатЗапроса = Запрос.Выполнить();
ТаблицаЗапроса = РезультатЗапроса.Выгрузить();
ОсновнаяТаблица = ПолучитьДанныеИзДругогоИсточника();
ОсновнаяТаблица.Объединить(ТаблицаЗапроса);
Если структуры таблиц отличаются, предварительно выровняйте колонки.