Разработка и Конфигурация · 12 мин
Как объединить таблицы в запросе 1С
Типы соединений в запросах 1С, синтаксис ЛЕВОЕ и ВНУТРЕННЕЕ СОЕДИНЕНИЕ, ОБЪЕДИНИТЬ, условия связи, типичные ошибки и проверка результата.
Объединение таблиц — одна из базовых операций языка запросов 1С. Практически любой отчёт или выборка требует данных сразу из нескольких источников: номенклатуры и остатков, документов и контрагентов, заказов и оплат. Язык запросов 1С предлагает два принципиально разных механизма: соединения (СОЕДИНЕНИЕ), которые «склеивают» строки по горизонтали по условию связи, и объединения (ОБЪЕДИНИТЬ), которые складывают выборки по вертикали.
Ошибки в объединении таблиц — частая причина неверных итогов: задвоенные суммы, пропавшие строки, дубли документов. При этом синтаксис 1С в целом прощает неточности: запрос выполнится без ошибки, просто вернёт неправильные данные. Поэтому важно понимать не только синтаксис, но и логику каждого типа связи и способы проверки результата.
Ниже разобраны все типы соединений, объединение выборок, условия связи, типичные ошибки и способы контроля результата. Примеры приведены на типовых объектах: справочник «Номенклатура», регистр накопления «ТоварыНаСкладах», документ «РеализацияТоваровУслуг».
Какие типы соединений существуют в запросах 1С
Соединение объединяет две таблицы по условию связи: к каждой строке левой таблицы подбираются подходящие строки правой. В языке запросов 1С доступны четыре типа соединений, и выбор типа определяет, что произойдёт со строками, для которых пара не нашлась.
ВНУТРЕННЕЕ СОЕДИНЕНИЕ возвращает только те строки, для которых условие связи выполнено в обеих таблицах. Если у товара нет остатков, он не попадёт в результат. ЛЕВОЕ СОЕДИНЕНИЕ возвращает все строки левой таблицы; если пары нет, поля правой таблицы будут NULL. ПРАВОЕ СОЕДИНЕНИЕ — зеркальный вариант: все строки правой таблицы. ПОЛНОЕ СОЕДИНЕНИЕ возвращает строки обеих таблиц независимо от наличия пары.
На практике чаще всего используется ЛЕВОЕ СОЕДИНЕНИЕ: основная таблица (справочник, документ) берётся целиком, а данные регистров подтягиваются к ней. ПРАВОЕ СОЕДИНЕНИЕ почти всегда можно переписать как ЛЕВОЕ, поменяв таблицы местами, — так запрос читается единообразнее.
Сравнение типов соединений
Только совпавшие строки. Подходит, когда нужны пары, гарантированно существующие в обеих таблицах.
Все строки левой таблицы плюс данные правой. Основной вариант для «справочник + регистр».
Все строки обеих таблиц. Нужно для сопоставления двух независимых наборов, например плана и факта.
Синтаксис соединения и условия связи
Соединение описывается в секции ИЗ: сначала указывается основная таблица с псевдонимом, затем тип соединения, вторая таблица и условие после ключевого слова ПО. Псевдонимы обязательны для читаемости и позволяют обращаться к полям обеих таблиц однозначно.
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
Остатки.КоличествоОстаток КАК Остаток
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Товары.Ссылка = Остатки.Номенклатура
ГДЕ
НЕ Товары.ПометкаУдаления
Условие связи может включать несколько полей через И, а также произвольные выражения и параметры. Например, при соединении с виртуальной таблицей остатков регистра сведений с несколькими измерениями нужно указывать связь по каждому значимому измерению — иначе получите декартово произведение и раздутый результат.
Важно: условия в секции ПО и в секции ГДЕ не эквивалентны для левых соединений. Если отбор по полю правой таблицы поместить в ГДЕ, строки с NULL будут отброшены, и ЛЕВОЕ СОЕДИНЕНИЕ фактически превратится во ВНУТРЕННЕЕ. Отборы по правой таблице, которые не должны «съедать» строки, помещайте в ПО.
Соединение с виртуальными таблицами регистров
Наиболее частый сценарий — соединение справочника или документа с виртуальной таблицей регистра: Остатки, Обороты, ОстаткиИОбороты, СрезПоследних. Виртуальные таблицы принимают параметры (период, отбор), которые задаются в круглых скобках после имени таблицы.
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(
&Период, Склад = &Склад) КАК Остатки
ПО Товары.Ссылка = Остатки.Номенклатура
Отборы по измерениям регистра (склад, организация, контрагент) эффективнее передавать в параметры виртуальной таблицы, а не в условие соединения. Тогда СУБД сначала сформирует компактную выборку и только потом соединит её с основной таблицей, что заметно снижает нагрузку на больших регистрах.
Для регистров сведений с режимом «Периодический» применяйте СрезПоследних или СрезПервых с указанием периода. Типичная ошибка — соединяться напрямую с физической таблицей регистра сведений вместо среза: в результат попадут все исторические записи, и к каждой строке справочника приклеится несколько значений.
Объединение выборок через ОБЪЕДИНИТЬ
Оператор ОБЪЕДИНИТЬ складывает результаты двух и более запросов в одну выборку: строки первого запроса, затем строки второго. Это не соединение — условия связи не требуются, но наборы полей должны совпадать по количеству и быть совместимы по типам. Имена полей берутся из первого запроса.
ВЫБРАТЬ
Поступление.Контрагент КАК Контрагент,
Поступление.СуммаДокумента КАК Сумма
ИЗ
Документ.ПоступлениеТоваровУслуг КАК Поступление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Реализация.Контрагент,
-Реализация.СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
Различие между ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ принципиально. ОБЪЕДИНИТЬ удаляет полностью совпадающие строки (аналог DISTINCT), что требует дополнительной сортировки и замедляет запрос. ОБЪЕДИНИТЬ ВСЕ просто складывает выборки без проверки дублей — это быстрее и чаще всего именно то, что нужно. Используйте «чистое» ОБЪЕДИНИТЬ только когда дубли действительно возможны и недопустимы.
Типичные задачи для ОБЪЕДИНИТЬ ВСЕ: сбор движений из нескольких видов документов, объединение данных нескольких регистров со схожей структурой, формирование списка из основной таблицы и дополняющих записей. После объединения результат можно обернуть во вложенный запрос и сгруппировать.
ВЫБРАТЬ Т.Контрагент, СУММА(Т.Сумма) КАК Итого ИЗ (ВЫБРАТЬ ... ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ...) КАК Т СГРУППИРОВАТЬ ПО Т.КонтрагентНесколько соединений в одном запросе
В одной секции ИЗ допустимо несколько соединений подряд: к основной таблице последовательно присоединяются остатки, цены, данные контрагента. Каждое соединение пишется отдельной строкой со своим условием ПО, условие может ссылаться на любую из уже присоединённых таблиц.
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК ТабЧасть
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Шапка
ПО ТабЧасть.Ссылка = Шапка.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Товары
ПО ТабЧасть.Номенклатура = Товары.Ссылка
Ограничение, о котором стоит помнить: соединение табличных частей разных документов напрямую почти всегда даёт декартово произведение внутри документа — каждая строка одной табличной части перемножается на каждую строку другой. Если нужны итоги по нескольким табличным частям, сначала сгруппируйте каждую во вложенном запросе до уровня шапки и только потом соединяйте.
С ростом числа соединений падает читаемость и производительность. Если соединений больше четырёх-пяти, имеет смысл разбить запрос на пакет с временными таблицами: промежуточные результаты помещаются во временные таблицы (ПОМЕСТИТЬ), а финальный запрос соединяет уже подготовленные компактные выборки.
- 1Определите основную таблицу — ту, все строки которой должны попасть в результат.
- 2Выберите тип соединения: ЛЕВОЕ для необязательных данных, ВНУТРЕННЕЕ для обязательных пар.
- 3Запишите условие связи по ключевым полям в секции ПО, добавьте все значимые измерения.
- 4Перенесите отборы по правой таблице в ПО или в параметры виртуальной таблицы.
- 5Выполните запрос в консоли и сверьте количество строк и итоги с ожидаемыми.
Типичные ошибки и как их избежать
Самая распространённая ошибка — дублирование строк из-за связи «один ко многим» там, где разработчик ожидал «один к одному». Если к номенклатуре присоединить обороты без группировки по периоду, а в регистре несколько записей на товар, каждая строка справочника размножится, и СУММА по числовым полям левой таблицы завысится.
Вторая группа ошибок связана с NULL. При левом соединении поля правой таблицы без пары содержат NULL: сравнение NULL = 0 ложно, арифметика с NULL даёт NULL. Используйте функцию ЕСТЬNULL(Поле, 0) для числовых полей и ЕСТЬNULL(Поле, ЗНАЧЕНИЕ(...)) для ссылочных, чтобы результат был предсказуемым.
Третья ошибка — соединение по неуникальным текстовым полям (наименование, артикул) вместо ссылки. Наименования могут совпадать, артикулы — дублироваться у разных поставщиков. Связь всегда строится по ссылке или по полному набору измерений регистра.
Проверка результата и отладка
Проверять запрос удобнее всего в консоли запросов на копии базы или на тестовых данных. Базовый контроль — сравнение количества строк: выполните запрос только по основной таблице, затем с соединением. Для ЛЕВОГО СОЕДИНЕНИЯ при связи «один к одному» количество строк не должно измениться; рост числа строк — прямой признак дублей.
Для числовых итогов сверяйте контрольные суммы: сумма по документам до и после соединения должна совпадать. Полезный приём — временно добавить в выборку КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) и общее КОЛИЧЕСТВО строк: расхождение покажет размножение.
Если запрос работает медленно, проверьте, не соединяются ли виртуальные таблицы без параметров отбора и нет ли соединений по вычисляемым выражениям, которые блокируют использование индексов. План запроса можно посмотреть через технологический журнал или средства СУБД.
Как проверить результат
Для ЛЕВОГО СОЕДИНЕНИЯ совпадает с числом строк основной таблицы
Строк стало больше — есть дубли от связи «один ко многим»
Итог равен итогу по исходной таблице
Итог завышен — строки размножились
NULL обработаны через ЕСТЬNULL
Пустые значения ломают сравнения и арифметику
Часто задаваемые вопросы
Чем ЛЕВОЕ СОЕДИНЕНИЕ отличается от ВНУТРЕННЕГО на практике?
ЛЕВОЕ сохраняет все строки основной таблицы, даже если пары нет — поля второй таблицы будут NULL. ВНУТРЕННЕЕ отбрасывает такие строки. Если вы строите список товаров с остатками и хотите видеть товары без остатков, нужно ЛЕВОЕ; если интересуют только товары с наличием — ВНУТРЕННЕЕ.
Когда использовать ОБЪЕДИНИТЬ, а когда СОЕДИНЕНИЕ?
СОЕДИНЕНИЕ дополняет строки новыми колонками по условию связи — например, к товару добавляется его остаток. ОБЪЕДИНИТЬ складывает однотипные строки из разных источников в одну колонку — например, движения поступлений и реализаций в единый список операций.
Почему после соединения задвоились суммы?
Причина почти всегда в связи «один ко многим»: к одной строке основной таблицы подошло несколько строк присоединяемой. Проверьте, хватает ли полей в условии ПО, и при необходимости предварительно сгруппируйте правую таблицу во вложенном запросе до нужного уровня детализации.
Можно ли соединять более двух таблиц в одном запросе?
Да, количество соединений не ограничено: каждая следующая таблица присоединяется отдельной строкой со своим условием ПО. При большом числе источников удобнее и быстрее использовать пакетный запрос с временными таблицами через ПОМЕСТИТЬ.
Что быстрее: ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ?
ОБЪЕДИНИТЬ ВСЕ быстрее, потому что не выполняет устранение дублей. Вариант без ВСЕ нужен только когда дублирующиеся строки реально возможны и недопустимы в результате — в остальных случаях используйте ОБЪЕДИНИТЬ ВСЕ.
Как подставить 0 вместо NULL после левого соединения?
Используйте функцию ЕСТЬNULL: например, ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток. Для ссылочных полей вторым аргументом передают пустую ссылку нужного типа через ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка).
Что важно запомнить
Для связи таблиц по условию используйте СОЕДИНЕНИЕ (чаще всего ЛЕВОЕ), отборы по правой таблице держите в секции ПО, для сложения однотипных выборок — ОБЪЕДИНИТЬ ВСЕ. Контролируйте дубли по количеству строк и контрольным суммам, а NULL обрабатывайте через ЕСТЬNULL.