Работа с таблицами в 1С:Предприятие 8.3 — одна из самых востребованных задач среди разработчиков и аналитиков. Чаще всего требуется объединить данные из нескольких источников: справочников, документов или регистров. Но как правильно соединить две таблицы, чтобы не потерять данные и не получить дубли? В этой статье разберём все актуальные методы — от визуальных инструментов до программного кода.

Мы рассмотрим три основных подхода: объединение через запросы (с использованием LEFT JOIN, INNER JOIN и других операторов), программное соединение в модулях и визуальные методы в конфигураторе. Особое внимание уделим нюансам работы с большими объёмами данных и типичным ошибкам, которые приводят к потере информации или зависанию системы.

Если вы только начинаете осваивать , не переживайте — мы дадим простые примеры с пояснениями. Опытные разработчики найдут здесь оптимизированные решения для сложных случаев, включая работу с временными таблицами и динамическими соединениями.

📊 Какой способ объединения таблиц вы используете чаще?
Запросы (JOIN/UNION)
Программное объединение в модуле
Визуальные инструменты конфигуратора
Другой вариант

1. Объединение таблиц через запросы: JOIN и UNION

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

  • 🔗 INNER JOIN — возвращает только совпадающие записи из обеих таблиц.
  • 🔳 LEFT JOIN — включает все записи из левой таблицы и совпадающие из правой (если нет совпадений, поля правой таблицы заполняются NULL).
  • 🔲 RIGHT JOIN — аналогично LEFT JOIN, но для правой таблицы.
  • 🔄 FULL JOIN — возвращает все записи из обеих таблиц (в эмулируется через LEFT JOIN + RIGHT JOIN).
  • UNION — объединяет результаты двух запросов в одну таблицу (без дублей при UNION ALL).

Пример запроса с LEFT JOIN для соединения справочника Номенклатура и документа РеализацияТоваровУслуг:

ВЫБРАТЬ

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

РеализацияТоваровУслуг.Количество КАК Колво,

РеализацияТоваровУслуг.Цена КАК Цена

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

ПО Номенклатура.Ссылка = РеализацияТоваровУслуг.Номенклатура

ГДЕ

РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Обратите внимание на параметры &НачалоПериода и &КонецПериода — они позволяют динамически фильтровать данные без изменения кода запроса. Если вам нужно объединить таблицы с разной структурой, используйте UNION:

ВЫБРАТЬ

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

"Справочник" КАК Источник

ИЗ

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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ

ТоварыУслуги.Наименование,

"Документ" КАК Источник

ИЗ

Документ.ПоступлениеТоваровУслуг.Товары КАК ТоварыУслуги

⚠️ Внимание: При использовании UNION количество и типы полей в обоих запросах должны совпадать. Если в одной таблице есть поле, которого нет в другой, добавьте его с значением NULL или пустой строкой.
💡

Для ускорения запросов с соединением добавьте индексы на поля, по которым выполняется JOIN. В конфигураторе это делается через свойства реквизитов (установите флаг "Индексировать").

2. Программное объединение таблиц в модуле

Если нужно соединить таблицы динамически (например, в обработке или отчёте), можно использовать объекты ТаблицаЗначений и ДеревоЗначений. Этот метод полезен, когда:

  • 📊 Требуется предварительная обработка данных перед объединением.
  • 🔧 Нужно реализовать нестандартную логику соединения (например, по нескольким условиям).
  • 🖥️ Работа ведётся с временными данными, которые не хранятся в базе.

Пример кода для объединения двух таблиц значений по полю Код:

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

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

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

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

Таблица1.Добавить().Заполнить(1, "Товар А");

Таблица1.Добавить().Заполнить(2, "Товар Б");

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

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

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

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

Таблица2.Добавить().Заполнить(1, 1000);

Таблица2.Добавить().Заполнить(3, 1500);

// Объединяем таблицы (аналог LEFT JOIN)

Результат = Новый ТаблицаЗначений;

Результат.Колонки.Добавить("Код");

Результат.Колонки.Добавить("Наименование");

Результат.Колонки.Добавить("Цена");

// Проходим по первой таблице

Для Каждого Строка1 Из Таблица1 Цикл

НоваяСтрока = Результат.Добавить();

НоваяСтрока.Код = Строка1.Код;

НоваяСтрока.Наименование = Строка1.Наименование;

// Ищем совпадение во второй таблице

Найдено = Таблица2.Найти(Строка1.Код, "Код");

Если Найдено <> Неопределено Тогда

НоваяСтрока.Цена = Найдено.Цена;

Иначе

НоваяСтрока.Цена = 0; // или NULL

КонецЕсли;

КонецЦикла;

Для больших таблиц (более 10 000 строк) такой подход может быть медленным. В этом случае лучше использовать запросы или оптимизировать код с помощью:

  • 🔍 Индексировать колонки перед поиском (метод ИндексироватьКолонки()).
  • 🚀 Замены циклов на Соответствие или Структура для хранения промежуточных данных.
⚠️ Внимание: При программном объединении легко допустить ошибку с типами данных. Например, если в одной таблице поле Код имеет тип Число, а в другой — Строка, метод Найти() не сработает. Всегда проверяйте типы перед соединением.

3. Визуальные методы: объединение в конфигураторе

Если вы не хотите писать код, 1С:Предприятие предлагает визуальные инструменты для соединения таблиц:

  1. Конструктор запросов — позволяет построить запрос с соединениями через графический интерфейс. Откройте его через меню Файл → Новый → Запрос или кнопку Конструктор в окне редактирования запроса.
  2. Схемы компоновки данных — в отчётах можно настроить связи между наборами данных (аналог JOIN).
  3. Динамические списки — если таблицы связаны через ссылки (например, документ ссылается на справочник), автоматически построит соединение при выводе данных.

Пример настройки соединения в конструкторе запросов:

  1. Добавьте две таблицы в запрос (например, Справочник.Контрагенты и Документ.ЗаказыПокупателей).
  2. Перетащите поле Ссылка из первой таблицы на поле Контрагент во второй — автоматически создаст INNER JOIN.
  3. Чтобы изменить тип соединения, кликните правой кнопкой на линию между таблицами и выберите LEFT JOIN или RIGHT JOIN.

Для схем компоновки данных:

  1. В отчёте перейдите на закладку НастройкиНаборы данных.
  2. Создайте два набора данных (например, Номенклатура и ОстаткиТоваров).
  3. В параметрах набора данных укажите связь по полю (например, Номенклатура.Ссылка = ОстаткиТоваров.Номенклатура).
Метод Когда использовать Плюсы Минусы
Запросы (JOIN/UNION) Для сложных соединений, больших объёмов данных ⚡ Быстрота, гибкость, поддержка индексов Требует знания языка запросов
Программное объединение Для динамической обработки, нестандартной логики 🛠️ Полный контроль над процессом Медленнее запросов, сложно поддерживать
Визуальные инструменты Для простых соединений без кода 🎨 Удобно для новичков Ограниченная функциональность

4. Типичные ошибки и как их избежать

При соединении таблиц в даже опытные разработчики сталкиваются с проблемами. Рассмотрим самые распространённые:

  • 🔄 "Картезианское произведение" — когда забывают указать условие соединения, и каждая строка первой таблицы соединяется с каждой строкой второй. Это приводит к экспоненциальному росту результата.
  • 🚫 Потеря данных — при использовании INNER JOIN исключаются записи, не имеющие совпадений. Если нужны все строки, используйте LEFT JOIN.
  • 🐢 Медленная работа — соединение неиндексированных полей или таблиц с миллионами записей может "подвесить" базу.
  • 🔢 Несовпадение типов — если поля для соединения имеют разные типы (например, Число и Строка), запрос вернёт пустой результат.

Как избежать ошибок:

Поля для JOIN имеют одинаковый тип данных

Добавлены индексы на ключевые поля

Указано условие соединения (WHERE или ON)

Для больших таблиц использован LEFT JOIN вместо INNER JOIN

Тестирование запроса на небольшом объёме данных-->

Критическая ошибка: если в запросе с UNION количество колонок в первом и втором запросах не совпадает, 1С не выдаст ошибку, но результат будет некорректным (лишние колонки заполнятся NULL). Всегда проверяйте структуру результата!

Пример "плохого" запроса, который создаёт картезианское произведение:

ВЫБРАТЬ

Номенклатура.Наименование,

ПоступлениеТоваров.Количество

ИЗ

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

Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваров

// Забыли условие соединения!

Исправленный вариант:

ВЫБРАТЬ

Номенклатура.Наименование,

ПоступлениеТоваров.Количество

ИЗ

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваров

ПО Номенклатура.Ссылка = ПоступлениеТоваров.Номенклатура

5. Оптимизация соединений для больших баз данных

Если вы работаете с базами объёмом более 10 ГБ или таблицами с миллионами записей, стандартные методы соединения могут работать слишком долго. Вот несколько способов оптимизации:

  • 📌 Индексы — добавьте индексы на поля, используемые в условиях WHERE и JOIN. В конфигураторе это делается через свойства реквизитов.
  • 🗃️ Временные таблицы — для сложных отчётов предварительно сохраните данные во временные таблицы, а затем соединяйте их.
  • 🔍 Фильтрация на ранних этапах — сначала отфильтруйте данные в подзапросах, а потом соединяйте уменьшенные наборы.
  • 🚀 Использование СУБД — для на PostgreSQL или MS SQL можно писать прямые SQL-запросы с оптимизированными планами выполнения.

Пример оптимизированного запроса с предварительной фильтрацией:

ВЫБРАТЬ

ПродажиКлиента.Клиент КАК Клиент,

СУММА(ПродажиКлиента.Сумма) КАК ОбщаяСумма

ИЗ

(ВЫБРАТЬ

Документ.РеализацияТоваровУслуг.Клиент КАК Клиент,

Документ.РеализацияТоваровУслуг.СуммаДокумента КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

ГДЕ

РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода) КАК ПродажиКлиента

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

ПродажиКлиента.Клиент

Для временных таблиц используйте конструкцию ПОМЕСТИТЬ ... ВТ:

ВЫБРАТЬ

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

Номенклатура.Наименование КАК Наименование

ПОМЕСТИТЬ ВТ_Номенклатура

ИЗ

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

ГДЕ

Номенклатура.ПометкаУдаления = ЛОЖЬ;

/////////////

ВЫБРАТЬ

ВТ_Номенклатура.Наименование,

Остатки.Количество

ИЗ

ВТ_Номенклатура КАК ВТ_Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО ВТ_Номенклатура.Номенклатура = Остатки.Номенклатура

⚠️ Внимание: Временные таблицы в существуют только в рамках одного запроса. Если вам нужно сохранить данные для нескольких запросов, используйте РегистрСведений или ТаблицуЗначений в памяти.

6. Альтернативные способы: объединение через СКД и внешние обработки

Если стандартные методы не подходят, рассмотрите альтернативные подходы:

  • 📊 Система компоновки данных (СКД) — позволяет строить сложные отчёты с несколькими наборами данных и связями между ними. Подходит для аналитических задач.
  • 🔧 Внешние обработки — можно написать универсальную обработку для объединения таблиц с гибкими настройками.
  • 🌐 HTTP-сервисы — если данные хранятся во внешних системах, соединяйте их через API, а затем загружайте в .

Пример настройки связи в СКД:

  1. Создайте два набора данных: например, Основной (справочник Контрагенты) и Дополнительный (документ Договоры).
  2. В настройках набора данных Дополнительный укажите параметр Родитель и выберите Основной.
  3. Укажите связь по полю (например, Контрагенты.Ссылка = Договоры.Контрагент).
  4. В макете отчёта добавьте поля из обоих наборов данных.

Для внешних обработок можно использовать шаблон:

&НаКлиенте

Процедура ОбъединитьТаблицы(Команда)

Таблица1 = ПолучитьДанныеИзИсточника1();

Таблица2 = ПолучитьДанныеИзИсточника2();

Результат = ОбъединитьТаблицыНаСервере(Таблица1, Таблица2);

ОткрытьФормуРезультата(Результат);

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

&НаСервере

Функция ОбъединитьТаблицыНаСервере(Таблица1, Таблица2)

// Логика объединения

Результат = Новый ТаблицаЗначений;

// ...

Возврат Результат;

КонецФункции

Если данные хранятся в разных базах, используйте распределённые информационные базы (РИБ) или обмен через XML/JSON. Для этого в есть стандартные механизмы:

  • ЗаписьXML() / ЧтениеXML() — для обмена данными в формате XML.
  • ЗаписьJSON() / ЧтениеJSON() — для работы с JSON (доступно с версии 8.3.10).
  • HTTPСоединение — для запросов к внешним API.
Как объединить данные из разных баз 1С?

Для объединения данных из нескольких баз 1С можно использовать:

1. Распределённые информационные базы (РИБ) — встроенный механизм синхронизации.

2. Универсальный обмен данными (УФ) — через планы обмена и XML-файлы.

3. Прямые запросы к SQL — если базы находятся на одном сервере (требует прав администратора).

4. HTTP-сервисы — если базы разнесены географически.

Для настройки РИБ перейдите в Администрирование → Распределённые информационные базы и создайте узел обмена.

7. Практический пример: объединение справочника и документа

Рассмотрим реальную задачу: нужно вывести список товаров из справочника Номенклатура с указанием количества продаж за месяц из документа РеализацияТоваровУслуг. Если товар не продавался, должно выводиться 0.

Решение через запрос с LEFT JOIN:

ВЫБРАТЬ

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

ЕСТЬNULL(Продажи.Количество, 0) КАК Продано

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ

(

ВЫБРАТЬ

РеализацияТоваровУслуг.Номенклатура КАК Номенклатура,

СУММА(РеализацияТоваровУслуг.Количество) КАК Количество

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслуг

ГДЕ

РеализацияТоваровУслуг.Ссылка.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца

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

РеализацияТоваровУслуг.Номенклатура

) КАК Продажи

ПО Номенклатура.Ссылка = Продажи.Номенклатура

ГДЕ

НЕ Номенклатура.ПометкаУдаления

Результат будет содержать все товары, даже те, которые не продавались в указанный период.

Альтернативное решение через программное объединение:

// Получаем список номенклатуры

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

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

// Получаем продажи

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

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Номенклатура КАК Номенклатура,

| СУММА(РеализацияТоваровУслуг.Количество) КАК Количество

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Ссылка.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца

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

| РеализацияТоваровУслуг.Номенклатура";

Запрос.УстановитьПараметр("НачалоМесяца", НачалоМесяца(ТекущаяДата()));

Запрос.УстановитьПараметр("КонецМесяца", КонецМесяца(ТекущаяДата()));

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

// Объединяем данные

Для Каждого Строка Из РезультатНоменклатура Цикл

Найдено = РезультатПродажи.Найти(Строка.Ссылка, "Номенклатура");

Если Найдено <> Неопределено Тогда

Строка.Вставить("Количество", Найдено.Количество);

Иначе

Строка.Вставить("Количество", 0);

КонецЕсли;

КонецЦикла;

💡

Для соединения таблиц с большим количеством записей всегда отдавайте предпочтение запросам с JOIN — они работают на уровне СУБД и оптимизированы для производительности. Программное объединение через ТаблицаЗначений подходит только для небольших объёмов данных или специфической логики.

FAQ: Частые вопросы по объединению таблиц в 1С

Как соединить таблицы, если ключевые поля имеют разные типы?

Если поля для соединения имеют разные типы (например, Число и Строка), нужно привести их к одному типу прямо в запросе. Например:

ПО СТРОКА(Таблица1.Код) = Таблица2.КодСтрокой

Или наоборот:

ПО Таблица1.Код = ЧИСЛО(Таблица2.КодСтрокой)

Если приведение типов невозможно, создайте в таблицах дополнительные реквизиты с одинаковыми типами специально для соединения.

Можно ли соединить более двух таблиц в одном запросе?

Да, в поддерживаются соединения любых вложенностей. Пример запроса с тремя таблицами:

ВЫБРАТЬ

Контрагенты.Наименование КАК Клиент,

Договоры.Номер КАК НомерДоговора,

Реализация.СуммаДокумента КАК СуммаПродажи

ИЗ

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ДоговорыКонтрагентов КАК Договоры

ПО Контрагенты.Ссылка = Договоры.Контрагент

ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация

ПО Договоры.Ссылка = Реализация.Договор

Главное правило: каждое новое соединение должно иметь условие (ПО), иначе получится картезианское произведение.

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

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

  1. Отсутствуют индексы на полях, используемых в условии ПО.
  2. Слишком широкий диапазон дат в условии ГДЕ (например, Дата > '01.01.2000' вместо Дата МЕЖДУ '01.01.2023' И '31.12.2023').
  3. Использование функций над полями в условии (например, ГОД(Документ.Дата) = 2023 вместо Документ.Дата МЕЖДУ ...).
  4. Соединение таблиц с миллионами записей без предварительной фильтрации.

Решения:

  • Добавьте индексы на ключевые поля.
  • Разбейте запрос на подзапросы с предварительной фильтрацией.
  • Используйте временные таблицы для промежуточных результатов.
Как объединить таблицы с разной структурой (разные колонки)?

Если таблицы имеют разные колонки, используйте UNION с явным указанием всех полей. Пример:

ВЫБРАТЬ

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

"" КАК ТипДанных, // Добавляем пустое поле, которого нет в первой таблице

Номенклатура.Артикул