В процессе работы с запросами в 1С часто возникают задачи, которые не решаются стандартными операторами. В таких ситуациях разработчику полезно иметь под рукой шпаргалку по языку запросов. Одна из таких задач — необходимость добавить (объединить) данные из второй таблицы к первой только при выполнении определенного условия: если первая таблица содержит хотя бы одну запись. Если же первая таблица пуста, итоговый результат тоже должен быть пустым.
Давайте разберем эту ситуацию. Стандартные операторы СОЕДИНЕНИЕ здесь не подходят, так как они предназначены для добавления столбцов по определенным связям, а не для добавления строк. Для добавления строк используется оператор ОБЪЕДИНИТЬ ВСЕ. Однако он не имеет встроенных условий для своего выполнения. Попытка решить эту задачу "в лоб" одним запросом приведет к сложностям, хотя такие методы позволяют обеспечить быстрый анализ данных и упростить работу аналитика.
Правильным и наиболее эффективным подходом для реализации такой условной логики в языке запросов 1С является использование пакетных запросов и временных таблиц. Для отладки подобных конструкций идеально подходит консоль запросов с полной поддержкой пакетных запросов и временных таблиц. Проанализируем этот метод по шагам.
Суть метода заключается в том, чтобы разбить нашу задачу на несколько последовательных шагов (пакетов):
ОБЪЕДИНИТЬ ВСЕ добавляем данные из второй таблицы. Но вторая выборка выполняется с хитрым условием в секции ГДЕ, которое проверяет, есть ли записи в нашей временной таблице.Такой подход гарантирует, что если в первом пакете ничего не будет выбрано, временная таблица останется пустой, и во втором пакете условие для объединения не выполнится, что приведет к пустому итоговому результату. При проектировании сложных схем можно также использовать консоль запросов для управляемых форм, которая поддерживает редактор объектов и логи ТЖ.
Рассмотрим исходную задачу. У нас есть две таблицы:
Ответственный, Подразделение, Выручка.Ассистент.Нам нужно получить итоговую таблицу со структурой ТаблицыА, в которую будут добавлены данные из ТаблицыБ (с сопоставлением полей и заполнением недостающих данных константами), но только если ТаблицаА не пустая.
Первым делом создадим временную таблицу, в которую поместим результат запроса к ТаблицеА. Назовем ее ВТ_ОсновнаяТаблица. Стоит отметить, что в современных версиях платформы появилось добавление данных в существующую временную таблицу, но в данном примере мы создаем таблицу "с нуля" в первом пакете запроса.
// -- Пакет 1: Создание временной таблицы с основными данными --
ВЫБРАТЬ
Т1.Ответственный,
Т1.Подразделение,
Т1.Выручка
ПОМЕСТИТЬ ВТ_ОсновнаяТаблица
ИЗ
ТаблицаА КАК Т1
ГДЕ
// Здесь могут быть ваши условия отбора для основной таблицы
; // <-- Важный момент: разделитель пакетов
После выполнения этого пакета у нас есть временная таблица ВТ_ОсновнаяТаблица, которая либо содержит данные, либо пуста, в зависимости от результатов выборки из ТаблицаА.
Теперь переходим ко второму, основному пакету. Здесь мы будем конструировать итоговый результат. Если ваша задача включает работу с иерархией, вам может пригодиться интерактивное формирование текста запроса для получения родителей всех уровней.
Запрос будет состоять из двух частей, соединенных через ОБЪЕДИНИТЬ ВСЕ.
Первая часть — простая выборка всех данных из нашей временной таблицы. Если она пуста, эта часть запроса ничего не вернет.
ВЫБРАТЬ
Ответственный,
Подразделение,
Выручка
ИЗ
ВТ_ОсновнаяТаблица
Вторая часть — это выборка из ТаблицаБ. И здесь кроется главный секрет. Мы добавляем условие ГДЕ, которое проверяет наличие записей во временной таблице ВТ_ОсновнаяТаблица с помощью вложенного запроса.
ВЫБРАТЬ
Т2.Ассистент КАК Ответственный,
NULL КАК Подразделение, // Заполняем недостающие поля константами или NULL
0 КАК Выручка
ИЗ
ТаблицаБ КАК Т2
ГДЕ
// Вот то самое условие!
(ВЫБРАТЬ КОЛИЧЕСТВО(1) ИЗ ВТ_ОсновнаяТаблица) > 0
Рассмотрим подробнее ключевую конструкцию: (ВЫБРАТЬ КОЛИЧЕСТВО(1) ИЗ ВТ_ОсновнаяТаблица) > 0.
ВЫБРАТЬ КОЛИЧЕСТВО(1) ИЗ ВТ_ОсновнаяТаблица подсчитывает количество записей в ранее созданной временной таблице. Это очень быстрая операция.ВТ_ОсновнаяТаблица содержит хотя бы одну запись, результат этого подзапроса будет больше нуля (например, 1, 5, 100), и условие > 0 станет истинным. В этом случае вторая часть ОБЪЕДИНИТЬ ВСЕ вернет данные из ТаблицаБ.ВТ_ОсновнаяТаблица пуста, подзапрос вернет 0, условие > 0 будет ложным, и вторая часть объединения вернет пустой результат.Обратите внимание, что мы приводим структуру выборки из ТаблицаБ к структуре ТаблицаА, используя псевдонимы полей (КАК Ответственный) и заполняя недостающие поля (Подразделение, Выручка) значениями по умолчанию, например NULL или 0.
Теперь соберем все части вместе. Полный пакетный запрос будет выглядеть так:
// -- Пакет 1: Создание временной таблицы с основными данными --
ВЫБРАТЬ
Т1.Ответственный,
Т1.Подразделение,
Т1.Выручка
ПОМЕСТИТЬ ВТ_ОсновнаяТаблица
ИЗ
ТаблицаА КАК Т1
ГДЕ
// ...ваши условия...
;
// -- Пакет 2: Финальная выборка с условным объединением --
ВЫБРАТЬ
Ответственный,
Подразделение,
Выручка
ИЗ
ВТ_ОсновнаяТаблица
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т2.Ассистент,
NULL, // Или "ПодразделениеПоУмолчанию"
0 // Константное значение для выручки
ИЗ
ТаблицаБ КАК Т2
ГДЕ
// Условие, которое выполнится, только если первая таблица не пустая
(ВЫБРАТЬ КОЛИЧЕСТВО(1) ИЗ ВТ_ОсновнаяТаблица) > 0
Сценарий 1: ТаблицаА содержит данные.
ВТ_ОсновнаяТаблица заполняется записями.ОБЪЕДИНИТЬ ВСЕ выбирает все записи из ВТ_ОсновнаяТаблица.(ВЫБРАТЬ КОЛИЧЕСТВО(1) ...) возвращает число больше 0. Условие в ГДЕ истинно.ОБЪЕДИНИТЬ ВСЕ выбирает данные из ТаблицаБ.ТаблицаА и ТаблицаБ. Задача выполнена.Сценарий 2: ТаблицаА пуста.
ВТ_ОсновнаяТаблица создается, но остается пустой.ОБЪЕДИНИТЬ ВСЕ пытается выбрать данные из пустой ВТ_ОсновнаяТаблица и возвращает пустой результат.(ВЫБРАТЬ КОЛИЧЕСТВО(1) ...) возвращает 0. Условие 0 > 0 ложно.ОБЪЕДИНИТЬ ВСЕ из-за ложного условия в ГДЕ также возвращает пустой результат.Таким образом, использование связки пакетного запроса, временной таблицы и вложенного запроса в условии ГДЕ позволяет элегантно и эффективно решать задачи с условной логикой, которые невозможно или очень сложно реализовать в рамках одного простого запроса.