Работа с данными в 1С:Предприятие часто требует объединения информации из нескольких таблиц — будь то справочники, документы или регистры. Без правильной связи таблиц вы получите либо неполные данные, либо ошибки выполнения. Эта статья поможет разобраться, как грамотно связывать таблицы в 1С 8.3 и 1С 8.2, используя разные типы соединений, виртуальные таблицы и параметры запросов.

Мы рассмотрим не только базовые операции типа INNER JOIN, но и нюансы работы с LEFT JOIN, FULL JOIN, а также покажем, как избежать типичных ошибок при связывании больших объемов данных. Особое внимание уделим оптимизации запросов с соединениями — это критично для производительности в крупных базах.

1. Основные типы соединений таблиц в 1С

В языке запросов поддерживаются все стандартные типы соединений, аналогичные SQL. Их выбор зависит от задачи: нужно ли получить только совпадающие записи, все записи из одной таблицы с дополнением из другой, или же полный набор данных из обеих таблиц.

Рассмотрим ключевые варианты:

  • 🔹 ВНУТРЕННЕЕ (INNER JOIN) — возвращает только строки, где есть совпадения в обеих таблицах. Самый частый и быстрый тип соединения.
  • 🔸 ЛЕВОЕ (LEFT JOIN) — включает все записи из левой таблицы и соответствующие им данные из правой. Если совпадений нет, поля правой таблицы заполняются NULL.
  • 🔶 ПРАВОЕ (RIGHT JOIN) — аналогично левому, но приоритет отдается правой таблице. В используется редко, так как его всегда можно заменить LEFT JOIN с перестановкой таблиц.
  • 🟣 ПОЛНОЕ (FULL JOIN) — возвращает все строки из обеих таблиц, дополняя отсутствующие данные NULL. В 1С 8.3 реализовано через комбинацию LEFT JOIN и UNION.

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

ВЫБРАТЬ

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

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

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

ИЗ

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

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

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

⚠️ Внимание: В 1С 8.2 синтаксис соединений строже — нельзя использовать псевдонимы таблиц в условии ПО без явного указания. Например, вместо ПО Ссылка = Номенклатура нужно писать ПО Таблица1.Ссылка = Таблица2.Ссылка.

2. Как связать таблицы через виртуальные таблицы

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

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

ВЫБРАТЬ

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

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

ИЗ

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

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

&ДатаОкончания,

Склад = &Склад

) КАК ОстаткиТоваров

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

Обратите внимание на параметры виртуальной таблицы &ДатаОкончания и &Склад — они обязательны для корректной выборки. Без указания склада или даты запрос либо вернет ошибку, либо будет выполняться крайне долго.

Указать все обязательные параметры (дата, измерения)

Проверить права доступа к регистру

Ограничить период выборки для ускорения запроса

Использовать индексированные поля для соединения-->

⚠️ Внимание: Виртуальные таблицы оборотов (например, .Обороты) могут существенно нагружать сервер при больших периодах. Всегда ограничивайте диапазон дат параметром &НачалоПериода и &КонецПериода.

3. Связь по нескольким полям: составные ключи

Иногда для точного связывания таблиц недостаточно одного поля. Например, в регистре ВзаиморасчетыСКонтрагентами уникальная запись определяется комбинацией Контрагент + Договор + Валюта. В таких случаях используют составные ключи.

Синтаксис соединения по нескольким полям:

ВЫБРАТЬ

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

РегистрБухгалтерии.Взаиморасчеты.Сумма КАК СуммаДолга

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Взаиморасчеты КАК РегистрБухгалтерии.Взаиморасчеты

ПО (Документ.ПоступлениеТоваров.Контрагент = РегистрБухгалтерии.Взаиморасчеты.Контрагент)

И (Документ.ПоступлениеТоваров.Договор = РегистрБухгалтерии.Взаиморасчеты.Договор)

И (Документ.ПоступлениеТоваров.ВалютаДокумента = РегистрБухгалтерии.Взаиморасчеты.Валюта)

Ключевые моменты:

  • 📌 Условия в скобках ПО (поле1 = поле1) И (поле2 = поле2) обязательно группировать.
  • 📌 Порядок полей в условии влияет на производительность — сначала указывайте поля с индексами.
  • 📌 Для регистров с большим количеством измерений составные ключи могут замедлить запрос. В таких случаях используйте временные таблицы.

Внутреннее (INNER JOIN)

Левое (LEFT JOIN)

Полное (FULL JOIN)

Не использую соединения-->

4. Связь таблиц с использованием параметров

Параметры в запросах позволяют динамически подставлять значения при выполнении. Это особенно удобно для связывания таблиц, где условия соединения зависят от пользовательского ввода или контекста (например, текущий склад, период, организация).

Пример запроса с параметрами для связи документа ЗаказПокупателя и регистра ЦеныНоменклатуры:

ВЫБРАТЬ

ЗаказПокупателя.Номенклатура КАК Номенклатура,

ЗаказПокупателя.Количество КАК Количество,

ЦеныНоменклатуры.Цена КАК Цена

ИЗ

Документ.ЗаказПокупателя КАК ЗаказПокупателя

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаЦены) КАК ЦеныНоменклатуры

ПО (ЗаказПокупателя.Номенклатура = ЦеныНоменклатуры.Номенклатура)

И (ЦеныНоменклатуры.ТипЦен = &ТипЦен)

И (ЦеныНоменклатуры.Организация = &Организация)

Важно:

  • 🔧 Параметры обозначаются знаком & (например, &ДатаЦены).
  • 🔧 Для дат используйте формат ГГГГММДД (например, 20231231 для 31.12.2023).
  • 🔧 Если параметр не задан, запрос вернет ошибку. Всегда проверяйте передачу параметров перед выполнением.
💡

Для отладки запросов с параметрами используйте конструктор запросов в конфигураторе. Он покажет, какие параметры ожидает запрос, и позволит протестировать их значения без написания кода.

5. Типичные ошибки при связывании таблиц и как их избежать

Даже опытные разработчики сталкиваются с ошибками при работе со связями таблиц. Рассмотрим наиболее распространенные проблемы и способы их решения.

Ошибка Причина Решение
Поле не найдено (Field not found) Опечатка в имени поля или таблицы, либо поле не существует в текущей версии конфигурации. Проверьте имена полей в метаданных (Ctrl+Shift+M в конфигураторе). Используйте автоподстановку в конструкторе запросов.
Недопустимое соединение таблиц Попытка связать таблицы по полям разных типов (например, Ссылка и Строка). Приведите поля к одному типу с помощью ВЫРАЗИТЬ или ЗНАЧЕНИЕ.
Запрос выполняется слишком долго Отсутствуют индексы на полях соединения или запрос извлекает слишком много данных. Добавьте индексы в конфигураторе (Индексировать = Истина). Ограничьте выборку условием ГДЕ.
Дублирование строк в результате Связь "многие ко многим" без группировки или неправильное использование FULL JOIN. Используйте РАЗЛИЧНЫЕ или ГРУППИРОВКА ПО для устранения дублей.

Одна из самых коварных ошибок — неявное преобразование типов. Например, если вы связываете поле типа Число с полем Строка, может автоматически преобразовать данные, но это приведет к непредсказуемым результатам. Всегда следите за типами полей!

Что делать, если запрос с соединением возвращает пустой результат?

1. Проверьте, есть ли данные в исходных таблицах (выполните отдельные запросы к каждой).

2. Убедитесь, что условия соединения (ПО) корректны — возможно, нет совпадающих записей.

3. Проверьте права доступа: у пользователя могут быть ограничения на чтение одной из таблиц.

4. Если используете виртуальные таблицы, проверьте передачу параметров (дата, измерения).

5. Включите трассировку SQL (в конфигураторе: Сервис → Параметры → Трассировка SQL) для анализа выполняемого запроса.

6. Оптимизация запросов со связями таблиц

Производительность запросов с соединениями критична для крупных баз данных. Неоптимизированный запрос может "подвесить" систему на несколько минут. Вот ключевые приемы оптимизации:

  • Индексируйте поля соединения — в конфигураторе отметьте Индексировать = Истина для полей, используемых в ПО.
  • Ограничивайте выборку — всегда добавляйте ГДЕ с фильтрами по дате, организации или другим критериям.
  • Используйте временные таблицы — для сложных соединений сначала сохраните промежуточные данные во временную таблицу, а затем связывайте ее с основными.
  • Избегайте FULL JOIN — этот тип соединения наиболее ресурсоемкий. Замените его комбинацией LEFT JOIN и RIGHT JOIN с UNION.

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

// Сначала сохраняем данные в временную таблицу

ВЫБРАТЬ РАЗЛИЧНЫЕ

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

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

ИЗ

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

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

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

ГДЕ

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

ИНДЕКСИРОВАТЬ ПО Номенклатура;

// Затем связываем с основной таблицей

ВЫБРАТЬ

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

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

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&КонецПериода) КАК Остатки

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

⚠️ Внимание: Временные таблицы в хранятся в памяти сервера. Если данных слишком много, это может привести к переполнению памяти. Всегда ограничивайте объем данных, помещаемых во временные таблицы.
💡

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

7. Связь таблиц в отчетах и системах компоновки данных

В многие отчеты строятся на основе системы компоновки данных (СКД). Здесь связь таблиц настраивается визуально, без написания кода. Однако есть нюансы:

  • 📊 В настройках СКД связь между наборами данных устанавливается через параметр Связь по полям.
  • 📊 Для связи доступны только поля, выбранные в наборах данных. Если нужно связать по полю, которого нет в выборке, добавьте его в набор.
  • 📊 В СКД можно использовать только INNER JOIN и LEFT JOIN. Для других типов соединений потребуется доработка схемы компоновки.

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

  1. Откройте схему компоновки данных.
  2. Перейдите на закладку Наборы данных.
  3. Выделите два набора, которые нужно связать.
  4. В панели свойств найдите параметр Связь по полям и укажите поля для соединения (например, Номенклатура.Ссылка).
  5. Выберите тип соединения: Внутреннее или Левое.

Если в отчете не хватает гибкости СКД, можно создать собственный запрос с нужными соединениями и подключить его как набор данных.

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

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

Нет, в стандартном языке запросов нельзя напрямую связывать таблицы из разных баз. Для этого нужно:

  1. Использовать распределенные информационные базы (РИБ).
  2. Настроить обмен данными через XML или веб-сервисы.
  3. Применить внешние источники данных (доступно в 1С:Предприятие 8.3.14+).

В последнем случае можно подключить внешнюю базу как источник и связать ее таблицы с локальными.

Как связать таблицу значений с таблицей базы данных?

Таблицу значений (ТаблицаЗначений) нельзя напрямую связать с таблицей базы в запросе. Решения:

  • 🔄 Временная таблица: Загрузите данные из таблицы значений во временную таблицу, затем свяжите ее с основными данными.
  • 🔄 Подзапрос: Используйте конструкцию ВЫБРАТЬ ... ГДЕ Поле В (&СписокЗначений).
  • 🔄 Обход в цикле: Для небольших объемов данных можно в цикле обращаться к базе для каждой строки таблицы значений (не рекомендуется для больших массивов).

Пример с временной таблицей:

// Загружаем таблицу значений во временную таблицу

ВТСписокНоменклатуры = Новый ВременнаяТаблица;

ВТСписокНоменклатуры.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

Для Каждого Строка Из ТаблицаЗначений Цикл

ВТСписокНоменклатуры.Добавить();

ВТСписокНоменклатуры.Номенклатура = Строка.Номенклатура;

КонецЦикла;

// Связываем с данными базы

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

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

"ВЫБРАТЬ

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

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

ИЗ

ВТСписокНоменклатуры КАК ВТСписокНоменклатуры

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

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

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

Запрос.ВременныеТаблицы.Добавить(ВТСписокНоменклатуры);

Почему при связывании таблиц возвращаются дубли строк?

Дубли возникают в двух случаях:

  1. Связь "многие ко многим": Например, в таблице Документ.Реализация одна номенклатура может встречаться несколько раз, и в таблице РегистрСведений.Цены для этой номенклатуры также несколько записей. В результате получается декартово произведение.
  2. Отсутствие уникального ключа: Если связь идет не по уникальному полю (например, по наименованию вместо ссылки), могут совпадать несколько записей.

Решения:

  • 🔹 Используйте РАЗЛИЧНЫЕ или ГРУППИРОВКА ПО.
  • 🔹 Добавьте в условие соединения дополнительные поля для уточнения (например, ПО Номенклатура = Номенклатура И Организация = Организация).
  • 🔹 Проверьте структуру данных — возможно, нужно нормализовать таблицы.
Как связать таблицы, если поля для соединения имеют разные типы?

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

  • ВЫРАЗИТЬ(Поле1 КАК Тип) — явно преобразует поле к указанному типу.
  • ЗНАЧЕНИЕ(Поле1) — преобразует значение к типу по умолчанию.
  • СТРОКА(Поле1) или ЧИСЛО(Поле1) — преобразует к строковому или числовому типу.

Пример:

ВЫБРАТЬ

Таблица1.Код КАК Код,

Таблица2.Наименование КАК Наименование

ИЗ

Документ.Таблица1 КАК Таблица1

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Таблица2 КАК Таблица2

ПО ВЫРАЗИТЬ(Таблица1.Код КАК Строка) = Таблица2.КодСтроковый

Осторожно: неявное преобразование типов может работать непредсказуемо. Например, сравнение числа 123 и строки "000123" вернет Ложь, если не привести их к одному типу.

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

Да, в можно связывать любое количество таблиц в одном запросе. Синтаксис аналогичен SQL:

ВЫБРАТЬ

Таблица1.Поле1,

Таблица2.Поле2,

Таблица3.Поле3

ИЗ

Таблица1 КАК Таблица1

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица2 КАК Таблица2

ПО Таблица1.Ключ = Таблица2.Ключ

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица3 КАК Таблица3

ПО Таблица2.Ссылка = Таблица3.Ссылка

Рекомендации:

  • 📌 Связывайте таблицы последовательно: сначала две, затем результат с третьей и т.д.
  • 📌 Для более чем 3-4 таблиц рассмотрите возможность разбиения запроса на несколько этапов с использованием временных таблиц.
  • 📌 Следите за производительностью — каждое дополнительное соединение увеличивает время выполнения.