Объединение таблиц в 1С 8.3: запрос, код и СКД
Содержание
Чтобы сложить строки одной таблицы под строками другой в запросе 1С 8.3, между двумя выборками ставят оператор ОБЪЕДИНИТЬ ВСЕ. Если нужно убрать полные дубли строк — тот же оператор, но без ВСЕ: просто ОБЪЕДИНИТЬ. В коде две таблицы значений объединяют циклом: проходят вторую и добавляют её строки в первую.
Сразу разведём два похожих слова. Объединение ставит строки друг под друга «по вертикали» — у таблиц должен совпадать набор колонок. Соединение (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ) склеивает таблицы «по горизонтали» по условию связи — получается больше колонок. Если вам надо дотянуть к строкам первой таблицы поля из второй по ключу — это соединение, а не объединение. Здесь разбираем именно объединение.
Способов несколько, и выбор зависит от того, где лежат данные. Данные в базе — пишите запрос. Данные уже собраны в ТаблицаЗначений в памяти — сливайте кодом. Промежуточные выборки в сложном запросе — через временные таблицы. Вывод в отчёт — через набор данных «Объединение» в СКД.
Оператор ОБЪЕДИНИТЬ ВСЕ в запросе
Базовый инструмент — конструкция ОБЪЕДИНИТЬ ВСЕ между двумя запросами. Результаты обеих выборок складываются в одну таблицу.
ВЫБРАТЬ
Номенклатура.Наименование КАК Наименование,
Номенклатура.Код КАК Код
ИЗ
Справочник.Номенклатура КАК Номенклатура
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Услуги.Наименование,
Услуги.Код
ИЗ
Справочник.Услуги КАК Услуги
Несколько правил, без которых запрос не выполнится или вернёт не то:
- 🔢 Число колонок в обеих выборках одинаковое. Иначе платформа выдаст ошибку о несовпадении количества полей.
- 🏷 Имена колонок берутся из первого запроса. Псевдонимы (
КАК ...) во второй и следующих выборках платформа игнорирует — порядок полей важнее названий. Поэтому второй запрос можно писать без псевдонимов. - 📑 Поля сопоставляются по порядку, а не по названию. Если в первой выборке вторая колонка — код, то и во второй выборке на этом месте должен стоять код, а не что-то другое.
- 🔀 Типы колонок складываются. Если в одной выборке колонка строковая, в другой — числовая, итоговая колонка получит составной тип. Это не ошибка, но на составных типах потом сложнее строить условия.
Так объединяют не только два, а сколько угодно запросов подряд — ограничения на число частей нет, ставьте ОБЪЕДИНИТЬ ВСЕ между каждой парой.
Ещё два момента, которые относятся ко всему объединённому результату, а не к отдельной выборке:
УПОРЯДОЧИТЬ ПОпишется один раз в самом конце — сортировка применится ко всем строкам сразу. Внутри отдельной части она невозможна.ВЫБРАТЬ ПЕРВЫЕ Nограничивает строки конкретной выборки, а не весь итог. Чтобы ограничить объединённый результат, оберните его во вложенный запрос иПЕРВЫЕпоставьте снаружи.
В конструкторе запроса объединение собирается без ручного набора текста: на закладке Объединения/Псевдонимы добавляется новый запрос, и платформа сама следит за соответствием колонок.
Объединение с удалением дубликатов
Теперь про разницу, из-за которой ломается половина отчётов. ОБЪЕДИНИТЬ ВСЕ оставляет все строки как есть. ОБЪЕДИНИТЬ (без ВСЕ) дополнительно убирает полностью совпадающие строки — те, у которых равны значения во всех колонках.
ВЫБРАТЬ
Контрагенты.ИНН КАК ИНН
ИЗ
Справочник.Контрагенты КАК Контрагенты
ОБЪЕДИНИТЬ // без ВСЕ — повторяющиеся ИНН схлопнутся в один
ВЫБРАТЬ
Партнеры.ИНН
ИЗ
Справочник.Партнеры КАК Партнеры
Проверка на уникальность стоит ресурсов: платформа сортирует весь результат и сравнивает строки. На больших выборках это заметно медленнее. Поэтому правило простое:
- дубли физически невозможны или вам всё равно →
ОБЪЕДИНИТЬ ВСЕ(быстрее); - дубли нужно убрать →
ОБЪЕДИНИТЬбезВСЕ.
Важный нюанс: дублем считается совпадение по всем колонкам сразу. Если во второй колонке у двух строк разные даты, а ИНН одинаковый, ОБЪЕДИНИТЬ их не схлопнет — строки считаются разными. Чтобы убирать дубли по части колонок, оставьте в выборке только нужные поля или сгруппируйте результат через СГРУППИРОВАТЬ ПО.
Программное объединение таблиц значений
Когда обе таблицы уже собраны в памяти как ТаблицаЗначений, запрос не нужен. Проходим вторую таблицу и переносим строки в первую:
Для Каждого СтрокаИсточника Из ТаблицаВторая Цикл
НоваяСтрока = ТаблицаПервая.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника);
КонецЦикла;
ЗаполнитьЗначенияСвойств переносит значения колонок с совпадающими именами. Колонки, которые есть только в источнике, просто не попадут в приёмник; колонки, которых в источнике нет, останутся пустыми. Это удобно: таблицы не обязаны совпадать колонка в колонку, лишь бы совпадали имена нужных полей.
Если во второй таблице есть колонки, которых нет в первой, а перенести их надо — добавьте колонки в приёмник заранее:
Для Каждого Колонка Из ТаблицаВторая.Колонки Цикл
Если ТаблицаПервая.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
ТаблицаПервая.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения);
КонецЕсли;
КонецЦикла;
После такого объединения уберите дубли методом Свернуть. Первым параметром — колонки группировки, вторым — колонки с суммированием:
// схлопнуть по номенклатуре, просуммировав количество и сумму
ТаблицаПервая.Свернуть("Номенклатура", "Количество, Сумма");
Свернуть меняет саму таблицу и удаляет колонки, не попавшие ни в группировку, ни в суммирование. Если исходные строки ещё нужны — сделайте копию методом Скопировать и сворачивайте копию.
Временные таблицы для сложных объединений
Когда объединять нужно не справочники напрямую, а результаты промежуточных вычислений, в дело идут временные таблицы. Они живут в рамках пакетного запроса и позволяют разложить логику на шаги.
Каждую часть помещаем в свою временную таблицу через ПОМЕСТИТЬ, а в финальном запросе объединяем:
ВЫБРАТЬ
Поступление.Номенклатура КАК Номенклатура,
Поступление.Количество КАК Количество
ПОМЕСТИТЬ ВТ_Движения
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК Поступление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Реализация.Номенклатура,
-Реализация.Количество // расход со знаком минус
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Реализация
;
////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Движения.Номенклатура КАК Номенклатура,
СУММА(ВТ_Движения.Количество) КАК Остаток
ИЗ
ВТ_Движения КАК ВТ_Движения
СГРУППИРОВАТЬ ПО
ВТ_Движения.Номенклатура
В коде такой пакет выполняется через менеджер временных таблиц — тогда данные можно переиспользовать в соседних запросах:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = ТекстПакетногоЗапроса;
Результат = Запрос.ВыполнитьПакет();
Плюс подхода — читаемость и скорость: платформа строит временную таблицу один раз, а дальше обращается к готовым данным. Минус — временные таблицы занимают память и место в базе tempdb (для клиент-серверного варианта), поэтому не держите в них лишние колонки.
Объединение наборов данных в СКД
Если результат нужен в отчёте, объединение собирают прямо в системе компоновки данных. В схеме компоновки добавляется набор данных типа «Объединение», а внутрь него вкладываются два набора-«Запроса». СКД сложит их строки так же, как оператор ОБЪЕДИНИТЬ ВСЕ.
Порядок действий в конструкторе схемы компоновки:
- На закладке
Наборы данныхнажмитеДобавить набор данных→Добавить набор данных - объединение. - Внутри него добавьте два набора данных типа «Запрос» с одинаковым набором полей.
- Проверьте, что имена полей в обоих наборах совпадают — СКД сопоставляет колонки по имени поля, а не по порядку. Если имена разошлись, во втором наборе переименуйте поле псевдонимом в запросе.
Второй способ в СКД — один набор-«Запрос», внутри которого уже стоит ОБЪЕДИНИТЬ ВСЕ. Он проще, когда обе выборки — к базе; набор «Объединение» выручает, когда части приходят из разных наборов (например, один запрос, а второй — внешний набор данных).
Не путайте «Объединение» со «связями наборов данных». Связи — это соединение по ключу (горизонтально), а объединение — укладка строк в стопку (вертикально).
Универсальная обработка для разовых задач
Разовое объединение двух таблиц из внешних источников (например, две выгрузки в табличных частях) удобно оформить внешней обработкой. Смысл — не изобретать новый механизм, а обернуть уже описанные приёмы в форму с кнопкой.
Логика обработки:
- на форме — две табличные части (или поля для выбора файлов-источников);
- обе выгрузки загружаются в
ТаблицаЗначенийметодомВыгрузить; - таблицы сливаются циклом с
ЗаполнитьЗначенияСвойств, при необходимости —Свернутьдля дублей; - результат показывается в третьей табличной части или выгружается обратно.
Табличную часть превращают в ТаблицаЗначений одной строкой, а дальше работают уже с привычным объектом:
Первая = Объект.ТабличнаяЧасть1.Выгрузить();
Вторая = Объект.ТабличнаяЧасть2.Выгрузить();
Для Каждого Строка Из Вторая Цикл
ЗаполнитьЗначенияСвойств(Первая.Добавить(), Строка);
КонецЦикла;
Объект.Результат.Загрузить(Первая); // показали итог в третьей таб. части
Такую обработку делают именно внешней (.epf), а не частью конфигурации: её переносят между базами без снятия с поддержки и обновлений. Для разовой задачи это аккуратнее, чем дорабатывать типовую.
Если источники — файлы Excel, их сначала читают в таблицу значений (через ПостроительЗапроса по макету или объект табличного документа), а затем сливают теми же двумя строками цикла. Механизм объединения от формата источника не зависит — меняется только способ загрузки.
ОБЪЕДИНИТЬ ВСЕ. Нужно убрать полные дубли — уберите ВСЕ.ЗаполнитьЗначенияСвойств, затем Свернуть от дублей.ПОМЕСТИТЬ и объедините их в финальном запросе пакета.ОБЪЕДИНИТЬ ВСЕ внутри одного запроса.Сравнение способов объединения
| Способ | Где данные | Дубли | Когда применять |
|---|---|---|---|
ОБЪЕДИНИТЬ ВСЕ | в базе | остаются | обычная выборка, дублей нет или не мешают |
ОБЪЕДИНИТЬ | в базе | убираются | нужны только уникальные строки |
Цикл + ЗаполнитьЗначенияСвойств | в памяти (ТЗ) | убираются Свернуть | таблицы уже собраны кодом |
| Временные таблицы | промежуточные расчёты | по оператору | сложный пакетный запрос из нескольких шагов |
| Набор «Объединение» в СКД | в отчёте | остаются | вывод в отчёт из разных наборов |
Запросные способы работают на стороне сервера и быстрее на больших объёмах. Программное слияние таблиц значений гибче, но вся обработка идёт в памяти — на десятках тысяч строк это ощутимо медленнее запроса.
Типичные ошибки при объединении
Ошибки здесь однотипные и легко узнаются по тексту платформы.
- ❌ «Число полей в запросе не совпадает с числом полей в объединяемом запросе». В выборках разное количество колонок. Приравняйте число полей; недостающие добавьте константами — например,
"" КАК Комментарийили0 КАК Количество. - ❌ Перепутали объединение и соединение. Ждали, что к строкам добавятся колонки из второй таблицы, а строки просто встали под низ. Нужны колонки — используйте
СОЕДИНЕНИЕпо ключу. - ❌ Поля перепутаны местами. Сопоставление идёт по порядку, а не по имени. Во всех выборках колонки должны идти в одной последовательности, иначе в одной колонке окажутся и коды, и наименования.
- ❌
ОБЪЕДИНИТЬтам, где хватило быОБЪЕДИНИТЬ ВСЕ. Запрос молча отрабатывает, но тратит время на поиск дублей, которых нет. На больших данных это лишняя нагрузка. - ❌
УПОРЯДОЧИТЬ ПОв середине. Сортировка относится ко всему объединённому результату, поэтому ставится один раз в самом конце — после последней выборки, а не после каждой.
Чем `ОБЪЕДИНИТЬ` отличается от `ОБЪЕДИНИТЬ ВСЕ`?
ОБЪЕДИНИТЬ ВСЕ оставляет все строки, ОБЪЕДИНИТЬ без ВСЕ дополнительно удаляет полностью совпадающие строки. Проверка на дубли замедляет запрос, поэтому ОБЪЕДИНИТЬ ВСЕ предпочтительнее, когда уникальность не нужна.Можно ли объединить таблицы с разным числом колонок?
0 КАК Количество, "" КАК Основание, ДАТАВРЕМЯ(1,1,1) КАК Дата.Чем объединение отличается от соединения таблиц?
Сколько таблиц можно объединить одним запросом?
ОБЪЕДИНИТЬ ВСЕ между каждой парой выборок — их может быть много. Важно лишь, чтобы во всех частях совпадало число и порядок колонок.Как объединить две таблицы значений с разными колонками в коде?
Колонки.Добавить, затем перенесите строки циклом с ЗаполнитьЗначенияСвойств — он копирует только совпадающие по имени поля.