Работа с данными в 1С:Предприятие часто требует объединения информации из нескольких таблиц — будь то справочники, документы или регистры. Без правильного подхода даже простой запрос может превратиться в медленную и нечитаемую конструкцию. Эта статья поможет разобраться, как грамотно объединять таблицы в запросах 1С 8.3 и 1С 8.2, избегая типичных ошибок.
Мы рассмотрим все основные способы объединения: от элементарного ОБЪЕДИНИТЬ до сложных соединений с условиями. Особое внимание уделим разнице между ЛЕВЫМ и ПРАВЫМ соединением — это критично для корректной выборки данных. В конце вас ждут практические примеры с пояснениями и FAQ по частым проблемам.
1. Базовые принципы объединения таблиц в 1С
Перед тем как перейти к синтаксису, важно понять ключевые концепции. В 1С:Предприятие объединение таблиц реализуется через:
- 🔹 Вертикальное объединение (
ОБЪЕДИНИТЬ) — когда строки добавляются одна под другой (аналог SQLUNION) - 🔹 Горизонтальное соединение (
СОЕДИНИТЬ,ЛЕВОЕ СОЕДИНЕНИЕ) — когда таблицы объединяются по общим полям (аналог SQLJOIN) - 🔹 Вложенные запросы — когда результат одного запроса используется в другом
Основное правило: всегда проверяйте типы данных в объединяемых полях. Например, если в одной таблице поле Дата имеет тип Дата, а в другой — Строка, запрос либо не выполнится, либо вернёт некорректные данные. Для диагностики используйте конструкцию ВЫРАЗИТЬ().
⚠️ Внимание: В платформе 1СОБЪЕДИНИТЬпо умолчанию удаляет дублирующиеся строки. Чтобы сохранить все записи, используйтеОБЪЕДИНИТЬ ВСЕ.
2. Вертикальное объединение: ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ
Этот метод применяется, когда нужно объединить результаты двух запросов с одинаковой структурой полей. Например, выбрать все документы РеализацияТоваровУслуг и ВозвратТоваровОтПокупателя в одном списке.
Синтаксис:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка КАК Документ,
РеализацияТоваровУслуг.Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ВозвратТоваровОтПокупателя.Ссылка КАК Документ,
ВозвратТоваровОтПокупателя.Дата
ИЗ
Документ.ВозвратТоваровОтПокупателя КАК ВозвратТоваровОтПокупателя
Ключевые моменты:
- 📌 Количество и типы полей в обоих запросах должны совпадать
- 📌 Порядок полей важен: первое поле первого запроса соответствует первому полю второго
- 📌
ОБЪЕДИНИТЬ ВСЕсохраняет дубли,ОБЪЕДИНИТЬ— удаляет
3. Горизонтальное соединение: ВНУТРЕННЕЕ, ЛЕВОЕ, ПРАВОЕ
Это основной способ связать таблицы по общим полям. В 1С доступны три типа соединений:
| Тип соединения | Синтаксис | Поведение | Аналог в SQL |
|---|---|---|---|
| Внутреннее | СОЕДИНИТЬ |
Только совпадающие строки | INNER JOIN |
| Левое | ЛЕВОЕ СОЕДИНЕНИЕ |
Все строки левой таблицы + совпадающие правой | LEFT JOIN |
| Правое | ПРАВОЕ СОЕДИНЕНИЕ |
Все строки правой таблицы + совпадающие левой | RIGHT JOIN |
| Полное | ПОЛНОЕ СОЕДИНЕНИЕ |
Все строки обеих таблиц | FULL JOIN |
Пример с ЛЕВЫМ СОЕДИНЕНИЕМ (самый распространённый случай):
ВЫБРАТЬ
Справочник.Номенклатура.Наименование,
РегистрНакопления.ОстаткиТоваров.КоличествоОстаток
ИЗ
Справочник.Номенклатура КАК Справочник.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров КАК РегистрНакопления.ОстаткиТоваров
ПО Справочник.Номенклатура.Ссылка = РегистрНакопления.ОстаткиТоваров.Номенклатура
Если в результате ЛЕВОГО СОЕДИНЕНИЯ вы получаете NULL в полях правой таблицы, это означает, что для строки из левой таблицы не найдено соответствий в правой. Это нормальное поведение, а не ошибка!
4. Соединение с условиями: WHERE vs ON
Многие разработчики путают, где указывать условия соединения: в секции ПО (аналог ON в SQL) или в ГДЕ (аналог WHERE). Правило простое:
- 🔧
ПО— условия соединения таблиц (определяют, как таблицы связываются) - 🔧
ГДЕ— условия фильтрации результата (отсеивают строки после соединения)
Пример с обоими типами условий:
ВЫБРАТЬ
Документ.ЗаказПокупателя.Номер,
Документ.ЗаказПокупателя.Дата,
Справочник.Контрагенты.Наименование КАК Покупатель
ИЗ
Документ.ЗаказПокупателя КАК Документ.ЗаказПокупателя
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Справочник.Контрагенты
ПО Документ.ЗаказПокупателя.Контрагент = Справочник.Контрагенты.Ссылка
ГДЕ
Документ.ЗаказПокупателя.Дата >= &НачалоПериода
И Документ.ЗаказПокупателя.Дата <= &КонецПериода
⚠️ Внимание: Условия в ПО влияют на производительность! Если вы соединяете таблицы по несвязанным полям (например, по дате вместо ссылки), запрос будет выполняться дольше в разы.
5. Практические примеры объединения таблиц
Разберём реальные задачи, с которыми сталкиваются разработчики 1С.
Пример 1: Объединение справочников и документов
Задача: получить список всех номенклатурных позиций с указанием остатков и последней цены продажи.
ВЫБРАТЬ
Номенклатура.Наименование КАК Товар,
Остатки.КоличествоОстаток КАК Остаток,
MAX(Продажи.Цена) КАК ПоследняяЦена
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Продажи
ПО Номенклатура.Ссылка = Продажи.Номенклатура
СГРУППИРОВАТЬ ПО
Номенклатура.Наименование,
Остатки.КоличествоОстаток
Пример 2: Объединение нескольких регистров
Задача: получить данные о движении товаров из регистров ОстаткиТоваров и ПродажиТоваров.
ВЫБРАТЬ
ДвиженияОстатков.Номенклатура КАК Товар,
ДвиженияОстатков.Количество КАК ИзменениеОстатка,
ДвиженияПродаж.Сумма КАК Выручка
ИЗ
РегистрНакопления.ОстаткиТоваров.Обороты(&НачалоПериода, &КонецПериода) КАК ДвиженияОстатков
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ПродажиТоваров.Обороты(&НачалоПериода, &КонецПериода) КАК ДвиженияПродаж
ПО ДвиженияОстатков.Номенклатура = ДвиженияПродаж.Номенклатура
Совпадают ли типы объединяемых полей?|Указаны ли все необходимые условия в ПО?|Нет ли лишних ЛЕВЫХ СОЕДИНЕНИЙ, которые можно заменить на ВНУТРЕННИЕ?|Проверены ли права доступа к таблицам?-->
6. Оптимизация запросов с объединением
Объединение таблиц может значительно замедлить выполнение запроса. Вот ключевые правила оптимизации:
- 🚀 Используйте индексированные поля для соединения (например,
Ссылка, а неНаименование) - 🚀 Заменяйте
ЛЕВОЕ СОЕДИНЕНИЕнаВНУТРЕННЕЕ, если не нужны строки без соответствий - 🚀 Ограничивайте выборку по датам в виртуальных таблицах регистров
- 🚀 Избегайте соединения более 3-4 таблиц в одном запросе — разбивайте на подзапросы
Пример оптимизированного запроса:
ВЫБРАТЬ
Заказы.Номер,
Заказы.Дата,
Контрагенты.Наименование КАК Покупатель,
Товары.Количество,
Товары.Цена
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя.Товары КАК Товары
ПО Заказы.Ссылка = Товары.Ссылка
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
ПО Заказы.Контрагент = Контрагенты.Ссылка
ГДЕ
Заказы.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
И Товары.Номенклатура = &ВыбраннаяНоменклатура
Самая частая ошибка — соединение по неиндексированным полям (например, по наименованию вместо ссылки). Это увеличивает время выполнения запроса в 10-100 раз!
7. Типичные ошибки и их решение
Даже опытные разработчики сталкиваются с проблемами при объединении таблиц. Разберём самые распространённые:
⚠️ Внимание: Если запрос возвращает пустой результат, проверьте:1) Совпадают ли типы данных в объединяемых полях (используйте
ВЫРАЗИТЬ()при необходимости)2) Есть ли вообще данные в таблицах за указанный период
3) Правильно ли указаны параметры (&Параметр)
Ошибка 1: "Поле не найдено"
Причина: опечатка в имени поля или таблицы. Решение — используйте конструктор запросов в конфигураторе для проверки синтаксиса.
Ошибка 2: Запрос выполняется слишком долго
Причины и решения:
- 🐢 Слишком много
ЛЕВЫХ СОЕДИНЕНИЙ→ замените наВНУТРЕННИЕ, где возможно- 🐢 Соединение по неиндексированным полям → добавьте индексы или используйте ссылки
- 🐢 Отсутствует фильтрация по датам → ограничьте период в виртуальных таблицах
Ошибка 3: Дублирующиеся строки в результате
Причина: неверное использование
ОБЪЕДИНИТЬвместоОБЪЕДИНИТЬ ВСЕили отсутствиеДИСТИНКТ. Решение — добавьтеРАЗЛИЧНЫЕв начало запроса.8. Альтернативные подходы: вложенные запросы и временные таблицы
Иногда вместо соединения таблиц удобнее использовать:
- 🔄 Вложенные запросы (подзапросы в секции
ГДЕилиВЫБРАТЬ)- 📝 Временные таблицы (для сложных многоэтапных выборок)
Пример с вложенным запросом:
ВЫБРАТЬТовары.Номенклатура КАК Товар,
Товары.Количество,
(
ВЫБРАТЬ МАКСИМУМ(Цена)
ИЗ Документ.РеализацияТоваровУслуг.Товары
ГДЕ Номенклатура = Товары.Номенклатура
) КАК ПоследняяЦена
ИЗ
Документ.ПоступлениеТоваров.Товары КАК Товары
Пример с временной таблицей:
// Создаём временную таблицу с остаткамиВЫБРАТЬ
Остатки.Номенклатура КАК Товар,
Остатки.КоличествоОстаток КАК Остаток
ПОМЕСТИТЬ втОстатки
ИЗ
РегистрНакопления.ОстаткиТоваров КАК Остатки
// Используем её в основном запросе
ВЫБРАТЬ
Заказы.Номер,
Заказы.Дата,
втОстатки.Остаток
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ЛЕВОЕ СОЕДИНЕНИЕ втОстатки КАК втОстатки
ПО Заказы.Товар = втОстатки.Товар
Когда использовать временные таблицы?
Временные таблицы оправданы, когда:
1. Нужно многократно обращаться к одним и тем же данным в сложном запросе
2. Работаете с большими объёмами данных (более 100 000 строк)
3. Нужно разбить сложный запрос на логические этапы
Но помните: каждая временная таблица увеличивает потребление памяти!
FAQ: Ответы на частые вопросы
Можно ли в 1С сделать FULL OUTER JOIN?
В синтаксисе 1С нет прямого аналога
FULL OUTER JOIN, но его можно эмулировать черезОБЪЕДИНИТЬ:ВЫБРАТЬ ... ЛЕВОЕ СОЕДИНЕНИЕ ...ОБЪЕДИНИТЬ
ВЫБРАТЬ ... ПРАВОЕ СОЕДИНЕНИЕ ...
Или через три запроса с
ЛЕВЫМ,ПРАВЫМиВНУТРЕННИМсоединениями.Почему при ЛЕВОМ СОЕДИНЕНИИ не показываются все строки?
Наиболее вероятные причины:
- В условии
ГДЕесть фильтр по полю из правой таблицы (перенесите его вПО)- Поле соединения в правой таблице содержит
NULL(проверьте данные)- Используется
ВНУТРЕННЕЕ СОЕДИНЕНИЕвместоЛЕВОГОКак объединить таблицы с разной структурой?
Используйте
ОБЪЕДИНИТЬс явным указанием полей:ВЫБРАТЬNULL КАК Поле1,
Таблица1.ПолеА КАК Поле2
ИЗ Таблица1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Таблица2.ПолеБ КАК Поле1,
NULL КАК Поле2
ИЗ Таблица2
Для несовпадающих полей используйте
NULLили функции типаВЫРАЗИТЬ().Как ускорить запрос с множеством соединений?
Попробуйте эти методы:
- Разбейте запрос на несколько с использованием временных таблиц
- Перенесите фильтры из
ГДЕв условия соединенияПО- Используйте
ИНДЕКСИРОВАТЬ ПОдля больших таблиц- Замените
ЛЕВОЕ СОЕДИНЕНИЕнаВНУТРЕННЕЕ, если не нужны пустые строкиМожно ли соединять таблицы из разных баз данных?
Прямого механизма нет, но есть обходные пути:
- Использовать распределённые информационные базы (РИБ)
- Настроить обмен данными через XML/JSON и загружать данные во временные таблицы
- Для 1С:ERP или 1С:УТ использовать сервис интеграции
В простых случаях можно экспортировать данные в Excel и обрабатывать там.