Переход с платформы 1С 8.x на 1С 7.7 часто вызывает у разработчиков культурный шок, особенно когда дело касается языка запросов. В «восьмерке» мы привыкли к мощному SQL-подобному синтаксису с операторами ОБЪЕДИНИТЬ (UNION) и СОЕДИНЕНИЕ (JOIN). В штатном языке запросов 1С 7.7 (так называемом «черном запросе») таких операторов просто не существует. Однако задачи по объединению данных из разных регистров или документов никуда не исчезают. Разберем подробно, как можно решить эту задачу, используя доступные инструменты «семерки».
Рассмотрим ситуацию, когда нам нужно собрать данные по остаткам или оборотам из двух похожих регистров (например, «Покупатели» и «Поставщики»). В 1С 7.7 предусмотрен механизм, который позволяет «схлопывать» данные из разных таблиц прямо в описании переменных запроса. Если мы перечислим источники через запятую, система попытается объединить их по группировкам.
Проанализируем пример кода:
ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|Фирма = Регистр.Покупатели.Фирма, Регистр.Поставщики.Фирма;
|Контрагент = Регистр.Покупатели.Договор.Владелец, Регистр.Поставщики.Договор.Владелец;
|Сумма = Регистр.Покупатели.СуммаРуб, Регистр.Поставщики.СуммаРуб;
|Функция ПриходСумма = Приход(Сумма);
|Группировка Контрагент без групп;
|";
Важные нюансы этого метода:
Если штатный запрос не справляется или вам нужно объединить данные из регистра и шапки документа, наиболее стабильным и гибким способом является использование объекта ТаблицаЗначений. Рассмотрим этот алгоритм по шагам.
Сначала мы выполняем первый запрос и выгружаем его в таблицу:
Запрос1 = СоздатьОбъект("Запрос");
Текст1 = "// Описание запроса к Регистру...";
Если Запрос1.Выполнить(Текст1) = 1 Тогда
ТЗ_Итог = СоздатьОбъект("ТаблицаЗначений");
Запрос1.Выгрузить(ТЗ_Итог);
КонецЕсли;
Затем мы выполняем второй запрос и добавляем его данные в ту же таблицу:
Запрос2 = СоздатьОбъект("Запрос");
Текст2 = "// Описание запроса к Документам...";
Если Запрос2.Выполнить(Текст2) = 1 Тогда
ТЗ_Временная = СоздатьОбъект("ТаблицаЗначений");
Запрос2.Выгрузить(ТЗ_Временная);
// Копируем строки из временной таблицы в основную
ТЗ_Временная.ВыбратьСтроки();
Пока ТЗ_Временная.ПолучитьСтроку() = 1 Цикл
ТЗ_Итог.НоваяСтрока();
// Здесь важно сопоставить колонки вручную, если они не совпадают
ТЗ_Итог.Контрагент = ТЗ_Временная.Контрагент;
ТЗ_Итог.Сумма = ТЗ_Временная.Сумма;
КонецЦикла;
КонецЕсли;
На финальном этапе мы используем метод Свернуть, который является аналогом GROUP BY в SQL и позволяет просуммировать данные по общим измерениям:
// Группируем по Контрагенту, суммируем поле Сумма
ТЗ_Итог.Свернуть("Контрагент", "Сумма");
ТЗ_Итог.Сортировать("Контрагент+");
Этот метод позволяет обойти любые ограничения языка запросов 1С 7.7, так как вся логика объединения переносится в программный код.
Для высоконагруженных систем или сложных отчетов (например, акты сверки за несколько лет) штатные средства 1С 7.7 работают крайне медленно. В профессиональной среде для решения задачи UNION используют внешнюю компоненту 1С++. Она позволяет писать запросы на чистом SQL (T-SQL для версии SQL или через драйвер ODBC для DBF).
Выясним причину популярности этого метода. С помощью объекта Recordset мы можем написать запрос, который физически объединит таблицы на уровне базы данных:
ТекстЗапроса = "
|SELECT
| $Рег.Контрагент as [Контрагент $Справочник.Контрагенты],
| $Рег.СуммаРуб as Сумма
|FROM
| $Регистр.Покупатели as Рег
|
|UNION ALL
|
|SELECT
| $Док.Контрагент as [Контрагент $Справочник.Контрагенты],
| $Док.ИтогСумма as Сумма
|FROM
| $Документ.Реализация as Док
|";
Преимущества прямого SQL-запроса:
UNION, UNION ALL, подзапросы и любые типы соединений.Выбор метода объединения в 1С 7.7 зависит от сложности задачи:
Свернуть().Помните, что 1С 7.7 не прощает ошибок в синтаксисе запроса: любая попытка вставить ключевое слово ОБЪЕДИНИТЬ приведет к ошибке исполнения, так как это слово зарезервировано для будущего использования или просто не поддерживается парсером штатных запросов.