Объединить все в запросе 1с
Несколько запросов можно объединить в один запрос. Для этого между двумя запросами нужно указать ключевое слово ОБЪЕДИНИТЬ ВСЕ.
Например, есть 3 таблицы:
Для того чтобы в одном запросе получить все записи из трех таблиц можно выполнить следующий запрос:
Таблиц в объединении может быть сколько угодно.
Количество полей в объединяемых запросах должно совпадать. Если попытаться выполнить следующий запрос:
У каждого запроса объединения свои секции ВЫБРАТЬ, ИЗ, СГРУППИРОВАТЬ ПО, ГДЕ. А секции УПОРЯДОЧИТЬ ПО и ИТОГИ общие.
Псевдоним для поля таблицы указывается только для первого запроса объединения. Если в разных таблицах одно поле имеет разный тип данных, то в результате запроса тип этого поля будет составным.
ОБЪЕДИНИТЬ ВСЕ и ОБЪЕДИНИТЬ
Помимо ОБЪЕДИНИТЬ ВСЕ для объединения можно использовать ключевое слово ОБЪЕДИНИТЬ. Например, если нужно выбрать только код справочника и выполнить запрос с ОБЪЕДИНИТЬ ВСЕ, то результат будет следующим:
То есть были выбраны все коды элементов из всех таблиц.
Если заменить ОБЪЕДИНИТЬ ВСЕ на ОБЪЕДИНИТЬ, то результат изменится:
В результате запроса остались только неповторяющиеся записи. То есть результат запроса был свернут по всем полям запроса. При этом достаточно, чтобы только в одном объединении было указано просто ОБЪЕДИНИТЬ, чтобы весь результат объединения был свернут:
//несмотря на то что здесь указано ВСЕ результат был свернут
Разница между соединением и объединением
Разница между соединением и объединением заключается в том, что при соединении будет выполнено горизонтальное соединение колонок разных таблиц. А при объединении будет выполнено вертикальное объединение строк разных таблиц, количество колонок останется без изменений.
В качестве источника в запросах можно указать несколько разных таблиц. Если не указать никакие условия для связи таблиц, то будет получено декартово произведение (все возможные комбинации строк) или как еще называют перекрестное соединение.
Например, в базе есть 2 таблицы: ЛеваяТаблица и ПраваяТаблица. Состав таблиц следующий:
В результате выполнения следующего запроса:
Будет получен такой результат:
Каждая запись из левой таблицы была связана с каждой записью из правой таблицы.
Виды соединений в запросе
Соединения нужны для того, чтобы соединить строки разных таблиц по какому-либо условию. Условия указываются после ключевого слова ПО. Может быть несколько условий при одном соединении.
Язык запросов 1С поддерживает следующие виды соединений:
- Внутреннее соединение
- Левое внешнее соединение
- Правое внешнее соединение
- Полное внешнее соединение
В запросах позволяется не указывать слова внутреннее и внешнее.
Внутреннее соединение
В результате внутреннего соединения таблиц в выборку попадут только те записи, которые удовлетворяют условию соединения:
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПраваяТаблица КАК ПраваяТаблица
В результат запроса не попала четвертая запись из левой таблицы, потому что для нее не нашлось записи в правой таблице, которая бы удовлетворяла условию ЛеваяТаблица.Код = ПраваяТаблица.Код.
Левое соединение
В результате левого соединения таблиц в выборку попадут все записи из левой таблицы, и только те записи из правой таблицы, которые удовлетворяют условию соединения:
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПраваяТаблица КАК ПраваяТаблица
В четвертой строке в полях ПравоеНаименование и ПравыйКод будет NULL.
Правое соединение
Это то же самое, что и левое соединение, только таблицы меняются местами. В результате правого соединения таблиц в выборку попадут все записи из правой таблицы, и только те записи из левой таблицы, которые удовлетворяют условию соединения. Очень редко используется на практике:
ПРАВОЕ СОЕДИНЕНИЕ Справочник.ПраваяТаблица КАК ПраваяТаблица
В четвертой строке в полях ЛевоеНаименование и ЛевыйКод будет NULL.
Полное соединение
ПОЛНОЕ СОЕДИНЕНИЕ Справочник.ЛеваяТаблица КАК ЛеваяТаблица
В четвертой строке в полях ЛевоеНаименование и ЛевыйКод будет NULL. В пятой строке в полях ПравоеНаименование и ПравыйКод будет NULL.
Два левых соединения в запросе
Допустим, что есть еще одна таблица со следующим содержимым:
И нужно связать и ее и правую таблицу с левой. Для этого можно использовать два левых соединения:
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПраваяТаблица КАК ПраваяТаблица ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ЕщеТаблица КАК ЕщеТаблица
Точно также можно связать и три таблицы, и четыре и т.д. То же самое относится и к внутреннему, правому и полному соединению.
Левое соединение с условием
Если при левом соединении наложить условие на поле правой таблицы, то соединение будет автоматически преобразовано во внутреннее соединение:
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПраваяТаблица КАК ПраваяТаблица
Чтобы получить правильный результат нужно условие перенести из предложения ГДЕ в условие соединения:
&НаСервере
Процедура ОбъединениеДвухТаблицВОдну ()
// Объединение "Контрагенты" и "Классификатор Сроков Полезного Использования"
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.Контрагенты
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.КлассификаторСроковПИ" );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ОбъединениеБолееДвухТаблицВОдну ()
// Объединение трех таблиц Контрагенты, Материалы и Страны
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.Контрагенты
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.Материалы
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.Страны" );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура СохранениеДубликатовВРезультатеОбъединенияТаблиц ()
// Объединение таблицы "Классификатор Сроков Полезного Использования" саму с собой так,
// чтобы дубликаты, которые получились сами по себе - остались в выборке (задвоились)
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.КлассификаторСроковПИ
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.КлассификаторСроковПИ" );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ОбъединениеТаблицСРазнымКоличествомПолей ()
// Создание дополнительных (недостающих) полей и заполнение их значениями
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование,
| Вес
|ИЗ
| Справочник.Материалы
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Наименование,
| 0
|ИЗ
| Справочник.Контрагенты" );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура УпорядочиваниеПриОбъединенииТаблиц ()
// Упорядочивание таблиц Материалы и КлассификаторСроковПИ по наименованию (алфавиту)
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.Материалы
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Наименование
|ИЗ
| Справочник.КлассификаторСроковПИ
|
|УПОРЯДОЧИТЬ ПО
| Наименование УБЫВ" );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
Учитывая, сколько нового я узнала из комментариев к предыдущей моей публикации, не могу не продолжить свой цикл статей по оптимизации. Критика и комментарии приветствуются.
На этот раз посмотрим оптимизацию запроса. Итак, имеется ЗУП версии 2.5.319.1 СУБД - MS SQL Платформа версии 8.3.14.1565 режим совместимости 8.2.13
От пользователей поступили жалобы на долгое формирование печатной формы Т13 из документа "Табель учета рабочего времени". Проверяем работу на тестовой базе под полными правами.
Включаем замер производительности, и в топ вылезает выполнение запроса.
Аж 34 секунды! Этот запрос растянулся больше, чем на 1000 строк, и понять без профайлера, где проблема, невозможно.
Данные, собранные подсистемой оценки производительности:
Как видно, apdex болтается где-то на дне. (Какая милая опечатка "дукумент"!) А среднее время выполнения операции на рабочей базе 25 секунд.
Итак, для настройки профайлера узнаем ID базы:
Настроим профайлер, выбрав необходимые события и установив отборы по длительности и ID базы:
На этот раз запрос выполнился быстрее, за 9 секунд. Находим самый тяжелый запрос:
Находим его в базе 1с:
Посмотрим структуру регистра сведений. Непериодический, независимый со следующими измерениями:
Казалось бы, как оптимизировать этот запрос? Он написан согласно рекомендациям от 1С, но индекс почему-то не используется, хотя стоят условия по первому измерению. Но ради эксперимента, давайте перепишем запрос, используя "ИЛИ":
И что же мы видим?
Выполнение запроса меньше чем за секунду.
Текст запроса на языке SQL:
После обновления в рабочей базы:
Аpdex по этой операции вырос до 0,914. Среднее время выполнения операции - 3 секунды.
Послесловие
На самом деле это не первый запрос в моей практике, где "ИЛИ" работает лучше чем "ОБЪЕДИНИТЬ ВСЕ". Почему оптимизатор не использовал индекс, ведь условие подходит? У меня есть предположение, что это зависит от версии СУБД. Но это только предположение, если у кого есть идеи лучше, пишите в комментариях.
Читайте также: